def check(self, m: Module): mode = self.instr[4:6] self.assert_flags(m) with m.If(mode == ModeBits.EXTENDED.value): self.assert_cycles(m, 3) addr_hi = self.assert_cycle_signals(m, 1, address=self.data.pre_pc + 1, vma=1, rw=1, ba=0) addr_lo = self.assert_cycle_signals(m, 2, address=self.data.pre_pc + 2, vma=1, rw=1, ba=0) self.assert_registers(m, PC=LCat(addr_hi, addr_lo)) with m.If(mode == ModeBits.INDEXED.value): self.assert_cycles(m, 4) offset = self.assert_cycle_signals(m, 1, address=self.data.pre_pc + 1, vma=1, rw=1, ba=0) self.assert_cycle_signals(m, 2, vma=0, ba=0) self.assert_cycle_signals(m, 3, vma=0, ba=0) self.assert_registers(m, PC=self.data.pre_x + offset)
def elaborate(self, platform): m = Module() with m.If(self.pending.w_stb): m.d.sync += self.pending.r_data.eq(self.pending.r_data & ~self.pending.w_data) with m.If(self.enable.w_stb): m.d.sync += self.enable.r_data.eq(self.enable.w_data) for i, event in enumerate(self._events): m.d.sync += self.status.r_data[i].eq(event.stb) if event.mode in ("rise", "fall"): event_stb_r = Signal.like(event.stb, name_suffix="_r") m.d.sync += event_stb_r.eq(event.stb) event_trigger = Signal(name="{}_trigger".format(event.name)) if event.mode == "level": m.d.comb += event_trigger.eq(event.stb) elif event.mode == "rise": m.d.comb += event_trigger.eq(~event_stb_r & event.stb) elif event.mode == "fall": m.d.comb += event_trigger.eq(event_stb_r & ~event.stb) else: assert False # :nocov: with m.If(event_trigger): m.d.sync += self.pending.r_data[i].eq(1) m.d.comb += self.irq.eq( (self.pending.r_data & self.enable.r_data).any()) return m
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = self.serdes # The symbol table reads the corresponding symbols for each # symbol in PACKET and outputs them on tx_data m.submodules.symboltable = symboltable = SymbolTable( table=pack_mem(TABLE, width=20), packet=Memory(width=16, depth=len(PACKET), init=[int(i) for i in np.array(PACKET) * 5000 / 20]), samples_per_symbol=int(5e9 / 1e6), tx_domain="tx") m.d.comb += [ symboltable.packet_length.eq(len(PACKET)), serdes.tx_data.eq(symboltable.tx_data) ] # Quick state machine to transmit and then wait a bit before # transmitting again counter = Signal(32) with m.FSM(): with m.State("START"): m.d.sync += symboltable.tx_reset.eq(1) m.next = "WAIT_DONE" with m.State("WAIT_DONE"): m.d.sync += symboltable.tx_reset.eq(0) with m.If(symboltable.tx_done): m.d.sync += counter.eq(0) m.next = "PAUSE" with m.State("PAUSE"): m.d.sync += counter.eq(counter + 1) with m.If(counter >= int(1e4)): m.next = "START" return m
def handle_jalr(self, m: Module): """Adds the JALR logic to the given module. rd <- PC + 4, PC <- (rs1 + imm) & 0xFFFFFFFE rs1 -> X imm -> Y ALU ADD -> Z Z -> memaddr --------------------- PC + 4 -> Z Z -> rd memaddr -> PC # This will zero the least significant bit """ 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.Else(): with m.If(self.memaddr_2_lsb[1] != 0): self.set_exception(m, ConstSelect.EXC_INSTR_ADDR_MISALIGN, mtval=SeqMuxSelect.MEMADDR_LSB_MASKED) with m.Else(): m.d.comb += [ self.z_mux_select.eq(SeqMuxSelect.PC_PLUS_4), self._z_reg_select.eq(InstrReg.RD), ] self.next_instr(m, NextPC.MEMADDR_NO_LSB)
def synth(core, m: Module): with m.If(core.cycle == 1): 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(2), ] with m.If(core.cycle == 2): m.d.comb += core.alu.oper.eq(Operation.NOP) m.d.sync += [ core.tmp.eq(core.dout), 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(3), ] with m.If(core.cycle == 3): m.d.comb += core.alu.oper.eq(Operation.NOP) m.d.sync += [ core.reg.PC.eq(Cat(core.tmp, core.dout)), core.enable.eq(1), core.addr.eq(Cat(core.tmp, core.dout)), core.RWB.eq(1), core.cycle.eq(1), ]
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the NextDay module.""" m = Module() m.submodules.nd = nd = cls() # We don't have to create a signal here. Using is_zero is like just copying the logic. is_zero = ((nd.next_year == 0) & (nd.next_month == 0) & (nd.next_day == 0)) m.d.comb += Assert(nd.invalid == is_zero) all_nonzero = ((nd.next_year != 0) & (nd.next_month != 0) & (nd.next_day != 0)) m.d.comb += Assert(all_nonzero | is_zero) with m.If(~nd.invalid): with m.If(nd.day == 31): m.d.comb += Assert(nd.next_day == 1) with m.If((nd.month == 12) & (nd.day == 31)): m.d.comb += Assert(nd.next_month == 1) with m.If(((nd.year % 2) == 1) & (nd.month == 2) & (nd.day == 29)): m.d.comb += Assert(nd.invalid) m.d.comb += Cover((nd.next_month == 2) & (nd.next_day == 29)) return m, [nd.year, nd.month, nd.day]
def mode_indexed(self, m: Module) -> Statement: """Generates logic to get the 16-bit address for indexed mode instructions. Returns a Statement containing a 16-bit address. After cycle 2, tmp16 contains the address. The address is not valid until after cycle 2. """ operand = self.tmp16 with m.If(self.cycle == 1): # Output during cycle 2: m.d.ph1 += self.tmp16[8:].eq(0) m.d.ph1 += self.tmp16[:8].eq(self.Din) m.d.ph1 += self.pc.eq(self.pc + 1) m.d.ph1 += self.Addr.eq(self.pc + 1) m.d.ph1 += self.RW.eq(1) m.d.ph1 += self.VMA.eq(0) if self.verification is not None: self.formalData.read(m, self.Addr, self.Din) with m.If(self.cycle == 2): # Output during cycle 3: m.d.ph1 += self.tmp16.eq(self.tmp16 + self.x) m.d.ph1 += self.VMA.eq(0) return operand
def check(self, m: Module): input1, input2, actual_output, size, use_a = self.common_check(m) carry_in = Signal() sum9 = Signal(9) sum8 = Signal(8) with_carry = self.instr[1] == 1 n = sum9[7] c = ~sum9[8] z = sum9[:8] == 0 v = sum8[7] ^ sum9[8] with m.If(with_carry): m.d.comb += carry_in.eq(self.data.pre_ccs[Flags.C]) with m.Else(): m.d.comb += carry_in.eq(0) m.d.comb += [ sum9.eq(input1 + ~input2 + ~carry_in), sum8.eq(input1[:7] + ~input2[:7] + ~carry_in), ] with m.If(use_a): self.assert_registers(m, A=sum9, PC=self.data.pre_pc + size) with m.Else(): self.assert_registers(m, B=sum9, PC=self.data.pre_pc + size) self.assert_flags(m, Z=z, N=n, V=v, C=c)
def elaborate(self, platform): m = Module() shifter = Signal(self._width) pos = Signal(self._width, reset=0b1) with m.If(self.i_enable): empty = Signal() m.d.usb += [ pos.eq(pos >> 1), shifter.eq(shifter >> 1), self.o_get.eq(empty), ] with m.If(empty): m.d.usb += [ shifter.eq(self.i_data), pos.eq(1 << (self._width - 1)), ] with m.If(self.i_clear): m.d.usb += [shifter.eq(0), pos.eq(1)] m.d.comb += [ empty.eq(pos[0]), self.o_empty.eq(empty), self.o_data.eq(shifter[0]), ] return 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_7416374(clk="ph") m.submodules += s with m.If(s.n_oe): m.d.comb += Assert(s.q == 0) with m.If(~s.n_oe & Rose(clk)): m.d.comb += Assert(s.q == Past(s.d)) with m.If(~s.n_oe & Fell(clk) & ~Past(s.n_oe)): m.d.comb += Assert(s.q == Past(s.q)) sync_clk = ClockSignal("sync") sync_rst = ResetSignal("sync") # 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")) return m, [sync_clk, sync_rst, s.n_oe, s.q, s.d]
def elaborate(self, platform): m = Module() with m.If(self.i_hlclk): m.d.sync += [ self.r_hline.eq(self.r_hline + 1), self.r_hline_count.eq(self.r_hline_count + 1), ] with m.FSM() as fsm: with m.State("SYNC"): with m.If(self.r_hline_count == self.syncv_vs): m.d.sync += self.r_hline_count.eq(1) m.next = "BACK-PORCH" with m.State("BACK-PORCH"): with m.If(self.r_hline_count == (self.syncv_vbp + self.syncv_vbpe)): m.d.sync += self.r_hline_count.eq(1) m.next = "DISPLAY" with m.State("DISPLAY"): with m.If(self.r_hline_count == self.syncv_vdp): m.d.sync += self.r_hline.eq(1) m.d.sync += self.r_hline_count.eq(1) m.next = "FRONT-PORCH" with m.State("FRONT-PORCH"): with m.If(self.r_hline_count == (self.syncv_vfp + self.syncv_vfpe)): m.d.sync += self.r_hline_count.eq(1) m.d.sync += self.o_odd.eq(~self.o_odd) m.next = "SYNC" return m
def elaborate(self, _: Platform) -> Module: """Implements the logic for the conditional right-shifter.""" m = Module() N = self._N with m.If(self.en): # The high N bits get either 0 or the most significant # bit in data_in, depending on arithmetic. msb = self.data_in[-1] w = len(self.data_out) # m.d.comb += self.data_out.bit_select(w-N, N).eq( # Mux(self.arithmetic, Repl(msb, N), 0)) with m.If(self.arithmetic): m.d.comb += self.data_out[w - N:].eq(Repl(msb, N)) with m.Else(): m.d.comb += self.data_out[w - N:].eq(0) # The rest are moved over. # m.d.comb += self.data_out.bit_select(0, w-N).eq( # self.data_in.bit_select(N, w-N)) m.d.comb += self.data_out[:w - N].eq(self.data_in[N:]) with m.Else(): m.d.comb += self.data_out.eq(self.data_in) return m
def elaborate(self, platform): m = Module() # This state machine recognizes sequences of 6 bits and drops the 7th # bit. The fsm implements a counter in a series of several states. # This is intentional to help absolutely minimize the levels of logic # used. drop_bit = Signal(1) with m.FSM(domain="usb_io"): for i in range(6): with m.State(f"D{i}"): with m.If(self.i_valid): with m.If(self.i_data): # Receiving '1' increments the bitstuff counter. m.next = (f"D{i + 1}") with m.Else(): # Receiving '0' resets the bitstuff counter. m.next = "D0" with m.State("D6"): with m.If(self.i_valid): m.d.comb += drop_bit.eq(1) # Reset the bitstuff counter, drop the data. m.next = "D0" m.d.usb_io += [ self.o_data.eq(self.i_data), self.o_stall.eq(drop_bit | ~self.i_valid), self.o_error.eq(drop_bit & self.i_data & self.i_valid), ] return m
def elaborate(self, platform: Platform) -> Module: m = Module() m.submodules.alu = alu = ALU8() # defaults m.d.comb += self.end_instr_flag.eq(0) m.d.comb += self.src8_1_select.eq(Reg8.NONE) m.d.comb += self.src8_2_select.eq(Reg8.NONE) m.d.comb += self.alu8_func.eq(ALU8Func.NONE) m.d.ph1 += self.VMA.eq(1) self.src_bus_setup(m, self.reg8_map, self.src8_1, self.src8_1_select) self.src_bus_setup(m, self.reg8_map, self.src8_2, self.src8_2_select) m.d.comb += alu.input1.eq(self.src8_1) m.d.comb += alu.input2.eq(self.src8_2) m.d.comb += self.alu8.eq(alu.output) m.d.comb += alu.func.eq(self.alu8_func) m.d.comb += self.ccs.eq(alu.ccs) self.reset_handler(m) with m.If(self.reset_state == 3): with m.If(self.cycle == 0): self.fetch(m) with m.Else(): self.execute(m) self.maybe_do_formal_verification(m) self.end_instr_flag_handler(m) return m
def mode_ext(self, m: Module) -> Statement: """Generates logic to get the 16-bit operand for extended mode instructions. Returns a Statement containing the 16-bit operand. After cycle 2, tmp16 contains the operand. """ operand = Mux(self.cycle == 2, Cat(self.Din, self.tmp16[8:]), self.tmp16) with m.If(self.cycle == 1): m.d.ph1 += self.tmp16[8:].eq(self.Din) m.d.ph1 += self.pc.eq(self.pc + 1) m.d.ph1 += self.Addr.eq(self.pc + 1) m.d.ph1 += self.RW.eq(1) m.d.ph1 += self.cycle.eq(2) if self.verification is not None: self.formalData.read(m, self.Addr, self.Din) with m.If(self.cycle == 2): m.d.ph1 += self.tmp16[:8].eq(self.Din) m.d.ph1 += self.pc.eq(self.pc + 1) m.d.ph1 += self.cycle.eq(3) if self.verification is not None: self.formalData.read(m, self.Addr, self.Din) return operand
def handle_branch(self, m: Module): """Adds the BRANCH logic to the given module. cond <- rs1 - rs2 < 0, rs1 - rs2 == 0 if f(cond): PC <- PC + imm else: PC <- PC + 4 rs1 -> X rs2 -> Y ALU SUB -> Z, cond --------------------- cond == 1 PC -> X imm/4 -> Y (imm for cond == 1, 4 otherwise) ALU ADD -> Z Z -> PC Z -> memaddr --------------------- cond == 0 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.reg_to_y.eq(1), self._y_reg_select.eq(InstrReg.RS2), self.alu_op_to_z.eq(AluOp.SUB), self._next_instr_phase.eq(1), ] with m.Elif(self._instr_phase == 1): with m.If(~self._funct3.matches(BranchCond.EQ, BranchCond.NE, BranchCond.LT, BranchCond.GE, BranchCond.LTU, BranchCond.GEU)): self.handle_illegal_instr(m) with m.Else(): with m.If(self.branch_cond): m.d.comb += self.y_mux_select.eq(SeqMuxSelect.IMM) with m.Else(): m.d.comb += self._const.eq(ConstSelect.SHAMT_4) m.d.comb += self.y_mux_select.eq(SeqMuxSelect.CONST) m.d.comb += [ self.x_mux_select.eq(SeqMuxSelect.PC), self.alu_op_to_z.eq(AluOp.ADD), ] with m.If(self.data_z_in_2_lsb0): self.next_instr(m, NextPC.Z) with m.Else(): m.d.comb += self._next_instr_phase.eq(2) m.d.comb += self.tmp_mux_select.eq(SeqMuxSelect.Z) with m.Else(): self.set_exception(m, ConstSelect.EXC_INSTR_ADDR_MISALIGN, mtval=SeqMuxSelect.TMP)
def elaborate(self, platform): m = Module() rx_port = self.user_rx_mem.read_port() tx_port = self.user_tx_mem.write_port() m.submodules += [self.mem_r_port, self.mem_w_port, rx_port, tx_port] led1 = platform.request("user_led", 0) led2 = platform.request("user_led", 1) m.d.comb += [ tx_port.addr.eq(0), tx_port.en.eq(0), tx_port.data.eq(0), rx_port.addr.eq(0), ] m.d.sync += [ led1.eq(rx_port.data & 1), led2.eq((rx_port.data & 2) >> 1), ] with m.FSM(): with m.State("IDLE"): m.d.sync += self.transmit_packet.eq(0) with m.If(self.packet_received): m.next = "RX" with m.State("RX"): with m.If(self.transmit_ready): m.d.sync += self.transmit_packet.eq(1) m.next = "IDLE" return m
def check(self, m: Module, instr: Value, data: FormalData): mode = instr[4:6] m.d.comb += [ Assert(data.post_ccs == data.pre_ccs), 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), ] with m.If(mode == ModeBits.EXTENDED.value): m.d.comb += [ Assert(data.addresses_read == 2), Assert(data.read_addr[0] == data.plus16(data.pre_pc, 1)), Assert(data.read_addr[1] == data.plus16(data.pre_pc, 2)), Assert( data.post_pc == Cat(data.read_data[1], data.read_data[0])), ] with m.If(mode == ModeBits.INDEXED.value): m.d.comb += [ Assert(data.addresses_read == 1), Assert(data.read_addr[0] == data.plus16(data.pre_pc, 1)), Assert( data.post_pc == (data.pre_x + data.read_data[0])[:16]), ]
def elaborate(self, platform): m = Module() mac = [Signal(8) for _ in range(6)] m.d.sync += self.mac_match.eq( reduce(operator.and_, [(mac[idx] == self.mac_addr[idx]) | (mac[idx] == 0xFF) for idx in range(6)])) with m.FSM(): with m.State("RESET"): m.d.sync += [mac[idx].eq(0) for idx in range(6)] with m.If(~self.reset): m.next = "BYTE0" for idx in range(6): next_state = f"BYTE{idx+1}" if idx < 5 else "DONE" with m.State(f"BYTE{idx}"): m.d.sync += mac[idx].eq(self.data) with m.If(self.reset): m.next = "RESET" with m.Elif(self.data_valid): m.next = next_state with m.State("DONE"): with m.If(self.reset): m.next = "RESET" return m
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 elaborate(self, platform): m = Module() crc = Signal(32) self.crctable = Memory(32, 256, make_crc32_table()) table_port = self.crctable.read_port() m.submodules += table_port m.d.comb += [ self.crc_out.eq(crc ^ 0xFFFFFFFF), self.crc_match.eq(crc == 0xDEBB20E3), table_port.addr.eq(crc ^ self.data), ] with m.FSM(): with m.State("RESET"): m.d.sync += crc.eq(0xFFFFFFFF) m.next = "IDLE" with m.State("IDLE"): with m.If(self.reset): m.next = "RESET" with m.Elif(self.data_valid): m.next = "BUSY" with m.State("BUSY"): with m.If(self.reset): m.next = "RESET" m.d.sync += crc.eq(table_port.data ^ (crc >> 8)) m.next = "IDLE" return m
def handle_CSRRWI(self, m: Module): m.d.comb += self._funct12_to_csr_num.eq(1) with m.If(self._instr_phase == 0): with m.If(self.rd0): m.d.comb += [ self._x_reg_select.eq(InstrReg.ZERO), self.reg_to_x.eq(1), ] with m.Else(): m.d.comb += [self.csr_to_x.eq(1)] m.d.comb += [ self.y_mux_select.eq(SeqMuxSelect.IMM), self.alu_op_to_z.eq(AluOp.Y), self.z_to_csr.eq(1), self.tmp_mux_select.eq(SeqMuxSelect.X), self._next_instr_phase.eq(1), ] with m.Else(): m.d.comb += [ self.z_mux_select.eq(SeqMuxSelect.TMP), self._z_reg_select.eq(InstrReg.RD), ] self.next_instr(m)
def elaborate(self, platform): m = Module() interface = self.interface # Create convenience aliases for our interface components. setup = interface.setup handshake = interface.handshake 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. # TODO: limit this to standard requests with m.If(setup.received): # Select which standard packet we're going to handler. m.next = 'UNHANDLED' # 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.stall.eq(1) m.next = 'IDLE' return m
def read(self, m: Module, addr: Value, data: Value): if self.verification is None: return with m.If(self.snapshot_taken): with m.If(self.addresses_read != 7): m.d.ph1 += self.addresses_read.eq(self.addresses_read + 1) m.d.ph1 += self.read_addr[self.addresses_read].eq(addr) m.d.ph1 += self.read_data[self.addresses_read].eq(data)
def elaborate(self, platform: Platform) -> Module: m = Module() # Signal defaults m.d.comb += self.ft.oe.o.eq(0) m.d.comb += self.ft.write.o.eq(0) m.d.comb += self.ft.read.o.eq(0) with m.FSM(): with m.State("READY"): # If there is data to read, we read it first before entering the write state with m.If(self.ft.rxf.i): m.d.comb += self.ft.oe.o.eq(1) m.d.comb += self.ft.data.oe.eq(0) m.d.comb += self.ft.be.oe.eq(0) m.next = "READ" with m.Elif(self.ft.txe.i & self.input_valid): m.d.comb += self.ft.data.oe.eq(1) m.d.comb += self.ft.be.oe.eq(1) m.next = "WRITE" with m.State("READ"): m.d.comb += self.ft.oe.o.eq(1) # Set pins in correct direction (input) m.d.comb += self.ft.data.oe.eq(0) m.d.comb += self.ft.be.oe.eq(0) # Connect FIFO m.d.comb += self.output_payload.eq(self.ft.data.i) m.d.comb += self.output_valid.eq(self.ft.rxf.i) m.d.comb += self.ft.read.o.eq(self.output_ready) with m.If(~self.ft.rxf.i): m.next = "READY" with m.State("WRITE"): # Set pins in correct direction (output) m.d.comb += self.ft.data.oe.eq(1) m.d.comb += self.ft.be.oe.eq(1) # All bytes are valid m.d.comb += self.ft.oe.o.eq(0) m.d.comb += self.ft.be.o.eq(0b11) # Connect FIFO m.d.comb += self.ft.data.o.eq(self.input_payload) m.d.comb += self.input_ready.eq(self.ft.txe.i) m.d.comb += self.ft.write.o.eq(self.input_valid) # TODO: Should we go to ready if there is data to read, or wait until write is done? with m.If(~self.ft.txe.i | ~self.input_valid): m.next = "READY" 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") ext1 = platform.request("ext1") pa_en_n_o = platform.request("pa_en_n_o") # clock domains m.domains += ClockDomain("clk60") m.d.comb += ClockSignal("clk60").eq(ft_clkout_i.i) # signals ctr = Signal(8, reset=0) ctr_last = Signal(8, reset=0) ft_txe_last = Signal(1, reset=0) # submodules m.submodules.fifo = fifo = AsyncFIFO(width=8, depth=1024, r_domain="clk60", w_domain="sync") # logic m.d.comb += [ ft_oe_n_o.o.eq(1), ft_rd_n_o.o.eq(1), ft_siwua_n_o.o.eq(1), ft_data_io.oe.eq(1), pa_en_n_o.o.eq(1), ] m.d.comb += [ ft_data_io.o.eq(fifo.r_data), fifo.w_data.eq(ctr), ] with m.If(fifo.w_rdy): m.d.comb += fifo.w_en.eq(1) m.d.sync += ctr.eq(ctr + 1) with m.Else(): m.d.comb += fifo.w_en.eq(0) with m.If(~ft_txe_n_i & ft_suspend_n_i & fifo.r_rdy): m.d.comb += ft_wr_n_o.o.eq(0) m.d.clk60 += fifo.r_en.eq(1) with m.Else(): m.d.comb += ft_wr_n_o.o.eq(1) m.d.clk60 += fifo.r_en.eq(0) return m
def write(self, m: Module, addr: Value, data: Value): if self.verification is None: return with m.If(self.snapshot_taken): with m.If(self.addresses_written != 7): m.d.ph1 += self.addresses_written.eq(self.addresses_written + 1) m.d.ph1 += self.write_addr[self.addresses_written].eq(addr) m.d.ph1 += self.write_data[self.addresses_written].eq(data)
def formal_ripple(cls) -> Tuple[Module, List[Signal]]: """Formal verification for a bunch of ALUs in ripple-carry mode.""" m = Module() alus = [None] * 8 m.submodules.alu0 = alus[0] = IC_74181() m.submodules.alu1 = alus[1] = IC_74181() m.submodules.alu2 = alus[2] = IC_74181() m.submodules.alu3 = alus[3] = IC_74181() m.submodules.alu4 = alus[4] = IC_74181() m.submodules.alu5 = alus[5] = IC_74181() m.submodules.alu6 = alus[6] = IC_74181() m.submodules.alu7 = alus[7] = IC_74181() a = Signal(32) b = Signal(32) f = Signal(32) cin = Signal() cout = Signal() s = Signal(4) mt = Signal() for x in range(8): m.d.comb += alus[x].a.eq(a[x * 4:x * 4 + 4]) m.d.comb += alus[x].b.eq(b[x * 4:x * 4 + 4]) m.d.comb += f[x * 4:x * 4 + 4].eq(alus[x].f) m.d.comb += alus[x].m.eq(mt) m.d.comb += alus[x].s.eq(s) for x in range(7): m.d.comb += alus[x + 1].n_carryin.eq(alus[x].n_carryout) m.d.comb += alus[0].n_carryin.eq(~cin) m.d.comb += cout.eq(~alus[7].n_carryout) add_mode = (s == 9) & (mt == 0) sub_mode = (s == 6) & (mt == 0) m.d.comb += Assume(add_mode | sub_mode) y = Signal(33) with m.If(add_mode): m.d.comb += y.eq(a + b + cin) m.d.comb += Assert(f == y[:32]) m.d.comb += Assert(cout == y[32]) with m.Elif(sub_mode): m.d.comb += y.eq(a - b - ~cin) m.d.comb += Assert(f == y[:32]) m.d.comb += Assert(cout == ~y[32]) # Check how equality, unsigned gt, and unsigned gte comparisons work. with m.If(cin == 0): all_eq = Cat(*[i.a_eq_b for i in alus]).all() m.d.comb += Assert(all_eq == (a == b)) m.d.comb += Assert(cout == (a > b)) with m.Else(): m.d.comb += Assert(cout == (a >= b)) return m, [a, b, f, cin, cout, s, mt, y]
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the active low 74182 chip.""" m = Module() m.submodules.clu = clu = IC_74182_active_low() # Verify the truth tables in the datasheet with m.If(clu.np.matches("0000")): m.d.comb += Assert(clu.group_np == 0) with m.Else(): m.d.comb += Assert(clu.group_np == 1) with m.If(clu.ng.matches("0---") & clu.np.matches("----")): m.d.comb += Assert(clu.group_ng == 0) with m.Elif(clu.ng.matches("-0--") & clu.np.matches("0---")): m.d.comb += Assert(clu.group_ng == 0) with m.Elif(clu.ng.matches("--0-") & clu.np.matches("00--")): m.d.comb += Assert(clu.group_ng == 0) with m.Elif(clu.ng.matches("---0") & clu.np.matches("000-")): m.d.comb += Assert(clu.group_ng == 0) with m.Else(): m.d.comb += Assert(clu.group_ng == 1) with m.If(clu.ng[0] == 0): m.d.comb += Assert(clu.carryout_x == 1) with m.Elif((clu.np[0] == 0) & (clu.carryin == 1)): m.d.comb += Assert(clu.carryout_x == 1) with m.Else(): m.d.comb += Assert(clu.carryout_x == 0) with m.If(clu.ng.matches("--0-") & clu.np.matches("----")): m.d.comb += Assert(clu.carryout_y == 1) with m.Elif(clu.ng.matches("---0") & clu.np.matches("--0-")): m.d.comb += Assert(clu.carryout_y == 1) with m.Elif( clu.ng.matches("----") & clu.np.matches("--00") & (clu.carryin == 1)): m.d.comb += Assert(clu.carryout_y == 1) with m.Else(): m.d.comb += Assert(clu.carryout_y == 0) with m.If(clu.ng.matches("-0--") & clu.np.matches("----")): m.d.comb += Assert(clu.carryout_z == 1) with m.Elif(clu.ng.matches("--0-") & clu.np.matches("-0--")): m.d.comb += Assert(clu.carryout_z == 1) with m.Elif(clu.ng.matches("---0") & clu.np.matches("-00-")): m.d.comb += Assert(clu.carryout_z == 1) with m.Elif( clu.ng.matches("----") & clu.np.matches("-000") & (clu.carryin == 1)): m.d.comb += Assert(clu.carryout_z == 1) with m.Else(): m.d.comb += Assert(clu.carryout_z == 0) return m, clu.ports()
def elaborate(self, platform): m = Module() # Register input data on the data_valid signal data_reg = Signal(8) with m.FSM() as fsm: m.d.comb += [ self.ready.eq(fsm.ongoing("IDLE") | fsm.ongoing("NIBBLE4")), self.txen.eq(~fsm.ongoing("IDLE")), ] with m.State("IDLE"): m.d.comb += [ self.txd0.eq(0), self.txd1.eq(0), ] m.d.sync += data_reg.eq(self.data) with m.If(self.data_valid): m.next = "NIBBLE1" with m.State("NIBBLE1"): m.d.comb += [ self.txd0.eq(data_reg[0]), self.txd1.eq(data_reg[1]), ] m.next = "NIBBLE2" with m.State("NIBBLE2"): m.d.comb += [ self.txd0.eq(data_reg[2]), self.txd1.eq(data_reg[3]), ] m.next = "NIBBLE3" with m.State("NIBBLE3"): m.d.comb += [ self.txd0.eq(data_reg[4]), self.txd1.eq(data_reg[5]), ] m.next = "NIBBLE4" with m.State("NIBBLE4"): m.d.comb += [ self.txd0.eq(data_reg[6]), self.txd1.eq(data_reg[7]), ] m.d.sync += data_reg.eq(self.data) with m.If(self.data_valid): m.next = "NIBBLE1" with m.Else(): m.next = "IDLE" return m