def construct(s): MemReqMsg, MemRespMsg = mk_mem_msg(8, 32, 32) # Interface s.xcel = XcelMinionIfcCL(XcelReqMsg, XcelRespMsg) s.mem = MemMasterIfcCL(*mk_mem_msg(8, 32, 32))
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()(commit_inst=s.commit_inst) s.xcel = XcelClass()(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 = NonBlockingCalleeIfc(Bits32) s.proc2mngr = NonBlockingCallerIfc(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() s.proc2mngr = SendIfcFL() s.imem = MemMasterIfcFL() s.dmem = MemMasterIfcFL() s.connect_pairs( s.mngr2proc, s.proc.mngr2proc, s.proc2mngr, s.proc.proc2mngr, s.imem, s.proc.imem, s.dmem, s.proc.dmem, )
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 = NonBlockingCallerIfc() s.mngr2proc = NonBlockingCalleeIfc() # Buffers to hold input messages s.imemresp_q = DelayPipeDeqCL(0)(enq=s.imem.resp) s.dmemresp_q = DelayPipeDeqCL(1)(enq=s.dmem.resp) s.mngr2proc_q = DelayPipeDeqCL(1)(enq=s.mngr2proc) s.xcelresp_q = DelayPipeDeqCL(0)(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 @s.update 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) @s.update 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 == "sub": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] - s.R[inst.rs2], DXM_W.arith)) elif inst_name == "mul": 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 == "slt": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1].int() < s.R[inst.rs2].int(), DXM_W.arith)) elif inst_name == "sltu": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] < s.R[inst.rs2], DXM_W.arith)) elif inst_name == "sra": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1].int() >> (s.R[inst.rs2].uint() & 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 == "or": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] | s.R[inst.rs2], DXM_W.arith)) elif inst_name == "xor": 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] + inst.i_imm.int(), DXM_W.arith)) elif inst_name == "andi": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] & inst.i_imm.int(), DXM_W.arith)) elif inst_name == "ori": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] | inst.i_imm.int(), DXM_W.arith)) elif inst_name == "xori": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] ^ inst.i_imm.int(), DXM_W.arith)) elif inst_name == "slli": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] << inst.i_imm.int(), DXM_W.arith)) elif inst_name == "srli": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] >> inst.i_imm.int(), DXM_W.arith)) elif inst_name == "srai": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1].int() >> (inst.i_imm.uint() & 0x1F), DXM_W.arith)) elif inst_name == "slti": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1].int() < inst.i_imm.int(), DXM_W.arith)) elif inst_name == "sltiu": s.DXM_W_queue.enq( (inst.rd, s.R[inst.rs1] < sext(inst.i_imm, 32), DXM_W.arith)) elif inst_name == "auipc": s.DXM_W_queue.enq((inst.rd, (s.pc - 4) + inst.u_imm, DXM_W.arith)) #not elegant elif inst_name == "lui": s.DXM_W_queue.enq((inst.rd, inst.u_imm, DXM_W.arith)) elif inst_name == "sh": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.WRITE, 0, s.R[inst.rs1] + inst.s_imm.int(), 2, s.R[inst.rs2][0:16])) s.DXM_W_queue.enq((0, 0, DXM_W.mem)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "sb": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.WRITE, 0, s.R[inst.rs1] + inst.s_imm.int(), 1, s.R[inst.rs2][0:8])) s.DXM_W_queue.enq((0, 0, DXM_W.mem)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "sw": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.WRITE, 0, s.R[inst.rs1] + inst.s_imm.int(), 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] + inst.i_imm.int(), 0)) s.DXM_W_queue.enq((inst.rd, 0, DXM_W.mem)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "lb": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.READ, 0, s.R[inst.rs1] + inst.i_imm.int(), 1)) s.DXM_W_queue.enq((inst.rd, 0, DXM_W.mem_signed)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "lh": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.READ, 0, s.R[inst.rs1] + inst.i_imm.int(), 2)) s.DXM_W_queue.enq((inst.rd, 0, DXM_W.mem_signed)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "lbu": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.READ, 0, s.R[inst.rs1] + inst.i_imm.int(), 1)) s.DXM_W_queue.enq((inst.rd, 0, DXM_W.mem)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "lhu": if s.dmem.req.rdy(): s.dmem.req( memreq_cls(MemMsgType.READ, 0, s.R[inst.rs1] + inst.i_imm.int(), 2)) s.DXM_W_queue.enq((inst.rd, 0, DXM_W.mem)) else: s.DXM_status = PipelineStatus.stall elif inst_name == "jal": s.DXM_W_queue.enq((inst.rd, s.pc, DXM_W.arith)) s.pc = s.pc + sext(inst.j_imm, 32) - 4 elif inst_name == "jalr": s.DXM_W_queue.enq((inst.rd, s.pc, DXM_W.arith)) s.pc = (s.R[inst.rs1] + sext(inst.i_imm, 32)) & 0xFFFFFFFE elif inst_name == "bne": if s.R[inst.rs1] != s.R[inst.rs2]: s.redirected_pc_DXM = pc + inst.b_imm.int() s.DXM_W_queue.enq(None) elif inst_name == "beq": if s.R[inst.rs1] == s.R[inst.rs2]: s.redirected_pc_DXM = pc + inst.b_imm.int() s.DXM_W_queue.enq(None) elif inst_name == "blt": if s.R[inst.rs1].int() < s.R[inst.rs2].int(): s.redirected_pc_DXM = pc + inst.b_imm.int() s.DXM_W_queue.enq(None) elif inst_name == "bge": if s.R[inst.rs1].int() >= s.R[inst.rs2].int(): s.redirected_pc_DXM = pc + inst.b_imm.int() s.DXM_W_queue.enq(None) elif inst_name == "bltu": if s.R[inst.rs1] < s.R[inst.rs2]: s.redirected_pc_DXM = pc + inst.b_imm.int() s.DXM_W_queue.enq(None) elif inst_name == "bgeu": if s.R[inst.rs1] >= s.R[inst.rs2]: s.redirected_pc_DXM = pc + inst.b_imm.int() 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) @s.update def W(): s.commit_inst = Bits1(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.mem_signed: if s.dmemresp_q.deq.rdy(): if rd > 0: # load s.R[rd] = Bits32( sext(s.dmemresp_q.deq().data, 32)) 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 = Bits1(1)
def construct( s ): MemReqMsg, MemRespMsg = mk_mem_msg( 8,32,32 ) # Interface s.xcel = XcelMinionIfcCL( XcelReqMsg, XcelRespMsg ) s.mem = MemMasterIfcCL( *mk_mem_msg(8,32,32) ) # ''' LAB TASK '''''''''''''''''''''''''''''''''''''''''''''''''''''' # Create CL model for sorting xcel # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''\/ # Components s.xcelreq_q = PipeQueueCL( num_entries=1 )( enq = s.xcel.req ) s.memresp_q = PipeQueueCL( num_entries=1 )( enq = s.mem.resp ) # Internal state s.base_addr = 0 s.size = 0 s.inner_count = 0 s.outer_count = 0 s.a = b32(0) s.b = b32(0) # State s.STATE_XCFG = 0 s.STATE_FIRST0 = 1 s.STATE_FIRST1 = 2 s.STATE_BUBBLE0 = 3 s.STATE_BUBBLE1 = 4 s.STATE_LAST = 5 s.state = s.STATE_XCFG # Line tracing s.prev_state = 0 s.xcfg_trace = " " # logic @s.update def block(): # Line tracing string s.prev_state = s.state #------------------------------------------------------------------- # STATE: XCFG #------------------------------------------------------------------- # In this state we handle the accelerator configuration protocol, # where we write the base address, size, and then tell the # accelerator to start. We also handle responding when the # accelerator is done. if s.state == s.STATE_XCFG: s.xcfg_trace = " " if s.xcelreq_q.deq.rdy() and s.xcel.resp.rdy(): xcelreq_msg = s.xcelreq_q.deq() if xcelreq_msg.type_ == XCEL_TYPE_WRITE: assert xcelreq_msg.addr in [0,1,2], \ "Only reg writes to 0,1,2 allowed during setup!" if xcelreq_msg.addr == 0: s.xcfg_trace = "X0" s.outer_count = 0 s.state = s.STATE_FIRST0 elif xcelreq_msg.addr == 1: s.xcfg_trace = "X1" s.base_addr = xcelreq_msg.data.uint() elif xcelreq_msg.addr == 2: s.xcfg_trace = "X2" s.size = xcelreq_msg.data.uint() # Send xcel response message s.xcel.resp( XcelRespMsg(XCEL_TYPE_WRITE, 0) ) else: s.xcfg_trace = "x0" assert xcelreq_msg.addr == 0 # Send xcel response message, obviously you only want to # send the response message when accelerator is done s.xcel.resp( XcelRespMsg(XCEL_TYPE_READ, 1) ) #------------------------------------------------------------------- # STATE: FIRST0 #------------------------------------------------------------------- # Send the first memory read request for the very first # element in the array. elif s.state == s.STATE_FIRST0: if s.mem.req.rdy(): s.mem.req( MemReqMsg( MemMsgType.READ, 0, s.base_addr, 0 ) ) s.inner_count = 1 s.state = s.STATE_FIRST1 #------------------------------------------------------------------- # STATE: FIRST1 #------------------------------------------------------------------- # Wait for the memory response for the first element in the array, # and once it arrives store this element in a, and send the memory # read request for the second element. elif s.state == s.STATE_FIRST1: if s.mem.req.rdy() and s.memresp_q.deq.rdy(): s.a = s.memresp_q.deq().data addr = s.base_addr + 4*s.inner_count s.mem.req( MemReqMsg( MemMsgType.READ, 4, addr, 0 ) ) s.state = s.STATE_BUBBLE0 #------------------------------------------------------------------- # STATE: BUBBLE0 #------------------------------------------------------------------- # Wait for the memory read response to get the next element, # compare the new value to the previous max value, update b with # the new max value, and send a memory request to store the new min # value. Notice how we decrement the write address by four since we # want to store to the new min value _previous_ element. elif s.state == s.STATE_BUBBLE0: if s.mem.req.rdy() and s.memresp_q.deq.rdy(): s.b = deepcopy( s.memresp_q.deq().data ) max_value = max( s.a, s.b ) min_value = min( s.a, s.b ) s.a = max_value addr = s.base_addr + 4*s.inner_count s.mem.req( MemReqMsg( MemMsgType.WRITE, 4, addr-4, 0, min_value ) ) s.state = s.STATE_BUBBLE1 #------------------------------------------------------------------- # STATE: BUBBLE1 #------------------------------------------------------------------- # Wait for the memory write response, and then check to see if we # have reached the end of the array. If we have not reached the end # of the array, then make a new memory read request for the next # element; if we have reached the end of the array, then make a # final write request (with value from a) to update the final # element in the array. elif s.state == s.STATE_BUBBLE1: if s.mem.req.rdy() and s.memresp_q.deq.rdy(): s.memresp_q.deq() s.inner_count += 1 if s.inner_count < s.size: addr = s.base_addr + 4*s.inner_count s.mem.req( MemReqMsg( MemMsgType.READ, 4, addr, 0 ) ) s.state = s.STATE_BUBBLE0 else: addr = s.base_addr + 4*s.inner_count s.mem.req( MemReqMsg( MemMsgType.WRITE, 4, addr-4, 0, s.a ) ) s.state = s.STATE_LAST #------------------------------------------------------------------- # STATE: LAST #------------------------------------------------------------------- # Wait for the last response, and then check to see if we need to # go through the array again. If we do need to go through array # again, then make a new memory read request for the very first # element in the array; if we do not need to go through the array # again, then we are all done and we can go back to accelerator # configuration. elif s.state == s.STATE_LAST: if s.mem.req.rdy() and s.memresp_q.deq.rdy(): s.memresp_q.deq() s.outer_count += 1 if s.outer_count < s.size: s.mem.req( MemReqMsg( MemMsgType.READ, 4, s.base_addr, 0 ) ) s.inner_count = 1 s.state = s.STATE_FIRST1 else: s.state = s.STATE_XCFG