Description
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 aFragment
orModule
(Elaboratable
). See above. -
Per IRC, a formal
Platform
is probably desirable. Current approach is to injectplatform=formal
intortlil/verilog.convert()
or similar instead of usingnmigen.build
. I have some thoughts here:- I think it's reasonable that
rtlil/verilog.convert()
on it's own either emits or excludesassert
s/assume
s via an option. - My gut feeling tells that
build
ing 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/oassert
s/assume
s, and another set of.il
/v
forsby
.
- I would still like the ability to easily clean up formal output artifacts without them intermingling with synthesis output artifacts; for instance, invoking via
- I think it's reasonable that
-
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
withinnmigen
, 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 "alln
clocks must have ticked at least once in the pastn
cycles" might work?). I think we should review this.