Example #1
0
  def construct( s, EntryType, num_entries=2 ):

    # Interface

    s.enq_msg =  InPort( EntryType )
    s.deq_ret = OutPort( EntryType )

    s.wen     = InPort( Bits1 )
    s.waddr   = InPort( mk_bits( clog2( num_entries ) ) )
    s.raddr   = InPort( mk_bits( clog2( num_entries ) ) )
    s.mux_sel = InPort( Bits1 )

    # Component

    s.queue = m = RegisterFile( EntryType, num_entries )
    m.raddr[0] //= s.raddr
    m.wen[0]   //= s.wen
    m.waddr[0] //= s.waddr
    m.wdata[0] //= s.enq_msg

    s.mux = m = Mux( EntryType, 2 )
    m.sel    //= s.mux_sel
    m.in_[0] //= s.queue.rdata[0]
    m.in_[1] //= s.enq_msg
    m.out    //= s.deq_ret
Example #2
0
  def construct( s, EntryType ):

    # Interface

    s.enq   = EnqIfcRTL( EntryType )
    s.deq   = DeqIfcRTL( EntryType )
    s.count = OutPort  ( Bits1     )

    # Components

    s.entry = Wire( EntryType )
    s.full  = Wire( Bits1 )

    s.bypass_mux = m = Mux( EntryType, 2 )
    m.in_[0] //= s.enq.msg
    m.in_[1] //= s.entry
    m.out    //= s.deq.ret
    m.sel    //= s.full

    # Logic

    s.count //= s.full

    s.enq.rdy //= lambda: ~s.reset & ~s.full
    s.deq.rdy //= lambda: ~s.reset & ( s.full | s.enq.en )

    @update_ff
    def ff_bypass1():
      s.full <<= ~s.reset & ( ~s.deq.en & (s.enq.en | s.full) )

      if s.enq.en & ~s.deq.en:
        s.entry <<= s.enq.msg
Example #3
0
    def construct(s, Type):
        s.enq = InValRdyIfc(Type)
        s.deq = OutValRdyIfc(Type)

        s.buffer = RegEn(Type)
        s.buffer.in_ //= s.enq.msg

        s.next_full = Wire(Bits1)
        s.full = Wire(Bits1)

        s.byp_mux = m = Mux(Type, 2)
        m.out //= s.deq.msg
        m.in_[0] //= s.enq.msg
        m.in_[1] //= s.buffer.out
        m.sel //= s.full  # full -- buffer.out, empty -- bypass

        @update_ff
        def up_full():
            s.full <<= s.next_full

        @update
        def up_bypq_set_enq_rdy():
            s.enq.rdy @= ~s.full

        @update
        def up_bypq_internal():
            s.buffer.en @= (~s.deq.rdy) & (s.enq.val & s.enq.rdy)
            s.next_full @= (~s.deq.rdy) & s.deq.val

        # this enables the sender to make enq.val depend on enq.rdy
        @update
        def up_bypq_set_deq_val():
            s.deq.val @= s.full | s.enq.val
    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
Example #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)
Example #6
0
  def construct( s, PacketType, num_inports=5 ):

    # Local parameters

    s.num_inports = num_inports
    s.sel_width   = clog2( num_inports )

    # Interface

    s.recv = [ RecvIfcRTL( PacketType ) for _ in range( s.num_inports ) ]
    s.send = SendIfcRTL( PacketType )

    # Components

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

    s.mux = Mux( PacketType, num_inports )
    s.mux.out //= s.send.msg

    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.recv[i].val //= s.arbiter.reqs[i]
      s.recv[i].msg //= s.mux.in_[i]

    @update
    def up_send_val():
      s.send.val @= s.arbiter.grants > 0

    # TODO: assert at most one rdy bit
    @update
    def up_get_en():
      for i in range( num_inports ):
        s.recv[i].rdy @= s.send.rdy & ( s.mux.sel == i )
Example #7
0
    def construct(s, out_nbits, max_nblocks):

        # Local parameter

        InType = mk_bits(out_nbits * (max_nblocks))
        OutType = mk_bits(out_nbits)
        CountType = mk_bits(clog2(max_nblocks + 1))

        s.STATE_IDLE = b1(0)
        s.STATE_SEND = b1(1)

        s.sel_nbits = clog2(max_nblocks)

        # Interface

        s.recv = RecvIfcRTL(InType)
        s.send = SendIfcRTL(OutType)
        s.len = InPort(CountType)

        # Components

        s.state = Wire(Bits1)
        s.state_next = Wire(Bits1)
        s.in_r = Wire(InType)
        s.len_r = Wire(CountType)

        s.counter = Counter(CountType)
        s.counter.decr //= 0
        s.mux = Mux(OutType, max_nblocks)

        # Input register

        @update_ff
        def up_in_r():
            if s.recv.en & (s.state_next != s.STATE_IDLE):
                s.in_r <<= s.recv.msg
                # Force len to 1 if it is set to be 0 to avoid undefined behavior
                s.len_r <<= s.len if s.len > 0 else 1
            else:
                s.in_r <<= s.in_r
                s.len_r <<= 0 if s.state_next == s.STATE_IDLE else s.len_r

        # Mux logic

        for i in range(max_nblocks):
            s.mux.in_[i] //= s.in_r[i * out_nbits:(i + 1) * out_nbits]
        s.mux.sel //= s.counter.count[0:s.sel_nbits]

        # Counter load

        s.counter.load //= lambda: s.recv.en | (s.state_next == s.STATE_IDLE)
        s.counter.incr //= lambda: s.send.en & (s.state_next != s.STATE_IDLE)

        @update
        def up_counter_load_value():
            if (s.state == s.STATE_IDLE) & s.send.rdy & (s.state_next !=
                                                         s.STATE_IDLE):
                s.counter.load_value @= 1
            else:
                s.counter.load_value @= 0

        # Recv logic

        s.recv.rdy //= lambda: s.state == s.STATE_IDLE

        # Send logic

        @update
        def up_send_msg():
            if (s.state == s.STATE_IDLE) & s.recv.en & s.send.rdy:
                s.send.msg @= s.recv.msg[0:out_nbits]
            else:
                s.send.msg @= s.mux.out

        @update
        def up_send_en():
            if ( s.state == s.STATE_IDLE ) & s.recv.en & s.send.rdy | \
               ( s.state == s.STATE_SEND ) & s.send.rdy:
                s.send.en @= 1
            else:
                s.send.en @= 0

        # State transition logic

        @update_ff
        def up_state():
            if s.reset:
                s.state <<= s.STATE_IDLE
            else:
                s.state <<= s.state_next

        @update
        def up_state_next():
            if s.state == s.STATE_IDLE:
                # If length is 1, bypass to IDLE
                if (s.len == 1) & s.send.en:
                    s.state_next @= s.STATE_IDLE

                elif s.recv.en:
                    s.state_next @= s.STATE_SEND

                else:
                    s.state_next @= s.STATE_IDLE

            else:  # STATE_SEND
                if (s.counter.count == s.len_r - 1) & s.send.rdy:
                    s.state_next @= s.STATE_IDLE
                else:
                    s.state_next @= s.STATE_SEND
Example #8
0
  def construct( s ):

    #---------------------------------------------------------------------
    # Interface
    #---------------------------------------------------------------------

    # imem ports
    s.imemreq_addr   = OutPort( Bits32 )
    s.imemresp_data  = InPort ( Bits32 )

    # dmem ports
    s.dmemreq_addr   = OutPort( Bits32 )
    s.dmemreq_data   = OutPort( Bits32 )
    s.dmemresp_data  = InPort ( Bits32 )

    # mngr ports
    s.mngr2proc_data = InPort ( Bits32 )
    s.proc2mngr_data = OutPort( Bits32 )

    # xcel ports
    s.xcelreq_addr   = OutPort( Bits5 )
    s.xcelreq_data   = OutPort( Bits32 )
    s.xcelresp_data  = InPort ( Bits32 )

    # Control signals (ctrl->dpath)

    s.reg_en_F         = InPort ( Bits1 )
    s.pc_sel_F         = InPort ( Bits1 )

    s.reg_en_D         = InPort ( Bits1 )
    s.op1_byp_sel_D    = InPort ( Bits2 )
    s.op2_byp_sel_D    = InPort ( Bits2 )
    s.op2_sel_D        = InPort ( Bits2 )
    s.imm_type_D       = InPort ( Bits3 )

    s.reg_en_X         = InPort ( Bits1 )
    s.alu_fn_X         = InPort ( Bits4 )

    s.reg_en_M         = InPort ( Bits1 )
    s.wb_result_sel_M  = InPort ( Bits2 )

    s.reg_en_W         = InPort ( Bits1 )
    s.rf_waddr_W       = InPort ( Bits5 )
    s.rf_wen_W         = InPort ( Bits1 )

    # Status signals (dpath->Ctrl)

    s.inst_D           = OutPort( Bits32 )
    s.ne_X             = OutPort( Bits1 )

    #---------------------------------------------------------------------
    # F stage
    #---------------------------------------------------------------------

    s.pc_F        = Wire( Bits32 )
    s.pc_plus4_F  = Wire( Bits32 )

    # PC+4 incrementer

    s.pc_incr_F = m = Incrementer( Bits32, amount=4 )
    m.in_ //= s.pc_F
    m.out //= s.pc_plus4_F

    # forward delaration for branch target and jal target

    s.br_target_X  = Wire( Bits32 )

    # PC sel mux

    s.pc_sel_mux_F = m = Mux( Bits32, 2 )
    m.in_[0] //= s.pc_plus4_F
    m.in_[1] //= s.br_target_X
    m.sel //= s.pc_sel_F
    m.out //= s.imemreq_addr

    # PC register

    s.pc_reg_F = m = RegEnRst( Bits32, reset_value=c_reset_vector-4 )
    m.en  //= s.reg_en_F
    m.in_ //= s.pc_sel_mux_F.out
    m.out //= s.pc_F

    #---------------------------------------------------------------------
    # D stage
    #---------------------------------------------------------------------

    # PC reg in D stage
    # This value is basically passed from F stage for the corresponding
    # instruction to use, e.g. branch to (PC+imm)

    s.pc_reg_D = m = RegEnRst( Bits32 )
    m.en  //= s.reg_en_D
    m.in_ //= s.pc_F

    # Instruction reg

    s.inst_D_reg = m = RegEnRst( Bits32, reset_value=c_reset_inst )
    m.en  //= s.reg_en_D
    m.in_ //= s.imemresp_data
    m.out //= s.inst_D # to ctrl

    # Register File
    # The rf_rdata_D wires, albeit redundant in some sense, are used to
    # remind people these data are from D stage.

    s.rf_rdata0_D = Wire( Bits32 )
    s.rf_rdata1_D = Wire( Bits32 )

    s.rf_wdata_W  = Wire( Bits32 )

    s.rf = m = RegisterFile( Bits32, nregs=32, rd_ports=2, wr_ports=1, const_zero=True )
    m.raddr[0] //= s.inst_D[ RS1 ]
    m.rdata[0] //= s.rf_rdata0_D
    m.raddr[1] //= s.inst_D[ RS2 ]
    m.rdata[1] //= s.rf_rdata1_D
    m.wen[0]   //= s.rf_wen_W
    m.waddr[0] //= s.rf_waddr_W
    m.wdata[0] //= s.rf_wdata_W

    # Immediate generator

    s.immgen_D = m = ImmGenRTL()
    m.imm_type //= s.imm_type_D
    m.inst     //= s.inst_D

    s.bypass_X = Wire( Bits32 )
    s.bypass_M = Wire( Bits32 )
    s.bypass_W = Wire( Bits32 )

    # op1 bypass mux

    s.op1_byp_mux_D = m = Mux( Bits32, 4 )
    m.in_[0] //= s.rf_rdata0_D
    m.in_[1] //= s.bypass_X
    m.in_[2] //= s.bypass_M
    m.in_[3] //= s.bypass_W
    m.sel    //= s.op1_byp_sel_D

    # op2 bypass mux

    s.op2_byp_mux_D = m = Mux( Bits32, 4 )
    m.in_[0] //= s.rf_rdata1_D
    m.in_[1] //= s.bypass_X
    m.in_[2] //= s.bypass_M
    m.in_[3] //= s.bypass_W
    m.sel    //= s.op2_byp_sel_D

    # op2 sel mux
    # This mux chooses among RS2, imm, and the mngr2proc.
    # Basically we are using two muxes here for pedagogy.

    s.op2_sel_mux_D = m = Mux( Bits32, 3 )
    m.in_[0] //= s.op2_byp_mux_D.out
    m.in_[1] //= s.immgen_D.imm
    m.in_[2] //= s.mngr2proc_data
    m.sel    //= s.op2_sel_D

    # Risc-V always calcs branch target by adding imm(generated above) to PC

    s.pc_plus_imm_D = m = Adder( Bits32 )
    m.in0 //= s.pc_reg_D.out
    m.in1 //= s.immgen_D.imm

    #---------------------------------------------------------------------
    # X stage
    #---------------------------------------------------------------------

    # br_target_reg_X
    # Since branches are resolved in X stage, we register the target,
    # which is already calculated in D stage, to X stage.

    s.br_target_reg_X = m = RegEnRst( Bits32, reset_value=0 )
    m.en  //= s.reg_en_X
    m.in_ //= s.pc_plus_imm_D.out
    m.out //= s.br_target_X

    # op1 reg

    s.op1_reg_X = m = RegEnRst( Bits32, reset_value=0 )
    m.en  //= s.reg_en_X
    m.in_ //= s.op1_byp_mux_D.out

    # op2 reg

    s.op2_reg_X = m = RegEnRst( Bits32, reset_value=0 )
    m.en  //= s.reg_en_X
    m.in_ //= s.op2_sel_mux_D.out

    # Send out xcelreq msg
    s.xcelreq_data //= s.op1_reg_X.out
    s.xcelreq_addr //= s.op2_reg_X.out[0:5]

    # store data reg
    # Since the op1 is the base address and op2 is the immediate so that
    # we could utilize ALU to do address calculation, we need one more
    # register to hold the R[rs2] we want to store to memory.

    s.store_reg_X = m = RegEnRst( Bits32, reset_value=0 )
    m.en  //= s.reg_en_X
    m.in_ //= s.op2_byp_mux_D.out # R[rs2]
    m.out //= s.dmemreq_data

    # ALU

    s.alu_X = m = AluRTL()
    m.in0    //= s.op1_reg_X.out
    m.in1    //= s.op2_reg_X.out
    m.fn     //= s.alu_fn_X
    m.ops_ne //= s.ne_X
    m.out    //= s.bypass_X
    m.out    //= s.dmemreq_addr

    #---------------------------------------------------------------------
    # M stage
    #---------------------------------------------------------------------

    # Alu execution result reg

    s.ex_result_reg_M = m = RegEnRst( Bits32, reset_value=0 )
    m.en  //= s.reg_en_M
    m.in_ //= s.alu_X.out

    # Writeback result selection mux

    s.wb_result_sel_mux_M = m = Mux( Bits32, 3 )
    m.in_[0] //= s.ex_result_reg_M.out
    m.in_[1] //= s.dmemresp_data
    m.in_[2] //= s.xcelresp_data
    m.sel //= s.wb_result_sel_M
    m.out //= s.bypass_M

    #---------------------------------------------------------------------
    # W stage
    #---------------------------------------------------------------------

    # Writeback result reg

    s.wb_result_reg_W = m = RegEnRst( Bits32, reset_value=0 )
    m.en  //= s.reg_en_W
    m.in_ //= s.wb_result_sel_mux_M.out
    m.out //= s.bypass_W
    m.out //= s.rf_wdata_W
    m.out //= s.proc2mngr_data
    def construct(s):

        #---------------------------------------------------------------------
        # Interface
        #---------------------------------------------------------------------

        s.req_msg_a = InPort(16)
        s.req_msg_b = InPort(16)
        s.resp_msg = OutPort(16)

        # Control signals (ctrl -> dpath)

        s.a_mux_sel = InPort(A_MUX_SEL_NBITS)
        s.a_reg_en = InPort()
        s.b_mux_sel = InPort(B_MUX_SEL_NBITS)
        s.b_reg_en = InPort()

        # Status signals (dpath -> ctrl)

        s.is_b_zero = OutPort()
        s.is_a_lt_b = OutPort()

        #---------------------------------------------------------------------
        # Structural composition
        #---------------------------------------------------------------------

        # A mux

        s.sub_out = Wire(16)
        s.b_reg_out = Wire(16)

        s.a_mux = m = Mux(Bits16, 3)
        m.sel //= s.a_mux_sel
        m.in_[A_MUX_SEL_IN] //= s.req_msg_a
        m.in_[A_MUX_SEL_SUB] //= s.sub_out
        m.in_[A_MUX_SEL_B] //= s.b_reg_out

        # A register

        s.a_reg = m = RegEn(Bits16)
        m.en //= s.a_reg_en
        m.in_ //= s.a_mux.out

        # B mux

        s.b_mux = m = Mux(Bits16, 2)
        m.sel //= s.b_mux_sel
        m.in_[B_MUX_SEL_A] //= s.a_reg.out
        m.in_[B_MUX_SEL_IN] //= s.req_msg_b

        # B register

        s.b_reg = m = RegEn(Bits16)
        m.en //= s.b_reg_en
        m.in_ //= s.b_mux.out
        m.out //= s.b_reg_out

        # Zero compare

        s.b_zero = m = ZeroComparator(Bits16)
        m.in_ //= s.b_reg.out
        m.out //= s.is_b_zero

        # Less-than comparator

        s.a_lt_b = m = LTComparator(Bits16)
        m.in0 //= s.a_reg.out
        m.in1 //= s.b_reg.out
        m.out //= s.is_a_lt_b

        # Subtractor

        s.sub = m = Subtractor(Bits16)
        m.in0 //= s.a_reg.out
        m.in1 //= s.b_reg.out
        m.out //= s.sub_out

        # connect to output port

        s.resp_msg //= s.sub.out