Exemple #1
0
    def __init__(self, id, coordinate, proc_engine):
        self.id = id
        self.coordinate = coordinate
        self.proc_engine = proc_engine
        self.logger = logging.getLogger(' ')

        # Process Attribute
        self.vcs_dictionary = NodeArray()
        self.vcs_target_north = []
        self.vcs_target_south = []
        self.vcs_target_east = []
        self.vcs_target_west = []
        self.vcs_target_pe = []
Exemple #2
0
    def __init__(self, env, id, coordinate, proc_engine):
        self.action = env.process(self.run())
        self.env = env
        self.id = id
        self.coordinate = coordinate
        self.proc_engine = proc_engine
        self.logger = logging.getLogger(' ')
        self.noc = None

        # Process Attribute
        self.vcs_dictionary = NodeArray()
        self.vcs_target_north = []
        self.vcs_target_south = []
        self.vcs_target_east = []
        self.vcs_target_west = []
        self.vcs_target_pe = []
        self.pipelined_sending = []
Exemple #3
0
 def setUp(self):
     self.nodeArray = NodeArray()
     self.vc_src = VirtualChannel(1, Direction.east, None, 1, 1)
     self.vc_target = VirtualChannel(1, Direction.east, None, 1, 1)
Exemple #4
0
class TestNode(unittest.TestCase):
    def setUp(self):
        self.nodeArray = NodeArray()
        self.vc_src = VirtualChannel(1, Direction.east, None, 1, 1)
        self.vc_target = VirtualChannel(1, Direction.east, None, 1, 1)

    def test_add(self):
        node = Node(self.vc_src, self.vc_target)
        self.nodeArray.add(node)

        self.assertEqual(len(self.nodeArray.array), 1)

        node2 = Node(self.vc_src, self.vc_target)
        self.nodeArray.add(node2)

        self.assertEqual(len(self.nodeArray.array), 2)

    def test_remove(self):
        node = Node(self.vc_src, self.vc_target)
        self.nodeArray.add(node)
        node2 = Node(self.vc_src, self.vc_target)
        self.nodeArray.add(node2)

        self.nodeArray.remove(self.vc_src)
        self.assertEqual(len(self.nodeArray.array), 1)

        self.nodeArray.remove(self.vc_src)
        self.assertEqual(len(self.nodeArray.array), 0)

    def test_get_target(self):
        node = Node(self.vc_src, self.vc_target)
        self.nodeArray.add(node)

        self.assertEqual(self.nodeArray.get_target(self.vc_src),
                         self.vc_target)

        self.nodeArray.remove(self.vc_src)

        self.assertIsNone(self.nodeArray.get_target(self.vc_src))
Exemple #5
0
class Router:
    def __init__(self, id, coordinate, proc_engine):
        self.id = id
        self.coordinate = coordinate
        self.proc_engine = proc_engine
        self.logger = logging.getLogger(' ')

        # Process Attribute
        self.vcs_dictionary = NodeArray()
        self.vcs_target_north = []
        self.vcs_target_south = []
        self.vcs_target_east = []
        self.vcs_target_west = []
        self.vcs_target_pe = []

    def inport_setting(self, inNorth, inSouth, inEast, inWest):
        self.inNorth = inNorth
        self.inSouth = inSouth
        self.inEast = inEast
        self.inWest = inWest

    def outport_setting(self, outNorth, outSouth, outEast, outWest):
        self.outNorth = outNorth
        self.outSouth = outSouth
        self.outEast = outEast
        self.outWest = outWest

    def proc_engine_setting(self, inPE, outPE):
        self.inPE = inPE
        self.outPE = outPE

    def route_computation(self, flit):
        # On X axe (Column)
        # By the West
        if self.coordinate.j > flit.destination.j:
            return self.outWest
        # By the East
        elif self.coordinate.j < flit.destination.j:
            return self.outEast
        # On Y axe (Row)
        else:
            if self.coordinate.i > flit.destination.i:
                return self.outNorth
            # By the East
            elif self.coordinate.i < flit.destination.i:
                return self.outSouth
            else:
                # Destination Reached
                return self.outPE

    def send_flit(self, vc, outport, time):

        if len(vc.flits) <= 0:
            return

        # getting the first flit in VC
        flit = vc.dequeue()
        if flit is None:
            return

        # if is a Head Flit
        if flit.type == FlitType.head:
            self.logger.debug('Time : (%d) - %s ready to be sent' % (time, flit))

            # Get idle VC from next Input
            vc_allotted = outport.inPort.vc_allocator()

            if vc_allotted is not None:
                self.logger.debug('Time : (%d) - VC (%s) allotted' % (time, vc_allotted))

                # send flit
                vc_allotted.enqueue(flit)
                self.logger.info('(%d) : %s - %s -> %s -> %s' % (time, flit, self, vc_allotted, vc_allotted.router))
                vc.credit_out()
                # registering VC allotted in dictionary
                self.vcs_dictionary.add(Node(vc, vc_allotted))
                # Next routing
                event = Event(EventType.VC_ELECTION, vc_allotted.router, time + 1)
                EVENT_LIST.push(event)

            else:  # No idle VC
                vc.restore(flit)  # restore
                # event push
                event = Event(EventType.SEND_FLIT, {'router': self,
                                                    'vc': vc,
                                                    'outport': outport}, time + 1)

                EVENT_LIST.push(event)
                self.logger.debug('Time : (%d) - %s was not sent - VC not allotted' % (time, flit))

        # if is a Body Flit
        elif flit.type == FlitType.body:
            self.logger.debug('Time : (%d) - %s ready to be sent' % (time, flit))
            # Getting the alloted vc
            vc_allotted = self.vcs_dictionary.get_target(vc)
            self.logger.debug('Time : (%d) - Retreiving allotted VC (%s)' % (time, vc_allotted))

            # Sending to the next router
            sent = vc_allotted.enqueue(flit)

            if not sent:  # No Place
                vc.restore(flit)  # restore
                # event push
                event = Event(EventType.SEND_FLIT, {'router': self,
                                                    'vc': vc,
                                                    'outport': outport}, time + 1)
                EVENT_LIST.push(event)
                self.logger.debug('Time : (%d) - %s was not sent - No Place in VC (%s)' % (time, flit, vc_allotted))

            else:
                # Next routing
                event = Event(EventType.VC_ELECTION, vc_allotted.router, time + 1)
                EVENT_LIST.push(event)
                self.logger.info('(%d) : %s - %s -> %s -> %s' % (time, flit, self, vc_allotted, vc_allotted.router))
                vc.credit_out()

        # if is a Tail Flit
        elif flit.type == FlitType.tail:
            self.logger.debug('Time : (%d) - %s ready to be sent' % (time, flit))

            # Getting the alloted vc
            vc_allotted = self.vcs_dictionary.get_target(vc)

            # Sending to the next router
            sent = vc_allotted.enqueue(flit)

            if not sent:  # No Place
                vc.restore(flit)  # restore
                # event push
                event = Event(EventType.SEND_FLIT, {'router': self,
                                                    'vc': vc,
                                                    'outport': outport}, time + 1)
                EVENT_LIST.push(event)
                self.logger.debug('Time : (%d) - %s was not sent - No Place in VC (%s)' % (time, flit, vc_allotted))

            else:
                self.logger.info('(%d) : %s - %s -> %s -> %s' % (time, flit, self, vc_allotted, vc_allotted.router))
                # Next routing
                event = Event(EventType.VC_ELECTION, vc_allotted.router, time + 1)
                EVENT_LIST.push(event)

                self.vcs_dictionary.remove(vc)
                vc.lock = False
                vc.credit_out()
                self.logger.debug('Time : (%d) - VC (%s) - released' % (time, vc))

        # If Quantum is finished
        if vc.quantum <= 0:
            # print('Quantum or VC finished for : %s' % vc)
            self.logger.debug('Time : (%d) - VC (%s) - quantum finished' % (time, vc))
            # new VC Election - event push
            event = Event(EventType.VC_ELECTION, self, time + 1)
            EVENT_LIST.push(event)
        elif len(vc.flits) <= 0:
            self.logger.debug('Time : (%d) - VC (%s) - NO Flits' % (time, vc))
            # new VC Election - event push
            event = Event(EventType.VC_ELECTION, self, time + 1)
            EVENT_LIST.push(event)

        # Another Quantum
        else:
            self.logger.debug('Time : (%d) - VC (%s) - quantum NOT finished' % (time, vc))
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': outport}, time + 1)
            EVENT_LIST.push(event)

    def arrived_flit(self, vc, time):
        flit = vc.dequeue()

        if flit.type == FlitType.tail:
            self.vcs_dictionary.remove(vc)
            vc.lock = False

        flit.set_arrival_time(time)

        # Flit store
        self.proc_engine.flit_receiving(flit)

        self.logger.info('(%d) : %s - %s -> %s' % (time, flit, self, self.proc_engine))

    """
    Fixed Round-Robin Arbitration
    """

    def vc_target_outport(self, vc):
        if len(vc.flits) > 0:
            if self.route_computation(vc.flits[0]) == self.outNorth \
                    and vc not in self.vcs_target_north:
                self.vcs_target_north.append(vc)
                vc.reset_credit()
            elif self.route_computation(vc.flits[0]) == self.outSouth \
                    and vc not in self.vcs_target_south:
                self.vcs_target_south.append(vc)
                vc.reset_credit()
            elif self.route_computation(vc.flits[0]) == self.outEast \
                    and vc not in self.vcs_target_east:
                self.vcs_target_east.append(vc)
                vc.reset_credit()
            elif self.route_computation(vc.flits[0]) == self.outWest \
                    and vc not in self.vcs_target_west:
                self.vcs_target_west.append(vc)
                vc.reset_credit()
            elif self.route_computation(vc.flits[0]) == self.outPE \
                    and vc not in self.vcs_target_pe:
                self.vcs_target_pe.append(vc)

    def rr_arbiter(self, time):

        for vc in self.inPE.vcs:
            self.vc_target_outport(vc)
        # Checking North VC
        for vc in self.inNorth.vcs:
            self.vc_target_outport(vc)
        # Checking South VC
        for vc in self.inSouth.vcs:
            self.vc_target_outport(vc)
        # Checking East VC
        for vc in self.inEast.vcs:
            self.vc_target_outport(vc)
        # Checking West VC
        for vc in self.inWest.vcs:
            self.vc_target_outport(vc)

        # VC targeting -> North
        if len(self.vcs_target_north) > 0:
            vc = self.vcs_target_north.pop(0)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outNorth}, time)
            EVENT_LIST.push(event)

        # VC targeting -> South
        if len(self.vcs_target_south) > 0:
            vc = self.vcs_target_south.pop(0)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outSouth}, time)
            EVENT_LIST.push(event)

        # VC targeting -> East
        if len(self.vcs_target_east) > 0:
            vc = self.vcs_target_east.pop(0)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outEast}, time)
            EVENT_LIST.push(event)

        # VC targeting -> West
        if len(self.vcs_target_west) > 0:
            vc = self.vcs_target_west.pop(0)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outWest}, time)
            EVENT_LIST.push(event)

        # VC targeting -> PE
        if len(self.vcs_target_pe) > 0:
            vc = self.vcs_target_pe.pop(0)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.ARR_FLIT, {'router': self, 'vc': vc}, time)
            EVENT_LIST.push(event)

    """
    Priority-based Arbitration
    """

    def priority_arbiter(self, time):
        for vc in self.inPE.vcs:
            self.vc_target_outport(vc)
        # Checking North VC
        for vc in self.inNorth.vcs:
            self.vc_target_outport(vc)
        # Checking South VC
        for vc in self.inSouth.vcs:
            self.vc_target_outport(vc)
        # Checking East VC
        for vc in self.inEast.vcs:
            self.vc_target_outport(vc)
        # Checking West VC
        for vc in self.inWest.vcs:
            self.vc_target_outport(vc)

        # VC targeting -> North
        if len(self.vcs_target_north) > 0:
            vc = self.get_most_prioritized_vc(self.vcs_target_north)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outNorth}, time)
            EVENT_LIST.push(event)

        # VC targeting -> South
        if len(self.vcs_target_south) > 0:
            vc = self.get_most_prioritized_vc(self.vcs_target_south)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outSouth}, time)
            EVENT_LIST.push(event)

        # VC targeting -> East
        if len(self.vcs_target_east) > 0:
            vc = self.get_most_prioritized_vc(self.vcs_target_east)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outEast}, time)
            EVENT_LIST.push(event)

        # VC targeting -> West
        if len(self.vcs_target_west) > 0:
            vc = self.get_most_prioritized_vc(self.vcs_target_west)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': self.outWest}, time)
            EVENT_LIST.push(event)

        # VC targeting -> PE
        if len(self.vcs_target_pe) > 0:
            vc = self.get_most_prioritized_vc(self.vcs_target_pe)
            self.logger.debug('Time : (%d) - %s -> Elected' % (time, vc))
            # event push
            event = Event(EventType.ARR_FLIT, {'router': self, 'vc': vc}, time)
            EVENT_LIST.push(event)

    def send_flit_by_priority(self, vc, outport, time):

        if len(vc.flits) <= 0:
            return

        # getting the first flit in VC
        flit = vc.dequeue()
        if flit is None:
            return

        # if is a Head Flit
        if flit.type == FlitType.head:
            self.logger.debug('Time : (%d) - %s ready to be sent' % (time, flit))

            # Get idle VC from next Input
            vc_allotted = outport.inPort.priority_vc_allocator(flit.get_priority())

            if vc_allotted is not None:
                self.logger.debug('Time : (%d) - VC (%s) allotted' % (time, vc_allotted))

                # send flit
                vc_allotted.enqueue(flit)
                self.logger.info('(%d) : %s - %s -> %s -> %s' % (time, flit, self, vc_allotted, vc_allotted.router))
                vc.credit_out()
                # registering VC allotted in dictionary
                self.vcs_dictionary.add(Node(vc, vc_allotted))
                # Next routing
                event = Event(EventType.VC_ELECTION, vc_allotted.router, time + 1)
                EVENT_LIST.push(event)

            else:  # No idle VC
                vc.restore(flit)  # restore
                # event push
                event = Event(EventType.SEND_FLIT, {'router': self,
                                                    'vc': vc,
                                                    'outport': outport}, time + 1)

                EVENT_LIST.push(event)
                self.logger.debug('Time : (%d) - %s was not sent - VC not allotted' % (time, flit))

        # if is a Body Flit
        elif flit.type == FlitType.body:
            self.logger.debug('Time : (%d) - %s ready to be sent' % (time, flit))
            # Getting the alloted vc
            vc_allotted = self.vcs_dictionary.get_target(vc)
            self.logger.debug('Time : (%d) - Retreiving allotted VC (%s)' % (time, vc_allotted))

            # Sending to the next router
            sent = vc_allotted.enqueue(flit)

            if not sent:  # No Place
                vc.restore(flit)  # restore
                # event push
                event = Event(EventType.SEND_FLIT, {'router': self,
                                                    'vc': vc,
                                                    'outport': outport}, time + 1)
                EVENT_LIST.push(event)
                self.logger.debug('Time : (%d) - %s was not sent - No Place in VC (%s)' % (time, flit, vc_allotted))

            else:
                # Next routing
                event = Event(EventType.VC_ELECTION, vc_allotted.router, time + 1)
                EVENT_LIST.push(event)
                self.logger.info('(%d) : %s - %s -> %s -> %s' % (time, flit, self, vc_allotted, vc_allotted.router))
                vc.credit_out()

        # if is a Tail Flit
        elif flit.type == FlitType.tail:
            self.logger.debug('Time : (%d) - %s ready to be sent' % (time, flit))

            # Getting the alloted vc
            vc_allotted = self.vcs_dictionary.get_target(vc)

            # Sending to the next router
            sent = vc_allotted.enqueue(flit)

            if not sent:  # No Place
                vc.restore(flit)  # restore
                # event push
                event = Event(EventType.SEND_FLIT, {'router': self,
                                                    'vc': vc,
                                                    'outport': outport}, time + 1)
                EVENT_LIST.push(event)
                self.logger.debug('Time : (%d) - %s was not sent - No Place in VC (%s)' % (time, flit, vc_allotted))

            else:
                self.logger.info('(%d) : %s - %s -> %s -> %s' % (time, flit, self, vc_allotted, vc_allotted.router))
                # Next routing
                event = Event(EventType.VC_ELECTION, vc_allotted.router, time + 1)
                EVENT_LIST.push(event)

                self.vcs_dictionary.remove(vc)
                vc.lock = False
                vc.credit_out()
                self.logger.debug('Time : (%d) - VC (%s) - released' % (time, vc))

        # If Quantum is finished
        if vc.quantum <= 0:
            # print('Quantum or VC finished for : %s' % vc)
            self.logger.debug('Time : (%d) - VC (%s) - quantum finished' % (time, vc))
            # new VC Election - event push
            event = Event(EventType.VC_ELECTION, self, time + 1)
            EVENT_LIST.push(event)
        elif len(vc.flits) <= 0:
            self.logger.debug('Time : (%d) - VC (%s) - NO Flits' % (time, vc))
            # new VC Election - event push
            event = Event(EventType.VC_ELECTION, self, time + 1)
            EVENT_LIST.push(event)

        # Another Quantum
        else:
            self.logger.debug('Time : (%d) - VC (%s) - quantum NOT finished' % (time, vc))
            event = Event(EventType.SEND_FLIT, {'router': self,
                                                'vc': vc,
                                                'outport': outport}, time + 1)
            EVENT_LIST.push(event)

    def get_most_prioritized_vc(self, vcs_target):
        priority = sys.maxsize  # lowest priority

        for i in range(len(vcs_target)):
            if vcs_target[i].id < priority:
                priority = i
        return vcs_target[priority]

    def __str__(self):
        return 'Router (%d,%d)' % (self.coordinate.i, self.coordinate.j)
Exemple #6
0
class Router:
    def __init__(self, env, id, coordinate, proc_engine):
        self.action = env.process(self.run())
        self.env = env
        self.id = id
        self.coordinate = coordinate
        self.proc_engine = proc_engine
        self.logger = logging.getLogger(' ')
        self.noc = None

        # Process Attribute
        self.vcs_dictionary = NodeArray()
        self.vcs_target_north = []
        self.vcs_target_south = []
        self.vcs_target_east = []
        self.vcs_target_west = []
        self.vcs_target_pe = []
        self.pipelined_sending = []

    def inport_setting(self, inNorth, inSouth, inEast, inWest):
        self.inNorth = inNorth
        self.inSouth = inSouth
        self.inEast = inEast
        self.inWest = inWest

    def outport_setting(self, outNorth, outSouth, outEast, outWest):
        self.outNorth = outNorth
        self.outSouth = outSouth
        self.outEast = outEast
        self.outWest = outWest

    def proc_engine_setting(self, inPE, outPE):
        self.inPE = inPE
        self.outPE = outPE

    def noc_settings(self, noc):
        self.noc = noc

    def run(self):
        while True:
            yield self.env.timeout(1)

            if self.noc.arbitration == "RR":
                self.rr_arbitration()

            elif self.noc.arbitration == "PRIORITY_PREEMPT":
                self.priority_preemptive_arbitration()

    def route_computation(self, flit):
        # On X axe (Column)
        # By the West
        if self.coordinate.j > flit.destination.j:
            return self.outWest
        # By the East
        elif self.coordinate.j < flit.destination.j:
            return self.outEast
        # On Y axe (Row)
        else:
            if self.coordinate.i > flit.destination.i:
                return self.outNorth
            # By the East
            elif self.coordinate.i < flit.destination.i:
                return self.outSouth
            else:
                # Destination Reached
                return self.outPE

    def is_packet_still_in_vc(self, packet):
        if self.inPE.is_packet_still_in_vc(packet) or \
                self.inSouth.is_packet_still_in_vc(packet) or \
                self.inNorth.is_packet_still_in_vc(packet) or \
                self.inWest.is_packet_still_in_vc(packet) or \
                self.inEast.is_packet_still_in_vc(packet):
            return True
        else:
            return False

    def receiving_from_pe(self, packet):
        if self.is_packet_still_in_vc(packet):
            return False

        if self.noc.arbitration == "RR":
            requested_vc = self.inPE.vc_allocator()
        elif self.noc.arbitration == "PRIORITY_PREEMPT":
            requested_vc = self.inPE.priority_vc_allocator(packet.priority)
        else:
            requested_vc = None

        if requested_vc is not None:
            for flit in packet.flits:
                requested_vc.enqueue(flit)
                self.logger.info(
                    '(%d) : %s - %s -> %s -> %s' % (self.env.now, flit, self.proc_engine, requested_vc, self))

                # set depart time for the first first in the first packet
                if flit.id == 0 and flit.packet.id == 0:
                    flit.packet.message.set_depart_time(self.env.now)

            return True
        else:
            return False

    def vc_target_outport(self, vc):

        if len(vc.flits) > 0:
            if self.route_computation(vc.flits[0]) == self.outNorth \
                    and vc not in self.vcs_target_north:
                self.vcs_target_north.append(vc)

            elif self.route_computation(vc.flits[0]) == self.outSouth \
                    and vc not in self.vcs_target_south:
                self.vcs_target_south.append(vc)

            elif self.route_computation(vc.flits[0]) == self.outEast \
                    and vc not in self.vcs_target_east:
                self.vcs_target_east.append(vc)

            elif self.route_computation(vc.flits[0]) == self.outWest \
                    and vc not in self.vcs_target_west:
                self.vcs_target_west.append(vc)

            elif self.route_computation(vc.flits[0]) == self.outPE \
                    and vc not in self.vcs_target_pe:
                self.vcs_target_pe.append(vc)

    def arrived_flit(self, vc):
        flit = vc.dequeue()

        # Flit Timestamp to avoid premature sending
        if flit.timestamp == self.env.now:
            vc.restore(flit)
            return

        flit.timestamp = copy.copy(self.env.now)

        if flit.type == FlitType.tail:
            self.vcs_dictionary.remove(vc)
            vc.release()

        vc.credit_out()

        # Flit store
        self.proc_engine.flit_receiving(flit)

        TRACESET.set_flit_arrival(flit.packet.message, self.env.now)

        # set arrival time to the last flit into the message
        nb_flit = PACKET_DEFAULT_SIZE / FLIT_DEFAULT_SIZE
        nb_packet = math.ceil(flit.packet.message.size / PACKET_DEFAULT_SIZE)

        if flit.id == nb_flit - 1 and flit.packet.id == nb_packet - 1:
            flit.packet.message.set_arrival_time(self.env.now + 1)

        self.logger.info('(%d) : %s - %s -> %s' % (self.env.now, flit, self, self.proc_engine))

    def send_flit(self, vc, outport):

        # getting the first flit in VC
        flit = vc.dequeue()

        # Flit Timestamp to avoid premature sending
        if flit.timestamp == self.env.now:
            vc.restore(flit)
            return

        # if is a Head Flit
        if flit.type == FlitType.head:

            # Get idle VC from next Input
            if self.noc.arbitration == "RR":
                vc_allotted = outport.inPort.vc_allocator()
            elif self.noc.arbitration == "PRIORITY_PREEMPT":
                vc_allotted = outport.inPort.priority_vc_allocator(flit.packet.priority)
            else:
                vc_allotted = None

            if vc_allotted is not None:
                self.logger.debug('(%d) - VC (%s) allotted' % (self.env.now, vc_allotted))
                vc_allotted.enqueue(flit)
                flit.timestamp = copy.copy(self.env.now)
                self.logger.info(
                    '(%d) : %s ON %s- %s -> %s -> %s' % (self.env.now, flit, vc, self, vc_allotted, vc_allotted.router))
                # vc.credit_out()

                # registering VC allotted in dictionary
                self.vcs_dictionary.add(Node(vc, vc_allotted))

            else:  # No idle VC
                vc.restore(flit)  # restore
                self.logger.debug('(%d) - %s was not sent - VC not allotted ON %s' %
                                  (self.env.now, flit, outport.inPort.router))
                # outport.inPort.vcs_status()
                # time.sleep(1)

        # if is a Body Flit
        elif flit.type == FlitType.body:
            # Getting the alloted vc
            vc_allotted = self.vcs_dictionary.get_target(vc)
            self.logger.debug('(%d) - Retreiving allotted VC (%s)' % (self.env.now, vc_allotted))

            # Sending to the next router
            sent = vc_allotted.enqueue(flit)

            if not sent:  # No Place
                vc.restore(flit)  # restore
                self.logger.debug('(%d) - %s was not sent - No Place in VC (%s)' % (self.env.now, flit, vc_allotted))
            else:
                self.logger.info(
                    '(%d) : %s ON %s- %s -> %s -> %s' % (self.env.now, flit, vc, self, vc_allotted, vc_allotted.router))
                # vc.credit_out()
                flit.timestamp = copy.copy(self.env.now)

        # if is a Tail Flit
        elif flit.type == FlitType.tail:
            # Getting the alloted vc
            vc_allotted = self.vcs_dictionary.get_target(vc)

            # Sending to the next router
            sent = vc_allotted.enqueue(flit)

            if not sent:  # No Place
                vc.restore(flit)  # restore
                self.logger.debug('(%d) - %s was not sent - No Place in VC (%s)' % (self.env.now, flit, vc_allotted))
            else:
                self.vcs_dictionary.remove(vc)
                flit.timestamp = copy.copy(self.env.now)
                # vc.credit_out()
                vc.release()
                self.logger.debug('(%d) - VC (%s) - released' % (self.env.now, vc))

        vc.credit_out()

    def rr_arbitration(self):
        # ---------- VC election ----------
        for vc in self.inPE.vcs:
            self.vc_target_outport(vc)
        # Checking North VC
        for vc in self.inNorth.vcs:
            self.vc_target_outport(vc)
        # Checking South VC
        for vc in self.inSouth.vcs:
            self.vc_target_outport(vc)
        # Checking East VC
        for vc in self.inEast.vcs:
            self.vc_target_outport(vc)
        # Checking West VC
        for vc in self.inWest.vcs:
            self.vc_target_outport(vc)

        # VC targeting -> North
        if len(self.vcs_target_north) > 0:
            vc = self.vcs_target_north.pop(0)
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outNorth)

            # re-insert if credit is not finished
            self.vc_reinsertion(vc, self.vcs_target_north)

        # VC targeting -> South
        if len(self.vcs_target_south) > 0:
            vc = self.vcs_target_south.pop(0)
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outSouth)

            # re-insert if credit is not finished
            self.vc_reinsertion(vc, self.vcs_target_south)

        # VC targeting -> East
        if len(self.vcs_target_east) > 0:
            vc = self.vcs_target_east.pop(0)
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outEast)

            # re-insert if credit is not finished
            self.vc_reinsertion(vc, self.vcs_target_east)

        # VC targeting -> West
        if len(self.vcs_target_west) > 0:
            vc = self.vcs_target_west.pop(0)
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outWest)

            # re-insert if credit is not finished
            self.vc_reinsertion(vc, self.vcs_target_west)

        # VC targeting -> PE
        if len(self.vcs_target_pe) > 0:
            vc = self.vcs_target_pe.pop(0)
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.arrived_flit(vc)

            # re-insert if credit is not finished
            self.vc_reinsertion(vc, self.vcs_target_pe)

    def vc_reinsertion(self, vc, target_queue):
        if vc.quantum > 0 and len(vc.flits) > 0:
            target_queue.insert(0, vc)
        else:
            vc.reset_credit()

    def get_highest_preemptive_priority_vc(self, candidates):

        # No Arbitration
        if len(candidates) == 1:
            return candidates[0]

        # filtering by timestamp
        for can in candidates:
            if can.flits[-1].timestamp == self.env.now:
                candidates.remove(can)

        priority_vc = candidates[0]

        # Arbitration according to Priority
        for candidate in candidates[1:]:
            if priority_vc.id > candidate.id:
                priority_vc = candidate

        return priority_vc

    def priority_preemptive_arbitration(self):
        # ---------- VC election ----------
        for vc in self.inPE.vcs:
            self.vc_target_outport(vc)
        # Checking North VC
        for vc in self.inNorth.vcs:
            self.vc_target_outport(vc)
        # Checking South VC
        for vc in self.inSouth.vcs:
            self.vc_target_outport(vc)
        # Checking East VC
        for vc in self.inEast.vcs:
            self.vc_target_outport(vc)
        # Checking West VC
        for vc in self.inWest.vcs:
            self.vc_target_outport(vc)

        # VC targeting -> North
        if len(self.vcs_target_north) > 0:
            vc = self.get_highest_preemptive_priority_vc(self.vcs_target_north)
            self.vcs_target_north.clear()
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outNorth)

        # VC targeting -> South
        if len(self.vcs_target_south) > 0:
            vc = self.get_highest_preemptive_priority_vc(self.vcs_target_south)
            self.vcs_target_south.clear()
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outSouth)

        # VC targeting -> East
        if len(self.vcs_target_east) > 0:
            vc = self.get_highest_preemptive_priority_vc(self.vcs_target_east)
            self.vcs_target_east.clear()
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outEast)

        # VC targeting -> West
        if len(self.vcs_target_west) > 0:
            vc = self.get_highest_preemptive_priority_vc(self.vcs_target_west)
            self.vcs_target_west.clear()
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.send_flit(vc, self.outWest)

        # VC targeting -> PE
        if len(self.vcs_target_pe) > 0:
            vc = self.get_highest_preemptive_priority_vc(self.vcs_target_pe)
            self.vcs_target_pe.clear()
            self.logger.debug('(%d) - %s From %s -> Elected' % (self.env.now, vc, self))
            self.arrived_flit(vc)

    def __str__(self):
        return 'Router (%d,%d)' % (self.coordinate.i, self.coordinate.j)