def elaborate(self, platform): m = Module() invalid_r = Signal() invalid_w = Signal() # do the read m.d.comb += invalid_r.eq(0) for rport in self._read_ports: with m.Switch(rport.addr): for addr, csr in self._csr_map.items(): with m.Case(addr): m.d.comb += rport.data.eq(csr.read & csr.mask) with m.Default(): m.d.comb += invalid_r.eq(1) # do the write m.d.comb += invalid_r.eq(0) for wport in self._write_ports: with m.Switch(wport.addr): for addr, csr in self._csr_map.items(): with m.Case(addr): m.d.comb += [ csr.we.eq(wport.en), csr.write.eq(wport.data & csr.mask) ] with m.Default(): m.d.comb += invalid_r.eq(1) m.d.comb += self.invalid.eq(invalid_r | invalid_w) return m
def elaborate(self, _: Platform) -> Module: """Implements the logic of the buffer.""" m = Module() # OE_I = 0000011 | 0001111 | 0010011 # OE_S = 0100011 # OE_U = 0010111 | 0110111 # OE_B = 1100011 # OE_J = 1100111 | 1101111 # OE_SYS = 1110011 m.d.comb += [ self.i_n_oe.eq(1), self.s_n_oe.eq(1), self.u_n_oe.eq(1), self.b_n_oe.eq(1), self.j_n_oe.eq(1), self.sys_n_oe.eq(1), ] with m.Switch(self.opcode): with m.Case(0b0000011, 0b0001111, 0b0010011): # I m.d.comb += self.i_n_oe.eq(0) with m.Case(0b0100011): # S m.d.comb += self.s_n_oe.eq(0) with m.Case(0b0010111, 0b0110111): # U m.d.comb += self.u_n_oe.eq(0) with m.Case(0b1100011): m.d.comb += self.b_n_oe.eq(0) with m.Case(0b1100111, 0b1101111): m.d.comb += self.j_n_oe.eq(0) with m.Default(): m.d.comb += self.sys_n_oe.eq(0) return m
def execute(self, m: Module): with m.Switch(self.registers.instr): for key, instr in self.instruction_set.instructions.items(): with m.Case(key): instr.implement(m, self) with m.Default(): self.halt(m)
def elaborate(self, p: Platform) -> Module: m = Module() comb = m.d.comb signed_lhs = as_signed(m, self.lhs) signed_rhs = as_signed(m, self.rhs) with m.If(self.en): if self.invalid_op is not None: comb += self.invalid_op.eq(0) with m.Switch(self.op): with m.Case(OpAlu.ADD): comb += self.output.eq(self.lhs + self.rhs) with m.Case(OpAlu.SLT): comb += self.output.eq(Mux(signed_lhs < signed_rhs, 1, 0)) with m.Case(OpAlu.SLTU): comb += self.output.eq(Mux(self.lhs < self.rhs, 1, 0)) with m.Case(OpAlu.AND): comb += self.output.eq(self.lhs & self.rhs) with m.Case(OpAlu.OR): comb += self.output.eq(self.lhs | self.rhs) with m.Case(OpAlu.XOR): comb += self.output.eq(self.lhs ^ self.rhs) with m.Default(): comb += self.output.eq(0) if self.invalid_op is not None: comb += self.invalid_op.eq(1) with m.Else(): self.output.eq(0) return m
def setup_src_bus(self, m: Module, reg_map: Dict[IntEnum, Register], bus: Signal, selector: Signal): with m.Switch(selector): for (e, reg) in reg_map.items(): with m.Case(e): m.d.comb += bus.eq(reg.register) with m.Default(): m.d.comb += bus.eq(0)
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the shifter.""" m = Module() m.submodules.shifter = shifter = ShiftCard() shamt = Signal(5) m.d.comb += shamt.eq(shifter.data_y[:5]) with m.If(shamt > 0): m.d.comb += Cover(shifter.data_z == 0xFFFFAAA0) with m.Switch(shifter.alu_op): with m.Case(AluOp.SLL): m.d.comb += Assert( shifter.data_z == (shifter.data_x << shamt)[:32]) with m.Case(AluOp.SRL): m.d.comb += Assert(shifter.data_z == (shifter.data_x >> shamt)) with m.Case(AluOp.SRA): m.d.comb += Assert( shifter.data_z == (shifter.data_x.as_signed() >> shamt)) with m.Default(): m.d.comb += Assert(shifter.data_z == 0) return m, [ shifter.alu_op, shifter.data_x, shifter.data_y, shifter.data_z ]
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("01111110"): # JMP ext self.JMPext(m) with m.Case("1-110110"): # LDA ext self.ALUext(m, ALU8Func.LD) with m.Case("1-110000"): # SUB ext self.ALUext(m, ALU8Func.SUB) with m.Case("1-110001"): # CMP ext self.ALUext(m, ALU8Func.SUB, store=False) with m.Case("1-110010"): # SBC ext self.ALUext(m, ALU8Func.SBC) with m.Case("1-110100"): # AND ext self.ALUext(m, ALU8Func.AND) with m.Case("1-110101"): # BIT ext self.ALUext(m, ALU8Func.AND, store=False) with m.Case("1-110111"): # STA ext self.STAext(m) with m.Case("1-111000"): # EOR ext self.ALUext(m, ALU8Func.EOR) with m.Case("1-111001"): # ADC ext self.ALUext(m, ALU8Func.ADC) with m.Case("1-111010"): # ORA ext self.ALUext(m, ALU8Func.ORA) with m.Case("1-111011"): # ADD ext self.ALUext(m, ALU8Func.ADD) with m.Default(): # Illegal self.end_instr(m, self.pc)
def src_bus_setup(self, m: Module, reg_map: Dict[IntEnum, Tuple[Signal, bool]], bus: Signal, selector: Signal): with m.Switch(selector): for e, reg in reg_map.items(): with m.Case(e): m.d.comb += bus.eq(reg[0]) with m.Default(): m.d.comb += bus.eq(0)
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the ALU.""" m = Module() m.submodules.alu = alu = AluCard() with m.Switch(alu.alu_op): with m.Case(AluOp.ADD): m.d.comb += Assert(alu.data_z == (alu.data_x + alu.data_y)[:32]) with m.Case(AluOp.SUB): m.d.comb += [ Assert(alu.data_z == (alu.data_x - alu.data_y)[:32]), Assert(alu.alu_eq == (alu.data_x == alu.data_y)), Assert(alu.alu_ltu == (alu.data_x < alu.data_y)), Assert(alu.alu_lt == ( alu.data_x.as_signed() < alu.data_y.as_signed())), ] with m.Case(AluOp.AND): m.d.comb += Assert(alu.data_z == (alu.data_x & alu.data_y)) with m.Case(AluOp.AND_NOT): m.d.comb += Assert(alu.data_z == (alu.data_x & ~alu.data_y)) with m.Case(AluOp.OR): m.d.comb += Assert(alu.data_z == (alu.data_x | alu.data_y)) with m.Case(AluOp.XOR): m.d.comb += Assert(alu.data_z == (alu.data_x ^ alu.data_y)) with m.Case(AluOp.SLTU): with m.If(alu.data_x < alu.data_y): m.d.comb += Assert(alu.data_z == 1) with m.Else(): m.d.comb += Assert(alu.data_z == 0) with m.Case(AluOp.SLT): with m.If(alu.data_x.as_signed() < alu.data_y.as_signed()): m.d.comb += Assert(alu.data_z == 1) with m.Else(): m.d.comb += Assert(alu.data_z == 0) with m.Case(AluOp.X): m.d.comb += Assert(alu.data_z == alu.data_x) with m.Case(AluOp.Y): m.d.comb += Assert(alu.data_z == alu.data_y) with m.Default(): m.d.comb += Assert(alu.data_z == 0) return m, [alu.alu_op, alu.data_x, alu.data_y, alu.data_z]
def elaborate(self, platform: Platform) -> Module: m = Module() with m.Switch(self.op): with m.Case(Funct3.XOR): m.d.comb += self.result.eq(self.dat1 ^ self.dat2) with m.Case(Funct3.OR): m.d.comb += self.result.eq(self.dat1 | self.dat2) with m.Case(Funct3.AND): m.d.comb += self.result.eq(self.dat1 & self.dat2) with m.Default(): m.d.comb += self.result.eq(0) return m
def make_fakemem(self, m: Module, mem: Dict[int, int]): comb: List[Statement] = m.d.comb with m.If(self.mem2core.en): with m.Switch(self.mem2core.addr): for address, value in mem.items(): with m.Case(address): word_value = value | ( mem.get(address + 1, 0xff) << 8) | ( mem.get(address + 2, 0xff) << 16) | ( mem.get(address + 3, 0xff) << 24) comb += self.mem2core.value.eq(word_value) with m.Default(): comb += self.mem2core.value.eq(0xFFFFFFFF) comb += self.mem2core.ready.eq(1) with m.Else(): comb += self.mem2core.ready.eq(1)
def elaborate(self, platform: Platform) -> Module: m = Module() invalid_undef = Signal() # The register is not defined invalid_ro = Signal() # The register is read-only. invalid_priv = Signal() # The priviledge mode is incorrect. # ---------------------------------------------------------------------- # access for idx, port in enumerate(self._ports): if idx == 0: # The first write port is for pipeline use, and is the only one that # can generate exceptions # Other write ports do not generate exceptions: for debug use, for example. # Priv mode must be greater or equal to the priv mode of the register. m.d.comb += [ invalid_ro.eq(port.addr[10:12] == 0b11), invalid_priv.eq(port.addr[8:10] > self.privmode) ] with m.Switch(port.addr): for addr, csr in self._csr_map.items(): with m.Case(addr): m.d.comb += [ csr.we.eq(port.en & ~(invalid_ro | invalid_priv)), port.data_r.eq(csr.read & csr.mask), csr.write.eq(port.data_w & csr.mask) ] with m.Default(): m.d.comb += invalid_undef.eq(1) m.d.comb += self.invalid.eq(invalid_undef | (invalid_ro & port.en) | invalid_priv) else: with m.Switch(port.addr): for addr, csr in self._csr_map.items(): with m.Case(addr): m.d.comb += [ csr.we.eq(port.en), port.data_r.eq(csr.read & csr.mask), csr.write.eq(port.data_w & csr.mask) ] return m
def elaborate(self, platform: Platform) -> Module: m = Module() m.submodules.alu = self.alu = ALU() """Fetch the opcode, common for all instr""" m.d.sync += self.opcode.eq(Mux(self.cycle == 1, self.dout, self.opcode)) with m.Switch(Mux(self.cycle == 1, self.dout, self.opcode)): for i in implemented.implemented: with m.Case(i.opcode): i.synth(self, m) with m.Default(): m.d.comb += core.alu.oper.eq(Operation.NOP) m.d.sync += [ core.reg.PC.eq(add16(core.reg.PC, 1)), core.enable.eq(1), core.addr.eq(add16(core.reg.PC, 1)), core.RWB.eq(1), core.cycle.eq(1), ] if self.verification is not None: self.verify(m) with m.If(Initial()): m.d.sync += [ self.reg.A.eq(AnyConst(8)), self.reg.X.eq(AnyConst(8)), self.reg.Y.eq(AnyConst(8)), self.reg.SP.eq(AnyConst(16)), self.reg.PC.eq(AnyConst(16)), ] m.d.sync += [ self.reg.PSW.N.eq(AnyConst(1)), self.reg.PSW.V.eq(AnyConst(1)), self.reg.PSW.P.eq(AnyConst(1)), self.reg.PSW.B.eq(AnyConst(1)), self.reg.PSW.H.eq(AnyConst(1)), self.reg.PSW.I.eq(AnyConst(1)), self.reg.PSW.Z.eq(AnyConst(1)), self.reg.PSW.C.eq(AnyConst(1)), ] return m
def elaborate(self, _: Platform) -> Module: """Implements the logic for the NextDay module.""" m = Module() is_leap_year = Signal() max_day = Signal.like(self.day) m.d.comb += is_leap_year.eq(0) # We can override this below! with m.If((self.year % 4) == 0): m.d.comb += is_leap_year.eq(1) with m.If((self.year % 100) == 0): m.d.comb += is_leap_year.eq(0) with m.If((self.year % 400) == 0): m.d.comb += is_leap_year.eq(1) with m.Switch(self.month): with m.Case(1, 3, 5, 7, 8, 10, 12): m.d.comb += max_day.eq(31) with m.Case(2): m.d.comb += max_day.eq(28 + is_leap_year) with m.Default(): m.d.comb += max_day.eq(30) m.d.comb += self.next_year.eq(self.year) m.d.comb += self.next_month.eq(self.month) m.d.comb += self.next_day.eq(self.day + 1) with m.If(self.day == max_day): m.d.comb += self.next_day.eq(1) m.d.comb += self.next_month.eq(self.month + 1) with m.If(self.month == 12): m.d.comb += self.next_month.eq(1) m.d.comb += self.next_year.eq(self.year + 1) m.d.comb += self.invalid.eq(0) with m.If((self.day < 1) | (self.day > max_day) | (self.month < 1) | (self.month > 12) | (self.year < 1) | (self.year > 9999)): m.d.comb += self.invalid.eq(1) with m.If(self.invalid): m.d.comb += self.next_year.eq(0) m.d.comb += self.next_month.eq(0) m.d.comb += self.next_day.eq(0) return m
def elaborate(self, platform): m = Module() with m.Switch(self.op): with m.Case(Funct3.BEQ): m.d.comb += self.cmp_ok.eq(self.zero) with m.Case(Funct3.BNE): m.d.comb += self.cmp_ok.eq(~self.zero) with m.Case(Funct3.BLT, Funct3.SLT): m.d.comb += self.cmp_ok.eq(~self.zero & (self.negative != self.overflow)) with m.Case(Funct3.BLTU, Funct3.SLTU): m.d.comb += self.cmp_ok.eq(~self.zero & self.carry) with m.Case(Funct3.BGE): m.d.comb += self.cmp_ok.eq(self.negative == self.overflow) with m.Case(Funct3.BGEU): m.d.comb += self.cmp_ok.eq(~self.carry) with m.Default(): m.d.comb += self.cmp_ok.eq(0) return m
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_csrs(self, m: Module): """Adds the SYSTEM (CSR opcodes) logic to the given module. Some points of interest: * Attempts to write a read-only register result in an illegal instruction exception. * Attempts to access a CSR that doesn't exist result in an illegal instruction exception. * Attempts to write read-only bits to a read/write CSR are ignored. Because we're building this in hardware, which is expensive, we're not implementing any CSRs that aren't strictly necessary. The documentation for the misa, mvendorid, marchid, and mimpid registers state that they can return zero if unimplemented. This implies that unimplemented CSRs still exist. The mhartid, because we only have one HART, can just return zero. """ with m.Switch(self._funct3): with m.Case(SystemFunc.CSRRW): self.handle_CSRRW(m) with m.Case(SystemFunc.CSRRWI): self.handle_CSRRWI(m) with m.Case(SystemFunc.CSRRS): self.handle_CSRRS(m) with m.Case(SystemFunc.CSRRSI): self.handle_CSRRSI(m) with m.Case(SystemFunc.CSRRC): self.handle_CSRRC(m) with m.Case(SystemFunc.CSRRCI): self.handle_CSRRCI(m) with m.Default(): self.handle_illegal_instr(m)
def formal(cls) -> Tuple[Module, List[Signal]]: m = Module() ph = ClockDomain("ph") clk = ClockSignal("ph") m.domains += ph m.d.sync += clk.eq(~clk) s = IC_reg32_with_mux(clk="ph", N=2, faster=True) m.submodules += s sync_clk = ClockSignal("sync") sync_rst = ResetSignal("sync") with m.If(Rose(clk)): with m.Switch(~Past(s.n_sel)): with m.Case(0b11): m.d.comb += Assert(0) with m.Case(0b01): m.d.comb += Assert(s.q == Past(s.d[0])) with m.Case(0b10): m.d.comb += Assert(s.q == Past(s.d[1])) with m.Default(): m.d.comb += Assert(s.q == Past(s.q)) # Make sure the clock is clocking m.d.comb += Assume(sync_clk == ~Past(sync_clk)) # Don't want to test what happens when we reset. m.d.comb += Assume(~sync_rst) m.d.comb += Assume(~ResetSignal("ph")) m.d.comb += Assume(s.n_sel != 0) return m, [sync_clk, sync_rst, s.d[0], s.d[1], s.n_sel, s.q]
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 yield yield
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: 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 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) -> Module: """Implements the logic of the ALU card.""" m = Module() output_buffer = TransparentLatch(size=32) m.submodules += output_buffer m.d.comb += output_buffer.le.eq(1) m.d.comb += output_buffer.data_in.eq(0) m.d.comb += self.data_z.eq(output_buffer.data_out) m.d.comb += self.alu_eq.eq(0) m.d.comb += self.alu_lt.eq(0) m.d.comb += self.alu_ltu.eq(0) x = self.data_x y = self.data_y m.d.comb += self.alu_eq.eq(output_buffer.data_in == 0) m.d.comb += self.alu_ltu.eq(x < y) m.d.comb += self.alu_lt.eq(x.as_signed() < y.as_signed()) with m.Switch(self.alu_op): with m.Case(AluOp.ADD): m.d.comb += output_buffer.data_in.eq(x + y) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.SUB): m.d.comb += output_buffer.data_in.eq(x - y) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.SLTU): m.d.comb += output_buffer.data_in.eq(self.alu_ltu) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.SLT): m.d.comb += output_buffer.data_in.eq(self.alu_lt) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.AND): m.d.comb += output_buffer.data_in.eq(x & y) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.AND_NOT): m.d.comb += output_buffer.data_in.eq(x & ~y) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.OR): m.d.comb += output_buffer.data_in.eq(x | y) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.XOR): m.d.comb += output_buffer.data_in.eq(x ^ y) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.X): m.d.comb += output_buffer.data_in.eq(x) m.d.comb += output_buffer.n_oe.eq(0) with m.Case(AluOp.Y): m.d.comb += output_buffer.data_in.eq(y) 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() 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() # 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() # Set MTVEC to the RESET address, to avoid getting lost in limbo if there's an exception # before the boot code sets this to a valid value self.mtvec.read.base.reset = self.core_reset_address >> 2 privmode = Signal(PrivMode) privmode.reset = PrivMode.Machine # default mode is Machine m.d.comb += self.m_privmode.eq(privmode) # Read/write behavior for all registers for reg in self.get_csrs(): with m.If(reg.we): m.d.sync += reg.read.eq(reg.write) # constants (at least, the important ones) if self.enable_extra_csr: misa = 0x1 << 30 | (1 << (ord('i') - ord('a')) ) # 32-bits processor. RV32I if self.enable_rv32m: misa |= 1 << (ord('m') - ord('a')) # RV32M if self.enable_user_mode: misa |= 1 << (ord('u') - ord('a')) # User mode enabled m.d.sync += [ self.misa.read.eq(misa), self.mhartid.read.eq(0), # ID 0 FOREVER. self.mimpid.read.eq(0), # No implemented = 0 self.marchid.read.eq(0), # No implemented = 0 self.mvendorid.read.eq(0) # No implemented = 0 ] traps = m.submodules.traps = PriorityEncoder(ExceptionCause.MAX_NUM) 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( ExceptionCause.MAX_NUM) m.d.comb += [ interrupts.i[ExceptionCause.I_M_SOFTWARE].eq(self.mip.read.msip & self.mie.read.msie), interrupts.i[ExceptionCause.I_M_TIMER].eq(self.mip.read.mtip & self.mie.read.mtie), interrupts.i[ExceptionCause.I_M_EXTERNAL].eq(self.mip.read.meip & self.mie.read.meie), ] # generate the exception/trap/interrupt signal to kill the pipeline # interrupts are globally enable for less priviledge mode than Machine m.d.comb += self.m_exception.eq(~traps.n | ( ~interrupts.n & (self.mstatus.read.mie | (privmode != PrivMode.Machine)) & ~self.m_store)) # -------------------------------------------------------------------------------- # overwrite values from the RW circuit # -------------------------------------------------------------------------------- m.d.sync += [ self.mip.read.msip.eq(self.software_interrupt), self.mip.read.mtip.eq(self.timer_interrupt), self.mip.read.meip.eq(self.external_interrupt) ] if self.enable_user_mode: self.mstatus.read.mpp.reset = PrivMode.User with m.If(self.mstatus.write.mpp != PrivMode.User): # In case of writting an invalid priviledge mode, force a valid one # For this case, anything different to the User mode is forced to Machine mode. m.d.sync += self.mstatus.read.mpp.eq(PrivMode.Machine) else: self.mstatus.read.mpp.reset = PrivMode.Machine m.d.sync += self.mstatus.read.mpp.eq( PrivMode.Machine) # Only machine mode # Constant fields in MSTATUS # Disable because S-mode and User-level interrupts # are not supported. m.d.sync += [ self.mstatus.read.uie.eq(0), self.mstatus.read.upie.eq(0), self.mstatus.read.sie.eq(0), self.mstatus.read.spie.eq(0), self.mstatus.read.spp.eq(0), self.mstatus.read.mxr.eq(0), self.mstatus.read.sum.eq(0), self.mstatus.read.tvm.eq(0), self.mstatus.read.tsr.eq(0), self.mstatus.read.fs.eq(0), self.mstatus.read.xs.eq(0), self.mstatus.read.sd.eq(0) ] # MIP and MIE m.d.sync += [ self.mip.read.usip.eq(0), self.mip.read.ssip.eq(0), self.mip.read.utip.eq(0), self.mip.read.stip.eq(0), self.mip.read.ueip.eq(0), self.mip.read.seip.eq(0), self.mie.read.usie.eq(0), self.mie.read.ssie.eq(0), self.mie.read.utie.eq(0), self.mie.read.stie.eq(0), self.mie.read.ueie.eq(0), self.mie.read.seie.eq(0) ] # 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. m.d.sync += [ self.mepc.read.base.eq(self.m_pc[2:]), self.mstatus.read.mpie.eq(self.mstatus.read.mie), self.mstatus.read.mie.eq(0), # Change priviledge mode privmode.eq(PrivMode.Machine), self.mstatus.read.mpp.eq(privmode) ] # store cause/mtval with m.If(~traps.n): m.d.sync += [ self.mcause.read.ecode.eq(traps.o), self.mcause.read.interrupt.eq(0) ] with m.Switch(traps.o): with m.Case(ExceptionCause.E_INST_ADDR_MISALIGNED): m.d.sync += self.mtval.read.eq(self.m_pc_misalign) with m.Case(ExceptionCause.E_INST_ACCESS_FAULT): m.d.sync += self.mtval.read.eq( self.m_fetch_badaddr) with m.Case(ExceptionCause.E_ILLEGAL_INST): m.d.sync += self.mtval.read.eq(self.m_instruction) with m.Case(ExceptionCause.E_BREAKPOINT): m.d.sync += self.mtval.read.eq(self.m_pc) with m.Case( ExceptionCause.E_LOAD_ADDR_MISALIGNED, ExceptionCause.E_STORE_AMO_ADDR_MISALIGNED): m.d.sync += self.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.mtval.read.eq( self.m_load_store_badaddr) with m.Default(): m.d.sync += self.mtval.read.eq(0) with m.Else(): m.d.sync += [ self.mcause.read.ecode.eq(interrupts.o), self.mcause.read.interrupt.eq(1) ] with m.Elif(self.m_mret): # restore old mie # Restore priviledge mode m.d.sync += [ self.mstatus.read.mie.eq(self.mstatus.read.mpie), privmode.eq(self.mstatus.read.mpp), ] if self.enable_user_mode: m.d.sync += self.mstatus.read.mpp.eq(PrivMode.User) # counters if self.enable_extra_csr: mcycle = Signal(64) minstret = Signal(64) m.d.sync += [ self.mcycle.read.eq(mcycle[:32]), self.mcycleh.read.eq(mcycle[32:64]), # self.minstret.read.eq(minstret[:32]), self.minstreth.read.eq(minstret[32:64]) ] m.d.comb += mcycle.eq(Cat(self.mcycle.read, self.mcycleh.read) + 1) with m.If(self.w_retire): m.d.comb += minstret.eq( Cat(self.minstret.read, self.minstreth.read) + 1) with m.Else(): m.d.comb += minstret.eq( Cat(self.minstret.read, self.minstreth.read)) # shadow versions of MCYCLE and MINSTRET if self.enable_user_mode: m.d.sync += [ self.cycle.read.eq(mcycle[:32]), self.cycleh.read.eq(mcycle[32:64]), # self.instret.read.eq(minstret[:32]), self.instreth.read.eq(minstret[32:64]) ] 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 formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the register card.""" m = Module() ph1 = ClockDomain("ph1") ph2 = ClockDomain("ph2") regs = RegCard() m.domains += [ph1, ph2] m.submodules += regs # Generate the ph1 and ph2 clocks. cycle_count = Signal(8, reset=0, reset_less=True) phase_count = Signal(3, reset=0, reset_less=True) m.d.sync += phase_count.eq(phase_count + 1) with m.Switch(phase_count): with m.Case(0, 1, 2): m.d.comb += ph1.clk.eq(1) with m.Default(): m.d.comb += ph1.clk.eq(0) with m.Switch(phase_count): with m.Case(1, 4): m.d.comb += ph2.clk.eq(0) with m.Default(): m.d.comb += ph2.clk.eq(1) with m.If(phase_count == 5): m.d.sync += phase_count.eq(0) m.d.sync += cycle_count.eq(cycle_count + 1) # This is how we expect to use the card. with m.If(phase_count > 0): m.d.comb += [ Assume(Stable(regs.reg_x)), Assume(Stable(regs.reg_y)), Assume(Stable(regs.reg_z)), Assume(Stable(regs.reg_page)), Assume(Stable(regs.reg_to_x)), Assume(Stable(regs.reg_to_y)), Assume(Stable(regs.data_z)), ] # Figure out how to get to the point where X and Y are nonzero and different. m.d.comb += Cover((regs.data_x != 0) & (regs.data_y != 0) & (regs.data_x != regs.data_y)) # X and Y buses should not change during a cycle, except for the first phase with m.Switch(phase_count): with m.Case(2, 3, 4, 5): with m.If(regs.data_x != 0): m.d.comb += Assert(Stable(regs.data_x)) with m.If(regs.data_y != 0): m.d.comb += Assert(Stable(regs.data_y)) # X and Y buses should be zero if there is no data transfer. with m.If(regs.reg_to_x == 0): m.d.comb += Assert(regs.data_x == 0) with m.If(regs.reg_to_y == 0): m.d.comb += Assert(regs.data_y == 0) with m.If(phase_count > 0): # X and Y buses should be zero if we read from register 0. with m.If(regs.reg_to_x & (regs.reg_x == 0)): m.d.comb += Assert(regs.data_x == 0) with m.If(regs.reg_to_y & (regs.reg_y == 0)): m.d.comb += Assert(regs.data_y == 0) write_pulse = Signal() m.d.comb += write_pulse.eq(phase_count != 4) # On write, the data should have been written to both banks. past_mem_addr = Signal(6) m.d.comb += past_mem_addr[:5].eq(Past(regs.reg_z)) m.d.comb += past_mem_addr[5].eq(Past(regs.reg_page)) past_z = Past(regs.data_z) with m.If(Rose(write_pulse)): m.d.comb += Assert(regs._x_bank._mem[past_mem_addr] == past_z) m.d.comb += Assert(regs._y_bank._mem[past_mem_addr] == past_z) # Pick an register, any register, except 0. We assert that unless # it is written, its data will not change. check_addr = AnyConst(5) check_page = AnyConst(1) saved_data = Signal(32) stored_x_data = Signal(32) stored_y_data = Signal(32) write_pulse_domain = ClockDomain("write_pulse_domain", local=True) m.domains.write_pulse_domain = write_pulse_domain write_pulse_domain.clk = write_pulse mem_addr = Signal(6) m.d.comb += Assume(check_addr != 0) m.d.comb += [ mem_addr[:5].eq(check_addr), mem_addr[5].eq(check_page), stored_x_data.eq(regs._x_bank._mem[mem_addr]), stored_y_data.eq(regs._y_bank._mem[mem_addr]), ] with m.If((regs.reg_z == check_addr) & (regs.reg_page == check_page)): m.d.write_pulse_domain += saved_data.eq(regs.data_z) with m.If(Initial()): m.d.comb += Assume(saved_data == stored_x_data) m.d.comb += Assume(stored_x_data == stored_y_data) with m.Else(): m.d.comb += Assert(saved_data == stored_x_data) m.d.comb += Assert(saved_data == stored_y_data) return m, [regs.data_z, regs.reg_to_x, regs.reg_to_y, regs.reg_x, regs.reg_y, regs.reg_z, regs.reg_page, ph1.clk, ph2.clk, saved_data, stored_x_data, stored_y_data]
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