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
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
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
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)
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 )
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
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