def check(m: Module, data: Snapshot, alu: Signal): m.d.comb += [ Assert(data.read_data[0].matches(MUL.opcode)), ] for i in range(1, 10): m.d.comb += [ Assert(Past(alu.oper, i) == Operation.MUL), ] for i in range(3, 10): m.d.comb += [ Assert(Past(alu.inputa, i) == data.pre.Y), Assert(Past(alu.inputb, i) == data.pre.A), ] m.d.comb += [ Assert(data.post.A == Past(alu.result, 1)), Assert(data.post.X == data.pre.X), Assert(data.post.Y == Past(alu.result, 2)), Assert(data.post.SP == data.pre.SP), Assert(data.post.PC == add16(data.pre.PC, 1)), ] m.d.comb += [ Assert(data.addresses_read == 1), Assert(data.addresses_written == 0), Assert(data.read_addr[0] == add16(data.pre.PC, 0)), ]
def check(m: Module, data: Snapshot, alu: Signal): m.d.comb += [ Assert(data.read_data[0].matches(JMP.opcode)), ] m.d.comb += [ Assert(Past(alu.oper, 3) == Operation.NOP), Assert(Past(alu.oper, 2) == Operation.NOP), Assert(Past(alu.oper, 1) == Operation.NOP), ] m.d.comb += [ Assert(data.post.A == data.pre.A), Assert(data.post.X == data.pre.X), Assert(data.post.Y == data.pre.Y), Assert(data.post.SP == data.pre.SP), Assert(data.post.PC[:8] == data.read_data[1]), Assert(data.post.PC[8:] == data.read_data[2]), Assert(data.post.PSW == data.pre.PSW), ] m.d.comb += [ Assert(data.addresses_read == 3), Assert(data.addresses_written == 0), Assert(data.read_addr[0] == add16(data.pre.PC, 0)), Assert(data.read_addr[1] == add16(data.pre.PC, 1)), Assert(data.read_addr[2] == add16(data.pre.PC, 2)), ]
def __main(): m = top = Module() clock = ClockInfo("i") m.domains.i = clock.domain top.submodules.regs = regs = RegisterFileModule(32) regs.aux_ports.append(clock.clk) regs.aux_ports.append(clock.rst) comb = m.d.comb with m.If(regs.rs1_in == 0): comb += Assert(regs.rs1_out == 0) with m.If(regs.rs2_in == 0): comb += Assert(regs.rs2_out == 0) with m.If(regs.rs2_in == regs.rs1_in): comb += Assert(regs.rs2_out == regs.rs2_out) with m.If((Past(regs.rd) == regs.rs1_in) & (~Past(clock.rst) & (~clock.rst))): with m.If(regs.rs1_in != 0): comb += Assert(regs.rs1_out == Past(regs.rd_value)) nmigen_main(top, ports=regs.ports())
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 past(self, signal): return [ signal, Past(signal), Past(signal, 2), Past(signal, 3), Past(signal, 4), ]
def check(m: Module, data: Snapshot, alu: Signal): m.d.comb += [ Assert(data.read_data[0].matches(MOV_A_read.opcode)), ] m.d.comb += [ Assert(Past(alu.oper, 4) == Operation.NOP), Assert(Past(alu.oper, 3) == Operation.NOP), Assert(Past(alu.oper, 2) == Operation.NOP), Assert(Past(alu.oper, 1) == Operation.OOR), Assert(Past(alu.inputa) == data.read_data[3]), Assert(Past(alu.inputb) == 0), Assert(Past(alu.result) == data.read_data[3]), ] m.d.comb += [ Assert(data.post.A == Past(alu.result)), Assert(data.post.X == data.pre.X), Assert(data.post.Y == data.pre.Y), Assert(data.post.SP == data.pre.SP), Assert(data.post.PC == add16(data.pre.PC, 3)), ] m.d.comb += [ Assert(data.addresses_read == 4), Assert(data.addresses_written == 0), Assert(data.read_addr[0] == add16(data.pre.PC, 0)), Assert(data.read_addr[1] == add16(data.pre.PC, 1)), Assert(data.read_addr[2] == add16(data.pre.PC, 2)), Assert(data.read_addr[3] == Cat(data.read_data[1], data.read_data[2])), ]
def verification_statements(m): #Create Local Reference to the LDPC_Decoder LDPC_Decoder = m.submodules.LDPC_Decoder #Ensure that done and output signals are reset when start is toggled. with m.If((LDPC_Decoder.start == 0) & Past(LDPC_Decoder.start)): m.d.sync += Assert((LDPC_Decoder.done == 0)) m.d.sync += Assert((LDPC_Decoder.data_output == 0)) return
def elaborate(self, platform): m = Module() MAX_AMOUNT = Const(22) with m.If(self.i_reset): m.d.sync += self.counter.eq(0) with m.Elif(self.i_start_signal & (self.counter == 0)): m.d.sync += self.counter.eq(MAX_AMOUNT - 1) with m.Elif(self.counter != 0): m.d.sync += self.counter.eq(self.counter - 1) m.d.sync += self.o_busy.eq((~self.i_reset) & \ ((self.i_start_signal & (self.counter == 0)) | \ (self.counter > 1))) if self.fv_mode: f_past_valid = Signal(1, reset=0) m.d.sync += f_past_valid.eq(1) m.d.comb += Assert(self.counter < MAX_AMOUNT) with m.If(f_past_valid & Past(self.i_start_signal) & Past(self.o_busy)): m.d.comb += Assume(self.i_start_signal) with m.Elif(f_past_valid & Past(self.i_start_signal) & ~Past(self.o_busy)): m.d.comb += Assume(~self.i_start_signal) m.d.comb += Assert(self.o_busy == (self.counter != 0)) with m.If(f_past_valid & Past(self.counter) != 0): m.d.comb += Assert(self.counter < Past(self.counter)) return m
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the Counter module.""" m = Module() m.submodules.c = c = cls() m.d.comb += Assert((c.count >= 1) & (c.count <= 999_999_999_999)) sync_clk = ClockSignal("sync") sync_rst = ResetSignal("sync") with m.If(Rose(sync_clk) & ~Initial()): with m.If(c.count == 1): m.d.comb += Assert(Past(c.count) == 999_999_999_999) with m.Else(): m.d.comb += Assert(c.count == (Past(c.count) + 1)) # 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) return m, [sync_clk, sync_rst]
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the transparent latch. Note that you MUST have multiclock on in the sby file, because there is more than one clock in the system -- the default formal clock and the local clock inside the transparent latch. """ m = Module() m.submodules.latch = latch = TransparentLatch(32) m.d.sync += Cover((latch.data_out == 0xAAAAAAAA) & (latch.le == 0) & (Past(latch.data_out, 2) == 0xBBBBBBBB) & (Past(latch.le, 2) == 0)) with m.If(latch.n_oe == 1): m.d.comb += Assert(latch.data_out == 0) with m.If((latch.n_oe == 0) & (latch.le == 1)): m.d.comb += Assert(latch.data_out == latch.data_in) with m.If((latch.n_oe == 0) & Fell(latch.le)): m.d.sync += Assert(latch.data_out == Past(latch.data_in)) return m, [latch.data_in, latch.le, latch.n_oe]
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]
def elaborate(self, platform): m = Module() # increments every clock cycle. when the high bit changes, the timers # are decremented -> 256 cycle decrement period for them. global_counter = Signal(9) do_decrement = Signal() m.d.sync += [ global_counter.eq(global_counter + 1), do_decrement.eq(global_counter[-1] != Past(global_counter)[-1]), ] # NOT arrays, we don't index them dynamically timer_val = tuple(Signal(16) for _ in range(NUM_TIMERS)) timer_ended = tuple(Signal(1) for _ in range(NUM_TIMERS)) # decrement timers (before they potentially get written to) for ti in range(NUM_TIMERS): with m.If((timer_val[ti] > 0) & do_decrement): m.d.sync += timer_val[ti].eq(timer_val[ti] - 1) with m.If(timer_val[ti] == 1): m.d.sync += timer_ended[ti].eq(1) # let the timer values be set with m.If(self.i_we): with m.Switch(self.i_addr): for ti in range(NUM_TIMERS): with m.Case(ti): m.d.sync += [ timer_val[ti].eq(self.i_wdata), timer_ended[ti].eq(0), ] with m.Case(): pass # and let the end status be read read_status = Signal() # bus expects one cycle of read latency m.d.sync += self.o_rdata.eq(Cat(read_status, 0)) with m.If(self.i_re): with m.Switch(self.i_addr): for ti in range(NUM_TIMERS): with m.Case(ti): m.d.comb += read_status.eq(timer_ended[ti]) with m.Case(): pass return m
def verification_statements(m): #Create Local Reference to the LDPC_Encoder LDPC_Encoder = m.submodules.LDPC_Encoder #Ensure all codewords can be obtained m.d.sync += Cover((LDPC_Encoder.data_output == 0b000000)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b011001)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b110010)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b101011)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b111100)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b100101)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b001110)) m.d.sync += Cover((LDPC_Encoder.data_output == 0b010111)) #Ensure invalid codewords cannot be obtained m.d.sync += Cover((LDPC_Encoder.data_output != 0b111111)) #Ensure the correct codeword output is obtained for each input word. m.d.sync += Cover((LDPC_Encoder.data_input == 0b000) & (LDPC_Encoder.data_output == 0b000000)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b011) & (LDPC_Encoder.data_output == 0b011001)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b110) & (LDPC_Encoder.data_output == 0b110010)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b101) & (LDPC_Encoder.data_output == 0b101011)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b111) & (LDPC_Encoder.data_output == 0b111100)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b100) & (LDPC_Encoder.data_output == 0b100101)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b001) & (LDPC_Encoder.data_output == 0b001110)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b010) & (LDPC_Encoder.data_output == 0b010111)) m.d.sync += Cover((LDPC_Encoder.data_input == 0b011) & (LDPC_Encoder.data_output != 0b010111)) #Ensure that done and output signals are reset when start is toggled. with m.If((LDPC_Encoder.start == 0) & Past(LDPC_Encoder.start)): m.d.sync += Assert((LDPC_Encoder.done == 0)) m.d.sync += Assert((LDPC_Encoder.data_output == 0)) return
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for my module.""" m = Module() m.submodules.my_class = my_class = cls() sync_clk = ClockSignal("sync") sync_rst = ResetSignal("sync") # Make sure that the output is always the same as the input m.d.comb += Assert(my_class.my_input == my_class.my_output) # Cover the case where the output is 1. m.d.comb += Cover(my_class.my_output == 1) # Make sure the clock is clocking m.d.comb += Assume(sync_clk == ~Past(sync_clk)) # Include this only if you don't want to test resets m.d.comb += Assume(~sync_rst) # Ensure sync's clock and reset signals are manipulable. return m, [sync_clk, sync_rst, my_class.my_input]
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the async memory. Note that you MUST have multiclock on in the sby file, because there is more than one clock in the system -- the default formal clock and the local clock inside the memory. """ m = Module() m.submodules.mem = mem = AsyncMemory(width=32, addr_lines=5) # Assume "good practices": # * n_oe and n_wr are never simultaneously 0, and any changes # are separated by at least a cycle to allow buffers to turn off. # * memory address remains stable throughout a write cycle, and # is also stable just before a write cycle. m.d.comb += Assume(mem.n_oe | mem.n_wr) # Paren placement is very important! While Python logical operators # and, or have lower precedence than ==, the bitwise operators # &, |, ^ have *higher* precedence. It can be confusing when it looks # like you're writing a boolean expression, but you're actually writing # a bitwise expression. with m.If(Fell(mem.n_oe)): m.d.comb += Assume((mem.n_wr == 1) & (Past(mem.n_wr) == 1)) with m.If(Fell(mem.n_wr)): m.d.comb += Assume((mem.n_oe == 1) & (Past(mem.n_oe) == 1)) with m.If(Rose(mem.n_wr) | (mem.n_wr == 0)): m.d.comb += Assume(Stable(mem.addr)) m.d.comb += Cover((mem.data_out == 0xAAAAAAAA) & (Past(mem.data_out) == 0xBBBBBBBB)) # Make sure that when the output is disabled, the output is zero, and # when enabled, it's whatever we're pointing at in memory. with m.If(mem.n_oe == 1): m.d.comb += Assert(mem.data_out == 0) with m.Else(): m.d.comb += Assert(mem.data_out == mem._mem[mem.addr]) # If we just wrote data, make sure that cell that we pointed at # for writing now contains the data we wrote. with m.If(Rose(mem.n_wr)): m.d.comb += Assert(mem._mem[Past(mem.addr)] == Past(mem.data_in)) # Pick an address, any address. check_addr = AnyConst(5) # We assert that unless that address is written, its data will not # change. To know when we've written the data, we have to create # a clock domain to let us save the data when written. saved_data_clk = ClockDomain("saved_data_clk") m.domains.saved_data_clk = saved_data_clk saved_data_clk.clk = mem.n_wr saved_data = Signal(32) with m.If(mem.addr == check_addr): m.d.saved_data_clk += saved_data.eq(mem.data_in) with m.If(Initial()): m.d.comb += Assume(saved_data == mem._mem[check_addr]) m.d.comb += Assume(mem.n_wr == 1) with m.Else(): m.d.comb += Assert(saved_data == mem._mem[check_addr]) return m, [mem.addr, mem.data_in, mem.n_wr, mem.n_oe]
def validate(self): with self.is_running(): with self.is_instruction(0xC6, 2): self.assert_equals(self.registers.b, Past(self.Din)) self.assert_end_of_instruction()
def elaborate(self, platform): m = Module() # hook up the modules which do the work m.submodules.txm = txm = Transmitter(self.divisor) m.submodules.rxm = rxm = Receiver(self.divisor) m.d.comb += [ rxm.i_rx.eq(self.i_rx), self.o_tx.eq(txm.o_tx), ] # define the signals that make up the registers r1_rx_error = SetReset(m, priority="set") r1_tx_overflow = SetReset(m, priority="set") r1_rx_timeout = SetReset(m, priority="set") r1_rx_overflow = SetReset(m, priority="set") r6_tx_full = SetReset(m, priority="set") # hook up transmit "buffer". it's just one byte. tx_data = Signal(8) m.d.comb += [ txm.i_start_tx.eq(r6_tx_full.value), txm.i_data.eq(tx_data), r6_tx_full.reset.eq(txm.o_re), ] # hook up receive FIFO. it's big so the CPU can be busy and not miss # stuff m.submodules.rx_fifo = rx_fifo = self.rx_fifo m.d.comb += [ r1_rx_overflow.set.eq(~rx_fifo.w_rdy & rxm.o_we), rx_fifo.w_data.eq(rxm.o_data), rx_fifo.w_en.eq(rxm.o_we), ] # hook up the CRC engine m.submodules.crc = crc = KermitCRC() # run the receive timeout timer rt_timeout_val = Signal(16) rt_timer_reset = SetReset(m, priority="set") rt_timer_curr = Signal(16) rt_subtimer = Signal(9) # keep reset if reception is ongoing with m.If(rxm.o_active): m.d.comb += rt_timer_reset.set.eq(1) # cancel reset request once it's been done m.d.sync += rt_timer_reset.reset.eq(rt_timer_reset.value) m.d.sync += rt_subtimer.eq(rt_subtimer - 1) with m.If(rt_timer_reset.value): m.d.sync += rt_timer_curr.eq(rt_timeout_val) with m.Elif(rt_timer_curr > 0): with m.If( rt_subtimer[-1] != Past(rt_subtimer)[-1]): # rolled over? m.d.sync += rt_timer_curr.eq(rt_timer_curr - 1) # timeout about to hit zero? m.d.comb += r1_rx_timeout.set.eq(rt_timer_curr == 1) # handle the boneless bus. read_data = Signal(16) # it expects one cycle of read latency m.d.sync += self.o_rdata.eq(read_data) with m.If(self.i_re): with m.Switch(self.i_addr[:3]): # we only have 8 registers with m.Case(0): # status register m.d.comb += [ # transmitter remains active as long as there is data to # transmit read_data[15].eq(txm.o_active), read_data[0].eq(rxm.o_active), ] with m.Case(1): # error register m.d.comb += [ read_data[15].eq(r1_rx_error.value), read_data[2].eq(r1_tx_overflow.value), read_data[1].eq(r1_rx_timeout.value), read_data[0].eq(r1_rx_overflow.value), ] with m.Case(2): # CRC value register m.d.comb += read_data.eq(crc.o_crc) with m.Case(4, 5): # rx status and receive data # the FIFO will be okay if we read from it while empty, so # we just read from it regardless m.d.comb += rx_fifo.r_en.eq(1) # can be read from low or high byte with m.If(self.i_addr[0]): # high byte m.d.comb += [ read_data[7:15].eq(rx_fifo.r_data), read_data[15].eq(~rx_fifo.r_rdy), ] with m.Else(): # low byte (rotated for status bit access) m.d.comb += [ read_data[15].eq(rx_fifo.r_data[0]), read_data[:7].eq(rx_fifo.r_data[1:]), read_data[14].eq(~rx_fifo.r_rdy), ] # if there actually was a byte, fold it into the CRC with m.If(rx_fifo.r_rdy): m.d.comb += [ crc.i_byte.eq(rx_fifo.r_data), crc.i_start.eq(1), ] with m.Case(6, 7): # tx fifo status m.d.comb += read_data[0].eq(r6_tx_full.value) with m.Elif(self.i_we): with m.Switch(self.i_addr[:3]): with m.Case(1): # error register m.d.comb += [ r1_rx_error.reset.eq(self.i_wdata[15]), r1_tx_overflow.reset.eq(self.i_wdata[2]), r1_rx_timeout.reset.eq(self.i_wdata[1]), r1_rx_overflow.reset.eq(self.i_wdata[0]), ] with m.If(self.i_wdata[1]): m.d.comb += rt_timer_reset.set.eq(1) with m.Case(2): # CRC reset register m.d.comb += crc.i_reset.eq(1) with m.Case(3): # receive timeout register m.d.sync += rt_timeout_val.eq(self.i_wdata) m.d.comb += rt_timer_reset.set.eq(1) with m.Case(6, 7): # transmit data register # can be written to low or high byte value = Signal(8) m.d.comb += value.eq( Mux(self.i_addr[0], self.i_wdata[8:], self.i_wdata[:8])) # do we have space available for it? with m.If(~r6_tx_full.value): # yes, store it and set that we've used the space m.d.sync += tx_data.eq(value) m.d.comb += r6_tx_full.set.eq(1) # and fold it into the CRC m.d.comb += [crc.i_byte.eq(value), crc.i_start.eq(1)] with m.Else(): # overflowed! drop the write and raise error. m.d.comb += r1_tx_overflow.set.eq(1) return m
rst = Signal() ph1clk = ClockSignal("ph1") ph1.rst = rst test_daa = Signal() m.submodules.alu2 = alu2 = ALU8() carry_in = Signal() sum9 = Signal(9) sum8 = Signal(8) sum5 = Signal(5) m.d.ph1 += Assume(rst == 0) m.d.comb += Assert(alu._ccs[6:] == 0b11) with m.If((~test_daa) | ~Past(test_daa)): with m.Switch(alu.func): with m.Case(ALU8Func.ADD, ALU8Func.ADC): # sumN = input1[:N] + input2[:N] (so sumN[N-1] is the carry bit) with m.If(alu.func == ALU8Func.ADD): m.d.comb += carry_in.eq(0) with m.Else(): m.d.comb += carry_in.eq(alu.ccs[Flags.C]) h = sum5[4] n = sum9[7] c = sum9[8] z = sum9[:8] == 0 v = sum8[7] ^ c m.d.comb += [ sum9.eq(alu.input1 + alu.input2 + carry_in), sum8.eq(alu.input1[:7] + alu.input2[:7] + carry_in),
def elaborate(self, platform: Platform) -> Module: m = Module() m.d.sync += self.PSW.eq(self._psw) m.d.comb += self._psw.eq(self.PSW) with m.Switch(self.oper): with m.Case(Operation.NOP): if self.verification is Operation.NOP: with m.If(~Initial()): m.d.comb += [ Assert(self._psw.N == self.PSW.N), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == self.PSW.Z), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.ADC): low = Cat(self.result[:4], self._psw.H) high = Cat(self.result[4:], self._psw.C) m.d.comb += [ low.eq(self.inputa[:4] + self.inputb[:4] + self.PSW.C), high.eq(self.inputa[4:] + self.inputb[4:] + self._psw.H), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), self._psw.V.eq(self.result[7] != self._psw.C), ] if self.verification is Operation.ADC: r = Signal(8) f = Signal(9) h = Signal(5) m.d.comb += [ r.eq(self.inputa.as_signed() + self.inputb.as_signed() + self.PSW.C), f.eq(self.inputa + self.inputb + self.PSW.C), h.eq(self.inputa[:4] + self.inputb[:4] + self.PSW.C), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self.result == f[:8]), Assert(self._psw.N == f[7]), Assert(self._psw.V == (f[7] ^ f[8])), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == h[4]), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(f[:8].bool())), Assert(self._psw.C == f[8]), ] with m.Case(Operation.SBC): low = Cat(self.result[:4], self._psw.H) high = Cat(self.result[4:], self._psw.C) m.d.comb += [ low.eq(self.inputa[:4] - self.inputb[:4] - self.PSW.C), high.eq(self.inputa[4:] - self.inputb[4:] - self._psw.H), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), self._psw.V.eq(self.result[7] != self._psw.C), ] if self.verification is Operation.SBC: r = Signal(8) f = Signal(9) h = Signal(5) m.d.comb += [ r.eq(self.inputa.as_signed() - self.inputb.as_signed() - self.PSW.C), f.eq(self.inputa - self.inputb - self.PSW.C), h.eq(self.inputa[:4] - self.inputb[:4] - self.PSW.C), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self.result == f[:8]), Assert(self._psw.N == f[7]), Assert(self._psw.V == (f[7] ^ f[8])), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == h[4]), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(f[:8].bool())), Assert(self._psw.C == f[8]), ] with m.Case(Operation.CMP): full = Cat(self.result, self._psw.C) m.d.comb += [ full.eq(self.inputa.as_signed() - self.inputb.as_signed()), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), self._psw.V.eq(self.result[7] != self._psw.C), ] if self.verification is Operation.CMP: r = Signal(9) m.d.comb += r.eq(self.inputa.as_signed() - self.inputb.as_signed()) with m.If(~Initial()): m.d.comb += [ Assert(self.result == r[:8]), Assert(self._psw.N == r[7]), Assert(self._psw.V == (r[7] ^ r[8])), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r[:8].bool())), Assert(self._psw.C == r[8]), ] with m.Case(Operation.AND): m.d.comb += [ self.result.eq(self.inputa & self.inputb), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.AND: r = Signal(8) m.d.comb += r.eq(self.inputa & self.inputb) with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.OOR): m.d.comb += [ self.result.eq(self.inputa | self.inputb), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.OOR: r = Signal(8) m.d.comb += [ r.eq(self.inputa | self.inputb), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.EOR): m.d.comb += [ self.result.eq(self.inputa ^ self.inputb), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.EOR: r = Signal(8) m.d.comb += [ r.eq(self.inputa ^ self.inputb), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.INC): m.d.comb += [ self.result.eq(self.inputa + 1), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.INC: r = Signal(8) m.d.comb += [ r.eq(self.inputa + 1), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.DEC): m.d.comb += [ self.result.eq(self.inputa - 1), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.DEC: r = Signal(8) m.d.comb += [ r.eq(self.inputa - 1), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == r[7]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.ASL): m.d.comb += [ Cat(self.result, self._psw.C).eq(Cat(Const(0), self.inputa)), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.ASL: r = Signal(8) m.d.comb += [ r.eq(self.inputa * 2), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.inputa[6]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[7]), ] with m.Case(Operation.LSR): m.d.comb += [ Cat(self._psw.C, self.result).eq(Cat(self.inputa, Const(0))), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.LSR: r = Signal(8) m.d.comb += [ r.eq(self.inputa // 2), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == 0), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[0]), ] with m.Case(Operation.ROL): m.d.comb += [ Cat(self.result, self._psw.C).eq(Cat(self.PSW.C, self.inputa)), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.ROL: r = Signal(8) m.d.comb += [ r.eq(self.inputa * 2 + self.PSW.C), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.inputa[6]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[7]), ] with m.Case(Operation.ROR): m.d.comb += [ Cat(self._psw.C, self.result).eq(Cat(self.inputa, self.PSW.C)), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.ROR: r = Signal(8) m.d.comb += [ r.eq(self.inputa // 2 + Cat(Signal(7), self.PSW.C)), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.PSW.C), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r.bool())), Assert(self._psw.C == self.inputa[0]), ] with m.Case(Operation.XCN): m.d.comb += [ self.result.eq(Cat(self.inputa[4:], self.inputa[:4])), self._psw.N.eq(self.result.as_signed() < 0), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.XCN: r = Signal(8) m.d.comb += [ r.eq(self.inputa * 16 + self.inputa // 16), ] with m.If(~Initial()): m.d.comb += [ Assert(self.result == r), Assert(self._psw.N == self.inputa[3]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(self.inputa.bool())), Assert(self._psw.C == self.PSW.C), ] with m.Case(Operation.DAA): temp = Signal().like(self.inputa) with m.If(self.PSW.C | (self.inputa > 0x99)): m.d.comb += self._psw.C.eq(1) m.d.comb += temp.eq(self.inputa + 0x60) with m.Else(): m.d.comb += temp.eq(self.inputa) with m.If(self.PSW.H | (temp[:4] > 0x09)): m.d.comb += self.result.eq(temp + 0x06) m.d.comb += [ self._psw.N.eq(self.result & 0x80), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.DAA: with m.If(~Initial()): m.d.comb += [Assert(False)] with m.Case(Operation.DAS): temp = Signal().like(self.inputa) with m.If(~self.PSW.C | (self.inputa > 0x99)): m.d.comb += self._psw.C.eq(0) m.d.comb += temp.eq(self.inputa - 0x60) with m.Else(): m.d.comb += temp.eq(self.inputa) with m.If(~self.PSW.H | (temp[:4] > 0x09)): m.d.comb += self.result.eq(temp - 0x06) m.d.comb += [ self._psw.N.eq(self.result & 0x80), self._psw.Z.eq(self.result == 0), ] if self.verification is Operation.DAS: with m.If(~Initial()): m.d.comb += [Assert(False)] # could be optimized with shift to right with m.Case(Operation.MUL): with m.Switch(self.count): for i in range(0, 8): with m.Case(i): prod = self.inputa * self.inputb[i] if i == 0: prod = Cat(prod[0:7], ~prod[7], Const(1)) elif i == 7: prod = Cat(~prod[0:7], prod[7], Const(1)) else: prod = Cat(prod[0:7], ~prod[7]) m.d.sync += self.partial.eq(self.partial + (prod << i)) m.d.sync += self.count.eq(i + 1) with m.Case(8): m.d.sync += self.partial_hi.eq(self.partial_lo) m.d.sync += self.count.eq(9) m.d.comb += [ self.result.eq(self.partial_hi), self._psw.N.eq(self.partial_hi.as_signed() < 0), self._psw.Z.eq(self.partial_hi == 0), ] with m.Case(9): m.d.sync += self.partial.eq(0) m.d.sync += self.count.eq(0) m.d.comb += [ self.result.eq(self.partial_hi), ] if self.verification is Operation.MUL: r = Signal(16) m.d.comb += [ r.eq(self.inputa.as_signed() * self.inputb.as_signed()), Cover(self.count == 9), ] with m.If(self.count == 9): m.d.comb += [ Assert(Past(self.result) == r[8:16]), Assert(self.result == r[0:8]), Assert(self._psw.N == r[15]), Assert(self._psw.V == self.PSW.V), Assert(self._psw.P == self.PSW.P), Assert(self._psw.B == self.PSW.B), Assert(self._psw.H == self.PSW.H), Assert(self._psw.I == self.PSW.I), Assert(self._psw.Z == ~(r[8:16].bool())), Assert(self._psw.C == self.PSW.C), ] with m.If(~Initial() & (self.count == 0)): m.d.comb += [ Assert(self.partial == 0), Assert((Past(self.count) == 0) | (Past(self.count) == 9)), ] with m.If(~Initial() & (self.count != 0)): m.d.comb += [ Assert(self.count == Past(self.count) + 1), Assume(self.inputa == Past(self.inputa)), Assume(self.inputb == Past(self.inputb)), ] with m.Case(Operation.DIV): over = Signal(reset=0) with m.Switch(self.count): with m.Case(0): m.d.sync += self.partial_hi.eq(self.inputa) # Y m.d.sync += self.count.eq(1) with m.Case(1): m.d.sync += self.partial_lo.eq(self.inputa) # A m.d.sync += self.count.eq(2) m.d.comb += self._psw.H.eq( Mux(self.partial_hi[0:4] >= self.inputb[0:4], 1, 0)) for i in range(2, 11): with m.Case(i): tmp1_w = Cat(self.partial << 1, over) tmp1_x = Signal(17) tmp1_y = Signal(17) tmp1_z = Signal(17) tmp2 = self.inputb << 9 m.d.comb += tmp1_x.eq(tmp1_w) with m.If(tmp1_w & 0x20000): m.d.comb += tmp1_x.eq((tmp1_w & 0x1FFFF) | 1) m.d.comb += tmp1_y.eq(tmp1_x) with m.If(tmp1_x >= tmp2): m.d.comb += tmp1_y.eq(tmp1_x ^ 1) m.d.comb += tmp1_z.eq(tmp1_y) with m.If(tmp1_y & 1): m.d.comb += tmp1_z.eq((tmp1_y - tmp2) & 0x1FFFF) m.d.sync += Cat(self.partial, over).eq(tmp1_z) m.d.sync += self.count.eq(i + 1) with m.Case(11): m.d.sync += self.count.eq(12) m.d.comb += [ self.result.eq( (Cat(self.partial, over) >> 9)), # Y % ] with m.Case(12): m.d.sync += self.partial.eq(0) m.d.sync += over.eq(0) m.d.sync += self.count.eq(0) m.d.comb += [ self.result.eq(self.partial_lo), # A / self._psw.N.eq(self.partial_lo.as_signed() < 0), self._psw.V.eq(over), self._psw.Z.eq(self.partial_lo == 0), ] if self.verification is Operation.DIV: m.d.comb += [ Cover(self.count == 12), ] with m.If(self.count == 12): m.d.comb += [Assert(False)] return m
def assert_inc16(self, signal, ago): if ago == 0: self.m.d.ph1 += Assert(signal == (Past(signal) + 1)[:16]) else: self.m.d.ph1 += Assert( Past(signal, ago) == (Past(signal, ago + 1) + 1)[:16])
def is_instruction(self, instruction, max_cycle): return self.m.If((Past(self.core.cycle) == max_cycle) & (Past(self.core.registers.instr) == instruction))
if __name__ == '__main__': parser = main_parser() args = parser.parse_args() b2d = Bin2Dec(8) m = Module() m.submodules.b2d = b2d m.d.comb += Cover(b2d.o_digit_rd == 1) m.d.comb += Cover(b2d.o_conv_rd == 1) # o_digit_rd is a 1-cycle strobe with m.If((Past(b2d.o_digit_rd, 2) == 0) & (Past(b2d.o_digit_rd, 1) == 1)): m.d.comb += Assert(b2d.o_digit_rd == 0) # i_bin_stb resets all outputs with m.If(Past(b2d.i_bin_stb) == 1): m.d.comb += Assert(b2d.o_digit == 0) m.d.comb += Assert(b2d.o_digit_rd == 0) m.d.comb += Assert(b2d.o_conv_rd == 0) # o_digit is stable if o_digit_rd is low with m.If((Past(ResetSignal()) == 0) & (Past(b2d.i_bin_stb) == 0) & (b2d.o_digit_rd == 0)): m.d.comb += Assert(Stable(b2d.o_digit)) # o_digit_rd rises with o_conv_rd and falls on the next cycle with m.If(Rose(b2d.o_conv_rd, 2)): m.d.comb += Assert(Rose(b2d.o_digit_rd, 2))
def make_term(): if expect: return Past(signal, n) else: return ~Past(signal, n)
def elaborate(self, platform: str): #-------- m = Module() #add_clk_domain(m, self.bus().clk) #add_clk_from_domain(m, self.bus.clk()) #-------- #-------- # Local variables bus = self.bus() loc = Blank() loc.arr = Array([Signal(bus.shape_t()) for _ in range(bus.SIZE())]) loc.PTR_WIDTH = width_from_arg(bus.SIZE()) loc.rd = Signal(loc.PTR_WIDTH) loc.wr = Signal(loc.PTR_WIDTH) loc.RD_PLUS_1 = loc.rd + 0x1 loc.WR_PLUS_1 = loc.wr + 0x1 loc.incr_rd = Signal(loc.PTR_WIDTH) loc.incr_wr = Signal(loc.PTR_WIDTH) loc.next_empty = Signal() loc.next_full = Signal() loc.next_rd = Signal(loc.PTR_WIDTH) loc.next_wr = Signal(loc.PTR_WIDTH) loc.rst = ResetSignal("sync") #loc.curr_en_cat = Signal(2) if self.FORMAL(): loc.formal = Blank() loc.formal.last_rd_val = Signal(bus.shape_t()) loc.formal.test_wr = Signal(loc.PTR_WIDTH) #loc.formal.empty = Signal() #loc.formal.full = Signal() loc.formal.wd_cnt = Signal(bus.shape_t(), reset=0xa0) #-------- #-------- if self.FORMAL(): m.d.sync \ += [ loc.formal.last_rd_val.eq(loc.arr[loc.rd]), loc.formal.wd_cnt.eq(loc.formal.wd_cnt - 0x10) ] m.d.comb \ += [ loc.formal.test_wr.eq((loc.wr + 0x1) % bus.SIZE()), ] #-------- #-------- # Combinational logic m.d.comb \ += [ loc.incr_rd.eq(Mux(loc.RD_PLUS_1 < bus.SIZE(), (loc.rd + 0x1), 0x0)), loc.incr_wr.eq(Mux(loc.WR_PLUS_1 < bus.SIZE(), (loc.wr + 0x1), 0x0)), loc.next_empty.eq(loc.next_wr == loc.next_rd), #loc.next_full.eq((loc.next_wr + 0x1) == loc.next_rd), #loc.curr_en_cat.eq(Cat(bus.rd_en, bus.wr_en)), ] with m.If(bus.rd_en & (~bus.empty)): m.d.comb += loc.next_rd.eq(loc.incr_rd) with m.Else(): m.d.comb += loc.next_rd.eq(loc.rd) with m.If(bus.wr_en & (~bus.full)): m.d.comb \ += [ loc.next_wr.eq(loc.incr_wr), loc.next_full.eq((loc.incr_wr + 0x1) == loc.next_rd), ] with m.Else(): m.d.comb \ += [ loc.next_wr.eq(loc.wr), loc.next_full.eq(loc.incr_wr == loc.next_rd), ] #-------- #-------- # Clocked behavioral code with m.If(loc.rst): #for elem in loc.arr: # m.d.sync += elem.eq(bus.shape_t()()) m.d.sync \ += [ loc.rd.eq(0x0), loc.wr.eq(0x0), #bus.rd_data.eq(bus.shape_t()()), bus.empty.eq(0b1), bus.full.eq(0b0), ] with m.Else(): # If(~loc.rst): #-------- m.d.sync \ += [ bus.empty.eq(loc.next_empty), bus.full.eq(loc.next_full), loc.rd.eq(loc.next_rd), loc.wr.eq(loc.next_wr), ] with m.If(bus.rd_en & (~bus.empty)): m.d.sync += bus.rd_data.eq(loc.arr[loc.rd]) with m.If(bus.wr_en & (~bus.full)): m.d.sync += loc.arr[loc.wr].eq(bus.wr_data) #-------- #-------- if self.FORMAL(): with m.If(Fell(loc.rst)): m.d.sync \ += [ Assert(loc.rd == 0x0), Assert(loc.wr == 0x0), Assert(bus.empty == 0b1), Assert(bus.full == 0b0), ] with m.Else(): # If(~Fell(loc.rst)): m.d.sync \ += [ Assert(bus.empty == Past(loc.next_empty)), Assert(bus.full == Past(loc.next_full)), Assert(loc.rd == Past(loc.next_rd)), Assert(loc.wr == Past(loc.next_wr)), ] with m.If(Past(bus.rd_en)): with m.If(Past(bus.empty)): m.d.sync \ += [ #Assert(Stable(bus.empty)), Assert(Stable(loc.rd)), ] with m.Else(): # If(~Past(bus.empty)): #with m.If(~Past(bus.wr_en)): m.d.sync \ += [ Assert(bus.rd_data == loc.arr[Past(loc.rd)]) ] with m.If(Past(bus.wr_en)): with m.If(Past(bus.full)): m.d.sync \ += [ Assert(Stable(loc.wr)), ] #with m.Else(): # If(~Past(bus.full)): # m.d.sync \ # += [ # Assert(Past(bus.wr_data)) # ] with m.Switch(Cat(bus.empty, bus.full)): with m.Case(0b00): m.d.sync \ += [ Assume(loc.wr != loc.rd), Assume(loc.formal.test_wr != loc.rd), ] with m.Case(0b01): m.d.sync \ += [ Assert(loc.wr == loc.rd) ] with m.Case(0b10): m.d.sync \ += [ Assert(loc.formal.test_wr == loc.rd), ] m.d.sync \ += [ Assert(~(bus.empty & bus.full)), #Assume(~Stable(bus.wr_data)), #Assume(bus.wr_data == loc.formal.wd_cnt), ] #-------- #-------- #-------- return m
def elaborate(self, platform): m = Module() m.submodules.cpu_core = cpu_core = self.cpu_core m.submodules.bootrom_r = bootrom_r = self.bootrom.read_port( transparent=False) m.submodules.bootrom_w = bootrom_w = self.bootrom.write_port() m.submodules.reset_req = reset_req = self.reset_req m.submodules.uart = uart = self.uart m.submodules.timer = timer = self.timer m.submodules.snes = snes = self.snes # hook up main bus. the main RAM gets the first half and the boot ROM # gets the second (though nominally, it's from 0xFF00 to 0xFFFF) mainram_en = Signal() bootrom_en = Signal() # the code area of the boot ROM can't be written to to avoid destroying # it by accident. if it got destroyed, then the bootloader wouldn't work # after reset; a full reconfiguration would be required. bootrom_writable = Signal() m.d.comb += [ mainram_en.eq(cpu_core.o_bus_addr[-1] == 0), bootrom_en.eq(cpu_core.o_bus_addr[-1] == 1), bootrom_writable.eq((cpu_core.o_bus_addr & 0xC0) == 0xC0) ] # wire the main bus to the memories m.d.comb += [ # address bus bootrom_r.addr.eq(cpu_core.o_bus_addr), bootrom_w.addr.eq(cpu_core.o_bus_addr), self.memory_signals.o_addr.eq(cpu_core.o_bus_addr), # write data bootrom_w.data.eq(cpu_core.o_mem_data), self.memory_signals.o_wdata.eq(cpu_core.o_mem_data), # enables bootrom_r.en.eq(bootrom_en & cpu_core.o_mem_re), bootrom_w.en.eq(bootrom_en & cpu_core.o_mem_we & bootrom_writable), self.memory_signals.o_re.eq(mainram_en & cpu_core.o_mem_re), self.memory_signals.o_we.eq(mainram_en & cpu_core.o_mem_we), ] # mux read results back to the cpu bus. the cpu gets the read value if # it addressed the memory last cycle. it can only address one memory at # a time (if it did more then all the results would be ORed together). mainram_rdata = Signal(16) bootrom_rdata = Signal(16) m.d.comb += [ mainram_rdata.eq( Mux(Past(mainram_en), self.memory_signals.i_rdata, 0)), bootrom_rdata.eq(Mux(Past(bootrom_en), bootrom_r.data, 0)), cpu_core.i_mem_data.eq(mainram_rdata | bootrom_rdata), ] # the main RAM runs with the system clock m.d.comb += [ self.memory_signals.o_clock.eq(ClockSignal("sync")), self.memory_signals.o_reset.eq(ResetSignal("sync")), ] # split up the external bus into (at most) 16 regions of 16 registers. # we use the first 128 words and last 128 words of the bus since those # regions can be addressed with the 1-word form of the external bus # instructions. each peripheral gets 1 read and 1 write enable bit, 4 # address bits, 16 write data bits, and gives back 16 read data bits NUM_PERIPHS = 4 periph_en = tuple(Signal(1) for _ in range(NUM_PERIPHS)) periph_re = tuple(Signal(1) for _ in range(NUM_PERIPHS)) periph_we = tuple(Signal(1) for _ in range(NUM_PERIPHS)) periph_addr = Signal(4) periph_wdata = Signal(16) periph_rdata = tuple(Signal(16) for _ in range(NUM_PERIPHS)) m.d.comb += periph_addr.eq(cpu_core.o_bus_addr[:4]) m.d.comb += periph_wdata.eq(cpu_core.o_ext_data) # hook up enable bits x_addr = cpu_core.o_bus_addr for pi in range(NUM_PERIPHS): m.d.comb += [ periph_en[pi].eq((x_addr[-1] == (pi >> 3)) & (x_addr[4:7] == (pi & 7))), periph_re[pi].eq(cpu_core.o_ext_re & periph_en[pi]), periph_we[pi].eq(cpu_core.o_ext_we & periph_en[pi]), ] # mux peripheral read data back to the CPU result_expr = Const(0, 16) for pi in range(NUM_PERIPHS): # this peripheral gets to put its result on the bus if it was # addressed last cycle result_expr = result_expr | \ Mux(Past(periph_en[pi]), periph_rdata[pi], 0) m.d.comb += cpu_core.i_ext_data.eq(result_expr) # hook up the reset request peripheral m.d.comb += [ reset_req.i_re.eq(periph_re[p_map.reset_req.periph_num]), reset_req.i_we.eq(periph_we[p_map.reset_req.periph_num]), reset_req.i_addr.eq(periph_addr), reset_req.i_wdata.eq(periph_wdata), periph_rdata[p_map.reset_req.periph_num].eq(reset_req.o_rdata), self.o_reset_req.eq(reset_req.o_reset_req), ] # hook up the UART m.d.comb += [ uart.i_re.eq(periph_re[p_map.uart.periph_num]), uart.i_we.eq(periph_we[p_map.uart.periph_num]), uart.i_addr.eq(periph_addr), uart.i_wdata.eq(periph_wdata), periph_rdata[p_map.uart.periph_num].eq(uart.o_rdata), uart.i_rx.eq(self.uart_signals.i_rx), self.uart_signals.o_tx.eq(uart.o_tx), ] # hook up the timers m.d.comb += [ timer.i_re.eq(periph_re[p_map.timer.periph_num]), timer.i_we.eq(periph_we[p_map.timer.periph_num]), timer.i_addr.eq(periph_addr), timer.i_wdata.eq(periph_wdata), periph_rdata[p_map.timer.periph_num].eq(timer.o_rdata), ] # hook up the SNES interface m.d.comb += [ snes.i_re.eq(periph_re[p_map.snes.periph_num]), snes.i_we.eq(periph_we[p_map.snes.periph_num]), snes.i_addr.eq(periph_addr), snes.i_wdata.eq(periph_wdata), periph_rdata[p_map.snes.periph_num].eq(snes.o_rdata), ] return m
def validate(self): with self.is_running(): with self.is_instruction(0x1B, 2): self.assert_equals(self.registers.a, Past(self.registers.a) + Past(self.registers.b)) self.assert_end_of_instruction()
def build_formal(bld: Builder): m = Module() in_data = AnySeq(8) en_data = AnySeq(1) hsync = AnySeq(1) vsync = AnySeq(1) enc_char = Signal(10) real_chr_bias = Signal(signed(5)) real_dc_bias = Signal(signed(5)) m.submodules.enc = enc = TMDSEncoder() m.submodules.dec = dec = TMDSDecoder() m.d.comb += [ enc.i_data.eq(in_data), enc.i_en_data.eq(en_data), enc.i_hsync.eq(hsync), enc.i_vsync.eq(vsync), dec.i_char.eq(enc.o_char), enc_char.eq(enc.o_char), ] m.d.comb += [ real_chr_bias.eq(popcount(enc.o_char) - 5), Assert(real_dc_bias >= -5), Assert(real_dc_bias <= +5), Assert(real_dc_bias[:4] == enc.dc_bias), ] m.d.sync += [ real_dc_bias.eq(real_dc_bias + real_chr_bias), ] with m.If(~enc.i_en_data): m.d.sync += real_dc_bias.eq(real_dc_bias) m.d.comb += Cover( (Past(dec.o_en_data, 4) & (Past(enc.o_char, 4)[8:10] == 0b00)) & (Past(dec.o_en_data, 3) & (Past(enc.o_char, 3)[8:10] == 0b01)) & (Past(dec.o_en_data, 2) & (Past(enc.o_char, 2)[8:10] == 0b10)) & (Past(dec.o_en_data, 1) & (Past(enc.o_char, 1)[8:10] == 0b11)) & (dec.o_vsync)) m.d.comb += Assert(dec.o_en_data == enc.i_en_data) with m.If(dec.o_en_data): m.d.comb += Assert(dec.o_data == enc.i_data) # Check that XNOR choice matches reference algorithm in_pop = Signal(4) use_xnor = Signal() m.d.comb += [ in_pop.eq(popcount(in_data)), use_xnor.eq((in_pop > 4) | ((in_pop == 4) & (in_data[0] == 0))), Assert(enc.o_char[8] == ~use_xnor), ] with m.Else(): m.d.comb += [ Assert(dec.o_hsync == enc.i_hsync), Assert(dec.o_vsync == enc.i_vsync), ] with bld.temp_open("formal.il") as f: il_text = rtlil.convert(m, ports=[enc_char, real_chr_bias, real_dc_bias]) f.write(il_text)
def capture(self, m: Core, core: Core, past: int): comb = m.d.comb if past > 0: prefix = f"past{past}" else: prefix = "now" self.r = RegisterFile(core.xlen, prefix=prefix) for i in range(self.r.main_gpr_count()): comb += self.r[i].eq(Past(core.register_file.r[i], past)) comb += self.r.pc.eq(Past(core.pc, past)) # TODO: move to additional structure self.itype = IType(prefix=f"{prefix}_i") self.itype.elaborate(comb, Past(core.current_instruction, past)) self.jtype = JType(prefix=f"{prefix}_j") self.jtype.elaborate(comb, Past(core.current_instruction, past)) self.utype = UType(prefix=f"{prefix}_u") self.utype.elaborate(comb, Past(core.current_instruction, past)) self.btype = BType(prefix=f"{prefix}_b") self.btype.elaborate(comb, Past(core.current_instruction, past)) # TODO: membus self.input_ready = Signal.like(core.mem2core.ready, name=f"{prefix}_input_ready") self.input_data = Array([ Signal(core.xlen, name=f"{prefix}_input_{i}") for i in range(core.look_ahead) ]) self.cycle = Signal.like(core.cycle, name=f"{prefix}_cycle") comb += self.cycle.eq(Past(core.cycle, past)) # TODO: move to structure self.mem2core_addr = Signal.like(core.mem2core.addr, name=f"{prefix}_mem2core_addr") self.mem2core_en = Signal.like(core.mem2core.en, name=f"{prefix}_mem2core_en") self.mem2core_seq = Signal.like(core.mem2core.seq, name=f"{prefix}_mem2core_seq") comb += self.mem2core_addr.eq(Past(core.mem2core.addr, past)) comb += self.mem2core_en.eq(Past(core.mem2core.en, past)) comb += self.mem2core_seq.eq(Past(core.mem2core.seq, past)) comb += self.input_ready.eq(Past(core.mem2core.ready, past)) comb += self.input_data[0].eq(Past(core.mem2core.value, past))
if verification is not None: # Cycle counter cycle2 = Signal(6, reset_less=True) m.d.ph1 += cycle2.eq(cycle2 + 1) # Force a reset # m.d.comb += Assume(rst == (cycle2 < 8)) with m.If(cycle2 == 20): m.d.ph1 += Cover(core.formalData.snapshot_taken & core.end_instr_flag) m.d.ph1 += Assume(core.formalData.snapshot_taken & core.end_instr_flag) # Verify reset does what it's supposed to with m.If(Past(rst, 4) & ~Past(rst, 3) & ~Past(rst, 2) & ~Past(rst)): m.d.ph1 += Assert(Past(core.Addr, 2) == 0xFFFE) m.d.ph1 += Assert(Past(core.Addr) == 0xFFFF) m.d.ph1 += Assert(core.Addr[8:] == Past(core.Din, 2)) m.d.ph1 += Assert(core.Addr[:8] == Past(core.Din)) m.d.ph1 += Assert(core.Addr == core.pc) main_runner(parser, args, m, ports=core.ports() + [ph1clk, rst]) else: # Fake memory mem = { 0xFFFE: 0x12, 0xFFFF: 0x34, 0x1234: 0x7E, # JMP 0xA010 0x1235: 0xA0,
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]