예제 #1
0
    def construct(s, Type, num_inports=1):

        assert num_inports == 1, 'Null switch unit can only be used for single-input router!'

        # Interface

        s.get = [GetIfcRTL(Type) for _ in range(num_inports)]
        s.hold = [InPort() for _ in range(num_inports)]
        s.give = GiveIfcRTL(Type)

        connect(s.give, s.get[0])
예제 #2
0
    def construct(s, PacketType, PositionType, num_outports, n_fly=3):

        # Constants

        s.num_outports = num_outports
        k_ary = num_outports
        OutType = mk_bits(clog2(s.num_outports))
        rows = k_ary**(n_fly - 1)
        DstType = mk_bits(clog2(k_ary) * n_fly)
        RowWidth = clog2(k_ary)
        END = n_fly * RowWidth
        BEGIN = END - RowWidth

        # Interface

        s.get = GetIfcRTL(PacketType)
        s.give = [GiveIfcRTL(PacketType) for _ in range(s.num_outports)]
        s.pos = InPort(PositionType)

        # Componets

        s.out_dir = Wire(OutType)
        s.give_rdy = [Wire() for _ in range(s.num_outports)]
        s.give_ens = Wire(mk_bits(s.num_outports))

        # Connections

        for i in range(s.num_outports):
            s.give_ens[i] //= s.give[i].en
            s.give_rdy[i] //= s.give[i].rdy

        # Routing logic

        @update
        def up_ru_routing():
            for i in range(s.num_outports):
                s.give_rdy[i] @= 0

            if s.get.rdy:
                s.out_dir @= s.get.ret.dst[BEGIN:END]
                s.give_rdy[s.out_dir] @= 1

        @update
        def up_ru_get_en():
            s.get.en @= s.give_ens > 0
            for i in range(s.num_outports):
                s.give[i].ret @= s.get.ret
            if s.get.rdy:
                s.give[s.out_dir].ret.dst @= s.get.ret.dst << RowWidth
예제 #3
0
  def construct( s, PacketType, PositionType, num_outports = 8 ):

    # Constants

    s.num_outports = num_outports
    TType = mk_bits( clog2(num_outports) )

    # Interface

    s.get  = GetIfcRTL( PacketType )
    s.give = [ GiveIfcRTL (PacketType) for _ in range ( s.num_outports ) ]
    s.pos  = InPort( PositionType )

    # Componets

    s.give_ens = Wire( mk_bits( s.num_outports ) )
    s.give_rdy = [ Wire() for _ in range( s.num_outports )]

    # Connections

    for i in range( s.num_outports ):
      s.get.ret     //= s.give[i].ret
      s.give_ens[i] //= s.give[i].en
      s.give_rdy[i] //= s.give[i].rdy

    # Routing logic

    @update
    def up_ru_routing():

      s.out_dir @= 0
      for i in range( s.num_outports ):
        s.give_rdy[i] @= Bits1(0)

      if s.get.rdy:
        if (s.pos.pos_x == s.get.ret.dst_x) & (s.pos.pos_y == s.get.ret.dst_y):
          s.give_rdy[ Bits3( 4 ) + s.get.ret.dst_ter ] @= 1
        elif s.get.ret.dst_x < s.pos.pos_x:
          s.give_rdy[2] @= 1
        elif s.get.ret.dst_x > s.pos.pos_x:
          s.give_rdy[3] @= 1
        elif s.get.ret.dst_y < s.pos.pos_y:
          s.give_rdy[1] @= 1
        else:
          s.give_rdy[0] @= 1

    @update
    def up_ru_get_en():
      s.get.en = s.give_ens > 0
    def construct(s, Type, num_inports=5):

        # Local parameters
        s.num_inports = num_inports
        s.Type = Type
        s.sel_width = clog2(num_inports)

        # Interface
        s.get = [GetIfcRTL(s.Type) for _ in range(num_inports)]
        s.hold = InPort(num_inports)
        s.give = GiveIfcRTL(s.Type)

        # Components
        s.granted_get_rdy = Wire()
        s.any_hold = Wire()

        s.arbiter = GrantHoldArbiter(nreqs=num_inports)
        s.arbiter.hold //= s.any_hold
        s.arbiter.en //= lambda: ~s.any_hold & s.give.en

        s.mux = Mux(s.Type, num_inports)
        s.mux.out //= s.give.ret

        s.encoder = Encoder(num_inports, s.sel_width)
        s.encoder.in_ //= s.arbiter.grants
        s.encoder.out //= s.mux.sel

        # Combinational Logic
        @update
        def up_any_hold():
            s.any_hold @= s.hold > 0

        @update
        def up_granted_get_rdy():
            s.granted_get_rdy @= 0
            for i in range(num_inports):
                if s.arbiter.grants[i]:
                    s.granted_get_rdy @= s.get[i].rdy

        for i in range(num_inports):
            s.get[i].rdy //= s.arbiter.reqs[i]
            s.get[i].ret //= s.mux.in_[i]

        for i in range(num_inports):
            s.get[i].en //= lambda: s.give.en & (s.mux.sel == i)

        s.give.rdy //= s.granted_get_rdy
예제 #5
0
    def construct(s, PacketType, num_inports=5):

        # Local parameters

        s.num_inports = num_inports
        s.sel_width = clog2(num_inports)
        s.set_ocp = 0
        s.clear_ocp = 0

        # Interface

        s.get = [GetIfcRTL(PacketType) for _ in range(s.num_inports)]
        s.give = GiveIfcRTL(PacketType)
        s.out_ocp = OutPort()

        # Components

        s.get_en = [Wire() for _ in range(s.num_inports)]
        s.get_rdy = [Wire() for _ in range(s.num_inports)]

        s.arbiter = RoundRobinArbiterEn(num_inports)
        s.arbiter.en //= 1

        s.mux = Mux(PacketType, num_inports)
        s.mux.out //= s.give.ret

        s.encoder = Encoder(num_inports, s.sel_width)
        s.encoder.in_ //= s.arbiter.grants
        s.encoder.out //= s.mux.sel

        # Connections

        for i in range(num_inports):
            s.get[i].rdy //= s.arbiter.reqs[i]
            s.get[i].ret //= s.mux.in_[i]
            s.get[i].en //= s.get_en[i]
            s.get[i].rdy //= s.get_rdy[i]

        @update
        def up_give():
            s.give.rdy @= s.arbiter.grants > 0

        @update
        def up_get_en():
            for i in range(num_inports):
                s.get_en[i] @= s.give.en & (s.mux.sel == i)
예제 #6
0
파일: MiscRTL.py 프로젝트: yxd97/pymtl3
    def construct(s, dtype):

        s.drop = InPort()
        s.in_ = GetIfcRTL(dtype)
        s.out = GiveIfcRTL(dtype)

        s.out.ret //= s.in_.ret

        s.snoop_state = Wire()

        #------------------------------------------------------------------
        # state_transitions
        #------------------------------------------------------------------

        @s.update_ff
        def state_transitions():

            if s.reset:
                s.snoop_state <<= SNOOP

            elif s.snoop_state == SNOOP:
                if s.drop & ~s.in_.rdy:
                    s.snoop_state <<= WAIT

            elif s.snoop_state == WAIT:
                if s.in_.rdy:
                    s.snoop_state <<= SNOOP

        #------------------------------------------------------------------
        # set_outputs
        #------------------------------------------------------------------

        @s.update
        def set_outputs():
            s.out.rdy = b1(0)
            s.in_.en = b1(0)

            if s.snoop_state == SNOOP:
                s.out.rdy = s.in_.rdy & ~s.drop
                s.in_.en = s.out.en

            elif s.snoop_state == WAIT:
                s.out.rdy = b1(0)
                s.in_.en = s.in_.rdy
예제 #7
0
    def construct(s, PacketType, PositionType, num_outports):

        # Interface

        s.get = GetIfcRTL(PacketType)
        s.give = [GiveIfcRTL(PacketType) for _ in range(num_outports)]
        s.pos = InPort(PositionType)

        # Componets

        s.out_dir = Wire(mk_bits(clog2(num_outports)))
        s.give_ens = Wire(mk_bits(num_outports))

        # Connections

        for i in range(num_outports):
            s.get.ret //= s.give[i].ret
            s.give_ens[i] //= s.give[i].en

        # Routing logic
        @update
        def up_ru_routing():

            s.out_dir = Bits3(0)
            for i in range(num_outports):
                s.give[i].rdy = Bits1(0)

            if s.get.rdy:
                if s.pos.pos_x == s.get.ret.dst_x and s.pos.pos_y == s.get.ret.dst_y:
                    s.out_dir = SELF
                elif s.get.ret.dst_x < s.pos.pos_x:
                    s.out_dir = WEST
                elif s.get.ret.dst_x > s.pos.pos_x:
                    s.out_dir = EAST
                elif s.get.ret.dst_y > s.pos.pos_y:
                    s.out_dir = NORTH
                else:
                    s.out_dir = SOUTH
                s.give[s.out_dir].rdy = Bits1(1)

        @update
        def up_ru_give_en():
            s.get.en = s.give_ens > Bits5(0)
예제 #8
0
    def construct(s, PacketType, QueueType=None):

        # Local parameter
        gating_out = PacketType()

        # Interface
        s.get = GetIfcRTL(PacketType)
        s.send = SendIfcRTL(PacketType)

        s.QueueType = QueueType

        # If no queue type is assigned
        if s.QueueType != None:

            # Component
            s.queue = QueueType(PacketType)

            # Connections
            s.get.ret //= s.queue.enq.msg
            s.queue.deq.ret //= s.send.msg

            @update
            def up_get_deq():
                both_rdy = s.get.rdy & s.queue.enq.rdy
                s.get.en @= both_rdy
                s.queue.enq.en @= both_rdy

            @update
            def up_deq_send():
                both_rdy = s.send.rdy & s.queue.deq.rdy
                s.send.en @= both_rdy
                s.queue.deq.en @= both_rdy

        # No ouput queue
        else:

            s.send.msg //= lambda: s.get.ret if s.send.en else PacketType()

            @update
            def up_get_send():
                both_rdy = s.get.rdy & s.send.rdy
                s.get.en @= both_rdy
                s.send.en @= both_rdy
예제 #9
0
  def construct( s, MsgType, PositionType, num_outports = 5 ):

    # Interface

    s.get  = GetIfcRTL( MsgType )
    s.give = [ GiveIfcRTL (MsgType) for _ in range ( num_outports ) ]
    s.pos  = InPort( PositionType )

    # Componets

    s.give_ens = Wire( mk_bits( num_outports ) )

    # Connections

    for i in range( num_outports ):
      s.get.ret     //= s.give[i].ret
      s.give_ens[i] //= s.give[i].en

    # Routing logic
    @update
    def up_ru_routing():
      s.give[0].rdy @= 0
      s.give[1].rdy @= 0
      s.give[2].rdy @= 0
      s.give[3].rdy @= 0
      s.give[4].rdy @= 0

      if s.get.rdy:
        if (s.pos.pos_x == s.get.ret.dst_x) & (s.pos.pos_y == s.get.ret.dst_y):
          s.give[4].rdy @= 1
        elif s.get.ret.dst_y < s.pos.pos_y:
          s.give[1].rdy @= 1
        elif s.get.ret.dst_y > s.pos.pos_y:
          s.give[0].rdy @= 1
        elif s.get.ret.dst_x < s.pos.pos_x:
          s.give[2].rdy @= 1
        else:
          s.give[3].rdy @= 1

    @update
    def up_ru_get_en():
      s.get.en @= s.give_ens > 0
예제 #10
0
    def construct(s, PacketType, num_outports):

        # Local parameters

        dir_nbits = 1 if num_outports == 1 else clog2(num_outports)
        DirT = mk_bits(dir_nbits)
        BitsN = mk_bits(num_outports)

        # Interface

        s.get = GetIfcRTL(PacketType)
        s.give = [GiveIfcRTL(PacketType) for _ in range(num_outports)]

        # Componets

        s.out_dir = Wire(DirT)
        s.give_ens = Wire(BitsN)

        # Connections

        for i in range(num_outports):
            s.get.ret //= s.give[i].ret
            s.give_ens[i] //= s.give[i].en

        # Routing logic

        @update
        def up_ru_routing():
            s.out_dir @= trunc(s.get.ret.dst, dir_nbits)

            for i in range(num_outports):
                s.give[i].rdy @= b1(0)

            if s.get.rdy:
                s.give[s.out_dir].rdy @= b1(1)

        @update
        def up_ru_give_en():
            s.get.en @= s.give_ens > 0
예제 #11
0
    def construct(s, MsgType, vc=2, credit_line=2):
        assert vc > 1

        # Interface
        s.get = GetIfcRTL(MsgType)
        s.send = CreditSendIfcRTL(MsgType, vc)

        s.MsgType = MsgType
        s.vc = vc

        # Loval types
        credit_type = mk_bits(clog2(credit_line + 1))

        s.credit = [Counter(credit_type, credit_line) for _ in range(vc)]

        s.get.ret //= s.send.msg

        @update
        def up_credit_send():
            s.send.en @= 0
            s.get.en @= 0
            if s.get.rdy:
                # print( str(s) + " : " + str(s.get.ret) )
                for i in range(vc):
                    if (i == s.get.ret.vc_id) & (s.credit[i].count > 0):
                        s.send.en @= 1
                        s.get.en @= 1

        @update
        def up_counter_decr():
            for i in range(vc):
                s.credit[i].decr @= s.send.en & (i == s.send.msg.vc_id)

        for i in range(vc):
            s.credit[i].incr //= s.send.yum[i]
            s.credit[i].load //= 0
            s.credit[i].load_value //= 0
예제 #12
0
    def construct(s, PacketType, PositionType, num_routers=4):

        # Constants
        s.num_outports = 3
        s.num_routers = num_routers

        DistType = mk_bits(clog2(num_routers))
        s.last_idx = DistType(num_routers - 1)

        # Interface

        s.get = GetIfcRTL(PacketType)
        s.give = [GiveIfcRTL(PacketType) for _ in range(s.num_outports)]
        s.pos = InPort(PositionType)

        # Componets

        s.out_dir = Wire(mk_bits(clog2(s.num_outports)))
        s.give_ens = Wire(mk_bits(s.num_outports))

        s.left_dist = Wire(DistType)
        s.right_dist = Wire(DistType)
        s.give_msg_wire = Wire(PacketType)

        # Connections

        for i in range(s.num_outports):
            s.give_ens[i] //= s.give[i].en

        # Routing logic
        @update
        def up_left_right_dist():
            if s.get.ret.dst < s.pos:
                s.left_dist @= zext(s.pos, DistType) - zext(
                    s.get.ret.dst, DistType)
                s.right_dist @= zext(s.last_idx, DistType) - zext(
                    s.pos, DistType) + zext(s.get.ret.dst, DistType) + 1
            else:
                s.left_dist @= 1 + zext(s.last_idx, DistType) + zext(
                    s.pos, DistType) - zext(s.get.ret.dst, DistType)
                s.right_dist @= zext(s.get.ret.dst, DistType) - zext(
                    s.pos, DistType)

        @update
        def up_ru_routing():

            s.out_dir @= 0
            s.give_msg_wire @= s.get.ret
            for i in range(s.num_outports):
                s.give[i].rdy @= 0

            if s.get.rdy:
                if s.pos == s.get.ret.dst:
                    s.out_dir @= SELF
                elif s.left_dist < s.right_dist:
                    s.out_dir @= LEFT
                else:
                    s.out_dir @= RIGHT

                if (s.pos == s.last_idx) & (s.out_dir == RIGHT):
                    s.give_msg_wire.vc_id @= 1
                elif (s.pos == 0) & (s.out_dir == LEFT):
                    s.give_msg_wire.vc_id @= 1

                s.give[s.out_dir].rdy @= 1
                s.give[s.out_dir].ret @= s.give_msg_wire

        @update
        def up_ru_get_en():
            s.get.en @= s.give_ens > 0
예제 #13
0
    def construct(s, PositionType, plen_field_name='plen'):

        # Local parameter

        assert PitonNoCHeader.nbits == 64
        s.num_outports = 5
        s.PhitType = Bits64
        s.STATE_HEADER = 0
        s.STATE_BODY = 1

        PLenType = Bits8
        XType = get_field_type(PositionType, 'pos_x')
        YType = get_field_type(PositionType, 'pos_y')

        # Interface

        s.get = GetIfcRTL(s.PhitType)
        s.pos = InPort(
            PositionType)  # TODO: figure out a way to encode position

        s.give = [GiveIfcRTL(s.PhitType) for _ in range(s.num_outports)]
        s.hold = [OutPort(Bits1) for _ in range(s.num_outports)]

        # Components

        s.header = Wire(PitonNoCHeader)
        s.state = Wire(Bits1)
        s.state_next = Wire(Bits1)
        s.out_dir_r = Wire(Bits3)
        s.out_dir = Wire(Bits3)
        s.any_give_en = Wire(Bits1)

        s.offchip = Wire(Bits1)
        s.dst_x = Wire(Bits8)
        s.dst_y = Wire(Bits8)

        s.counter = Counter(PLenType)
        s.counter.incr //= 0
        s.counter.load_value //= s.header.plen

        connect_bitstruct(s.get.ret, s.header)

        for i in range(5):
            s.get.ret //= s.give[i].ret
        s.get.en //= s.any_give_en

        @update
        def up_any_give_en():
            s.any_give_en @= 0
            for i in range(s.num_outports):
                if s.give[i].en:
                    s.any_give_en @= 1

        # State transition logic

        @update_ff
        def up_state_r():
            if s.reset:
                s.state <<= s.STATE_HEADER
            else:
                s.state <<= s.state_next

        @update
        def up_state_next():
            s.state_next @= s.state
            if s.state == s.STATE_HEADER:
                # If the packet has body flits
                if s.any_give_en & (s.header.plen > 0):
                    s.state_next @= s.STATE_BODY

            else:  # STATE_BODY
                if (s.counter.count == 1) & s.any_give_en:
                    s.state_next @= s.STATE_HEADER

        # State output logic

        @update
        def up_counter_decr():
            s.counter.decr @= 0
            if s.state != s.STATE_HEADER:
                s.counter.decr @= s.any_give_en

        @update
        def up_counter_load():
            s.counter.load @= 0
            if s.state == s.STATE_HEADER:
                s.counter.load @= (s.state_next == s.STATE_BODY)

        # Routing logic

        s.offchip //= s.header.chipid[13]

        @update
        def up_dst():
            s.dst_x @= 0
            s.dst_y @= 0
            if ~s.offchip:
                s.dst_x @= s.header.xpos
                s.dst_y @= s.header.ypos

        @update
        def up_out_dir():
            s.out_dir @= s.out_dir_r

            if (s.state == s.STATE_HEADER) & s.get.rdy:
                s.out_dir @= 0
                # Offchip port
                if (s.pos.pos_x == 0) & (s.pos.pos_y == 0) & s.offchip:
                    s.out_dir @= WEST

                elif (s.dst_x == s.pos.pos_x) & (s.dst_y == s.pos.pos_y):
                    s.out_dir @= SELF
                elif s.dst_x < s.pos.pos_x:
                    s.out_dir @= WEST
                elif s.dst_x > s.pos.pos_x:
                    s.out_dir @= EAST
                elif s.dst_y < s.pos.pos_y:
                    s.out_dir @= NORTH
                elif s.dst_y > s.pos.pos_y:
                    s.out_dir @= SOUTH

        @update_ff
        def up_out_dir_r():
            s.out_dir_r <<= s.out_dir

        @update
        def up_give_rdy_hold():
            for i in range(s.num_outports):
                s.give[i].rdy @= (i == s.out_dir) & s.get.rdy
                s.hold[i] @= (i == s.out_dir) & (s.state == s.STATE_BODY)
예제 #14
0
    def construct(s, PacketType, PositionType, ncols=2, nrows=2):

        # Constants

        num_outports = 5
        s.ncols = ncols
        s.nrows = nrows

        # Here we add 1 to avoid overflow

        posx_type = mk_bits(clog2(ncols))
        posy_type = mk_bits(clog2(nrows))
        ns_dist_type = mk_bits(clog2(nrows + 1))
        we_dist_type = mk_bits(clog2(ncols + 1))

        s.last_row_id = nrows - 1
        s.last_col_id = ncols - 1

        # Interface

        s.get = GetIfcRTL(PacketType)
        s.give = [GiveIfcRTL(PacketType) for _ in range(num_outports)]
        s.pos = InPort(PositionType)

        # Componets

        s.out_dir = Wire(Bits3)
        s.give_ens = Wire(Bits5)
        s.turning = Wire(Bits1)
        s.north_dist = Wire(ns_dist_type)
        s.south_dist = Wire(ns_dist_type)
        s.west_dist = Wire(we_dist_type)
        s.east_dist = Wire(we_dist_type)
        s.give_msg_wire = Wire(PacketType)

        # Connections

        for i in range(num_outports):
            s.give_ens[i] //= s.give[i].en
            s.give_msg_wire //= s.give[i].ret

        # Calculate distance

        @update
        def up_ns_dist():
            if s.get.ret.dst_y < s.pos.pos_y:
                s.south_dist @= zext(s.pos.pos_y, ns_dist_type) - zext(
                    s.get.ret.dst_y, ns_dist_type)
                s.north_dist @= s.last_row_id - zext(
                    s.pos.pos_y, ns_dist_type) + 1 + zext(
                        s.get.ret.dst_y, ns_dist_type)
            else:
                s.south_dist @= zext(s.pos.pos_y,
                                     ns_dist_type) + 1 + s.last_row_id - zext(
                                         s.get.ret.dst_y, ns_dist_type)
                s.north_dist @= zext(s.get.ret.dst_y, ns_dist_type) - zext(
                    s.pos.pos_y, ns_dist_type)

        @update
        def up_we_dist():
            if s.get.ret.dst_x < s.pos.pos_x:
                s.west_dist @= zext(s.pos.pos_x, we_dist_type) - zext(
                    s.get.ret.dst_x, we_dist_type)
                s.east_dist @= s.last_col_id - zext(
                    s.pos.pos_x, we_dist_type) + 1 + zext(
                        s.get.ret.dst_x, we_dist_type)
            else:
                s.west_dist @= zext(s.pos.pos_x,
                                    we_dist_type) + 1 + s.last_col_id - zext(
                                        s.get.ret.dst_x, we_dist_type)
                s.east_dist @= zext(s.get.ret.dst_x, we_dist_type) - zext(
                    s.pos.pos_x, we_dist_type)

        # Routing logic

        @update
        def up_ru_routing():

            s.give_msg_wire @= s.get.ret
            s.out_dir @= 0
            s.turning @= 0

            for i in range(num_outports):
                s.give[i].rdy @= 0

            if s.get.rdy:
                if (s.pos.pos_x == s.get.ret.dst_x) & (s.pos.pos_y
                                                       == s.get.ret.dst_y):
                    s.out_dir @= SELF
                elif s.get.ret.dst_y != s.pos.pos_y:
                    s.out_dir @= NORTH if s.north_dist < s.south_dist else SOUTH
                else:
                    s.out_dir @= WEST if s.west_dist < s.east_dist else EAST

                # Turning logic

                s.turning @= ( s.get.ret.src_x == s.pos.pos_x ) & \
                             ( s.get.ret.src_y != s.pos.pos_y ) & \
                             ( s.out_dir == WEST ) | ( s.out_dir == EAST )

                # Dateline logic

                if s.turning:
                    s.give_msg_wire.vc_id @= 0

                if (s.pos.pos_x == 0) & (s.out_dir == WEST):
                    s.give_msg_wire.vc_id @= 1
                elif (s.pos.pos_x == s.last_col_id) & (s.out_dir == EAST):
                    s.give_msg_wire.vc_id @= 1
                elif (s.pos.pos_y == 0) & (s.out_dir == SOUTH):
                    s.give_msg_wire.vc_id @= 1
                elif (s.pos.pos_y == s.last_row_id) & (s.out_dir == NORTH):
                    s.give_msg_wire.vc_id @= 1

                s.give[s.out_dir].rdy @= 1

        @update
        def up_ru_get_en():
            s.get.en @= s.give_ens > 0
    def construct(s, HeaderFormat, num_outports=4, plen_field_name='plen'):
        # Meta data
        s.num_outports = num_outports
        s.HeaderFormat = HeaderFormat
        s.PhitType = mk_bits(HeaderFormat.nbits)
        dir_nbits = clog2(num_outports) if num_outports > 1 else 1
        DirType = mk_bits(dir_nbits)
        PLenType = get_plen_type(HeaderFormat)
        s.STATE_HEADER = b1(0)
        s.STATE_BODY = b1(1)

        # Interface
        s.get = GetIfcRTL(s.PhitType)

        s.give = [GiveIfcRTL(s.PhitType) for _ in range(s.num_outports)]
        s.hold = [OutPort(Bits1) for _ in range(s.num_outports)]

        # Components
        s.header = Wire(HeaderFormat)
        s.state = Wire()
        s.state_next = Wire()
        s.out_dir_r = Wire(dir_nbits)
        s.out_dir = Wire(dir_nbits)
        s.any_give_en = Wire()

        s.counter = Counter(PLenType)
        s.counter.incr //= 0
        s.counter.load_value //= s.header.plen

        @update
        def up_header():
            s.header @= s.get.ret

        for i in range(s.num_outports):
            s.get.ret //= s.give[i].ret
        s.get.en //= s.any_give_en

        @update
        def up_any_give_en():
            s.any_give_en @= 0
            for i in range(s.num_outports):
                if s.give[i].en:
                    s.any_give_en @= 1

        # State transition logic
        @update_ff
        def up_state_r():
            if s.reset:
                s.state <<= s.STATE_HEADER
            else:
                s.state <<= s.state_next

        @update
        def up_state_next():
            s.state_next @= s.state
            if s.state == s.STATE_HEADER:
                # If the packet has body flits
                if s.any_give_en & (s.header.plen > 0):
                    s.state_next @= s.STATE_BODY

            else:  # STATE_BODY
                if (s.counter.count == 1) & s.any_give_en:
                    s.state_next @= s.STATE_HEADER

        # State output logic
        @update
        def up_counter_decr():
            if s.state == s.STATE_HEADER:
                s.counter.decr @= 0
            else:
                s.counter.decr @= s.any_give_en

        @update
        def up_counter_load():
            if s.state == s.STATE_HEADER:
                s.counter.load @= (s.state_next == s.STATE_BODY)
            else:
                s.counter.load @= 0

        # Routing logic
        # TODO: Figure out how to encode dest id
        @update
        def up_out_dir():
            if (s.state == s.STATE_HEADER) & s.get.rdy:
                s.out_dir @= s.header.dst[0:dir_nbits]
            else:
                s.out_dir @= s.out_dir_r

        @update_ff
        def up_out_dir_r():
            s.out_dir_r <<= s.out_dir

        @update
        def up_give_rdy_hold():
            for i in range(s.num_outports):
                s.give[i].rdy @= (i == s.out_dir) & s.get.rdy
                s.hold[i] @= (i == s.out_dir) & (s.state == s.STATE_BODY)
    def construct(s, HeaderFormat, PositionType, plen_field_name='plen'):
        # Meta data
        s.num_outports = 5
        s.HeaderFormat = HeaderFormat
        s.PhitType = mk_bits(HeaderFormat.nbits)
        s.STATE_HEADER = b1(0)
        s.STATE_BODY = b1(1)

        PLenType = get_plen_type(HeaderFormat)

        # Interface
        s.get = GetIfcRTL(s.PhitType)
        s.pos = InPort(
            PositionType)  # TODO: figure out a way to encode position

        s.give = [GiveIfcRTL(s.PhitType) for _ in range(s.num_outports)]
        s.hold = [OutPort(Bits1) for _ in range(s.num_outports)]

        # Components
        s.header = Wire(HeaderFormat)
        s.state = Wire(Bits1)
        s.state_next = Wire(Bits1)
        s.out_dir_r = Wire(Bits3)
        s.out_dir = Wire(Bits3)
        s.any_give_en = Wire(Bits1)

        s.counter = m = Counter(PLenType)
        m.incr //= 0
        m.load_value //= s.header.plen

        @update
        def up_get_ret():
            s.header @= s.get.ret

        for i in range(5):
            s.get.ret //= s.give[i].ret
        s.get.en //= s.any_give_en

        @update
        def up_any_give_en():
            s.any_give_en @= 0
            for i in range(s.num_outports):
                if s.give[i].en:
                    s.any_give_en @= 1

        # State transition logic
        @update_ff
        def up_state_r():
            if s.reset:
                s.state <<= s.STATE_HEADER
            else:
                s.state <<= s.state_next

        @update
        def up_state_next():
            if s.state == s.STATE_HEADER:
                # If the packet has body flits
                if s.any_give_en & (s.header.plen > 0):
                    s.state_next @= s.STATE_BODY

                else:
                    s.state_next @= s.STATE_HEADER

            else:  # STATE_BODY
                if (s.counter.count == 1) & s.any_give_en:
                    s.state_next @= s.STATE_HEADER
                else:
                    s.state_next @= s.STATE_BODY

        # State output logic
        @update
        def up_counter_decr():
            if s.state == s.STATE_HEADER:
                s.counter.decr @= 0
            else:
                s.counter.decr @= s.any_give_en

        @update
        def up_counter_load():
            if s.state == s.STATE_HEADER:
                s.counter.load @= (s.state_next == s.STATE_BODY)
            else:
                s.counter.load @= 0

        # Routing logic
        # TODO: Figure out how to encode dest id
        @update
        def up_out_dir():
            if (s.state == s.STATE_HEADER) & s.get.rdy:
                if (s.header.dst_x == s.pos.pos_x) & (s.header.dst_y
                                                      == s.pos.pos_y):
                    s.out_dir @= SELF
                elif s.header.dst_x < s.pos.pos_x:
                    s.out_dir @= WEST
                elif s.header.dst_x > s.pos.pos_x:
                    s.out_dir @= EAST
                elif s.header.dst_y < s.pos.pos_y:
                    s.out_dir @= SOUTH
                else:
                    s.out_dir @= NORTH

            else:
                s.out_dir @= s.out_dir_r

        @update_ff
        def up_out_dir_r():
            s.out_dir_r <<= s.out_dir

        @update
        def up_give_rdy_hold():
            for i in range(s.num_outports):
                s.give[i].rdy @= (i == s.out_dir) & s.get.rdy
                s.hold[i] @= (i == s.out_dir) & (s.state == s.STATE_BODY)