def construct(s): # If translated into Verilog, we use the explicit name s.set_metadata(VerilogTranslationPass.explicit_module_name, 'SramMinionRTL') # Default memory message has 8 bits opaque field and 32 bits address MemReqType, MemRespType = mk_mem_msg(8, 32, 32) # Interface s.minion = stream.ifcs.MinionIfcRTL(MemReqType, MemRespType)
def construct(s, ProcClass, XcelClass): req_class, resp_class = mk_mem_msg(8, 32, 32) s.commit_inst = OutPort(Bits1) # Instruction Memory Request/Response Interface s.proc = ProcClass() s.proc.commit_inst //= s.commit_inst s.xcel = XcelClass() s.xcel.xcel //= s.proc.xcel if isinstance(s.proc.imem, MemMasterIfcRTL): # RTL proc s.mngr2proc = RecvIfcRTL(Bits32) s.proc2mngr = SendIfcRTL(Bits32) s.imem = MemMasterIfcRTL(req_class, resp_class) s.dmem = MemMasterIfcRTL(req_class, resp_class) elif isinstance(s.proc.imem, MemMasterIfcCL): # CL proc s.mngr2proc = CalleeIfcCL(Type=Bits32) s.proc2mngr = CallerIfcCL(Type=Bits32) s.imem = MemMasterIfcCL(req_class, resp_class) s.dmem = MemMasterIfcCL(req_class, resp_class) elif isinstance(s.proc.imem, MemMasterIfcFL): # FL proc s.mngr2proc = GetIfcFL(Type=Bits32) s.proc2mngr = SendIfcFL(Type=Bits32) s.imem = MemMasterIfcFL() s.dmem = MemMasterIfcFL() s.mngr2proc //= s.proc.mngr2proc s.proc2mngr //= s.proc.proc2mngr s.imem //= s.proc.imem s.dmem //= s.proc.dmem
def construct( s ): req_class, resp_class = mk_mem_msg( 8, 32, 32 ) # Proc/Mngr Interface s.mngr2proc = RecvIfcRTL( Bits32 ) s.proc2mngr = SendIfcRTL( Bits32 ) # Instruction Memory Request/Response Interface s.imem = MemMasterIfcRTL( req_class, resp_class ) # Data Memory Request/Response Interface s.dmem = MemMasterIfcRTL( req_class, resp_class ) # Xcel Request/Response Interface xreq_class, xresp_class = mk_xcel_msg( 5, 32 ) s.xcel = XcelMasterIfcRTL( xreq_class, xresp_class ) # val_W port used for counting commited insts. s.commit_inst = OutPort( Bits1 ) # Bypass queues s.imemreq_q = BypassQueue2RTL( req_class, 2 ) # We have to turn input receive interface into get interface s.imemresp_q = BypassQueueRTL( resp_class, 1 ) s.dmemresp_q = BypassQueueRTL( resp_class, 1 ) s.mngr2proc_q = BypassQueueRTL( Bits32, 1 ) s.xcelresp_q = BypassQueueRTL( xresp_class, 1 ) # imem drop unit s.imemresp_drop = m = DropUnitRTL( Bits32 ) m.in_.en //= s.imemresp_q.deq.en m.in_.rdy //= s.imemresp_q.deq.rdy m.in_.ret //= s.imemresp_q.deq.ret.data # connect all the queues s.imemreq_q.deq //= s.imem.req s.imemresp_q.enq //= s.imem.resp s.dmemresp_q.enq //= s.dmem.resp s.mngr2proc_q.enq //= s.mngr2proc s.xcelresp_q.enq //= s.xcel.resp # Control s.ctrl = m = ProcCtrl() # imem port m.imemresp_drop //= s.imemresp_drop.drop m.imemreq_en //= s.imemreq_q.enq.en m.imemreq_rdy //= s.imemreq_q.enq.rdy m.imemresp_en //= s.imemresp_drop.out.en m.imemresp_rdy //= s.imemresp_drop.out.rdy # dmem port m.dmemreq_en //= s.dmem.req.en m.dmemreq_rdy //= s.dmem.req.rdy m.dmemreq_type //= s.dmem.req.msg.type_ m.dmemresp_en //= s.dmemresp_q.deq.en m.dmemresp_rdy //= s.dmemresp_q.deq.rdy # xcel port m.xcelreq_type //= s.xcel.req.msg.type_ m.xcelreq_en //= s.xcel.req.en m.xcelreq_rdy //= s.xcel.req.rdy m.xcelresp_en //= s.xcelresp_q.deq.en m.xcelresp_rdy //= s.xcelresp_q.deq.rdy # proc2mngr and mngr2proc m.proc2mngr_en //= s.proc2mngr.en m.proc2mngr_rdy //= s.proc2mngr.rdy m.mngr2proc_en //= s.mngr2proc_q.deq.en m.mngr2proc_rdy //= s.mngr2proc_q.deq.rdy # commit inst for counting m.commit_inst //= s.commit_inst # Dpath s.dpath = m = ProcDpath() # imem ports m.imemreq_addr //= s.imemreq_q.enq.msg.addr m.imemresp_data //= s.imemresp_drop.out.ret # dmem ports m.dmemreq_addr //= s.dmem.req.msg.addr m.dmemreq_data //= s.dmem.req.msg.data m.dmemresp_data //= s.dmemresp_q.deq.ret.data # xcel ports m.xcelreq_addr //= s.xcel.req.msg.addr m.xcelreq_data //= s.xcel.req.msg.data m.xcelresp_data //= s.xcelresp_q.deq.ret.data # mngr m.mngr2proc_data //= s.mngr2proc_q.deq.ret m.proc2mngr_data //= s.proc2mngr.msg # Ctrl <-> Dpath s.ctrl.reg_en_F //= s.dpath.reg_en_F s.ctrl.pc_sel_F //= s.dpath.pc_sel_F s.ctrl.reg_en_D //= s.dpath.reg_en_D s.ctrl.op1_byp_sel_D //= s.dpath.op1_byp_sel_D s.ctrl.op2_byp_sel_D //= s.dpath.op2_byp_sel_D s.ctrl.op2_sel_D //= s.dpath.op2_sel_D s.ctrl.imm_type_D //= s.dpath.imm_type_D s.ctrl.reg_en_X //= s.dpath.reg_en_X s.ctrl.alu_fn_X //= s.dpath.alu_fn_X s.ctrl.reg_en_M //= s.dpath.reg_en_M s.ctrl.wb_result_sel_M //= s.dpath.wb_result_sel_M s.ctrl.reg_en_W //= s.dpath.reg_en_W s.ctrl.rf_waddr_W //= s.dpath.rf_waddr_W s.ctrl.rf_wen_W //= s.dpath.rf_wen_W s.dpath.inst_D //= s.ctrl.inst_D s.dpath.ne_X //= s.ctrl.ne_X
def construct(s): s.set_metadata(VerilogTranslationPass.explicit_module_name, "SramMinionRTL") # size is fixed as 32x128 num_bits = 32 num_words = 128 addr_width = clog2(num_words) addr_start = clog2(num_bits / 8) addr_end = addr_start + addr_width BitsAddr = mk_bits(addr_width) BitsData = mk_bits(num_bits) # Default memory message has 8 bits opaque field and 32 bits address. MemReqType, MemRespType = mk_mem_msg(8, 32, num_bits) # Interface s.minion = stream.ifcs.MinionIfcRTL(MemReqType, MemRespType) #--------------------------------------------------------------------- # M0 stage #--------------------------------------------------------------------- s.sram_addr_M0 = Wire(BitsAddr) s.sram_wen_M0 = Wire(Bits1) s.sram_en_M0 = Wire(Bits1) s.sram_wdata_M0 = Wire(BitsData) # translation work around MEM_MSG_TYPE_WRITE = b4(MemMsgType.WRITE) @update def comb_M0(): s.sram_addr_M0 @= s.minion.req.msg.addr[addr_start:addr_end] s.sram_wen_M0 @= s.minion.req.val & (s.minion.req.msg.type_ == MEM_MSG_TYPE_WRITE) s.sram_en_M0 @= s.minion.req.val & s.minion.req.rdy s.sram_wdata_M0 @= s.minion.req.msg.data # SRAM s.sram = m = SramRTL(num_bits, num_words) m.port0_idx //= s.sram_addr_M0 m.port0_type //= s.sram_wen_M0 m.port0_val //= s.sram_en_M0 m.port0_wdata //= s.sram_wdata_M0 #--------------------------------------------------------------------- # M1 stage #--------------------------------------------------------------------- # Pipeline registers s.memreq_val_reg_M1 = m = RegRst(Bits1) m.in_ //= s.sram_en_M0 s.memreq_msg_reg_M1 = m = Reg(MemReqType) m.in_ //= s.minion.req.msg # Create the memory response message with data from SRAM if read s.memresp_msg_M1 = Wire(MemRespType) # translation work around MEM_MSG_TYPE_READ = b4(MemMsgType.READ) @update def comb_M1a(): s.memresp_msg_M1.type_ @= s.memreq_msg_reg_M1.out.type_ s.memresp_msg_M1.opaque @= s.memreq_msg_reg_M1.out.opaque s.memresp_msg_M1.test @= 0 s.memresp_msg_M1.len @= s.memreq_msg_reg_M1.out.len if s.memreq_msg_reg_M1.out.type_ == MEM_MSG_TYPE_READ: s.memresp_msg_M1.data @= s.sram.port0_rdata else: s.memresp_msg_M1.data @= 0 # Bypass queue s.memresp_q = stream.BypassQueueRTL(MemRespType, num_entries=2) @update def comb_M1b(): # enqueue messages into the bypass queue s.memresp_q.recv.val @= s.memreq_val_reg_M1.out s.memresp_q.recv.msg @= s.memresp_msg_M1 # dequeue messages from the bypass queue s.minion.resp.val @= s.memresp_q.send.val s.memresp_q.send.rdy @= s.minion.resp.rdy s.minion.resp.msg @= s.memresp_q.send.msg # stop the minion interface if not enough skid buffering s.minion.req.rdy @= s.memresp_q.count == 0
Date : Apr 20, 2020 ''' import pytest from pymtl3 import * from pymtl3.stdlib.mem import mk_mem_msg, MemMsgType, MagicMemoryCL as MemoryCL from pymtl3.stdlib.test_utils.test_srcs import TestSrcCL as TestSource from pymtl3.stdlib.test_utils.test_sinks import TestSinkCL as TestSink from pymtl3.stdlib.test_utils import run_sim, mk_test_case_table from ..MasterMinionXbarGeneric import MasterMinionXbarGeneric as Xbar #------------------------------------------------------------------------- # constants #------------------------------------------------------------------------- Req, Resp = mk_mem_msg(8, 32, 32) rd = MemMsgType.READ wr = MemMsgType.WRITE hexwords = [ 0x8badf00d, 0xdeadbeef, 0xfeedbabe, 0xdeadc0de, 0xc001d00d, 0xdeadfa11, 0xfaceb00c, 0xc001cafe, 0xdeafbabe, 0x8badcafe, ]
#========================================================================= from __future__ import print_function import pytest import random from pymtl3 import * from pymtl3.stdlib import stream from pymtl3.stdlib.test_utils import mk_test_case_table, run_sim, config_model_with_cmdline_opts from pymtl3.stdlib.test_utils import TestSrcCL, TestSinkCL from pymtl3.stdlib.mem import mk_mem_msg, MemMsgType from tut8_sram.SramMinionRTL import SramMinionRTL MemReqType, MemRespType = mk_mem_msg(8, 32, 32) #------------------------------------------------------------------------- # TestHarness #------------------------------------------------------------------------- class TestHarness(Component): def construct(s, dut): # Instantiate models s.src = stream.SourceRTL(MemReqType) s.sram = dut s.sink = stream.SinkRTL(MemRespType)
def construct( s ): memreq_cls, memresp_cls = mk_mem_msg( 8,32,32 ) xreq_class, xresp_class = mk_xcel_msg(5,32) # Interface s.commit_inst = OutPort( Bits1 ) s.imem = MemMasterIfcCL( memreq_cls, memresp_cls ) s.dmem = MemMasterIfcCL( memreq_cls, memresp_cls ) s.xcel = XcelMasterIfcCL( xreq_class, xresp_class ) s.proc2mngr = CallerIfcCL() s.mngr2proc = CalleeIfcCL() # Buffers to hold input messages s.imemresp_q = DelayPipeDeqCL(0) s.imemresp_q.enq //= s.imem.resp s.dmemresp_q = DelayPipeDeqCL(1) s.dmemresp_q.enq //= s.dmem.resp s.mngr2proc_q = DelayPipeDeqCL(1) s.mngr2proc_q.enq //= s.mngr2proc s.xcelresp_q = DelayPipeDeqCL(0) s.xcelresp_q.enq //= s.xcel.resp s.pc = b32( 0x200 ) s.R = RegisterFile( 32 ) s.F_DXM_queue = PipeQueueCL(1) s.DXM_W_queue = PipeQueueCL(1) s.F_status = PipelineStatus.idle s.DXM_status = PipelineStatus.idle s.W_status = PipelineStatus.idle @update_once def F(): s.F_status = PipelineStatus.idle if s.reset: s.pc = b32( 0x200 ) return if s.imem.req.rdy() and s.F_DXM_queue.enq.rdy(): if s.redirected_pc_DXM >= 0: s.imem.req( memreq_cls( MemMsgType.READ, 0, s.redirected_pc_DXM ) ) s.pc = s.redirected_pc_DXM else: s.imem.req( memreq_cls( MemMsgType.READ, 0, s.pc ) ) s.F_DXM_queue.enq( s.pc ) s.F_status = PipelineStatus.work s.pc += 4 else: s.F_status = PipelineStatus.stall s.redirected_pc_DXM = -1 s.raw_inst = b32(0) @update_once def DXM(): s.redirected_pc_DXM = -1 s.DXM_status = PipelineStatus.idle if s.F_DXM_queue.deq.rdy() and s.imemresp_q.deq.rdy(): if not s.DXM_W_queue.enq.rdy(): s.DXM_status = PipelineStatus.stall else: pc = s.F_DXM_queue.peek() s.raw_inst = s.imemresp_q.peek().data inst = TinyRV0Inst( s.raw_inst ) inst_name = inst.name s.DXM_status = PipelineStatus.work if inst_name == "nop": pass elif inst_name == "add": s.DXM_W_queue.enq( (inst.rd, s.R[ inst.rs1 ] + s.R[ inst.rs2 ], DXM_W.arith) ) elif inst_name == "sll": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] << (s.R[inst.rs2] & 0x1F), DXM_W.arith) ) elif inst_name == "srl": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] >> (s.R[inst.rs2].uint() & 0x1F), DXM_W.arith) ) # ''' TUTORIAL TASK '''''''''''''''''''''''''''''''''''''''''''' # Implement instruction AND in CL processor # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''\/ #; Make an "elif" statement here to implement instruction AND #; that applies bit-wise "and" operator to rs1 and rs2 and #; pass the result to the pipeline. elif inst_name == "and": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] & s.R[inst.rs2], DXM_W.arith) ) # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''/\ elif inst_name == "addi": s.DXM_W_queue.enq( (inst.rd, s.R[ inst.rs1 ] + sext(inst.i_imm, 32), DXM_W.arith) ) elif inst_name == "sw": if s.dmem.req.rdy(): s.dmem.req( memreq_cls( MemMsgType.WRITE, 0, s.R[ inst.rs1 ] + sext(inst.s_imm, 32), 0, s.R[ inst.rs2 ] ) ) s.DXM_W_queue.enq( (0, 0, DXM_W.mem) ) else: s.DXM_status = PipelineStatus.stall elif inst_name == "lw": if s.dmem.req.rdy(): s.dmem.req( memreq_cls( MemMsgType.READ, 0, s.R[ inst.rs1 ] + sext(inst.i_imm, 32), 0 ) ) s.DXM_W_queue.enq( (inst.rd, 0, DXM_W.mem) ) else: s.DXM_status = PipelineStatus.stall elif inst_name == "bne": if s.R[ inst.rs1 ] != s.R[ inst.rs2 ]: s.redirected_pc_DXM = pc + sext(inst.b_imm, 32) s.DXM_W_queue.enq( None ) elif inst_name == "csrw": if inst.csrnum == 0x7C0: # CSR: proc2mngr # We execute csrw in W stage s.DXM_W_queue.enq( (0, s.R[ inst.rs1 ], DXM_W.mngr) ) elif 0x7E0 <= inst.csrnum <= 0x7FF: if s.xcel.req.rdy(): s.xcel.req( xreq_class( XcelMsgType.WRITE, inst.csrnum[0:5], s.R[inst.rs1]) ) s.DXM_W_queue.enq( (0, 0, DXM_W.xcel) ) else: s.DXM_status = PipelineStatus.stall elif inst_name == "csrr": if inst.csrnum == 0xFC0: # CSR: mngr2proc if s.mngr2proc_q.deq.rdy(): s.DXM_W_queue.enq( (inst.rd, s.mngr2proc_q.deq(), DXM_W.arith) ) else: s.DXM_status = PipelineStatus.stall elif 0x7E0 <= inst.csrnum <= 0x7FF: if s.xcel.req.rdy(): s.xcel.req( xreq_class( XcelMsgType.READ, inst.csrnum[0:5], s.R[inst.rs1]) ) s.DXM_W_queue.enq( (inst.rd, 0, DXM_W.xcel) ) else: s.DXM_status = PipelineStatus.stall # If we execute any instruction, we pop from queues if s.DXM_status == PipelineStatus.work: s.F_DXM_queue.deq() s.imemresp_q.deq() s.rd = b5(0) @update_once def W(): s.commit_inst @= 0 s.W_status = PipelineStatus.idle if s.DXM_W_queue.deq.rdy(): entry = s.DXM_W_queue.peek() if entry is not None: rd, data, entry_type = entry s.rd = rd if entry_type == DXM_W.mem: if s.dmemresp_q.deq.rdy(): if rd > 0: # load s.R[ rd ] = Bits32( s.dmemresp_q.deq().data ) else: # store s.dmemresp_q.deq() s.W_status = PipelineStatus.work else: s.W_status = PipelineStatus.stall elif entry_type == DXM_W.xcel: if s.xcelresp_q.deq.rdy(): if rd > 0: # csrr s.R[ rd ] = Bits32( s.xcelresp_q.deq().data ) else: # csrw s.xcelresp_q.deq() s.W_status = PipelineStatus.work else: s.W_status = PipelineStatus.stall elif entry_type == DXM_W.mngr: if s.proc2mngr.rdy(): s.proc2mngr( data ) s.W_status = PipelineStatus.work else: s.W_status = PipelineStatus.stall else: # other WB insts assert entry_type == DXM_W.arith if rd > 0: s.R[ rd ] = Bits32( data ) s.W_status = PipelineStatus.work else: # non-WB insts s.W_status = PipelineStatus.work if s.W_status == PipelineStatus.work: s.DXM_W_queue.deq() s.commit_inst @= 1