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 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 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)
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 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 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 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 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 check(self, m: Module, instr: Value, data: FormalData): m.d.comb += [ Assert(data.post_a == data.pre_a), Assert(data.post_b == data.pre_b), Assert(data.post_x == data.pre_x), Assert(data.post_sp == data.pre_sp), Assert(data.addresses_written == 0), Assert(data.addresses_read == 0), ] m.d.comb += Assert(data.post_pc == data.plus16(data.pre_pc, 1)) c = Signal() v = Signal() i = Signal() m.d.comb += c.eq(data.pre_ccs[Flags.C]) m.d.comb += v.eq(data.pre_ccs[Flags.V]) m.d.comb += i.eq(data.pre_ccs[Flags.I]) with m.Switch(instr): with m.Case(CLV): m.d.comb += v.eq(0) with m.Case(SEV): m.d.comb += v.eq(1) with m.Case(CLC): m.d.comb += c.eq(0) with m.Case(SEC): m.d.comb += c.eq(1) with m.Case(CLI): m.d.comb += i.eq(0) with m.Case(SEI): m.d.comb += i.eq(1) self.assertFlags(m, data.post_ccs, data.pre_ccs, V=v, C=c, I=i)
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 elaborate(self, platform): m = Module() interface = self.interface setup = self.interface.setup # # Class request handlers. # with m.If(setup.type == USBRequestType.CLASS): with m.Switch(setup.request): # SET_LINE_CODING: The host attempts to tell us how it wants serial data # encoding. Since we output a stream, we'll ignore the actual line coding. with m.Case(self.SET_LINE_CODING): # Always ACK the data out... with m.If(interface.rx_ready_for_response): m.d.comb += interface.handshakes_out.ack.eq(1) # ... and accept whatever the request was. with m.If(interface.status_requested): m.d.comb += self.send_zlp() with m.Case(): # # Stall unhandled requests. # with m.If(interface.status_requested | interface.data_requested): m.d.comb += interface.handshakes_out.stall.eq(1) return m
def branch_check(self, m: Module) -> Signal: """Generates logic for a 1-bit value for branching. Returns a 1-bit Signal which is set if the branch should be taken. The branch logic is determined by the instruction. """ invert = self.instr[0] cond = Signal() take_branch = Signal() with m.Switch(self.instr[1:4]): with m.Case("000"): # BRA, BRN m.d.comb += cond.eq(1) with m.Case("001"): # BHI, BLS m.d.comb += cond.eq(~(self.ccs[Flags.C] | self.ccs[Flags.Z])) with m.Case("010"): # BCC, BCS m.d.comb += cond.eq(~self.ccs[Flags.C]) with m.Case("011"): # BNE, BEQ m.d.comb += cond.eq(~self.ccs[Flags.Z]) with m.Case("100"): # BVC, BVS m.d.comb += cond.eq(~self.ccs[Flags.V]) with m.Case("101"): # BPL, BMI m.d.comb += cond.eq(~self.ccs[Flags.N]) with m.Case("110"): # BGE, BLT m.d.comb += cond.eq(~(self.ccs[Flags.N] ^ self.ccs[Flags.V])) with m.Case("111"): # BGT, BLE m.d.comb += cond.eq(~(self.ccs[Flags.Z] | (self.ccs[Flags.N] ^ self.ccs[Flags.V]))) m.d.comb += take_branch.eq(cond ^ invert) return take_branch
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 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 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), ] with m.Switch(self.i_y_coord & 3): with m.Case(0): self._dither(m, self.i_dm00, self.i_dm01, self.i_dm02, self.i_dm03) with m.Case(1): self._dither(m, self.i_dm10, self.i_dm11, self.i_dm12, self.i_dm13) with m.Case(2): self._dither(m, self.i_dm20, self.i_dm21, self.i_dm22, self.i_dm23) with m.Case(3): self._dither(m, self.i_dm30, self.i_dm31, self.i_dm32, self.i_dm33) return m
def check(self, m: Module): self.assert_cycles(m, 2) c = Signal() v = Signal() i = Signal() m.d.comb += c.eq(self.data.pre_ccs[Flags.C]) m.d.comb += v.eq(self.data.pre_ccs[Flags.V]) m.d.comb += i.eq(self.data.pre_ccs[Flags.I]) with m.Switch(self.instr): with m.Case(CLV): m.d.comb += v.eq(0) with m.Case(SEV): m.d.comb += v.eq(1) with m.Case(CLC): m.d.comb += c.eq(0) with m.Case(SEC): m.d.comb += c.eq(1) with m.Case(CLI): m.d.comb += i.eq(0) with m.Case(SEI): m.d.comb += i.eq(1) self.assert_registers(m, PC=self.data.pre_pc + 1) self.assert_flags(m, V=v, C=c, I=i)
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 decode_imm(self, m: Module): """Decodes the immediate value out of the instruction.""" with m.Switch(self._imm_format): # Format I instructions. Surprisingly, SLTIU (Set if Less Than # Immediate Unsigned) actually does sign-extend the immediate # value, and then compare as if the sign-extended immediate value # were unsigned! with m.Case(OpcodeFormat.I): tmp = Signal(signed(12)) m.d.comb += tmp.eq(self.state._instr[20:]) m.d.comb += self._imm.eq(tmp) # Format S instructions: with m.Case(OpcodeFormat.S): tmp = Signal(signed(12)) m.d.comb += tmp[0:5].eq(self.state._instr[7:12]) m.d.comb += tmp[5:].eq(self.state._instr[25:]) m.d.comb += self._imm.eq(tmp) # Format R instructions: with m.Case(OpcodeFormat.R): m.d.comb += self._imm.eq(0) # Format U instructions: with m.Case(OpcodeFormat.U): m.d.comb += self._imm.eq(0) m.d.comb += self._imm[12:].eq(self.state._instr[12:]) # Format B instructions: with m.Case(OpcodeFormat.B): tmp = Signal(signed(13)) m.d.comb += [ tmp[12].eq(self.state._instr[31]), tmp[11].eq(self.state._instr[7]), tmp[5:11].eq(self.state._instr[25:31]), tmp[1:5].eq(self.state._instr[8:12]), tmp[0].eq(0), self._imm.eq(tmp), ] # Format J instructions: with m.Case(OpcodeFormat.J): tmp = Signal(signed(21)) m.d.comb += [ tmp[20].eq(self.state._instr[31]), tmp[12:20].eq(self.state._instr[12:20]), tmp[11].eq(self.state._instr[20]), tmp[1:11].eq(self.state._instr[21:31]), tmp[0].eq(0), self._imm.eq(tmp), ] with m.Case(OpcodeFormat.SYS): m.d.comb += [ self._imm[0:5].eq(self.state._instr[15:]), self._imm[5:].eq(0), ]
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): m = Module() # # Our module has three core parts: # - an encoder, which converts from our one-hot signal to a mux select line # - a multiplexer, which handles multiplexing e.g. payload signals # - a set of OR'ing logic, which joints together our simple or'd signals # Create our encoder... m.submodules.encoder = encoder = Encoder(len(self._inputs)) for index, interface in enumerate(self._inputs): # ... and tie its inputs to each of our 'valid' signals. valid_signal = getattr(interface, self._valid_field) m.d.comb += encoder.i[index].eq(valid_signal) # Create our multiplexer, and drive each of our output signals from it. with m.Switch(encoder.o): for index, interface in enumerate(self._inputs): # If an interface is selected... with m.Case(index): for identifier in self._mux_signals: # ... connect all of its muxed signals through to the output. output_signal = self._get_signal( self.output, identifier) input_signal = self._get_signal(interface, identifier) m.d.comb += output_signal.eq(input_signal) # Create the OR'ing logic for each of or or_signals. for identifier in self._or_signals: # Figure out the signals we want to work with... output_signal = self._get_signal(self.output, identifier) input_signals = (self._get_signal(i, identifier) for i in self._inputs) # ... and OR them together. or_reduced = functools.reduce(operator.__or__, input_signals, 0) m.d.comb += output_signal.eq(or_reduced) # Finally, pass each of our pass-back signals from the output interface # back to each of our input interfaces. for identifier in self._pass_signals: output_signal = self._get_signal(self.output, identifier) for interface in self._inputs: input_signal = self._get_signal(interface, identifier) m.d.comb += input_signal.eq(output_signal) return m
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 handle_op(self, m: Module): """Adds the OP logic to the given module. rd <- rs1 op rs2 PC <- PC + 4 rs1 -> X rs2 -> Y ALU op -> Z Z -> rd PC + 4 -> PC PC + 4 -> memaddr """ with m.If(~self._alu_func.matches( AluFunc.ADD, AluFunc.SUB, AluFunc.SLL, AluFunc.SLT, AluFunc.SLTU, AluFunc.XOR, AluFunc.SRL, AluFunc.SRA, AluFunc.OR, AluFunc.AND)): self.handle_illegal_instr(m) with m.Else(): m.d.comb += [ self.reg_to_x.eq(1), self._x_reg_select.eq(InstrReg.RS1), self.reg_to_y.eq(1), self._y_reg_select.eq(InstrReg.RS2), self._z_reg_select.eq(InstrReg.RD), ] with m.Switch(self._alu_func): with m.Case(AluFunc.ADD): m.d.comb += self.alu_op_to_z.eq(AluOp.ADD) with m.Case(AluFunc.SUB): m.d.comb += self.alu_op_to_z.eq(AluOp.SUB) with m.Case(AluFunc.SLL): m.d.comb += self.alu_op_to_z.eq(AluOp.SLL) with m.Case(AluFunc.SLT): m.d.comb += self.alu_op_to_z.eq(AluOp.SLT) with m.Case(AluFunc.SLTU): m.d.comb += self.alu_op_to_z.eq(AluOp.SLTU) with m.Case(AluFunc.XOR): m.d.comb += self.alu_op_to_z.eq(AluOp.XOR) with m.Case(AluFunc.SRL): m.d.comb += self.alu_op_to_z.eq(AluOp.SRL) with m.Case(AluFunc.SRA): m.d.comb += self.alu_op_to_z.eq(AluOp.SRA) with m.Case(AluFunc.OR): m.d.comb += self.alu_op_to_z.eq(AluOp.OR) with m.Case(AluFunc.AND): m.d.comb += self.alu_op_to_z.eq(AluOp.AND) self.next_instr(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 setup(self, m: Module): with m.Switch(self.reset_state): with m.Case(0): m.d.ph1 += self.core.Addr.eq(0xFFFE) m.d.ph1 += self.core.RW.eq(1) m.d.ph1 += self.reset_state.eq(1) with m.Case(1): m.d.ph1 += self.core.Addr.eq(0xFFFF) m.d.ph1 += self.core.RW.eq(1) m.d.ph1 += self.core.registers.tmp8.eq(self.core.Din) m.d.ph1 += self.reset_state.eq(2) with m.Case(2): m.d.ph1 += self.reset_state.eq(3) reset_vec = Cat(self.core.Din, self.core.registers.tmp8) m.d.ph1 += self.core.registers.ccr.eq((1 << Ccr.RUN) | (1 << Ccr.RUN_2)) self.core.next(m, reset_vec)
def reset_handler(self, m: Module): """Generates logic for reading the reset vector at 0xFFFE and jumping there.""" with m.Switch(self.reset_state): with m.Case(0): m.d.ph1 += self.Addr.eq(0xFFFE) m.d.ph1 += self.RW.eq(1) m.d.ph1 += self.reset_state.eq(1) with m.Case(1): m.d.ph1 += self.Addr.eq(0xFFFF) m.d.ph1 += self.RW.eq(1) m.d.ph1 += self.tmp8.eq(self.Din) m.d.ph1 += self.reset_state.eq(2) with m.Case(2): m.d.ph1 += self.reset_state.eq(3) reset_vec = Cat(self.Din, self.tmp8) self.end_instr(m, reset_vec)
def elaborate(self, platform): m = Module() interface = self.interface setup = self.interface.setup # Grab a reference to the board's LEDs. leds = Cat(platform.request("led", i) for i in range(6)) # # Vendor request handlers. # with m.If(setup.type == USBRequestType.VENDOR): with m.Switch(setup.request): # SET_LEDS request handler: handler that sets the board's LEDS # to a user provided value with m.Case(self.REQUEST_SET_LEDS): # If we have an active data byte, splat it onto the LEDs. # # For simplicity of this example, we'll accept any byte in # the packet; and not just the first one; each byte will # cause an update. This is fun; we can PWM the LEDs with # USB packets. :) with m.If(interface.rx.valid & interface.rx.next): m.d.usb += leds.eq(interface.rx.payload) # Once the receive is complete, respond with an ACK. with m.If(interface.rx_ready_for_response): m.d.comb += interface.handshakes_out.ack.eq(1) # If we reach the status stage, send a ZLP. with m.If(interface.status_requested): m.d.comb += self.send_zlp() with m.Case(): # # Stall unhandled requests. # with m.If(interface.status_requested | interface.data_requested): m.d.comb += interface.handshakes_out.stall.eq(1) 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() # Collection that will store each of our descriptor-generation submodules. descriptor_generators = {} # # 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 # ... 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), generator.start.eq(self.start), generator.max_length.eq(self.length) ] # 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