def decode_const(self, m: Module): const_sig = Signal(32) with m.Switch(self._const): with m.Case(ConstSelect.EXC_INSTR_ADDR_MISALIGN): m.d.comb += const_sig.eq( TrapCause.EXC_INSTR_ADDR_MISALIGN) with m.Case(ConstSelect.EXC_ILLEGAL_INSTR): m.d.comb += const_sig.eq(TrapCause.EXC_ILLEGAL_INSTR) with m.Case(ConstSelect.EXC_BREAKPOINT): m.d.comb += const_sig.eq(TrapCause.EXC_BREAKPOINT) with m.Case(ConstSelect.EXC_LOAD_ADDR_MISALIGN): m.d.comb += const_sig.eq( TrapCause.EXC_LOAD_ADDR_MISALIGN) with m.Case(ConstSelect.EXC_STORE_AMO_ADDR_MISALIGN): m.d.comb += const_sig.eq( TrapCause.EXC_STORE_AMO_ADDR_MISALIGN) with m.Case(ConstSelect.EXC_ECALL_FROM_MACH_MODE): m.d.comb += const_sig.eq( TrapCause.EXC_ECALL_FROM_MACH_MODE) with m.Case(ConstSelect.INT_MACH_EXTERNAL): m.d.comb += const_sig.eq(TrapCause.INT_MACH_EXTERNAL) with m.Case(ConstSelect.INT_MACH_TIMER): m.d.comb += const_sig.eq(TrapCause.INT_MACH_TIMER) with m.Case(ConstSelect.SHAMT_0): m.d.comb += const_sig.eq(0) with m.Case(ConstSelect.SHAMT_4): m.d.comb += const_sig.eq(4) with m.Case(ConstSelect.SHAMT_8): m.d.comb += const_sig.eq(8) with m.Case(ConstSelect.SHAMT_16): m.d.comb += const_sig.eq(16) with m.Case(ConstSelect.SHAMT_24): m.d.comb += const_sig.eq(24) with m.Default(): m.d.comb += const_sig.eq(0) return const_sig
def handle_store(self, m: Module): """Adds the STORE logic to the given module. Note that byte stores are byte-aligned, half-word stores are 16-bit aligned, and word stores are 32-bit aligned. Attempting to stores unaligned will lead to undefined behavior. addr <- rs1 + imm data <- rs2 PC <- PC + 4 rs1 -> X imm -> Y ALU ADD -> Z Z -> memaddr --------------------- rs2 -> X shamt -> Y ALU SLL -> Z Z -> wrdata -> wrmask --------------------- PC + 4 -> PC PC + 4 -> memaddr """ with m.If(self._instr_phase == 0): m.d.comb += [ self.reg_to_x.eq(1), self._x_reg_select.eq(InstrReg.RS1), self.y_mux_select.eq(SeqMuxSelect.IMM), self.alu_op_to_z.eq(AluOp.ADD), self.memaddr_mux_select.eq(SeqMuxSelect.Z), self._next_instr_phase.eq(1), ] with m.Elif(self._instr_phase == 1): # Check for exception conditions first with m.If((self._funct3 == MemAccessWidth.H) & self.memaddr_2_lsb[0]): self.set_exception(m, ConstSelect.EXC_STORE_AMO_ADDR_MISALIGN, mtval=SeqMuxSelect.MEMADDR) with m.Elif((self._funct3 == MemAccessWidth.W) & (self.memaddr_2_lsb != 0)): self.set_exception(m, ConstSelect.EXC_STORE_AMO_ADDR_MISALIGN, mtval=SeqMuxSelect.MEMADDR) with m.Elif(~self._funct3.matches( MemAccessWidth.B, MemAccessWidth.H, MemAccessWidth.W)): self.handle_illegal_instr(m) with m.Else(): m.d.comb += [ self.reg_to_x.eq(1), self._x_reg_select.eq(InstrReg.RS2), self.y_mux_select.eq(SeqMuxSelect.CONST), self.alu_op_to_z.eq(AluOp.SLL), self.memdata_wr_mux_select.eq(SeqMuxSelect.Z), self._next_instr_phase.eq(2), ] with m.Switch(self._funct3): with m.Case(MemAccessWidth.B): with m.Switch(self.memaddr_2_lsb): with m.Case(0): m.d.comb += self._const.eq(ConstSelect.SHAMT_0) with m.Case(1): m.d.comb += self._const.eq(ConstSelect.SHAMT_8) with m.Case(2): m.d.comb += self._const.eq( ConstSelect.SHAMT_16) with m.Case(3): m.d.comb += self._const.eq( ConstSelect.SHAMT_24) with m.Case(MemAccessWidth.H): with m.Switch(self.memaddr_2_lsb): with m.Case(0): m.d.comb += self._const.eq(ConstSelect.SHAMT_0) with m.Case(2): m.d.comb += self._const.eq( ConstSelect.SHAMT_16) with m.Case(MemAccessWidth.W): m.d.comb += self._const.eq(ConstSelect.SHAMT_0) with m.Else(): with m.Switch(self._funct3): with m.Case(MemAccessWidth.B): with m.Switch(self.memaddr_2_lsb): with m.Case(0): m.d.comb += self.mem_wr_mask.eq(0b0001) with m.Case(1): m.d.comb += self.mem_wr_mask.eq(0b0010) with m.Case(2): m.d.comb += self.mem_wr_mask.eq(0b0100) with m.Case(3): m.d.comb += self.mem_wr_mask.eq(0b1000) with m.Case(MemAccessWidth.H): with m.Switch(self.memaddr_2_lsb): with m.Case(0): m.d.comb += self.mem_wr_mask.eq(0b0011) with m.Case(2): m.d.comb += self.mem_wr_mask.eq(0b1100) with m.Case(MemAccessWidth.W): m.d.comb += self.mem_wr_mask.eq(0b1111) m.d.comb += self.mem_wr.eq(1) self.next_instr(m)
def elaborate(self, platform: Platform) -> Module: m = Module() opcode = Signal(Opcode) funct3 = Signal(Funct3) funct7 = Signal(Funct7) funct12 = Signal(Funct12) iimm12 = Signal((12, True)) simm12 = Signal((12, True)) bimm12 = Signal((13, True)) uimm20 = Signal(20) jimm20 = Signal((21, True)) itype = Signal(Type) instruction = self.instruction with m.Switch(opcode): with m.Case(Opcode.LUI): m.d.comb += itype.eq(Type.U) with m.Case(Opcode.AUIPC): m.d.comb += itype.eq(Type.U) with m.Case(Opcode.JAL): m.d.comb += itype.eq(Type.J) with m.Case(Opcode.JALR): m.d.comb += itype.eq(Type.I) with m.Case(Opcode.BRANCH): m.d.comb += itype.eq(Type.B) with m.Case(Opcode.LOAD): m.d.comb += itype.eq(Type.I) with m.Case(Opcode.STORE): m.d.comb += itype.eq(Type.S) with m.Case(Opcode.OP_IMM): m.d.comb += itype.eq(Type.I) with m.Case(Opcode.OP): m.d.comb += itype.eq(Type.R) with m.Case(Opcode.FENCE): m.d.comb += itype.eq(Type.I) with m.Case(Opcode.SYSTEM): m.d.comb += itype.eq(Type.I) with m.Switch(itype): with m.Case(Type.I): m.d.comb += self.immediate.eq(iimm12) with m.Case(Type.S): m.d.comb += self.immediate.eq(simm12) with m.Case(Type.B): m.d.comb += self.immediate.eq(bimm12) with m.Case(Type.U): m.d.comb += self.immediate.eq(uimm20 << 12) with m.Case(Type.J): m.d.comb += self.immediate.eq(jimm20) m.d.comb += [ opcode.eq(instruction[:7]), funct3.eq(instruction[12:15]), funct7.eq(instruction[25:32]), funct12.eq(instruction[20:32]), iimm12.eq(instruction[20:32]), simm12.eq(Cat(instruction[7:12], instruction[25:32])), bimm12.eq( Cat(0, instruction[8:12], instruction[25:31], instruction[7], instruction[31])), uimm20.eq(instruction[12:32]), jimm20.eq( Cat(0, instruction[21:31], instruction[20], instruction[12:20], instruction[31])) ] m.d.comb += [ self.gpr_rs1.eq(instruction[15:20]), self.gpr_rs1_use.eq( reduce( or_, [itype == tmp for tmp in (Type.R, Type.I, Type.S, Type.B)])), self.gpr_rs2.eq(instruction[20:25]), self.gpr_rs2_use.eq( reduce(or_, [itype == tmp for tmp in (Type.R, Type.S, Type.B)])), self.gpr_rd.eq(instruction[7:12]), self.gpr_we.eq( reduce( or_, [itype == tmp for tmp in (Type.R, Type.I, Type.U, Type.J)])), self.funct3.eq(funct3) ] m.d.comb += [ self.needed_in_x.eq(self.lui | self.aiupc | self.jump | self.aritmetic | self.logic | self.multiply), self.needed_in_m.eq(self.compare | self.shift | self.divide), ] # ---------------------------------------------------------------------- # define functions to handle the match Fields = List[Tuple[int, Optional[int], Optional[int], Optional[int]]] # Tuple: (Opcode, F3, F7, F12) def match(fields: Fields) -> bool: def __check(op, f3=None, f7=None, f12=None): op_match = opcode == op f3_match = funct3 == f3 if f3 is not None else 1 f7_match = funct7 == f7 if f7 is not None else 1 f12_match = funct12 == f12 if f12 is not None else 1 return op_match & f3_match & f7_match & f12_match return reduce(or_, [__check(*instr) for instr in fields]) # ---------------------------------------------------------------------- m.d.comb += [ self.lui.eq(opcode == Opcode.LUI), self.aiupc.eq(opcode == Opcode.AUIPC), self.jump.eq( match([(Opcode.JAL, None, None, None), (Opcode.JALR, 0, None, None)])), self.branch.eq( match([(Opcode.BRANCH, Funct3.BEQ, None, None), (Opcode.BRANCH, Funct3.BNE, None, None), (Opcode.BRANCH, Funct3.BLT, None, None), (Opcode.BRANCH, Funct3.BGE, None, None), (Opcode.BRANCH, Funct3.BLTU, None, None), (Opcode.BRANCH, Funct3.BGEU, None, None)])), self.load.eq( match([(Opcode.LOAD, Funct3.B, None, None), (Opcode.LOAD, Funct3.H, None, None), (Opcode.LOAD, Funct3.W, None, None), (Opcode.LOAD, Funct3.BU, None, None), (Opcode.LOAD, Funct3.HU, None, None)])), self.store.eq( match([(Opcode.STORE, Funct3.B, None, None), (Opcode.STORE, Funct3.H, None, None), (Opcode.STORE, Funct3.W, None, None)])), self.aritmetic.eq( match([(Opcode.OP_IMM, Funct3.ADD, None, None), (Opcode.OP, Funct3.ADD, Funct7.ADD, None), (Opcode.OP, Funct3.ADD, Funct7.SUB, None)])), self.logic.eq( match([(Opcode.OP_IMM, Funct3.XOR, None, None), (Opcode.OP_IMM, Funct3.OR, None, None), (Opcode.OP_IMM, Funct3.AND, None, None), (Opcode.OP, Funct3.XOR, 0, None), (Opcode.OP, Funct3.OR, 0, None), (Opcode.OP, Funct3.AND, 0, None)])), self.compare.eq( match([(Opcode.OP_IMM, Funct3.SLT, None, None), (Opcode.OP_IMM, Funct3.SLTU, None, None), (Opcode.OP, Funct3.SLT, 0, None), (Opcode.OP, Funct3.SLTU, 0, None)])), self.shift.eq( match([(Opcode.OP_IMM, Funct3.SLL, 0, None), (Opcode.OP_IMM, Funct3.SR, Funct7.SRL, None), (Opcode.OP_IMM, Funct3.SR, Funct7.SRA, None), (Opcode.OP, Funct3.SLL, 0, None), (Opcode.OP, Funct3.SR, Funct7.SRL, None), (Opcode.OP, Funct3.SR, Funct7.SRA, None)])), self.csr.eq( match([ (Opcode.SYSTEM, Funct3.CSRRW, None, None), (Opcode.SYSTEM, Funct3.CSRRS, None, None), (Opcode.SYSTEM, Funct3.CSRRC, None, None), (Opcode.SYSTEM, Funct3.CSRRWI, None, None), (Opcode.SYSTEM, Funct3.CSRRSI, None, None), (Opcode.SYSTEM, Funct3.CSRRCI, None, None), ])), self.ecall.eq( match([(Opcode.SYSTEM, Funct3.PRIV, None, Funct12.ECALL)])), self.ebreak.eq( match([(Opcode.SYSTEM, Funct3.PRIV, None, Funct12.EBREAK)])), self.mret.eq((self.privmode == PrivMode.Machine) & match([(Opcode.SYSTEM, Funct3.PRIV, None, Funct12.MRET)])), self.fence_i.eq(match([(Opcode.FENCE, Funct3.FENCEI, None, None) ])), self.fence.eq(match([(Opcode.FENCE, Funct3.FENCE, None, None)])), self.substract.eq( match([(Opcode.OP, Funct3.ADD, Funct7.SUB, None)])), self.shift_direction.eq(funct3 == Funct3.SR), self.shit_signed.eq(funct7 == Funct7.SRA), self.csr_we.eq(~funct3[1] | (self.gpr_rs1 != 0)), ] if (self.enable_rv32m): m.d.comb += [ self.multiply.eq( match([(Opcode.OP, Funct3.MUL, Funct7.MULDIV, None), (Opcode.OP, Funct3.MULH, Funct7.MULDIV, None), (Opcode.OP, Funct3.MULHU, Funct7.MULDIV, None), (Opcode.OP, Funct3.MULHSU, Funct7.MULDIV, None)])), self.divide.eq( match([(Opcode.OP, Funct3.DIV, Funct7.MULDIV, None), (Opcode.OP, Funct3.DIVU, Funct7.MULDIV, None), (Opcode.OP, Funct3.REM, Funct7.MULDIV, None), (Opcode.OP, Funct3.REMU, Funct7.MULDIV, None)])) ] m.d.comb += self.illegal.eq(~reduce(or_, [ self.lui, self.aiupc, self.jump, self.branch, self.load, self.store, self.aritmetic, self.logic, self.shift, self.compare, self.csr, self.ecall, self.ebreak, self.mret, self.fence_i, self.fence, self.multiply, self.divide ])) return m
def elaborate(self, platform): m = Module() interface = self.interface # Create convenience aliases for our interface components. setup = interface.setup handshake_generator = interface.handshakes_out tx = interface.tx # # Submodules # # Handler for Get Descriptor requests; responds with our various fixed descriptors. m.submodules.get_descriptor = get_descriptor_handler = GetDescriptorHandler( self.descriptors) m.d.comb += [ get_descriptor_handler.value.eq(setup.value), get_descriptor_handler.length.eq(setup.length), ] # Handler for various small-constant-response requests (GET_CONFIGURATION, GET_STATUS). m.submodules.transmitter = transmitter = \ StreamSerializer(data_length=2, domain="usb", stream_type=USBInStreamInterface, max_length_width=2) # # Handlers. # with m.If(setup.type == USBRequestType.STANDARD): with m.FSM(domain="usb"): # IDLE -- not handling any active request with m.State('IDLE'): # If we've received a new setup packet, handle it. with m.If(setup.received): # Select which standard packet we're going to handler. with m.Switch(setup.request): with m.Case(USBStandardRequests.GET_STATUS): m.next = 'GET_STATUS' with m.Case(USBStandardRequests.SET_ADDRESS): m.next = 'SET_ADDRESS' with m.Case(USBStandardRequests.SET_CONFIGURATION): m.next = 'SET_CONFIGURATION' with m.Case(USBStandardRequests.GET_DESCRIPTOR): m.next = 'GET_DESCRIPTOR' with m.Case(USBStandardRequests.GET_CONFIGURATION): m.next = 'GET_CONFIGURATION' with m.Case(): m.next = 'UNHANDLED' # GET_STATUS -- Fetch the device's status. # For now, we'll always return '0'. with m.State('GET_STATUS'): # TODO: handle reporting endpoint stall status # TODO: copy the remote wakeup and bus-powered attributes from bmAttributes of the relevant descriptor? self.handle_simple_data_request(m, transmitter, 0, length=2) # SET_ADDRESS -- The host is trying to assign us an address. with m.State('SET_ADDRESS'): self.handle_register_write_request( m, interface.new_address, interface.address_changed) # SET_CONFIGURATION -- The host is trying to select an active configuration. with m.State('SET_CONFIGURATION'): # TODO: stall if we don't have a relevant configuration self.handle_register_write_request( m, interface.new_config, interface.config_changed) # GET_DESCRIPTOR -- The host is asking for a USB descriptor -- for us to "self describe". with m.State('GET_DESCRIPTOR'): m.d.comb += [ get_descriptor_handler.tx.attach(tx), handshake_generator.stall.eq( get_descriptor_handler.stall) ] # Respond to our data stage with a descriptor... with m.If(interface.data_requested): m.d.comb += get_descriptor_handler.start.eq(1), # ... and ACK our status stage. with m.If(interface.status_requested): m.d.comb += handshake_generator.ack.eq(1) m.next = 'IDLE' # GET_CONFIGURATION -- The host is asking for the active configuration number. with m.State('GET_CONFIGURATION'): self.handle_simple_data_request(m, transmitter, interface.active_config) # UNHANDLED -- we've received a request we're not prepared to handle with m.State('UNHANDLED'): # When we next have an opportunity to stall, do so, # and then return to idle. with m.If(interface.data_requested | interface.status_requested): m.d.comb += handshake_generator.stall.eq(1) m.next = 'IDLE' return m
def elaborate(self, _: Platform) -> Module: """Implements the logic of the sequencer card.""" m = Module() # Defaults m.d.comb += [ self._next_instr_phase.eq(0), self.reg_to_x.eq(0), self.reg_to_y.eq(0), self.alu_op_to_z.eq(AluOp.NONE), self.mem_rd.eq(0), self.mem_wr.eq(0), self.mem_wr_mask.eq(0), self.csr_to_x.eq(0), self.z_to_csr.eq(0), self._funct12_to_csr_num.eq(0), self._mepc_num_to_csr_num.eq(0), self._mcause_to_csr_num.eq(0), self._x_reg_select.eq(0), self._y_reg_select.eq(0), self._z_reg_select.eq(0), self.enter_trap.eq(0), self.exit_trap.eq(0), self.save_trap_csrs.eq(0), self.pc_mux_select.eq(SeqMuxSelect.PC), self.memaddr_mux_select.eq(SeqMuxSelect.MEMADDR), self.memdata_wr_mux_select.eq(SeqMuxSelect.MEMDATA_WR), self.tmp_mux_select.eq(SeqMuxSelect.TMP), self.x_mux_select.eq(SeqMuxSelect.X), self.y_mux_select.eq(SeqMuxSelect.Y), self.z_mux_select.eq(SeqMuxSelect.Z), self._const.eq(0), ] m.d.comb += [ self.load_trap.eq(0), self.next_trap.eq(0), self.load_exception.eq(0), self.next_exception.eq(0), self.next_fatal.eq(0), ] with m.If(self.enable_sequencer_rom): # Output control signals with m.Switch(self.opcode_select): with m.Case(OpcodeSelect.LUI): self.handle_lui(m) with m.Case(OpcodeSelect.AUIPC): self.handle_auipc(m) with m.Case(OpcodeSelect.OP_IMM): self.handle_op_imm(m) with m.Case(OpcodeSelect.OP): self.handle_op(m) with m.Case(OpcodeSelect.JAL): self.handle_jal(m) with m.Case(OpcodeSelect.JALR): self.handle_jalr(m) with m.Case(OpcodeSelect.BRANCH): self.handle_branch(m) with m.Case(OpcodeSelect.LOAD): self.handle_load(m) with m.Case(OpcodeSelect.STORE): self.handle_store(m) with m.Case(OpcodeSelect.CSRS): self.handle_csrs(m) with m.Case(OpcodeSelect.MRET): self.handle_MRET(m) with m.Case(OpcodeSelect.ECALL): self.handle_ECALL(m) with m.Case(OpcodeSelect.EBREAK): self.handle_EBREAK(m) with m.Default(): self.handle_illegal_instr(m) return m
def elaborate(self, platform): m = Module() cpu = Core() m.submodules += cpu m.domains.ph1 = ph1 = ClockDomain("ph1") m.domains.ph2 = ph2 = ClockDomain("ph2", clk_edge="neg") # Hook up clocks and reset to pins if not SLOWCLK: clk1 = platform.request("clk1") clk2 = platform.request("clk2") rst = platform.request("rst") m.d.comb += [ ph1.rst.eq(rst.i), ph2.rst.eq(rst.i), ph1.clk.eq(clk1.i), ph2.clk.eq(clk2.i), ] if SLOWCLK: clk_freq = platform.default_clk_frequency timer = Signal(range(0, int(clk_freq // 2)), reset=int(clk_freq // 2) - 1) tick = Signal() sync = ClockDomain() with m.If(timer == 0): m.d.sync += timer.eq(timer.reset) m.d.sync += tick.eq(~tick) with m.Else(): m.d.sync += timer.eq(timer - 1) m.d.comb += [ ph1.rst.eq(sync.rst), ph2.rst.eq(sync.rst), ph1.clk.eq(tick), ph2.clk.eq(~tick), ] # Hook up address lines to pins for i in range(16): pin = platform.request("addr", i) m.d.comb += pin.o.eq(cpu.Addr[i]) if not FAKEMEM: # Hook up data in/out + direction to pins for i in range(8): pin = platform.request("data", i) m.d.comb += pin.o.eq(cpu.Dout[i]) m.d.ph2 += cpu.Din[i].eq(pin.i) m.d.comb += pin.oe.eq(~cpu.RW) if FAKEMEM: with m.Switch(cpu.Addr): for addr, data in mem.items(): with m.Case(addr): m.d.comb += cpu.Din.eq(data) with m.Default(): m.d.comb += cpu.Din.eq(0xFF) for i in range(8): pin = platform.request("led", i) m.d.comb += pin.o.eq(cpu.Addr[i]) for i in range(2): pin = platform.request("reset_state", i) m.d.comb += pin.o.eq(cpu.reset_state[i]) rw = platform.request("rw") m.d.comb += rw.o.eq(cpu.RW) return m
def elaborate(self, platform): m = Module() interface = self.interface # Create convenience aliases for our interface components. setup = interface.setup handshake_generator = interface.handshakes_out tx = interface.tx # # Submodules # # Handler for Get Descriptor requests; responds with our various fixed descriptors. m.submodules.get_descriptor = get_descriptor_handler = GetDescriptorHandler( self.descriptors) m.d.comb += [ get_descriptor_handler.value.eq(setup.value), get_descriptor_handler.length.eq(setup.length), ] # Handler for various small-constant-response requests (GET_CONFIGURATION, GET_STATUS). m.submodules.transmitter = transmitter = \ StreamSerializer(data_length=2, domain="usb", stream_type=USBInStreamInterface, max_length_width=2) # # Handlers. # with m.If(setup.type == USBRequestType.STANDARD): with m.FSM(domain="usb"): # IDLE -- not handling any active request with m.State('IDLE'): m.d.usb += [ # Start at the beginning of our next / fresh GET_DESCRIPTOR request. get_descriptor_handler.start_position.eq(0), # Always start our responses with DATA1 pids, per [USB 2.0: 8.5.3]. self.interface.tx_data_pid.eq(1) ] # If we've received a new setup packet, handle it. with m.If(setup.received): # Select which standard packet we're going to handler. with m.Switch(setup.request): with m.Case(USBStandardRequests.GET_STATUS): m.next = 'GET_STATUS' with m.Case(USBStandardRequests.SET_ADDRESS): m.next = 'SET_ADDRESS' with m.Case(USBStandardRequests.SET_CONFIGURATION): m.next = 'SET_CONFIGURATION' with m.Case(USBStandardRequests.GET_DESCRIPTOR): m.next = 'GET_DESCRIPTOR' with m.Case(USBStandardRequests.GET_CONFIGURATION): m.next = 'GET_CONFIGURATION' with m.Case(): m.next = 'UNHANDLED' # GET_STATUS -- Fetch the device's status. # For now, we'll always return '0'. with m.State('GET_STATUS'): # TODO: handle reporting endpoint stall status # TODO: copy the remote wakeup and bus-powered attributes from bmAttributes of the relevant descriptor? self.handle_simple_data_request(m, transmitter, 0, length=2) # SET_ADDRESS -- The host is trying to assign us an address. with m.State('SET_ADDRESS'): self.handle_register_write_request( m, interface.new_address, interface.address_changed) # SET_CONFIGURATION -- The host is trying to select an active configuration. with m.State('SET_CONFIGURATION'): # TODO: stall if we don't have a relevant configuration self.handle_register_write_request( m, interface.new_config, interface.config_changed) # GET_DESCRIPTOR -- The host is asking for a USB descriptor -- for us to "self describe". with m.State('GET_DESCRIPTOR'): m.d.comb += [ get_descriptor_handler.tx.attach(tx), handshake_generator.stall.eq( get_descriptor_handler.stall) ] # Respond to our data stage with a descriptor... with m.If(interface.data_requested): m.d.comb += get_descriptor_handler.start.eq(1) # Each time we receive an ACK, advance in our descriptor. # This allows us to send descriptors with >64B of content. with m.If(interface.handshakes_in.ack): # NOTE: this logic might need to be scaled by bytes-per-word for USB3, if it's ever used. # For now, we're not using it on USB3 at all, since we assume descriptors always fit in a # USB3 packet. next_start_position = get_descriptor_handler.start_position + self._max_packet_size m.d.usb += [ # We've received an ACK; so mark the section we've sent of the descriptor as # received, and move forward... get_descriptor_handler.start_position.eq( next_start_position), # ... and toggle our data PID. self.interface.tx_data_pid.eq( ~self.interface.tx_data_pid) ] # ... and ACK our status stage. with m.If(interface.status_requested): m.d.comb += handshake_generator.ack.eq(1) m.next = 'IDLE' # GET_CONFIGURATION -- The host is asking for the active configuration number. with m.State('GET_CONFIGURATION'): self.handle_simple_data_request(m, transmitter, interface.active_config) # UNHANDLED -- we've received a request we're not prepared to handle with m.State('UNHANDLED'): # When we next have an opportunity to stall, do so, # and then return to idle. with m.If(interface.data_requested | interface.status_requested): m.d.comb += handshake_generator.stall.eq(1) m.next = 'IDLE' return m
def elaborate(self, platform): m = Module() ####################################################################### # Line State Recovery State Machine # # The receive path doesn't use a differential receiver. Because of # this there is a chance that one of the differential pairs will appear # to have changed to the new state while the other is still in the old # state. The following state machine detects transitions and waits an # extra sampling clock before decoding the state on the differential # pair. This transition period # will only ever last for one clock as # long as there is no noise on the line. If there is enough noise on # the line then the data may be corrupted and the packet will fail the # data integrity checks. # dpair = Signal(2) m.d.comb += dpair.eq(Cat(self._usbn, self._usbp)) # output signals for use by the clock recovery stage line_state_dt = Signal() line_state_dj = Signal() line_state_dk = Signal() line_state_se0 = Signal() line_state_se1 = Signal() # If we are in a transition state, then we can sample the pair and # move to the next corresponding line state. with m.FSM(domain="usb_io"): with m.State("DT"): m.d.comb += line_state_dt.eq(1) with m.Switch(dpair): with m.Case(0b10): m.next = "DJ" with m.Case(0b01): m.next = "DK" with m.Case(0b00): m.next = "SE0" with m.Case(0b11): m.next = "SE1" # If we are in a valid line state and the value of the pair changes, # then we need to move to the transition state. with m.State("DJ"): m.d.comb += line_state_dj.eq(1) with m.If(dpair != 0b10): m.next = "DT" with m.State("DK"): m.d.comb += line_state_dk.eq(1) with m.If(dpair != 0b01): m.next = "DT" with m.State("SE0"): m.d.comb += line_state_se0.eq(1) with m.If(dpair != 0b00): m.next = "DT" with m.State("SE1"): m.d.comb += line_state_se1.eq(1) with m.If(dpair != 0b11): m.next = "DT" ####################################################################### # Clock and Data Recovery # # The DT state from the line state recovery state machine is used to align to # transmit clock. The line state is sampled in the middle of the bit time. # # Example of signal relationships # ------------------------------- # line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ # line_state_valid ________----____________----____________----________----____ # bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2 # # We 4x oversample, so make the line_state_phase have # 4 possible values. line_state_phase = Signal(2) m.d.usb_io += [ self.line_state_valid.eq(line_state_phase == 1), # flop all the outputs to help with timing self.line_state_dj.eq(line_state_dj), self.line_state_dk.eq(line_state_dk), self.line_state_se0.eq(line_state_se0), self.line_state_se1.eq(line_state_se1), ] with m.If(line_state_dt): m.d.usb_io += [ # re-align the phase with the incoming transition line_state_phase.eq(0), # make sure we never assert valid on a transition self.line_state_valid.eq(0), ] with m.Else(): # keep tracking the clock by incrementing the phase m.d.usb_io += line_state_phase.eq(line_state_phase + 1) return m
def elaborate(self, platform): m = Module() # Move the pipeline along m.d.sync += [ self.o_x_coord.eq(self.i_x_coord), self.o_y_coord.eq(self.i_y_coord), self.o_z_coord.eq(self.i_z_coord), self.o_red.eq(self.i_red), self.o_green.eq(self.i_green), self.o_blue.eq(self.i_blue), self.o_alpha.eq(self.i_alpha) ] # Alpha Test, relative to AREF. test = Signal() with m.If(self.i_enable): with m.Switch(self.i_test): with m.Case(AlphaTestMode.NEVER): m.d.comb += test.eq(0) with m.Case(AlphaTestMode.ALWAYS): m.d.comb += test.eq(1) with m.Case(AlphaTestMode.LESS): m.d.comb += test.eq(self.i_alpha < self.i_aref) with m.Case(AlphaTestMode.LEQUAL): m.d.comb += test.eq(self.i_alpha <= self.i_aref) with m.Case(AlphaTestMode.EQUAL): m.d.comb += test.eq(self.i_alpha == self.i_aref) with m.Case(AlphaTestMode.GEQUAL): m.d.comb += test.eq(self.i_alpha >= self.i_aref) with m.Case(AlphaTestMode.GREATER): m.d.comb += test.eq(self.i_alpha > self.i_aref) with m.Case(AlphaTestMode.NOTEQUAL): m.d.comb += test.eq(self.i_alpha != self.i_aref) with m.Else(): m.d.comb += test.eq(1) with m.Switch(self.i_failmod): with m.Case(AlphaFailMode.KEEP): m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr & test), self.o_arndr.eq(self.i_arndr & test), self.o_zrndr.eq(self.i_zrndr & test) ] with m.Case(AlphaFailMode.FB_ONLY): m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr), self.o_arndr.eq(self.i_arndr), self.o_zrndr.eq(self.i_zrndr & test) ] with m.Case(AlphaFailMode.ZB_ONLY): m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr & test), self.o_arndr.eq(self.i_arndr & test), self.o_zrndr.eq(self.i_zrndr) ] with m.Case(AlphaFailMode.RGB_ONLY): # "RGB_ONLY is effective only when the color format is RGBA32. # In other formats, operation is made with FB_ONLY." - GS User's Manual with m.If(self.i_fbpxfmt == PixelFormat.PSMCT32): m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr), self.o_arndr.eq(self.i_arndr & test), self.o_zrndr.eq(self.i_zrndr & test) ] with m.Else(): m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr), self.o_arndr.eq(self.i_arndr), self.o_zrndr.eq(self.i_zrndr & test) ] return m
def elaborate(self, platform): m = Module() # Synchronize the USB signals at our I/O boundary. # Despite the assumptions made in ValentyUSB, this line rate recovery FSM # isn't enough to properly synchronize these inputs. We'll explicitly synchronize. sync_dp = synchronize(m, self._usbp, o_domain="usb_io") sync_dn = synchronize(m, self._usbn, o_domain="usb_io") ####################################################################### # Line State Recovery State Machine # # The receive path doesn't use a differential receiver. Because of # this there is a chance that one of the differential pairs will appear # to have changed to the new state while the other is still in the old # state. The following state machine detects transitions and waits an # extra sampling clock before decoding the state on the differential # pair. This transition period will only ever last for one clock as # long as there is no noise on the line. If there is enough noise on # the line then the data may be corrupted and the packet will fail the # data integrity checks. # dpair = Cat(sync_dp, sync_dn) # output signals for use by the clock recovery stage line_state_in_transition = Signal() with m.FSM(domain="usb_io") as fsm: m.d.usb_io += [ self.line_state_se0.eq(fsm.ongoing("SE0")), self.line_state_se1.eq(fsm.ongoing("SE1")), self.line_state_dj.eq(fsm.ongoing("DJ")), self.line_state_dk.eq(fsm.ongoing("DK")), ] # If we are in a transition state, then we can sample the pair and # move to the next corresponding line state. with m.State("DT"): m.d.comb += line_state_in_transition.eq(1) with m.Switch(dpair): with m.Case(0b10): m.next = "DJ" with m.Case(0b01): m.next = "DK" with m.Case(0b00): m.next = "SE0" with m.Case(0b11): m.next = "SE1" # If we are in a valid line state and the value of the pair changes, # then we need to move to the transition state. with m.State("DJ"): with m.If(dpair != 0b10): m.next = "DT" with m.State("DK"): with m.If(dpair != 0b01): m.next = "DT" with m.State("SE0"): with m.If(dpair != 0b00): m.next = "DT" with m.State("SE1"): with m.If(dpair != 0b11): m.next = "DT" ####################################################################### # Clock and Data Recovery # # The DT state from the line state recovery state machine is used to align to # transmit clock. The line state is sampled in the middle of the bit time. # # Example of signal relationships # ------------------------------- # line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ # line_state_valid ________----____________----____________----________----____ # bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2 # # We 4x oversample, so make the line_state_phase have # 4 possible values. line_state_phase = Signal(2) m.d.usb_io += self.line_state_valid.eq(line_state_phase == 1) with m.If(line_state_in_transition): m.d.usb_io += [ # re-align the phase with the incoming transition line_state_phase.eq(0), # make sure we never assert valid on a transition self.line_state_valid.eq(0), ] with m.Else(): # keep tracking the clock by incrementing the phase m.d.usb_io += line_state_phase.eq(line_state_phase + 1) return m
def elaborate(self, platform): """ """ m = Module() # pins ft_clkout_i = platform.request("ft_clkout_i") ft_wr_n_o = platform.request("ft_wr_n_o") ft_txe_n_i = platform.request("ft_txe_n_i") ft_suspend_n_i = platform.request("ft_suspend_n_i") ft_oe_n_o = platform.request("ft_oe_n_o") ft_rd_n_o = platform.request("ft_rd_n_o") ft_siwua_n_o = platform.request("ft_siwua_n_o") ft_data_io = platform.request("ft_data_io") adc_d_i = platform.request("adc_d_i") adc_oe_o = platform.request("adc_oe_o") adc_shdn_o = platform.request("adc_shdn_o") ext1 = platform.request("ext1") pa_en_n_o = platform.request("pa_en_n_o") mix_en_n_o = platform.request("mix_en_n_o") # signals clk80 = Signal() pll_fb = Signal() chan_a = Signal(self.ADC_WIDTH) chan_b = Signal(self.ADC_WIDTH) lsb = Signal() lock = Signal(RAW_STATE) sample_ctr = Signal(range(self.DECIMATE * self.FFT_LEN)) sample_ctr_max = Const(self.DECIMATE * self.FFT_LEN - 1) cons_done = Signal() cons_done_clk80_dom = Signal() send_start = Signal() send_stop = Signal() wait_prod = Signal() lock_ftclk_dom = Signal() lock_ftclk_dom_last = Signal() # clock domains clk40_neg = ClockDomain("clk40_neg", clk_edge="neg") m.domains.clk40_neg = clk40_neg m.d.comb += ClockSignal("clk40_neg").eq(ClockSignal("sync")) m.domains += ClockDomain("clk60") m.d.comb += ClockSignal("clk60").eq(ft_clkout_i.i) m.domains += ClockDomain("clk80") m.d.comb += ClockSignal("clk80").eq(clk80) # ======================== submodules ======================== # PLL m.submodules += Instance( "PLLE2_BASE", ("p", "CLKFBOUT_MULT", 24), ("p", "DIVCLK_DIVIDE", 1), ("p", "CLKOUT0_DIVIDE", 12), ("p", "CLKIN1_PERIOD", 25), ("o", "CLKOUT0", clk80), ("i", "CLKIN1", ClockSignal("sync")), ("i", "RST", 0), ("o", "CLKFBOUT", pll_fb), ("i", "CLKFBIN", pll_fb), ) # ADC m.submodules.ltc2292 = ltc2292 = LTC2292( posedge_domain="sync", negedge_domain="clk40_neg" ) m.d.comb += [ ltc2292.di.eq(adc_d_i.i), chan_a.eq(ltc2292.dao), chan_b.eq(ltc2292.dbo), ] # FIFO m.submodules.fifo = fifo = AsyncFIFO( width=self.USB_WIDTH, depth=self.DECIMATE * self.FFT_LEN * 2, r_domain="clk60", w_domain="clk80", ) with m.If(lsb): m.d.comb += fifo.w_data.eq(chan_a[: self.USB_WIDTH]) with m.Else(): m.d.comb += fifo.w_data.eq( Cat( chan_a[self.USB_WIDTH :], Const(0, 2 * self.USB_WIDTH - self.ADC_WIDTH), ) ) # consumption done sync m.submodules.cons_done_sync = cons_done_sync = FFSynchronizer( i=cons_done, o=cons_done_clk80_dom, o_domain="clk80" ) # lock synch m.submodules.lock_sync = lock_sync = FFSynchronizer( i=lock, o=lock_ftclk_dom, o_domain="clk60" ) # =========================== logic ========================== m.d.comb += [ pa_en_n_o.o.eq(1), mix_en_n_o.o.eq(1), adc_oe_o.o.eq(0b01), adc_shdn_o.o.eq(0b00), ext1.o[0].eq(0b0), ext1.o[3].eq(lock), ext1.o[1].eq(0b0), ext1.o[4].eq(fifo.r_en), ext1.o[2].eq(0b0), ext1.o[5].eq(fifo.w_en), ] # write clock domain with m.If(lock == RAW_STATE.PROD): with m.If(sample_ctr == sample_ctr_max): m.d.clk80 += [ lock.eq(RAW_STATE.CONS), sample_ctr.eq(0), lsb.eq(0), ] with m.Else(): with m.If(lsb): m.d.clk80 += sample_ctr.eq(sample_ctr + 1) m.d.clk80 += lsb.eq(~lsb) with m.Else(): with m.If(cons_done_clk80_dom): m.d.clk80 += [ lock.eq(RAW_STATE.PROD), sample_ctr.eq(0), lsb.eq(0), ] with m.Switch(lock): with m.Case(RAW_STATE.PROD): m.d.comb += fifo.w_en.eq(1) with m.Case(RAW_STATE.CONS): m.d.comb += fifo.w_en.eq(0) # read clock domain m.d.clk60 += lock_ftclk_dom_last.eq(lock_ftclk_dom) with m.If(lock_ftclk_dom == RAW_STATE.CONS & ~wait_prod): with m.If(~fifo.r_rdy): m.d.clk60 += wait_prod.eq(1) with m.Elif(lock_ftclk_dom == RAW_STATE.CONS): m.d.clk60 += wait_prod.eq(1) with m.Else(): m.d.clk60 += wait_prod.eq(0) m.d.comb += [ ft_oe_n_o.o.eq(1), ft_rd_n_o.o.eq(1), ft_siwua_n_o.o.eq(1), ] with m.Switch(lock_ftclk_dom): with m.Case(RAW_STATE.PROD): m.d.comb += [ send_start.eq(0), send_stop.eq(0), ft_data_io.o.eq(0), ft_wr_n_o.o.eq(1), fifo.r_en.eq(0), ] with m.Case(RAW_STATE.CONS): with m.If(lock_ftclk_dom_last == RAW_STATE.PROD): m.d.comb += send_start.eq(1) with m.Else(): m.d.comb += send_start.eq(0) with m.If(~fifo.r_rdy): m.d.comb += [send_stop.eq(1), cons_done.eq(1)] with m.Else(): m.d.comb += [send_stop.eq(0), cons_done.eq(0)] with m.If(send_start): m.d.comb += [ ft_data_io.o.eq(self.START_FLAG), ft_wr_n_o.o.eq(ft_txe_n_i.i), fifo.r_en.eq(1), ] with m.Elif(send_stop): m.d.comb += [ ft_data_io.o.eq(self.STOP_FLAG), ft_wr_n_o.o.eq(ft_txe_n_i.i), fifo.r_en.eq(0), ] with m.Else(): with m.If(wait_prod): m.d.comb += [ ft_data_io.o.eq(0), ft_wr_n_o.o.eq(1), fifo.r_en.eq(0), ] with m.Else(): m.d.comb += [ ft_data_io.o.eq(fifo.r_data), ft_wr_n_o.o.eq(~(~ft_txe_n_i.i & fifo.r_en)), fifo.r_en.eq(~ft_txe_n_i.i & fifo.r_rdy), ] return m
def elaborate(self, platform: Platform) -> Module: m = Module() m.d.comb += self._ccs.eq(self.ccs) m.d.ph1 += self.ccs.eq(self._ccs) # intermediates carry4 = Signal() carry7 = Signal() carry8 = Signal() overflow = Signal() with m.Switch(self.func): with m.Case(ALU8Func.LD): m.d.comb += self.output.eq(self.input2) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(0) with m.Case(ALU8Func.LDCHAIN): m.d.comb += self.output.eq(self.input2) m.d.comb += self._ccs[Flags.Z].eq((self.output == 0) & self.ccs[Flags.Z]) m.d.comb += self._ccs[Flags.V].eq(0) with m.Case(ALU8Func.ADD, ALU8Func.ADC): no_carry = (self.func == ALU8Func.ADD) carry_in = Mux(no_carry, 0, self.ccs[Flags.C]) sum0_3 = Cat(self.output[:4], carry4) m.d.comb += sum0_3.eq(self.input1[:4] + self.input2[:4] + carry_in) sum4_6 = Cat(self.output[4:7], carry7) m.d.comb += sum4_6.eq(self.input1[4:7] + self.input2[4:7] + carry4) sum7 = Cat(self.output[7], carry8) m.d.comb += sum7.eq(self.input1[7] + self.input2[7] + carry7) m.d.comb += overflow.eq(carry7 ^ carry8) m.d.comb += self._ccs[Flags.H].eq(carry4) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.V].eq(overflow) m.d.comb += self._ccs[Flags.C].eq(carry8) with m.Case(ALU8Func.SUB, ALU8Func.SBC, ALU8Func.CPXHI, ALU8Func.CPXLO): carry_in = Mux(self.func != ALU8Func.SBC, 0, self.ccs[Flags.C]) sum0_6 = Cat(self.output[:7], carry7) m.d.comb += sum0_6.eq(self.input1[:7] + ~self.input2[:7] + ~carry_in) sum7 = Cat(self.output[7], carry8) m.d.comb += sum7.eq(self.input1[7] + ~self.input2[7] + carry7) m.d.comb += overflow.eq(carry7 ^ carry8) with m.If(self.func != ALU8Func.CPXLO): m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.V].eq(overflow) with m.If(self.func != ALU8Func.CPXHI): m.d.comb += self._ccs[Flags.C].eq(~carry8) with m.Else(): m.d.comb += self._ccs[Flags.Z].eq((self.output == 0) & self.ccs[Flags.Z]) with m.Case(ALU8Func.AND): m.d.comb += self.output.eq(self.input1 & self.input2) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(0) with m.Case(ALU8Func.EOR): m.d.comb += self.output.eq(self.input1 ^ self.input2) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(0) with m.Case(ALU8Func.ORA): m.d.comb += self.output.eq(self.input1 | self.input2) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(0) with m.Case(ALU8Func.INC): m.d.comb += self.output.eq(self.input2 + 1) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(self.output == 0x80) with m.Case(ALU8Func.DEC): m.d.comb += self.output.eq(self.input2 - 1) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(self.output == 0x7F) with m.Case(ALU8Func.COM): m.d.comb += self.output.eq(0xFF ^ self.input2) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.V].eq(0) m.d.comb += self._ccs[Flags.C].eq(1) with m.Case(ALU8Func.ROL): # IIIIIIIIC -> # COOOOOOOO m.d.comb += [ LCat(self._ccs[Flags.C], self.output).eq(LCat(self.input2, self.ccs[Flags.C])), self._ccs[Flags.Z].eq(self.output == 0), self._ccs[Flags.N].eq(self.output[7]), self._ccs[Flags.V].eq(self._ccs[Flags.N] ^ self._ccs[Flags.C]), ] with m.Case(ALU8Func.ROR): # CIIIIIIII -> # OOOOOOOOC m.d.comb += [ LCat(self.output, self._ccs[Flags.C]).eq( LCat(self.ccs[Flags.C], self.input2)), self._ccs[Flags.Z].eq(self.output == 0), self._ccs[Flags.N].eq(self.output[7]), self._ccs[Flags.V].eq(self._ccs[Flags.N] ^ self._ccs[Flags.C]), ] with m.Case(ALU8Func.ASL): # IIIIIIII0 -> # COOOOOOOO m.d.comb += [ LCat(self._ccs[Flags.C], self.output).eq(LCat(self.input2, Const(0))), self._ccs[Flags.Z].eq(self.output == 0), self._ccs[Flags.N].eq(self.output[7]), self._ccs[Flags.V].eq(self._ccs[Flags.N] ^ self._ccs[Flags.C]), ] with m.Case(ALU8Func.ASR): # 7IIIIIIII -> ("7" is the repeat of input[7]) # OOOOOOOOC m.d.comb += [ LCat(self.output, self._ccs[Flags.C]).eq( LCat(self.input2[7], self.input2)), self._ccs[Flags.Z].eq(self.output == 0), self._ccs[Flags.N].eq(self.output[7]), self._ccs[Flags.V].eq(self._ccs[Flags.N] ^ self._ccs[Flags.C]), ] with m.Case(ALU8Func.LSR): # 0IIIIIIII -> # OOOOOOOOC m.d.comb += [ LCat(self.output, self._ccs[Flags.C]).eq(LCat(Const(0), self.input2)), self._ccs[Flags.Z].eq(self.output == 0), self._ccs[Flags.N].eq(self.output[7]), self._ccs[Flags.V].eq(self._ccs[Flags.N] ^ self._ccs[Flags.C]), ] with m.Case(ALU8Func.CLC): m.d.comb += self._ccs[Flags.C].eq(0) with m.Case(ALU8Func.SEC): m.d.comb += self._ccs[Flags.C].eq(1) with m.Case(ALU8Func.CLV): m.d.comb += self._ccs[Flags.V].eq(0) with m.Case(ALU8Func.SEV): m.d.comb += self._ccs[Flags.V].eq(1) with m.Case(ALU8Func.CLI): m.d.comb += self._ccs[Flags.I].eq(0) with m.Case(ALU8Func.SEI): m.d.comb += self._ccs[Flags.I].eq(1) with m.Case(ALU8Func.CLZ): m.d.comb += self._ccs[Flags.Z].eq(0) with m.Case(ALU8Func.SEZ): m.d.comb += self._ccs[Flags.Z].eq(1) with m.Case(ALU8Func.TAP): m.d.comb += self._ccs.eq(self.input1 | 0b11000000) with m.Case(ALU8Func.TPA): m.d.comb += self.output.eq(self.ccs | 0b11000000) with m.Case(ALU8Func.SEF): m.d.comb += self._ccs.eq(self.input1 | 0b11000000) with m.Case(ALU8Func.DAA): adjust = Signal(8) low = self.input1[:4] high = self.input1[4:] low_ten_or_more = low >= 0xA high_ten_or_more = high >= 0xA with m.If(low_ten_or_more | self.ccs[Flags.H]): m.d.comb += adjust[:4].eq(6) with m.If(high_ten_or_more | self.ccs[Flags.C] | (low_ten_or_more & (high == 9))): m.d.comb += adjust[4:].eq(6) sum9 = LCat(carry8, self.output) m.d.comb += sum9.eq(self.input1 + adjust) m.d.comb += self._ccs[Flags.N].eq(self.output[7]) m.d.comb += self._ccs[Flags.Z].eq(self.output == 0) m.d.comb += self._ccs[Flags.C].eq(carry8 | self.ccs[Flags.C]) with m.Default(): m.d.comb += self.output.eq(self.input1) return m
def multiplex_to_reg_nums(self, m: Module): with m.Switch(self._x_reg_select): with m.Case(InstrReg.ZERO): m.d.comb += self.x_reg.eq(0) with m.Case(InstrReg.RS1): m.d.comb += self.x_reg.eq(self._rs1) with m.Case(InstrReg.RS2): m.d.comb += self.x_reg.eq(self._rs2) with m.Case(InstrReg.RD): m.d.comb += self.x_reg.eq(self._rd) with m.Switch(self._y_reg_select): with m.Case(InstrReg.ZERO): m.d.comb += self.y_reg.eq(0) with m.Case(InstrReg.RS1): m.d.comb += self.y_reg.eq(self._rs1) with m.Case(InstrReg.RS2): m.d.comb += self.y_reg.eq(self._rs2) with m.Case(InstrReg.RD): m.d.comb += self.y_reg.eq(self._rd) with m.Switch(self._z_reg_select): with m.Case(InstrReg.ZERO): m.d.comb += self.z_reg.eq(0) with m.Case(InstrReg.RS1): m.d.comb += self.z_reg.eq(self._rs1) with m.Case(InstrReg.RS2): m.d.comb += self.z_reg.eq(self._rs2) with m.Case(InstrReg.RD): m.d.comb += self.z_reg.eq(self._rd)
def multiplex_to(self, m: Module, sig: Signal, sel: Signal, clk: str): with m.Switch(sel): with m.Case(SeqMuxSelect.MEMDATA_WR): m.d[clk] += sig.eq(self.state.memdata_wr) with m.Case(SeqMuxSelect.MEMDATA_RD): m.d[clk] += sig.eq(self.memdata_rd) with m.Case(SeqMuxSelect.MEMADDR): m.d[clk] += sig.eq(self.state.memaddr) with m.Case(SeqMuxSelect.MEMADDR_LSB_MASKED): m.d[clk] += sig.eq(self.state.memaddr & 0xFFFFFFFE) with m.Case(SeqMuxSelect.PC): m.d[clk] += sig.eq(self.state._pc) with m.Case(SeqMuxSelect.PC_PLUS_4): m.d[clk] += sig.eq(self._pc_plus_4) with m.Case(SeqMuxSelect.MTVEC): m.d[clk] += sig.eq(self.state._mtvec) with m.Case(SeqMuxSelect.MTVEC_LSR2): m.d[clk] += sig.eq(self.state._mtvec >> 2) with m.Case(SeqMuxSelect.TMP): m.d[clk] += sig.eq(self.state._tmp) with m.Case(SeqMuxSelect.IMM): m.d[clk] += sig.eq(self._imm) with m.Case(SeqMuxSelect.INSTR): m.d[clk] += sig.eq(self.state._instr) with m.Case(SeqMuxSelect.X): m.d[clk] += sig.eq(self.data_x_in) with m.Case(SeqMuxSelect.Y): m.d[clk] += sig.eq(self.data_y_in) with m.Case(SeqMuxSelect.Z): m.d[clk] += sig.eq(self.data_z_in) with m.Case(SeqMuxSelect.Z_LSL2): m.d[clk] += sig.eq(self.data_z_in << 2) with m.Case(SeqMuxSelect.CONST): m.d[clk] += sig.eq(self.decode_const(m))
def elaborate(self, platform: Platform) -> Module: m = Module() m.d.comb += self._ccs.eq(self.ccs) m.d.ph1 += self.ccs.eq(self._ccs) # intermediates carry4 = Signal() carry7 = Signal() carry8 = Signal() overflow = Signal() with m.Switch(self.func): with m.Case(ALU8Func.LD): m.d.comb += self.output.eq(self.input2) m.d.comb += self._ccs[_Z].eq(self.output == 0) m.d.comb += self._ccs[_N].eq(self.output[7]) m.d.comb += self._ccs[_V].eq(0) with m.Case(ALU8Func.ADD, ALU8Func.ADC): carry_in = Mux(self.func == ALU8Func.ADD, 0, self.ccs[_C]) sum0_3 = Cat(self.output[:4], carry4) m.d.comb += sum0_3.eq(self.input1[:4] + self.input2[:4] + carry_in) sum4_6 = Cat(self.output[4:7], carry7) m.d.comb += sum4_6.eq(self.input1[4:7] + self.input2[4:7] + carry4) sum7 = Cat(self.output[7], carry8) m.d.comb += sum7.eq(self.input1[7] + self.input2[7] + carry7) m.d.comb += overflow.eq(carry7 ^ carry8) m.d.comb += self._ccs[_H].eq(carry4) m.d.comb += self._ccs[_N].eq(self.output[7]) m.d.comb += self._ccs[_Z].eq(self.output == 0) m.d.comb += self._ccs[_V].eq(overflow) m.d.comb += self._ccs[_C].eq(carry8) with m.Case(ALU8Func.SUB, ALU8Func.SBC): carry_in = Mux(self.func == ALU8Func.SUB, 0, self.ccs[_C]) sum0_6 = Cat(self.output[:7], carry7) m.d.comb += sum0_6.eq(self.input1[:7] + ~self.input2[:7] + ~carry_in) sum7 = Cat(self.output[7], carry8) m.d.comb += sum7.eq(self.input1[7] + ~self.input2[7] + carry7) m.d.comb += overflow.eq(carry7 ^ carry8) m.d.comb += self._ccs[_N].eq(self.output[7]) m.d.comb += self._ccs[_Z].eq(self.output == 0) m.d.comb += self._ccs[_V].eq(overflow) m.d.comb += self._ccs[_C].eq(~carry8) with m.Case(ALU8Func.AND): m.d.comb += self.output.eq(self.input1 & self.input2) m.d.comb += self._ccs[_Z].eq(self.output == 0) m.d.comb += self._ccs[_N].eq(self.output[7]) m.d.comb += self._ccs[_V].eq(0) with m.Case(ALU8Func.EOR): m.d.comb += self.output.eq(self.input1 ^ self.input2) m.d.comb += self._ccs[_Z].eq(self.output == 0) m.d.comb += self._ccs[_N].eq(self.output[7]) m.d.comb += self._ccs[_V].eq(0) with m.Case(ALU8Func.ORA): m.d.comb += self.output.eq(self.input1 | self.input2) m.d.comb += self._ccs[_Z].eq(self.output == 0) m.d.comb += self._ccs[_N].eq(self.output[7]) m.d.comb += self._ccs[_V].eq(0) return m
def elaborate(self, _: Platform) -> Module: """Implements the logic of the shifter card.""" m = Module() input_reverse = _ConditionalReverser(width=32) shift1 = _ConditionalShiftRight(width=32, N=1) shift2 = _ConditionalShiftRight(width=32, N=2) shift4 = _ConditionalShiftRight(width=32, N=4) shift8 = _ConditionalShiftRight(width=32, N=8) shift16 = _ConditionalShiftRight(width=32, N=16) output_reverse = _ConditionalReverser(width=32) output_buffer = TransparentLatch(size=32) m.submodules += [ input_reverse, shift1, shift2, shift4, shift8, shift16, output_reverse, output_buffer ] # Hook up inputs and outputs m.d.comb += [ input_reverse.data_in.eq(self.data_x), shift1.data_in.eq(input_reverse.data_out), shift2.data_in.eq(shift1.data_out), shift4.data_in.eq(shift2.data_out), shift8.data_in.eq(shift4.data_out), shift16.data_in.eq(shift8.data_out), output_reverse.data_in.eq(shift16.data_out), output_buffer.data_in.eq(output_reverse.data_out), self.data_z.eq(output_buffer.data_out), ] # Some flags shift_arith = Signal() shift_left = Signal() m.d.comb += shift_arith.eq(self.alu_op == AluOp.SRA) m.d.comb += shift_left.eq(self.alu_op == AluOp.SLL) m.d.comb += [ input_reverse.en.eq(shift_left), output_reverse.en.eq(shift_left), shift1.arithmetic.eq(shift_arith), shift2.arithmetic.eq(shift_arith), shift4.arithmetic.eq(shift_arith), shift8.arithmetic.eq(shift_arith), shift16.arithmetic.eq(shift_arith), ] # Shift amount shamt = self.data_y[:5] m.d.comb += [ shift1.en.eq(shamt[0]), shift2.en.eq(shamt[1]), shift4.en.eq(shamt[2]), shift8.en.eq(shamt[3]), shift16.en.eq(shamt[4]), ] m.d.comb += output_buffer.le.eq(1) m.d.comb += output_buffer.n_oe.eq(1) with m.Switch(self.alu_op): with m.Case(AluOp.SLL, AluOp.SRL, AluOp.SRA): m.d.comb += output_buffer.n_oe.eq(0) with m.Default(): m.d.comb += output_buffer.n_oe.eq(1) return m
def elaborate(self, platform): m = Module() # constants (at least, the important ones) if self.configuration.getOption('isa', 'enable_extra_csr'): misa = 0x1 << 30 | (1 << (ord('i') - ord('a')) ) # 32-bits processor. RV32IM if self.configuration.getOption('isa', 'enable_rv32m'): misa |= 1 << (ord('m') - ord('a')) # RV32M m.d.sync += [ self.csr.misa.read.eq(misa), self.csr.mhartid.read.eq( 0), # ID 0 FOREVER. TODO: make this read only self.csr.mimpid.read.eq(0), # No implemented = 0 self.csr.marchid.read.eq(0), # No implemented = 0 self.csr.mvendorid.read.eq(0) # No implemented = 0 ] m.d.sync += self.csr.mstatus.read.mpp.eq(0b11) # Only machine mode traps = m.submodules.traps = PriorityEncoder(16) m.d.comb += [ traps.i[ExceptionCause.E_INST_ADDR_MISALIGNED].eq( self.m_fetch_misalign), traps.i[ExceptionCause.E_INST_ACCESS_FAULT].eq(self.m_fetch_error), traps.i[ExceptionCause.E_ILLEGAL_INST].eq(self.m_illegal), traps.i[ExceptionCause.E_BREAKPOINT].eq(self.m_ebreak), traps.i[ExceptionCause.E_LOAD_ADDR_MISALIGNED].eq( self.m_load_misalign), traps.i[ExceptionCause.E_LOAD_ACCESS_FAULT].eq(self.m_load_error), traps.i[ExceptionCause.E_STORE_AMO_ADDR_MISALIGNED].eq( self.m_store_misalign), traps.i[ExceptionCause.E_STORE_AMO_ACCESS_FAULT].eq( self.m_store_error), traps.i[ExceptionCause.E_ECALL_FROM_M].eq(self.m_ecall) ] interrupts = m.submodules.interrupts = PriorityEncoder(16) m.d.comb += [ interrupts.i[ExceptionCause.I_M_SOFTWARE].eq( self.csr.mip.read.msip & self.csr.mie.read.msie), interrupts.i[ExceptionCause.I_M_TIMER].eq( self.csr.mip.read.mtip & self.csr.mie.read.mtie), interrupts.i[ExceptionCause.I_M_EXTERNAL].eq( self.csr.mip.read.meip & self.csr.mie.read.meie), ] m.d.sync += [ self.csr.mip.read.msip.eq(self.software_interrupt), self.csr.mip.read.mtip.eq(self.timer_interrupt), self.csr.mip.read.meip.eq(self.external_interrupt) ] # generate the exception/trap/interrupt signal to kill the pipeline m.d.comb += self.m_exception.eq(~traps.n | ( ~interrupts.n & self.csr.mstatus.read.mie & ~self.m_store)) # default behavior for all registers. for reg in self.csr.csr_list: with m.If(reg.we): m.d.sync += reg.read.eq(reg.write) # behavior for exception handling with m.If(self.m_valid): with m.If(self.m_exception): # Register the exception and move one priviledge mode down. # No other priviledge mode, so stay in 'machine' mode m.d.sync += [ self.csr.mepc.read.base.eq(self.m_pc[2:]), self.csr.mstatus.read.mpie.eq(self.csr.mstatus.read.mie), self.csr.mstatus.read.mie.eq(0) ] # store cause/mtval with m.If(~traps.n): m.d.sync += [ self.csr.mcause.read.ecode.eq(traps.o), self.csr.mcause.read.interrupt.eq(0) ] with m.Switch(traps.o): with m.Case(ExceptionCause.E_INST_ADDR_MISALIGNED): m.d.sync += self.csr.mtval.read.eq( self.m_pc_misalign) with m.Case(ExceptionCause.E_INST_ACCESS_FAULT): m.d.sync += self.csr.mtval.read.eq( self.m_fetch_badaddr) with m.Case(ExceptionCause.E_ILLEGAL_INST): m.d.sync += self.csr.mtval.read.eq( self.m_instruction) with m.Case(ExceptionCause.E_BREAKPOINT): m.d.sync += self.csr.mtval.read.eq(self.m_pc) with m.Case( ExceptionCause.E_LOAD_ADDR_MISALIGNED, ExceptionCause.E_STORE_AMO_ADDR_MISALIGNED): m.d.sync += self.csr.mtval.read.eq( self.m_ls_misalign) with m.Case(ExceptionCause.E_LOAD_ACCESS_FAULT, ExceptionCause.E_STORE_AMO_ACCESS_FAULT): m.d.sync += self.csr.mtval.read.eq( self.m_load_store_badaddr) with m.Default(): m.d.sync += self.csr.mtval.read.eq(0) with m.Else(): m.d.sync += [ self.csr.mcause.read.ecode.eq(interrupts.o), self.csr.mcause.read.interrupt.eq(1) ] with m.Elif(self.m_mret): # restore old mie # No other priviledge mode, so nothing more to do m.d.sync += self.csr.mstatus.read.mie.eq( self.csr.mstatus.read.mpie) # counters if self.configuration.getOption('isa', 'enable_extra_csr'): mcycle = Signal(64) minstret = Signal(64) m.d.sync += [ self.csr.mcycle.read.eq(mcycle[:32]), self.csr.mcycleh.read.eq(mcycle[32:64]), # self.csr.minstret.read.eq(minstret[:32]), self.csr.minstreth.read.eq(minstret[32:64]) ] m.d.comb += mcycle.eq( Cat(self.csr.mcycle.read, self.csr.mcycleh.read) + 1) with m.If(self.w_retire): m.d.comb += minstret.eq( Cat(self.csr.minstret.read, self.csr.minstreth.read) + 1) with m.Else(): m.d.comb += minstret.eq( Cat(self.csr.minstret.read, self.csr.minstreth.read)) return m
def elaborate(self, platform: Platform) -> Module: m = Module() m.domains.ramg = ClockDomain(async_reset=True, local=True) m.domains.romb0 = ClockDomain(async_reset=True, local=True) m.domains.romb1 = ClockDomain(async_reset=True, local=True) m.domains.ramb = ClockDomain(async_reset=True, local=True) ramg_clk = ClockSignal("ramg") romb0_clk = ClockSignal("romb0") romb1_clk = ClockSignal("romb1") ramb_clk = ClockSignal("ramb") m.d.comb += [ ResetSignal("ramg").eq(self.cart_rst), ResetSignal("romb0").eq(self.cart_rst), ResetSignal("romb1").eq(self.cart_rst), ResetSignal("ramb").eq(self.cart_rst), ] ramg = Signal(8) romb0 = Signal(8, reset=0x01) romb1 = Signal(1) ramb = Signal(4) m.d.ramg += ramg.eq(self.cart_data) m.d.romb0 += romb0.eq(self.cart_data) m.d.romb1 += romb1.eq(self.cart_data) m.d.ramb += ramb.eq(self.cart_data) m.d.comb += [ ramg_clk.eq(1), romb0_clk.eq(1), romb1_clk.eq(1), ramb_clk.eq(1) ] with m.If(self.cart_wr): with m.Switch(self.cart_addr[12:]): with m.Case(0b0000): m.d.comb += ramg_clk.eq(0) with m.Case(0b0001): m.d.comb += ramg_clk.eq(0) with m.Case(0b0010): m.d.comb += romb0_clk.eq(0) with m.Case(0b0011): m.d.comb += romb1_clk.eq(0) with m.Case(0b0100): m.d.comb += ramb_clk.eq(0) with m.Case(0b0101): m.d.comb += ramb_clk.eq(0) m.d.comb += [ self.ram_en.eq(ramg == 0x0A), self.ram_bank.eq(ramb), ] with m.If(self.cart_addr[14]): m.d.comb += self.rom_bank.eq(Cat(romb0, romb1)) with m.Else(): m.d.comb += self.rom_bank.eq(0) return m
def execute(self, m: Module): """Execute the instruction in the instr register.""" with m.Switch(self.instr): with m.Case("00000001"): # NOP self.NOP(m) with m.Case("00000110"): # TAP self.TAP(m) with m.Case("00000111"): # TPA self.TPA(m) with m.Case("0000100-"): # INX/DEX self.IN_DE_X(m) with m.Case("0000101-"): # CLV, SEV self.CL_SE_V(m) with m.Case("0000110-"): # CLC, SEC self.CL_SE_C(m) with m.Case("0000111-"): # CLI, SEI self.CL_SE_I(m) with m.Case("0010----"): # Branch instructions self.BR(m) with m.Case("01--0000"): # NEG self.ALU2(m, ALU8Func.SUB, 0, 1) with m.Case("01--0011"): # COM self.ALU2(m, ALU8Func.COM, 0, 1) with m.Case("01--0100"): # LSR self.ALU2(m, ALU8Func.LSR, 0, 1) with m.Case("01--0110"): # ROR self.ALU2(m, ALU8Func.ROR, 0, 1) with m.Case("01--0111"): # ASR self.ALU2(m, ALU8Func.ASR, 0, 1) with m.Case("01--1000"): # ASL self.ALU2(m, ALU8Func.ASL, 0, 1) with m.Case("01--1001"): # ROL self.ALU2(m, ALU8Func.ROL, 0, 1) with m.Case("01--1010"): # DEC self.ALU2(m, ALU8Func.DEC, 0, 1) with m.Case("01--1100"): # INC self.ALU2(m, ALU8Func.INC, 0, 1) with m.Case("01--1101"): # TST self.ALU2(m, ALU8Func.SUB, 1, 0, store=False) with m.Case("011-1110"): # JMP self.JMP(m) with m.Case("01--1111"): # CLR self.ALU2(m, ALU8Func.SUB, 1, 1) with m.Case("1---0110"): # LDA self.ALU(m, ALU8Func.LD) with m.Case("1---0000"): # SUB self.ALU(m, ALU8Func.SUB) with m.Case("1---0001"): # CMP self.ALU(m, ALU8Func.SUB, store=False) with m.Case("1---0010"): # SBC self.ALU(m, ALU8Func.SBC) with m.Case("1---0100"): # AND self.ALU(m, ALU8Func.AND) with m.Case("1---0101"): # BIT self.ALU(m, ALU8Func.AND, store=False) with m.Case("1--10111", "1-100111"): # STA self.STA(m) with m.Case("1---1000"): # EOR self.ALU(m, ALU8Func.EOR) with m.Case("1---1001"): # ADC self.ALU(m, ALU8Func.ADC) with m.Case("1---1010"): # ORA self.ALU(m, ALU8Func.ORA) with m.Case("1---1011"): # ADD self.ALU(m, ALU8Func.ADD) with m.Default(): # Illegal self.end_instr(m, self.pc)
def elaborate(self, platform): m = Module() # Move the pipeline along m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr), self.o_arndr.eq(self.i_arndr), self.o_zrndr.eq(self.i_zrndr), self.o_x_coord.eq(self.i_x_coord), self.o_y_coord.eq(self.i_y_coord), self.o_z_coord.eq(self.i_z_coord), self.o_alpha.eq(self.i_alpha), ] a_red = Signal(8) a_green = Signal(8) a_blue = Signal(8) with m.Switch(self.i_blend_a): with m.Case(BlendRGB.SRC): m.d.comb += a_red.eq(self.i_red) m.d.comb += a_green.eq(self.i_green) m.d.comb += a_blue.eq(self.i_blue) with m.Case(BlendRGB.FB): m.d.comb += a_red.eq(self.i_fbred) m.d.comb += a_green.eq(self.i_fbgreen) m.d.comb += a_blue.eq(self.i_fbblue) with m.Case(BlendRGB.ZERO): m.d.comb += a_red.eq(0) m.d.comb += a_green.eq(0) m.d.comb += a_blue.eq(0) b_red = Signal(8) b_green = Signal(8) b_blue = Signal(8) with m.Switch(self.i_blend_b): with m.Case(BlendRGB.SRC): m.d.comb += b_red.eq(self.i_red) m.d.comb += b_green.eq(self.i_green) m.d.comb += b_blue.eq(self.i_blue) with m.Case(BlendRGB.FB): m.d.comb += b_red.eq(self.i_fbred) m.d.comb += b_green.eq(self.i_fbgreen) m.d.comb += b_blue.eq(self.i_fbblue) with m.Case(BlendRGB.ZERO): m.d.comb += b_red.eq(0) m.d.comb += b_green.eq(0) m.d.comb += b_blue.eq(0) c = Signal(8) with m.Switch(self.i_blend_c): with m.Case(BlendAlpha.SRC): m.d.comb += c.eq(self.i_alpha) with m.Case(BlendAlpha.FB): m.d.comb += c.eq(self.i_fbalpha) with m.Case(BlendAlpha.FIX): m.d.comb += c.eq(self.i_fix) d_red = Signal(8) d_green = Signal(8) d_blue = Signal(8) with m.Switch(self.i_blend_d): with m.Case(BlendRGB.SRC): m.d.comb += d_red.eq(self.i_red) m.d.comb += d_green.eq(self.i_green) m.d.comb += d_blue.eq(self.i_blue) with m.Case(BlendRGB.FB): m.d.comb += d_red.eq(self.i_fbred) m.d.comb += d_green.eq(self.i_fbgreen) m.d.comb += d_blue.eq(self.i_fbblue) with m.Case(BlendRGB.ZERO): m.d.comb += d_red.eq(0) m.d.comb += d_green.eq(0) m.d.comb += d_blue.eq(0) with m.If(self.i_enable & (~self.i_alphaen | self.i_alpha[7])): m.d.sync += [ self.o_red.eq((((a_red - b_red) * c) >> 7) + d_red), self.o_green.eq((((a_green - b_green) * c) >> 7) + d_green), self.o_blue.eq((((a_blue - b_blue) * c) >> 7) + d_blue) ] with m.Else(): m.d.sync += [ self.o_red.eq(self.i_red), self.o_green.eq(self.i_green), self.o_blue.eq(self.i_blue) ] return m
def elaborate(self, platform): m = Module() cpu = Core() m.submodules += cpu m.domains.ph1 = ph1 = ClockDomain("ph1") m.domains.ph2 = ph2 = ClockDomain("ph2", clk_edge="neg") # Hook up clocks and reset to pins if not SLOWCLK: clk1 = platform.request("clk1") clk2 = platform.request("clk2") rst = platform.request("rst") m.d.comb += [ ph1.rst.eq(rst.i), ph2.rst.eq(rst.i), ph1.clk.eq(clk1.i), ph2.clk.eq(clk2.i), ] if SLOWCLK: clk_freq = platform.default_clk_frequency timer = Signal(range(0, int(clk_freq // 2)), reset=int(clk_freq // 2) - 1) tick = Signal() sync = ClockDomain() with m.If(timer == 0): m.d.sync += timer.eq(timer.reset) m.d.sync += tick.eq(~tick) with m.Else(): m.d.sync += timer.eq(timer - 1) m.d.comb += [ ph1.rst.eq(sync.rst), ph2.rst.eq(sync.rst), ph1.clk.eq(tick), ph2.clk.eq(~tick), ] # Hook up address lines to pins addr = [] for i in range(16): pin = platform.request("addr", i) m.d.comb += pin.o.eq(cpu.Addr[i]) addr.append(pin) data = [] if not FAKEMEM: # Hook up data in/out + direction to pins for i in range(8): pin = platform.request("data", i) m.d.comb += pin.o.eq(cpu.Dout[i]) m.d.ph2 += cpu.Din[i].eq(pin.i) data.append(pin) if FAKEMEM: with m.Switch(cpu.Addr): for a, d in mem.items(): with m.Case(a): m.d.comb += cpu.Din.eq(d) with m.Default(): m.d.comb += cpu.Din.eq(0x00) for i in range(8): pin = platform.request("led", i) m.d.comb += pin.o.eq(cpu.Addr[i]) rw = platform.request("rw") m.d.comb += rw.o.eq(cpu.RW) nIRQ = platform.request("n_irq") nNMI = platform.request("n_nmi") m.d.ph2 += cpu.IRQ.eq(~nIRQ) m.d.ph2 += cpu.NMI.eq(~nNMI) ba = platform.request("ba") m.d.comb += ba.o.eq(cpu.BA) m.d.comb += rw.oe.eq(~cpu.BA) for i in range(len(addr)): m.d.comb += addr[i].oe.eq(~cpu.BA) for i in range(len(data)): m.d.comb += data[i].oe.eq(~cpu.BA & ~cpu.RW) return m
def elaborate(self, platform: Platform) -> Module: m = Module() m.d.sync += self.PSW.eq(self._psw) m.d.comb += self._psw.eq(self.PSW) with m.Switch(self.oper): with m.Case(Operation.NOP): if self.verification is Operation.NOP: with m.If(~Initial()): m.d.comb += [ Assert(self._psw.N == self.PSW.N), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == self.PSW.Z), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.ADC): low = Cat(self.result[:4], self._psw.H) high = Cat(self.result[4:], self._psw.C) m.d.comb += [ low.eq(self.inputa[:4] + self.inputb[:4] + self.PSW.C), high.eq(self.inputa[4:] + self.inputb[4:] + self._psw.H), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), self._psw.V.eq(self.result[7] != self._psw.C), ] if self.verification is Operation.ADC: r = Signal(8) f = Signal(9) h = Signal(5) m.d.comb += [ r.eq(self.inputa.as_signed() + self.inputb.as_signed() + self.PSW.C), f.eq(self.inputa + self.inputb + self.PSW.C), h.eq(self.inputa[:4] + self.inputb[:4] + self.PSW.C), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self.result == f[:8]), Assert(self._psw.N == f[7]), Assert(self._psw.V == (f[7] ^ f[8])), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == h[4]), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(f[:8].bool())), Assert(self._psw.C == f[8]), ] with m.Case(Operation.SBC): low = Cat(self.result[:4], self._psw.H) high = Cat(self.result[4:], self._psw.C) m.d.comb += [ low.eq(self.inputa[:4] - self.inputb[:4] - self.PSW.C), high.eq(self.inputa[4:] - self.inputb[4:] - self._psw.H), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), self._psw.V.eq(self.result[7] != self._psw.C), ] if self.verification is Operation.SBC: r = Signal(8) f = Signal(9) h = Signal(5) m.d.comb += [ r.eq(self.inputa.as_signed() - self.inputb.as_signed() - self.PSW.C), f.eq(self.inputa - self.inputb - self.PSW.C), h.eq(self.inputa[:4] - self.inputb[:4] - self.PSW.C), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self.result == f[:8]), Assert(self._psw.N == f[7]), Assert(self._psw.V == (f[7] ^ f[8])), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == h[4]), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(f[:8].bool())), Assert(self._psw.C == f[8]), ] with m.Case(Operation.CMP): full = Cat(self.result, self._psw.C) m.d.comb += [ full.eq(self.inputa.as_signed() - self.inputb.as_signed()), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), self._psw.V.eq(self.result[7] != self._psw.C), ] if self.verification is Operation.CMP: r = Signal(9) m.d.comb += r.eq(self.inputa.as_signed() - self.inputb.as_signed()) with m.If(~Initial()): m.d.comb += [ Assert(self.result == r[:8]), Assert(self._psw.N == r[7]), Assert(self._psw.V == (r[7] ^ r[8])), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r[:8].bool())), Assert(self._psw.C == r[8]), ] with m.Case(Operation.AND): m.d.comb += [ self.result.eq(self.inputa & self.inputb), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.AND: r = Signal(8) m.d.comb += r.eq(self.inputa & self.inputb) with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.OOR): m.d.comb += [ self.result.eq(self.inputa | self.inputb), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.OOR: r = Signal(8) m.d.comb += [ r.eq(self.inputa | self.inputb), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.EOR): m.d.comb += [ self.result.eq(self.inputa ^ self.inputb), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.EOR: r = Signal(8) m.d.comb += [ r.eq(self.inputa ^ self.inputb), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.INC): m.d.comb += [ self.result.eq(self.inputa + 1), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.INC: r = Signal(8) m.d.comb += [ r.eq(self.inputa + 1), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.DEC): m.d.comb += [ self.result.eq(self.inputa - 1), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.DEC: r = Signal(8) m.d.comb += [ r.eq(self.inputa - 1), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.ASL): m.d.comb += [ Cat(self.result, self._psw.C).eq(Cat(Const(0), self.inputa)), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.ASL: r = Signal(8) m.d.comb += [ r.eq(self.inputa * 2), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.inputa[6]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[7]), ] with m.Case(Operation.LSR): m.d.comb += [ Cat(self._psw.C, self.result).eq(Cat(self.inputa, Const(0))), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.LSR: r = Signal(8) m.d.comb += [ r.eq(self.inputa // 2), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == 0), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[0]), ] with m.Case(Operation.ROL): m.d.comb += [ Cat(self.result, self._psw.C).eq(Cat(self.PSW.C, self.inputa)), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.ROL: r = Signal(8) m.d.comb += [ r.eq(self.inputa * 2 + self.PSW.C), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.inputa[6]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[7]), ] with m.Case(Operation.ROR): m.d.comb += [ Cat(self._psw.C, self.result).eq(Cat(self.inputa, self.PSW.C)), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.ROR: r = Signal(8) m.d.comb += [ r.eq(self.inputa // 2 + Cat(Signal(7), self.PSW.C)), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.PSW.C), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[0]), ] with m.Case(Operation.XCN): m.d.comb += [ self.result.eq(Cat(self.inputa[4:], self.inputa[:4])), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.XCN: r = Signal(8) m.d.comb += [ r.eq(self.inputa * 16 + self.inputa // 16), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.inputa[3]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(self.inputa.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.DAA): temp = Signal().like(self.inputa) with m.If(self.PSW.C | (self.inputa > 0x99)): m.d.comb += self._psw.C.eq(1) m.d.comb += temp.eq(self.inputa + 0x60) with m.Else(): m.d.comb += temp.eq(self.inputa) with m.If(self.PSW.H | (temp[:4] > 0x09)): m.d.comb += self.result.eq(temp + 0x06) m.d.comb += [ self._psw.N.eq(self.result & 0x80), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.DAA: with m.If(~Initial()): m.d.comb += [Assert(False)] with m.Case(Operation.DAS): temp = Signal().like(self.inputa) with m.If(~self.PSW.C | (self.inputa > 0x99)): m.d.comb += self._psw.C.eq(0) m.d.comb += temp.eq(self.inputa - 0x60) with m.Else(): m.d.comb += temp.eq(self.inputa) with m.If(~self.PSW.H | (temp[:4] > 0x09)): m.d.comb += self.result.eq(temp - 0x06) m.d.comb += [ self._psw.N.eq(self.result & 0x80), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.DAS: with m.If(~Initial()): m.d.comb += [Assert(False)] # could be optimized with shift to right with m.Case(Operation.MUL): with m.Switch(self.count): for i in range(0, 8): with m.Case(i): prod = self.inputa * self.inputb[i] if i == 0: prod = Cat(prod[0:7], ~prod[7], Const(1)) elif i == 7: prod = Cat(~prod[0:7], prod[7], Const(1)) else: prod = Cat(prod[0:7], ~prod[7]) m.d.sync += self.partial.eq(self.partial + (prod << i)) m.d.sync += self.count.eq(i + 1) with m.Case(8): m.d.sync += self.partial_hi.eq(self.partial_lo) m.d.sync += self.count.eq(9) m.d.comb += [ self.result.eq(self.partial_hi), self._psw.N.eq(self.partial_hi.as_signed() < 0), self._psw.Z.eq(self.partial_hi == 0), ] with m.Case(9): m.d.sync += self.partial.eq(0) m.d.sync += self.count.eq(0) m.d.comb += [ self.result.eq(self.partial_hi), ] if self.verification is Operation.MUL: r = Signal(16) m.d.comb += [ r.eq(self.inputa.as_signed() * self.inputb.as_signed()), Cover(self.count == 9), ] with m.If(self.count == 9): m.d.comb += [ Assert(Past(self.result) == r[8:16]), Assert(self.result == r[0:8]), Assert(self._psw.N == r[15]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r[8:16].bool())), Assert(self._psw.C == self.PSW.C), ] with m.If(~Initial() & (self.count == 0)): m.d.comb += [ Assert(self.partial == 0), Assert((Past(self.count) == 0) | (Past(self.count) == 9)), ] with m.If(~Initial() & (self.count != 0)): m.d.comb += [ Assert(self.count == Past(self.count) + 1), Assume(self.inputa == Past(self.inputa)), Assume(self.inputb == Past(self.inputb)), ] with m.Case(Operation.DIV): over = Signal(reset=0) with m.Switch(self.count): with m.Case(0): m.d.sync += self.partial_hi.eq(self.inputa) # Y m.d.sync += self.count.eq(1) with m.Case(1): m.d.sync += self.partial_lo.eq(self.inputa) # A m.d.sync += self.count.eq(2) m.d.comb += self._psw.H.eq( Mux(self.partial_hi[0:4] >= self.inputb[0:4], 1, 0)) for i in range(2, 11): with m.Case(i): tmp1_w = Cat(self.partial << 1, over) tmp1_x = Signal(17) tmp1_y = Signal(17) tmp1_z = Signal(17) tmp2 = self.inputb << 9 m.d.comb += tmp1_x.eq(tmp1_w) with m.If(tmp1_w & 0x20000): m.d.comb += tmp1_x.eq((tmp1_w & 0x1FFFF) | 1) m.d.comb += tmp1_y.eq(tmp1_x) with m.If(tmp1_x >= tmp2): m.d.comb += tmp1_y.eq(tmp1_x ^ 1) m.d.comb += tmp1_z.eq(tmp1_y) with m.If(tmp1_y & 1): m.d.comb += tmp1_z.eq((tmp1_y - tmp2) & 0x1FFFF) m.d.sync += Cat(self.partial, over).eq(tmp1_z) m.d.sync += self.count.eq(i + 1) with m.Case(11): m.d.sync += self.count.eq(12) m.d.comb += [ self.result.eq( (Cat(self.partial, over) >> 9)), # Y % ] with m.Case(12): m.d.sync += self.partial.eq(0) m.d.sync += over.eq(0) m.d.sync += self.count.eq(0) m.d.comb += [ self.result.eq(self.partial_lo), # A / self._psw.N.eq(self.partial_lo.as_signed() < 0), self._psw.V.eq(over), self._psw.Z.eq(self.partial_lo == 0), ] if self.verification is Operation.DIV: m.d.comb += [ Cover(self.count == 12), ] with m.If(self.count == 12): m.d.comb += [Assert(False)] return m
def elaborate(self, platform): m = Module() # Collection that will store each of our descriptor-generation submodules. descriptor_generators = {} # # Figure out the maximum length we're willing to send. # length = Signal(16) # We'll never send more than our MaxPacketSize. This means that we'll want to send a maximum of # either our maximum packet length, or the amount of data we have remaining; whichever is less. # # Note that this doesn't take into account the length of the actual data to be sent; this is handled # in the stream generator. words_remaining = self.length - self.start_position with m.If(words_remaining <= self._max_packet_length): m.d.comb += length.eq(words_remaining) with m.Else(): m.d.comb += length.eq(self._max_packet_length) # # Create our constant-stream generators for each of our descriptors. # for type_number, index, raw_descriptor in self._descriptors: # Create the generator... generator = USBDescriptorStreamGenerator(raw_descriptor) descriptor_generators[(type_number, index)] = generator m.d.comb += [ generator.max_length .eq(length), generator.start_position .eq(self.start_position) ] # ... and attach it to this module. m.submodules += generator # # Connect up each of our generators. # with m.Switch(self.value): # Generate a conditional interconnect for each of our items. for (type_number, index), generator in descriptor_generators.items(): # If the value matches the given type number... with m.Case(type_number << 8 | index): # ... connect the relevant generator to our output. m.d.comb += generator.stream .attach(self.tx) m.d.usb += generator.start .eq(self.start), # If none of our descriptors match, stall any request that comes in. with m.Case(): m.d.comb += self.stall.eq(self.start) return m
def elaborate(self, platform): m = Module() # create the byte selector with m.Switch(self.x_funct3): with m.Case(Funct3.B): m.d.comb += self.x_byte_sel.eq(0b0001 << self.x_offset) with m.Case(Funct3.H): m.d.comb += self.x_byte_sel.eq(0b0011 << self.x_offset) with m.Case(Funct3.W): m.d.comb += self.x_byte_sel.eq(0b1111) # format output data with m.Switch(self.x_funct3): with m.Case(Funct3.B): m.d.comb += self.x_data_w.eq(Repl(self.x_store_data[:8], 4)) with m.Case(Funct3.H): m.d.comb += self.x_data_w.eq(Repl(self.x_store_data[:16], 2)) with m.Case(Funct3.W): m.d.comb += self.x_data_w.eq(self.x_store_data) # format input data _byte = Signal((8, True)) _half = Signal((16, True)) m.d.comb += [ _byte.eq(self.m_data_r.word_select(self.m_offset, 8)), _half.eq(self.m_data_r.word_select(self.m_offset[1], 16)), ] with m.Switch(self.m_funct3): with m.Case(Funct3.B): m.d.comb += self.m_load_data.eq(_byte) with m.Case(Funct3.BU): m.d.comb += self.m_load_data.eq(Cat(_byte, 0)) # make sign bit = 0 with m.Case(Funct3.H): m.d.comb += self.m_load_data.eq(_half) with m.Case(Funct3.HU): m.d.comb += self.m_load_data.eq(Cat(_half, 0)) # make sign bit = 0 with m.Case(Funct3.W): m.d.comb += self.m_load_data.eq(self.m_data_r) # misalignment with m.Switch(self.x_funct3): with m.Case(Funct3.H, Funct3.HU): m.d.comb += self.x_misaligned.eq(self.x_offset[0]) with m.Case(Funct3.W): m.d.comb += self.x_misaligned.eq(self.x_offset != 0) return m
def handle_load(self, m: Module): """Adds the LOAD logic to the given module. Note that byte loads are byte-aligned, half-word loads are 16-bit aligned, and word loads are 32-bit aligned. Attempting to load unaligned will lead to undefined behavior. Operation is to load 32 bits from a 32-bit aligned address, and then perform at most two shifts to get the desired behavior: a shift left to get the most significant byte into the leftmost position, then a shift right to zero or sign extend the value. For example, for loading a half-word starting at address A where A%4=0, we first load the full 32 bits at that address, resulting in XYHL, where X and Y are unwanted and H and L are the half-word we want to load. Then we shift left by 16: HL00. And finally we shift right by 16, either signed or unsigned depending on whether we are doing an LH or an LHU: ssHL / 00HL. addr <- rs1 + imm rd <- data at addr, possibly sign-extended PC <- PC + 4 If we let N be addr%4, then: instr N shift1 shift2 -------------------------- LB 0 SLL 24 SRA 24 LB 1 SLL 16 SRA 24 LB 2 SLL 8 SRA 24 LB 3 SLL 0 SRA 24 LBU 0 SLL 24 SRL 24 LBU 1 SLL 16 SRL 24 LBU 2 SLL 8 SRL 24 LBU 3 SLL 0 SRL 24 LH 0 SLL 16 SRA 16 LH 2 SLL 0 SRA 16 LHU 0 SLL 16 SRL 16 LHU 2 SLL 0 SRL 16 LW 0 SLL 0 SRA 0 (all other N are misaligned accesses) Where there is an SLL 0, the machine cycle could be skipped, but in the interests of simpler logic, we will not do that. rs1 -> X imm -> Y ALU ADD -> Z Z -> memaddr --------------------- memdata -> X shamt1 -> Y ALU SLL -> Z Z -> rd --------------------- rd -> X shamt2 -> Y ALU SRA/SRL -> Z Z -> rd PC + 4 -> PC PC + 4 -> memaddr """ with m.If(self._instr_phase == 0): m.d.comb += [ self.reg_to_x.eq(1), self._x_reg_select.eq(InstrReg.RS1), self.y_mux_select.eq(SeqMuxSelect.IMM), self.alu_op_to_z.eq(AluOp.ADD), self.memaddr_mux_select.eq(SeqMuxSelect.Z), self._next_instr_phase.eq(1), ] with m.Elif(self._instr_phase == 1): # Check for exception conditions first with m.If( self._funct3.matches(MemAccessWidth.H, MemAccessWidth.HU) & self.memaddr_2_lsb[0]): self.set_exception(m, ConstSelect.EXC_LOAD_ADDR_MISALIGN, mtval=SeqMuxSelect.MEMADDR) with m.Elif((self._funct3 == MemAccessWidth.W) & (self.memaddr_2_lsb != 0)): self.set_exception(m, ConstSelect.EXC_LOAD_ADDR_MISALIGN, mtval=SeqMuxSelect.MEMADDR) with m.Elif(~self._funct3.matches( MemAccessWidth.B, MemAccessWidth.BU, MemAccessWidth.H, MemAccessWidth.HU, MemAccessWidth.W)): self.handle_illegal_instr(m) with m.Else(): m.d.comb += [ self.mem_rd.eq(1), self.x_mux_select.eq(SeqMuxSelect.MEMDATA_RD), self.y_mux_select.eq(SeqMuxSelect.CONST), self.alu_op_to_z.eq(AluOp.SLL), self._z_reg_select.eq(InstrReg.RD), self._next_instr_phase.eq(2), ] with m.Switch(self._funct3): with m.Case(MemAccessWidth.B, MemAccessWidth.BU): with m.Switch(self.memaddr_2_lsb): with m.Case(0): m.d.comb += self._const.eq( ConstSelect.SHAMT_24) with m.Case(1): m.d.comb += self._const.eq( ConstSelect.SHAMT_16) with m.Case(2): m.d.comb += self._const.eq(ConstSelect.SHAMT_8) with m.Case(3): m.d.comb += self._const.eq(ConstSelect.SHAMT_0) with m.Case(MemAccessWidth.H, MemAccessWidth.HU): with m.Switch(self.memaddr_2_lsb): with m.Case(0): m.d.comb += self._const.eq( ConstSelect.SHAMT_16) with m.Case(2): m.d.comb += self._const.eq(ConstSelect.SHAMT_0) with m.Case(MemAccessWidth.W): m.d.comb += self._const.eq(ConstSelect.SHAMT_0) with m.Else(): m.d.comb += [ self.reg_to_x.eq(1), self._x_reg_select.eq(InstrReg.RD), self.y_mux_select.eq(SeqMuxSelect.CONST), self._z_reg_select.eq(InstrReg.RD), ] with m.Switch(self._funct3): with m.Case(MemAccessWidth.B): m.d.comb += [ self._const.eq(ConstSelect.SHAMT_24), self.alu_op_to_z.eq(AluOp.SRA), ] with m.Case(MemAccessWidth.BU): m.d.comb += [ self._const.eq(ConstSelect.SHAMT_24), self.alu_op_to_z.eq(AluOp.SRL), ] with m.Case(MemAccessWidth.H): m.d.comb += [ self._const.eq(ConstSelect.SHAMT_16), self.alu_op_to_z.eq(AluOp.SRA), ] with m.Case(MemAccessWidth.HU): m.d.comb += [ self._const.eq(ConstSelect.SHAMT_16), self.alu_op_to_z.eq(AluOp.SRL), ] with m.Case(MemAccessWidth.W): m.d.comb += [ self._const.eq(ConstSelect.SHAMT_0), self.alu_op_to_z.eq(AluOp.SRL), ] self.next_instr(m)
def elaborate(self, platform): m = Module() size = self.configuration.getOption('predictor', 'size') if size == 0 or (size & (size - 1)): raise ValueError(f'size must be a power of 2: {size}') _bits_index = log2_int(size) _bits_tag = 32 - _bits_index _btb_width = 1 + 32 + _bits_tag # valid + data + tag _btb_depth = 1 << _bits_index _btb_layout = [('target', 32), ('tag', _bits_tag), ('valid', 1)] _pc_layout = [('index', _bits_index), ('tag', _bits_tag)] btb = Memory(width=_btb_width, depth=_btb_depth) btb_rp = btb.read_port() btb_wp = btb.write_port() bht = Memory(width=2, depth=_btb_depth) bht_rp = bht.read_port() bht_wp = bht.write_port() m.submodules += btb_rp, btb_wp m.submodules += bht_rp, bht_wp btb_r = Record(_btb_layout) a_pc = Record(_pc_layout) f_pc = Record(_pc_layout) m_pc = Record(_pc_layout) hit = Signal() pstate_next = Signal(2) m.d.comb += [ btb_rp.addr.eq(Mux(self.a_stall, f_pc.index, a_pc.index)), bht_rp.addr.eq(Mux(self.a_stall, f_pc.index, a_pc.index)), btb_r.eq(btb_rp.data), # a_pc.eq(self.a_pc), f_pc.eq(self.f_pc), hit.eq(btb_r.valid & (btb_r.tag == f_pc.tag)), # self.f_prediction.eq(hit & bht_rp.data[1]), self.f_prediction_state.eq(bht_rp.data), self.f_prediction_pc.eq(btb_r.target) ] # update m.d.comb += [ btb_wp.addr.eq(m_pc.index), btb_wp.data.eq(Cat(self.m_target_pc, m_pc.tag, 1)), btb_wp.en.eq(self.m_update), bht_wp.addr.eq(m_pc.index), bht_wp.data.eq(pstate_next), bht_wp.en.eq(self.m_update), m_pc.eq(self.m_pc), pstate_next.eq(0) ] with m.Switch(Cat(self.m_prediction_state, self.m_take_jmp_branch)): with m.Case(0b000, 0b001): m.d.comb += pstate_next.eq(0b00) with m.Case(0b010, 0b100): m.d.comb += pstate_next.eq(0b01) with m.Case(0b011, 0b101): m.d.comb += pstate_next.eq(0b10) with m.Case(0b110, 0b111): m.d.comb += pstate_next.eq(0b11) return m
def elaborate(self, platform: Platform) -> Module: m = Module() triggers = [Record.like(self.tdata1.read) for _ in range(self.ntriggers)] triggers_data = [Record.like(self.tdata2.read) for _ in range(self.ntriggers)] for t in triggers: m.d.comb += t.type.eq(TriggerType.MATCH) # support only address/data match # handle writes to tselect with m.If(self.tselect.we): with m.If(self.tselect.write < self.ntriggers): # no more than ntriggers m.d.sync += self.tselect.read.eq(self.tselect.write) # select the trigger with m.Switch(self.tselect.read): for idx, (trigger, trigger_data) in enumerate(zip(triggers, triggers_data)): with m.Case(idx): m.d.comb += [ self.tdata1.read.eq(trigger), # trigger visible @tdata1 self.tdata2.read.eq(trigger_data) # data visible @tdata2 ] # handle writes to tdata1 with m.If(self.tdata1.we): mcontrol = Record([('i', mcontrol_layout), ('o', mcontrol_layout)]) m.d.comb += [ mcontrol.i.eq(self.tdata1.write.data), # casting mcontrol.o.execute.eq(mcontrol.i.execute), mcontrol.o.store.eq(mcontrol.i.store), mcontrol.o.load.eq(mcontrol.i.load), mcontrol.o.m.eq(mcontrol.i.m), mcontrol.o.u.eq(mcontrol.i.u), mcontrol.o.action.eq(mcontrol.i.action) ] m.d.sync += [ trigger.dmode.eq(self.tdata1.write.dmode), trigger.data.eq(mcontrol.o) ] # handle writes to tdata2 with m.If(self.tdata2.we): m.d.sync += trigger_data.data.eq(self.tdata2.write) # trigger logic hit = Signal() halt = Signal() hit_v = Signal(self.ntriggers) halt_v = Signal(self.ntriggers) for idx, (trigger, trigger_data) in enumerate(zip(triggers, triggers_data)): with m.Switch(trigger.type): with m.Case(TriggerType.MATCH): match = Signal() mcontrol = Record(mcontrol_layout) m.d.comb += mcontrol.eq(trigger) # casting, lol with m.If(mcontrol.execute): m.d.comb += match.eq(self.x_valid & (trigger_data == self.x_pc)) with m.Elif(mcontrol.store): m.d.comb += match.eq(self.x_valid & self.x_store & (trigger_data == self.x_bus_addr)) with m.Elif(mcontrol.load): m.d.comb += match.eq(self.x_valid & self.x_load & (trigger_data == self.x_bus_addr)) if self.enable_user_mode: # check the current priv mode, and check the priv enable mode priv_m = self.privmode == PrivMode.Machine priv_u = self.privmode == PrivMode.User hit_tmp = match & ((mcontrol.m & priv_m) | (mcontrol.u & priv_u)) else: hit_tmp = match & mcontrol.m m.d.comb += [ hit_v[idx].eq(hit_tmp), halt_v[idx].eq(mcontrol.action) ] # request signals: halt/exception m.d.comb += [ hit.eq(reduce(or_, hit_v, 0)), halt.eq(reduce(or_, halt_v, 0)) ] with m.If(hit): with m.If(halt): # halt = mcontrol.action m.d.comb += self.haltreq.eq(self.tdata1.read.dmode) # enter debug mode only if dmode = 1 with m.Else(): m.d.comb += self.trap.eq(1) # generate exception return m
m.submodules.alu = alu = ALU8() m.domains.ph1 = ph1 = ClockDomain("ph1") rst = Signal() ph1clk = ClockSignal("ph1") ph1.rst = rst carry_in = Signal() sum9 = Signal(9) sum8 = Signal(8) sum5 = Signal(5) m.d.comb += Assert(alu._ccs[6:] == 0b11) with m.Switch(alu.func): with m.Case(ALU8Func.ADD, ALU8Func.ADC): # sumN = input1[:N] + input2[:N] (so sumN[N-1] is the carry bit) with m.If(alu.func == ALU8Func.ADD): m.d.comb += carry_in.eq(0) with m.Else(): m.d.comb += carry_in.eq(alu.ccs[_C]) h = sum5[4] n = sum9[7] c = sum9[8] z = (sum9[:8] == 0) v = (sum8[7] ^ c) m.d.comb += [ sum9.eq(alu.input1 + alu.input2 + carry_in), sum8.eq(alu.input1[:7] + alu.input2[:7] + carry_in), sum5.eq(alu.input1[:4] + alu.input2[:4] + carry_in), Assert(alu.output == sum9[:8]),
main_runner(parser, args, m, ports=core.ports() + [ph1clk, rst]) else: # Fake memory mem = { 0xFFFE: 0x12, 0xFFFF: 0x34, 0x1234: 0x7E, # JMP 0xA010 0x1235: 0xA0, 0x1236: 0x10, 0xA010: 0x01, # NOP } with m.Switch(core.Addr): for addr, data in mem.items(): with m.Case(addr): m.d.comb += core.Din.eq(data) with m.Default(): m.d.comb += core.Din.eq(0xFF) sim = Simulator(m) sim.add_clock(1e-6, domain="ph1") def process(): yield yield yield yield yield yield yield
def encode_opcode_select(self, m: Module): m.d.comb += self.opcode_select.eq(OpcodeSelect.NONE) m.d.comb += self._imm_format.eq(OpcodeFormat.R) with m.Switch(self._opcode): with m.Case(Opcode.LUI): m.d.comb += self.opcode_select.eq(OpcodeSelect.LUI) m.d.comb += self._imm_format.eq(OpcodeFormat.U) with m.Case(Opcode.AUIPC): m.d.comb += self.opcode_select.eq(OpcodeSelect.AUIPC) m.d.comb += self._imm_format.eq(OpcodeFormat.U) with m.Case(Opcode.OP_IMM): m.d.comb += self.opcode_select.eq(OpcodeSelect.OP_IMM) m.d.comb += self._imm_format.eq(OpcodeFormat.I) with m.Case(Opcode.OP): m.d.comb += self.opcode_select.eq(OpcodeSelect.OP) m.d.comb += self._imm_format.eq(OpcodeFormat.R) with m.Case(Opcode.JAL): m.d.comb += self.opcode_select.eq(OpcodeSelect.JAL) m.d.comb += self._imm_format.eq(OpcodeFormat.J) with m.Case(Opcode.JALR): m.d.comb += self.opcode_select.eq(OpcodeSelect.JALR) m.d.comb += self._imm_format.eq(OpcodeFormat.J) with m.Case(Opcode.BRANCH): m.d.comb += self.opcode_select.eq(OpcodeSelect.BRANCH) m.d.comb += self._imm_format.eq(OpcodeFormat.B) with m.Case(Opcode.LOAD): m.d.comb += self.opcode_select.eq(OpcodeSelect.LOAD) m.d.comb += self._imm_format.eq(OpcodeFormat.I) with m.Case(Opcode.STORE): m.d.comb += self.opcode_select.eq(OpcodeSelect.STORE) m.d.comb += self._imm_format.eq(OpcodeFormat.S) with m.Case(Opcode.SYSTEM): m.d.comb += self._imm_format.eq(OpcodeFormat.SYS) with m.If(self._funct3 == SystemFunc.PRIV): with m.Switch(self.state._instr): with m.Case(Instr.MRET): m.d.comb += self.opcode_select.eq( OpcodeSelect.MRET) with m.Case(Instr.ECALL): m.d.comb += self.opcode_select.eq( OpcodeSelect.ECALL) with m.Case(Instr.EBREAK): m.d.comb += self.opcode_select.eq( OpcodeSelect.EBREAK) with m.Else(): m.d.comb += self.opcode_select.eq(OpcodeSelect.CSRS)