def __init__(s, dispatch_interface): UseInterface(s, dispatch_interface) preg_nbits = IssueMsg().rs1.nbits data_nbits = DispatchMsg().rs1.nbits s.require( # Methods needed from dflow: MethodSpec( 'read', args={'tag': preg_nbits}, rets={ 'value': data_nbits, }, call=False, rdy=False, count=2, ),) s.connect(s.process_accepted, 1) s.dispatched_ = Wire(DispatchMsg()) s.connect(s.process_out, s.dispatched_) # connect the register file read s.connect(s.read_tag[0], s.process_in_.rs1) s.connect(s.read_tag[1], s.process_in_.rs2) @s.combinational def set_output(): s.dispatched_.v = 0 s.dispatched_.hdr.v = s.process_in_.hdr if s.process_in_.hdr_status != PipelineMsgStatus.PIPELINE_MSG_STATUS_VALID: s.dispatched_.exception_info.v = s.process_in_.exception_info # Copy exception info s.dispatched_.exception_info.v = s.process_in_.exception_info else: s.dispatched_.rs1.v = s.read_value[0] s.dispatched_.rs1_val.v = s.process_in_.rs1_val s.dispatched_.rs2.v = s.read_value[1] s.dispatched_.rs2_val.v = s.process_in_.rs2_val s.dispatched_.rd.v = s.process_in_.rd s.dispatched_.rd_val.v = s.process_in_.rd_val s.dispatched_.areg_d.v = s.process_in_.areg_d s.dispatched_.execution_data.v = s.process_in_.execution_data
def __init__(s): # the order above (0 for CSR 1 for ALU comes from this array # This is bad UseInterface( s, PipelineSplitterInterface( DispatchMsg(), ['csr', 'alu', 'branch', 'm_pipe', 'mem_data'])) s.require( MethodSpec( 'in_peek', args=None, rets={ 'msg': DispatchMsg(), }, call=False, rdy=True, ), MethodSpec( 'in_take', args=None, rets=None, call=True, rdy=False, ), ) s.splitter = PipelineSplitter(s.interface) s.controller = PipeSelectorController() s.connect_m(s.splitter.sort, s.controller.sort) s.connect_m(s.splitter.in_peek, s.in_peek) s.connect_m(s.splitter.in_take, s.in_take) for client in s.interface.clients: s.connect_m(getattr(s.splitter, '{}_peek'.format(client)), getattr(s, '{}_peek'.format(client))) s.connect_m(getattr(s.splitter, '{}_take'.format(client)), getattr(s, '{}_take'.format(client)))
def __init__(s): UseInterface(s, PipelineSplitterControllerInterface(DispatchMsg(), 5)) @s.combinational def handle_sort(): if s.sort_msg.hdr_status != PipelineMsgStatus.PIPELINE_MSG_STATUS_VALID: s.sort_pipe.v = 0 # CSR pipe elif s.sort_msg.op_class == OpClass.OP_CLASS_CSR or s.sort_msg.op_class == OpClass.OP_CLASS_SYSTEM: s.sort_pipe.v = 0 # CSR pipe elif s.sort_msg.op_class == OpClass.OP_CLASS_ALU: s.sort_pipe.v = 1 # ALU pipe elif s.sort_msg.op_class == OpClass.OP_CLASS_BRANCH or s.sort_msg.op_class == OpClass.OP_CLASS_JUMP: s.sort_pipe.v = 2 # Branch pipe elif s.sort_msg.op_class == OpClass.OP_CLASS_MUL: s.sort_pipe.v = 3 # Mul pipe elif s.sort_msg.op_class == OpClass.OP_CLASS_MEM: s.sort_pipe.v = 4 # Mem data pipe else: s.sort_pipe.v = 0 # Error CSR pipe
def __init__(s): UseInterface(s, MPipeInterface()) # Require the methods of an incoming pipeline stage # Name the methods in_peek, in_take s.require(*[ m.variant(name='in_{}'.format(m.name)) for m in PipelineStageInterface(DispatchMsg(), None).methods.values() ]) s.div = Div() s.mult = Mult() s.connect(s.div.in_peek_msg, s.in_peek_msg) s.connect(s.mult.in_peek_msg, s.in_peek_msg) s.connect_m(s.div.kill_notify, s.kill_notify) s.connect_m(s.mult.kill_notify, s.kill_notify) @s.combinational def route_input(): if s.in_peek_msg.m_msg_func == MFunc.M_FUNC_MUL: s.mult.in_peek_rdy.v = s.in_peek_rdy s.in_take_call.v = s.mult.in_take_call s.div.in_peek_rdy.v = 0 else: s.div.in_peek_rdy.v = s.in_peek_rdy s.in_take_call.v = s.div.in_take_call s.mult.in_peek_rdy.v = 0 @s.combinational def route_output(): if s.div.peek_rdy: s.peek_rdy.v = s.div.peek_rdy s.peek_msg.v = s.div.peek_msg s.div.take_call.v = s.take_call s.mult.take_call.v = 0 else: s.peek_rdy.v = s.mult.peek_rdy s.peek_msg.v = s.mult.peek_msg s.mult.take_call.v = s.take_call s.div.take_call.v = 0
def __init__(s, interface): UseInterface(s, interface) s.require( MethodSpec( 'in_peek', args=None, rets={ 'msg': DispatchMsg(), }, call=False, rdy=True, ), MethodSpec( 'in_take', args=None, rets=None, call=True, rdy=False, ), MethodSpec( 'enter_store_data', args={ 'id_': STORE_IDX_NBITS, 'data': XLEN, }, rets=None, call=True, rdy=False, ), ) s.connect(s.in_take_call, s.in_peek_rdy) s.connect(s.enter_store_data_id_, s.in_peek_msg.hdr_store_id) s.connect(s.enter_store_data_data, s.in_peek_msg.rs2) s.connect(s.enter_store_data_call, s.in_peek_rdy)
def BranchInterface(): return StageInterface(DispatchMsg(), ExecuteMsg())
def CSRInterface(): return StageInterface(DispatchMsg(), ExecuteMsg()())
def __init__(s): UseInterface(s, ALUInterface()) imm_len = DispatchMsg().imm.nbits data_len = XLEN OP_LUT_MAP = { AluFunc.ALU_FUNC_ADD: alu.ALUFunc.ALU_ADD, AluFunc.ALU_FUNC_SUB: alu.ALUFunc.ALU_SUB, AluFunc.ALU_FUNC_AND: alu.ALUFunc.ALU_AND, AluFunc.ALU_FUNC_OR: alu.ALUFunc.ALU_OR, AluFunc.ALU_FUNC_XOR: alu.ALUFunc.ALU_XOR, AluFunc.ALU_FUNC_SLL: alu.ALUFunc.ALU_SLL, AluFunc.ALU_FUNC_SRL: alu.ALUFunc.ALU_SRL, AluFunc.ALU_FUNC_SRA: alu.ALUFunc.ALU_SRA, AluFunc.ALU_FUNC_SLT: alu.ALUFunc.ALU_SLT, AluFunc.ALU_FUNC_AUIPC: alu.ALUFunc.ALU_ADD, # We are just adding to the PC AluFunc.ALU_FUNC_LUI: alu.ALUFunc.ALU_OR, } s.op_lut_ = LookupTable( LookupTableInterface(DispatchMsg().alu_msg_func.nbits, alu.ALUFunc.bits), OP_LUT_MAP) s.alu_ = alu.ALU(alu.ALUInterface(data_len)) s.msg_ = Wire(DispatchMsg()) s.msg_imm_ = Wire(imm_len) # PYMTL_BROKEN, cant do msg.src1[:32] s.src1_ = Wire(data_len) s.src1_32_ = Wire(32) s.src2_ = Wire(data_len) s.src2_32_ = Wire(32) s.imm_ = Wire(data_len) s.imm_l20_ = Wire(data_len) s.res_ = Wire(data_len) s.res_32_ = Wire(32) # Connect up lookup table s.connect(s.op_lut_.lookup_in_, s.msg_.alu_msg_func) s.connect(s.alu_.exec_func, s.op_lut_.lookup_out) # Connect to disptach get method s.connect(s.msg_, s.process_in_) s.connect(s.process_accepted, 1) # Connect up alu call s.connect(s.alu_.exec_unsigned, s.msg_.alu_msg_unsigned) s.connect(s.alu_.exec_call, s.process_call) # PYMTL_BROKEN s.rs1_ = Wire(data_len) s.rs2_ = Wire(data_len) s.res_ = Wire(data_len) s.res_trunc_ = Wire(data_len) s.connect_wire(s.rs1_, s.msg_.rs1) s.connect_wire(s.rs2_, s.msg_.rs2) s.connect(s.res_, s.alu_.exec_res) @s.combinational def slice32(): s.src1_32_.v = s.rs1_[:32] s.src2_32_.v = s.rs2_[:32] s.res_32_.v = s.res_[:32] @s.combinational def set_src_res(): if s.msg_.alu_msg_op32: if s.msg_.alu_msg_unsigned or s.msg_.alu_msg_func == AluFunc.ALU_FUNC_SRL: s.src1_.v = zext(s.src1_32_, data_len) s.src2_.v = zext(s.src2_32_, data_len) else: s.src1_.v = sext(s.src1_32_, data_len) s.src2_.v = sext(s.src2_32_, data_len) # If op32 shift w, need to ignore bit 5 s.src2_[5].v &= not ( s.msg_.alu_msg_func == AluFunc.ALU_FUNC_SLL or s.msg_.alu_msg_func == AluFunc.ALU_FUNC_SRL or s.msg_.alu_msg_func == AluFunc.ALU_FUNC_SRA) s.res_trunc_.v = zext( s.res_32_, data_len) if s.msg_.alu_msg_unsigned else sext( s.res_32_, data_len) else: s.src1_.v = s.rs1_ s.src2_.v = s.rs2_ s.res_trunc_.v = s.res_ if s.msg_.alu_msg_func == AluFunc.ALU_FUNC_AUIPC: s.src1_.v = s.msg_.hdr_pc elif s.msg_.alu_msg_func == AluFunc.ALU_FUNC_LUI: # LUI is a special case s.src1_.v = 0 @s.combinational def set_inputs(): # PYMTL_BROKEN: sext, concat, and zext only work with wires and constants s.msg_imm_.v = s.msg_.imm s.imm_.v = sext(s.msg_imm_, data_len) if s.msg_.alu_msg_func == AluFunc.ALU_FUNC_AUIPC or s.msg_.alu_msg_func == AluFunc.ALU_FUNC_LUI: s.imm_.v = s.imm_ << 12 s.alu_.exec_src0.v = s.src1_ s.alu_.exec_src1.v = s.src2_ if s.msg_.rs2_val else s.imm_ @s.combinational def set_process_out(): s.process_out.v = 0 s.process_out.hdr.v = s.msg_.hdr s.process_out.result.v = s.res_trunc_ s.process_out.rd.v = s.msg_.rd s.process_out.rd_val.v = s.msg_.rd_val s.process_out.areg_d.v = s.msg_.areg_d
def __init__(s): UseInterface(s, DivInterface()) # Require the methods of an incoming pipeline stage # Name the methods in_peek, in_take s.require(*[ m.variant(name='in_{}'.format(m.name)) for m in PipelineStageInterface(DispatchMsg(), None).methods.values() ]) s.divider = NonRestoringDivider(DivideInterface(XLEN), DIV_NSTEPS) s.vvm = gen_valid_value_manager(MultDropController)() s.can_take_input = Wire(1) s.output_rdy = Wire(1) s.connect_m(s.vvm.kill_notify, s.kill_notify) @s.combinational def handle_control(): s.can_take_input.v = s.in_peek_rdy and s.divider.div_rdy s.output_rdy.v = s.divider.result_rdy and s.vvm.peek_rdy s.connect(s.in_take_call, s.can_take_input) s.connect(s.divider.div_call, s.can_take_input) s.connect(s.vvm.add_call, s.can_take_input) s.connect(s.peek_rdy, s.output_rdy) s.connect(s.divider.preempt_call, s.vvm.dropping_out) s.connect(s.vvm.take_call, s.take_call) s.connect(s.divider.result_call, s.take_call) s.rs1_32 = Wire(32) s.rs2_32 = Wire(32) # PYMTL_BROKEN # Cannot double-slice so must first assign parts s.workaround_rs1 = Wire(XLEN) s.workaround_rs2 = Wire(XLEN) s.connect(s.workaround_rs1, s.in_peek_msg.rs1) s.connect(s.workaround_rs2, s.in_peek_msg.rs2) @s.combinational def handle_add(): s.rs1_32.v = s.workaround_rs1[:32] s.rs2_32.v = s.workaround_rs2[:32] s.divider.div_dividend.v = s.in_peek_msg.rs1 s.divider.div_divisor.v = s.in_peek_msg.rs2 s.divider.div_signed.v = s.in_peek_msg.m_msg_variant == MVariant.M_VARIANT_N if s.in_peek_msg.m_msg_op32: if s.in_peek_msg.m_msg_variant == MVariant.M_VARIANT_N: # signed s.divider.div_dividend.v = sext(s.rs1_32, XLEN) s.divider.div_divisor.v = sext(s.rs2_32, XLEN) else: s.divider.div_dividend.v = zext(s.rs1_32, XLEN) s.divider.div_divisor.v = zext(s.rs2_32, XLEN) @s.combinational def handle_vvm_add_msg(): s.vvm.add_msg.v = 0 s.vvm.add_msg.hdr.v = s.in_peek_msg.hdr s.vvm.add_msg.result.v = zext(s.in_peek_msg.m_msg, XLEN) s.vvm.add_msg.rd.v = s.in_peek_msg.rd s.vvm.add_msg.rd_val.v = s.in_peek_msg.rd_val s.vvm.add_msg.areg_d.v = s.in_peek_msg.areg_d s.mul_msg = Wire(MMsg()) s.res_32 = Wire(32) num_bits = MMsg().nbits # PYMTL_BROKEN # can't slice a bitstrut (illegal verilog double array) s.peek_msg_result = Wire(XLEN) s.connect(s.peek_msg_result, s.vvm.peek_msg.result) @s.combinational def handle_output_msg(msg_bits=num_bits): s.peek_msg.v = s.vvm.peek_msg s.mul_msg.v = s.peek_msg_result[:msg_bits] s.res_32.v = s.divider.result_quotient[:32] s.peek_msg.result.v = s.divider.result_quotient if s.mul_msg.func == MFunc.M_FUNC_REM: s.res_32.v = s.divider.result_rem[:32] s.peek_msg.result.v = s.divider.result_rem if s.mul_msg.op32: s.peek_msg.result.v = sext(s.res_32, XLEN)
def MemInputPipelineAdapter(): return BranchMaskInputPipelineAdapter( BranchMaskInputPipelineAdapterInterface(DispatchMsg()))
def __init__(s, interface): UseInterface(s, interface) s.mem_request = MemRequest(MemRequestInterface()) s.mem_response = MemResponse(MemResponseInterface()) s.require( MethodSpec( 'recv_load', args=None, rets={ 'data': XLEN, }, call=True, rdy=True, ), MethodSpec( 'store_pending', args={ 'live_mask': Bits(STORE_QUEUE_SIZE), 'addr': XLEN, 'size': MEM_SIZE_NBITS, }, rets={ 'pending': Bits(1), }, call=False, rdy=False, ), MethodSpec( 'send_load', args={ 'addr': XLEN, 'size': MEM_SIZE_NBITS, }, rets=None, call=True, rdy=True, ), MethodSpec( 'enter_store_address', args={ 'id_': STORE_IDX_NBITS, 'addr': XLEN, 'size': MEM_SIZE_NBITS, }, rets=None, call=True, rdy=False, ), MethodSpec( 'valid_store_mask', args=None, rets={ 'mask': STORE_QUEUE_SIZE, }, call=False, rdy=False, ), ) s.connect_m(s.mem_request.store_pending, s.store_pending) s.connect_m(s.mem_request.send_load, s.send_load) s.connect_m(s.mem_request.enter_store_address, s.enter_store_address) s.connect_m(s.mem_request.valid_store_mask, s.valid_store_mask) s.connect_m(s.mem_response.recv_load, s.recv_load) # Require the methods of an incoming pipeline stage # Name the methods in_peek, in_take s.require(*[ m.variant(name='in_{}'.format(m.name)) for m in PipelineStageInterface(DispatchMsg(), None).methods.values() ]) s.connect_m(s.mem_request.in_peek, s.in_peek) s.connect_m(s.mem_request.in_take, s.in_take) s.connect_m(s.mem_response.in_peek, s.mem_request.peek) s.connect_m(s.mem_response.in_take, s.mem_request.take) s.connect_m(s.peek, s.mem_response.peek) s.connect_m(s.take, s.mem_response.take)
def MemResponseInterface(): return StageInterface(DispatchMsg(), ExecuteMsg())
def DispatchDropController(): return PipelineKillDropController( DropControllerInterface(DispatchMsg(), DispatchMsg(), KillType(MAX_SPEC_DEPTH)))
def __init__(s, branch_interface): UseInterface(s, branch_interface) imm_len = DispatchMsg().imm.nbits data_len = XLEN spec_idx_len = DispatchMsg().hdr_spec.nbits seq_idx_nbits = DispatchMsg().hdr_seq.nbits speculative_mask_nbits = DispatchMsg().hdr_branch_mask.nbits s.require( MethodSpec( 'cflow_redirect', args={ 'seq': Bits(seq_idx_nbits), 'spec_idx': Bits(spec_idx_len), 'branch_mask': Bits(speculative_mask_nbits), 'target': Bits(data_len), 'force': Bits(1), }, rets={}, call=True, rdy=False, ), MethodSpec( 'btb_write', args={ 'key': XLEN, 'remove': Bits(1), 'value': XLEN, }, rets=None, call=True, rdy=False, ), ) s.connect(s.process_accepted, 1) s.cmp_ = Comparator(ComparatorInterface(data_len)) s.msg_ = Wire(DispatchMsg()) s.msg_imm_ = Wire(imm_len) s.imm_ = Wire(data_len) s.take_branch_ = Wire(1) s.branch_target_ = Wire(data_len) s.branch_target_pcimm_ = Wire(data_len) s.branch_target_rs1imm_ = Wire(data_len) s.branch_target_fallthrough_ = Wire(data_len) OP_LUT_MAP = { BranchType.BRANCH_TYPE_EQ: CMPFunc.CMP_EQ, BranchType.BRANCH_TYPE_NE: CMPFunc.CMP_NE, BranchType.BRANCH_TYPE_LT: CMPFunc.CMP_LT, BranchType.BRANCH_TYPE_GE: CMPFunc.CMP_GE, } s.op_lut_ = LookupTable( LookupTableInterface(DispatchMsg().branch_msg_type_.nbits, CMPFunc.bits), OP_LUT_MAP) # Connect to disptach get method s.connect(s.msg_, s.process_in_) # Connect lookup opmap s.connect(s.op_lut_.lookup_in_, s.msg_.branch_msg_type_) s.connect(s.cmp_.exec_func, s.op_lut_.lookup_out) # Connect up cmp call s.connect(s.cmp_.exec_src0, s.msg_.rs1) s.connect(s.cmp_.exec_src1, s.msg_.rs2) s.connect(s.cmp_.exec_unsigned, s.msg_.branch_msg_unsigned) s.connect(s.cmp_.exec_call, s.process_call) # Connect up to controlflow redirect method s.connect(s.cflow_redirect_spec_idx, s.msg_.hdr_spec) s.connect(s.cflow_redirect_seq, s.msg_.hdr_seq) s.connect(s.cflow_redirect_branch_mask, s.msg_.hdr_branch_mask) s.connect(s.cflow_redirect_target, s.branch_target_) s.connect(s.cflow_redirect_force, 0) s.connect(s.cflow_redirect_call, s.process_call) @s.combinational def set_take_branch(): s.take_branch_.v = s.cmp_.exec_res or s.msg_.op_class == OpClass.OP_CLASS_JUMP @s.combinational def compute_target(): s.msg_imm_.v = s.msg_.imm # PYMTL_BROKEN: sext(s.msg_.imm) does not create valid verilog # Vivado errors: "range is not allowed in prefix" s.imm_.v = sext(s.msg_imm_, data_len) s.branch_target_pcimm_.v = s.msg_.hdr_pc + s.imm_ s.branch_target_rs1imm_.v = s.msg_.rs1 + s.imm_ s.branch_target_rs1imm_[0].v = 0 s.branch_target_fallthrough_.v = s.msg_.hdr_pc + ILEN_BYTES if s.take_branch_: # Branch or JAL if s.msg_.op_class == OpClass.OP_CLASS_BRANCH or not s.msg_.rs1_val: s.branch_target_.v = s.branch_target_pcimm_ else: s.branch_target_.v = s.branch_target_rs1imm_ else: s.branch_target_.v = s.branch_target_fallthrough_ @s.combinational def set_value_reg_input(): s.process_out.v = 0 s.process_out.hdr.v = s.msg_.hdr s.process_out.result.v = s.msg_.hdr_pc + ILEN_BYTES s.process_out.rd.v = s.msg_.rd s.process_out.rd_val.v = s.msg_.rd_val s.process_out.areg_d.v = s.msg_.areg_d @s.combinational def update_btb(): s.btb_write_key.v = s.msg_.hdr_pc s.btb_write_value.v = s.branch_target_ s.btb_write_remove.v = not s.take_branch_ s.btb_write_call.v = s.process_call
def MemRequestInterface(): return StageInterface(DispatchMsg(), DispatchMsg())
def MultInputPipelineAdapterInterface(): return InputPipelineAdapterInterface(DispatchMsg(), MultIn(), ExecuteMsg())
def DispatchInterface(): return StageInterface(IssueMsg(), DispatchMsg())