Skip to content

Commit 52409e4

Browse files
[major] Adjust syntax of formal unit tests (#252)
Adjust the syntax of the `formal` declaration to no longer expect a single fixed `bound = <N>` parameter, but instead accept a list of user-defined parameters similar to an `extmodule`. The parameters can be integers, strings, arrays, and dictionaries. They are passed through to the tooling running the formal test. As we build out that tooling, we may standardize some of the parameters. Marking this as "major" since it technically is a breaking change, but in practice there are no users of `formal` as of today and the original syntax has never been released as part of the spec.
1 parent b111312 commit 52409e4

File tree

2 files changed

+51
-41
lines changed

2 files changed

+51
-41
lines changed

revision-history.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ revisionHistory:
2929
- Add language clarifying behavior statements affected by conditionals.
3030
- No abstract reset on externally-defined modules.
3131
- Add Property type and primitive operations for List.
32-
- Add "formal" construct to mark modules for bounded model checking.
32+
- Add `formal` unit test construct.
3333
- Add Property primitive operation for integer shift left
3434
abi:
3535
- Use EBNF to describe probe port macros and filename.

spec.md

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -286,61 +286,63 @@ circuit Foo :
286286
public module Foo enablelayer A :
287287
```
288288

289-
## Formal Tests
289+
## Formal Unit Tests
290290

291-
Formal tests are named top-level constructs which allow for formal test harnesses to be definied
292-
as bounded model checking (BMC) problems. The body of the formal test harness is converted
293-
into a BMC formula which encodes a state-transition system version of the design using one
294-
of the formal backends (targetting either BTOR2 or SMTLib).
295-
Formal tests have 3 operands:
291+
The `formal`{.firrtl} keyword declares a formal unit test.
292+
Tools may look for these constructs and automatically run them as part of a regression test suite.
296293

297-
1. A name that the test can be referred to with.
298-
2. The name of the formal test harness module.
299-
3. A positive integer bound for the test. This number indicates the depth to which the model will be checked.
294+
A formal unit test has a unique name and refers to a module declaration that contains the design to be verified and any necessary test harness.
295+
Additionally, the test may also declare a list of user-defined named parameters which can be integers, strings, arrays, or dictionaries.
296+
These parameters are passed on to any tools that execute the tests.
297+
No parameters with well-known semantics are defined yet.
298+
During execution of the formal test, all input ports of the target module are treated as symbolic values that may change in every cycle.
299+
All output ports are ignored.
300300

301-
``` firrtl
301+
The circuit below shows a module run as a formal unit test:
302+
303+
``` {.firrtl .notest}
302304
FIRRTL version 4.0.0
303305
circuit Foo :
304306
public module Foo :
305-
; ...
306-
formal testFoo of Foo, bound = 20
307+
formal myTest of Foo :
307308
```
308309

309-
More details about how bounded model checking works and what the bound refers to can be found in
310-
[Biere et al. 2003](https://doi.org/10.1016/S0065-2458(03)58003-2).
310+
A module may be reused in multiple unit tests, for example to run with different testing parameters:
311311

312-
### Formal Test Harness
312+
``` {.firrtl .notest}
313+
FIRRTL version 4.0.0
314+
circuit Foo :
315+
public module Foo :
316+
formal myTestA of Foo :
317+
mode = "bmc"
318+
bound = 42
319+
formal myTestB of Foo :
320+
mode = "induction"
321+
bound = 100
322+
```
313323

314-
A public module definition may be used as a formal test harness.
315-
Their input ports act as symbolic variables for the test.
324+
### Test Harnesses
316325

317-
Example:
326+
It may be necessary to define additional verification constructs and hardware in addition to the design that should be run in a formal unit test.
327+
To achieve this, an additional module may act as a test harness and instantiate the design to be tested alongside any other necessary verification collateral:
318328

319-
``` firrtl
329+
``` {.firrtl .notest}
320330
FIRRTL version 4.0.0
331+
circuit Foo :
332+
public module Foo :
333+
input a : UInt<42>
334+
output b : UInt<42>
335+
; ...
321336
322-
circuit Foo:
323-
public module Foo:
324-
input data : UInt<32>
325-
input c : UInt<1>
326-
output out : UInt<32>
327-
;; Foo body
328-
329-
public module FooTest:
330-
;; symbolic input -- maps to input in btor2
331-
input s_foo_c : UInt<1>
332-
input s_foo_data : UInt<32>
333-
;; example test
337+
public module FooTest :
338+
input clk : Clock
339+
input a : UInt<42>
334340
inst foo of Foo
335-
;; feed the symbolic inputs to the instance
336-
connect foo.c, s_foo_c
337-
connect foo.data, s_foo_data
338-
;; example assertion that uses the symbolic inputs and outputs
339-
intrinsic(circt_verif_assert, intrinsic(
340-
circt_ltl_implication : UInt<1>, s_foo_c, eq(foo.out, s_foo_data))
341-
)
341+
connect foo.a, a
342+
assert(clk, eq(foo.b, add(a, UInt(42))), UInt<1>(h1), "foo computes a + 42")
343+
assume(clk, gt(a, UInt(2)), UInt<1>(h1), "input a > 2")
342344
343-
formal testFormal of FooTest, bound = 20
345+
formal testFoo of FooTest :
344346
```
345347

346348
# Circuit Components
@@ -4292,7 +4294,15 @@ decl_layer =
42924294
dedent ;
42934295
42944296
decl_formal =
4295-
"formal" , id , "of" , id , "," , "bound" , "=" , int;
4297+
"formal" , id , "of" , id , ":" , [ info ] , newline , indent ,
4298+
{ id , "=" , decl_formal_param , newline } ,
4299+
dedent ;
4300+
decl_formal_param =
4301+
int
4302+
| string_dq
4303+
| string_sq
4304+
| "[" , [ decl_formal_param , { "," , decl_formal_param } ] , "]"
4305+
| "{" , [ id , "=" , decl_formal_param , { "," , id , "=" , decl_formal_param } ] , "}"
42964306
42974307
decl_type_alias = "type", id, "=", type ;
42984308

0 commit comments

Comments
 (0)