Example #1
0
    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]
Example #2
0
    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]
Example #3
0
    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]
Example #4
0
    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]
Example #5
0
    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())
Example #6
0
    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]