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 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]]: 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 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]
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)) m.d.comb += Assert(Fell(b2d.o_digit_rd, 1)) main_runner(parser, args, m, ports=b2d.ports())
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]