Skip to content

Formal Platform Integration #505

@cr1901

Description

@cr1901

Right now, the scope of formal is the following, copied directly from IRC:

(11:56:43 AM) whitequark: the entire scope of formal verification in nmigen at the moment is "it can generate verilog or rtlil with assert/assume statements"
(11:57:10 AM) whitequark: i do not, at the moment, provide anything beyond that, and doing it requires thinking first and coding second

This is a pre-RFC to discuss what other functionality we'd want out of formal integration. Specifically, I'm assuming an end goal will be something along the lines of:

Given a test harness w/ assert/assume and a design w/ assert/assume statements, running a formal verification flow of an Elaboratable in nmigen will be of comparable complexity to synthesizing and programming a bitstream via nmigen.build.plat.Platform.build(). Formal (in symbiyosys, either Bounded Model Check (BMC) and/or k-induction)

To start, I can think of at least three things I want:

  • Minimal hassle to invoke symbiyosys that "does the right thing" on a Fragment or Module (Elaboratable). See above.

  • Per IRC, a formal Platform is probably desirable. Current approach is to inject platform=formal into rtlil/verilog.convert() or similar instead of using nmigen.build. I have some thoughts here:

    • I think it's reasonable that rtlil/verilog.convert() on it's own either emits or excludes asserts/assumes via an option.
    • My gut feeling tells that building for a platform which has assertions and synthesizing a bitstream should be mutually exclusive because synth and formal are meant to do two different tasks. Failing that:
      • I would still like the ability to easily clean up formal output artifacts without them intermingling with synthesis output artifacts; for instance, invoking via sby -d sby_dir formal.sby.
      • Input artifact mingling should also be kept to a minimum. A minimum set of inputs affected by emitting for both formal ans synthesis might be: the sby file, one set of .il/v input for synthesis w/o asserts/assumes, and another set of .il/v for sby.
  • Multiclock support. This one is tougher, it's easy to make a design w/ multiclock fail because the solver will hold one of the clocks steady to prevent forward progress (when a constraint violation is imminent) until n timesteps have elapsed. One way around this is to utilize the $global_clock clock and do something like this for each clock to force each clock to eventually tick:

    reg last_clk = 0;
    
    always @($global_clock) begin
          last_clk <= clk;
          assume(last_clk != clk);
    end
    

    When we discussed $global_clock last year, we agreed to not expose $global_clock within nmigen, but we couldn't come up with a good set of constraints that should be autogenerated for formal testbenches with multiple clocks to force forward progress (I think "all n clocks must have ticked at least once in the past n cycles" might work?). I think we should review this.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions