Skip to content

Commit 92d4c7f

Browse files
mndstrmrmarnovandermaas
authored andcommitted
[dv/formal] Introduce an Open Source Formal Flow
This commit introduces a formal flow for Ibex that does not depend on Jasper, instead using yosys and our fork of the yosys-slang frontend to produce an aiger file, which the rIC3 model checker, under the instruction of conductor.py, can then verify. Just one aiger file is created, and is subsequently reconfigured by the Rust aig-manip tool. See dv/formal/README.md for more details, but in general: 1. We generate the specification module and psgen RTL in roughly the same way as the Jasper flow, with small changes to the psgen output in particular. 2. We use a fork of yosys-slang as the frontend for yosys. It has comprehensive SystemVerilog support, and handles both the specification and Ibex easily. It lacks SVA support by default, hence the need for the fork, though hopefully this will be upstreamed soon. The RTL source list is constructed by fusesoc in the same way as for Jasper. 3. The yosys build script is then specified in build_all.ys. It makes use of three custom passes, which may be found in yosys_formal. See their source files for more explanation of what they do. Yosys takes ~10 minutes to build an aiger file. See aig-manip/src/main.rs for more description of aiger files. 4. In order to prove a property, the rIC3 model checker can be used. However, the aiger file produced by yosys in step 3 contains all properties as assertions. To focus on just one, and to take all prior steps as assumptions the aig-manip tool is used. After this invocation of rIC3 is straightforward for IC3, k-induction or BMC. If a CEX is discovered it may be analysed by the aig-manip tool, which can lift the AIW (aiger witness) into a VCD file, for use in gtkwave etc. 5. When considering the proof as a whole, the conductor.py script is used to discover proof strategies, and then run proofs while maximising memory usage. It caches proofs for each step under strategies/step*.json. Additonal notes: 1. The actual proof is relatively unchanged, with just a couple of new properties. 2. The proof is fast (it takes 40 minutes or so on a good machine) 3. smt2 based proofs are also available, e.g. for k-induction, since the build script (build_all.ys) will produce an smt2 file, which can be manipulated by smt2manip.py in the same that aig-manip does for an aiger file. 4. The transformation made to a global clock will confuse clock gating. It *should* be fine, since the clock signal it generates is essentially ignored anyway. 5. This commit also switches from poetry to UV. 6. This runs on a small memory bound (the smallest possible bound). See check/protocol/mem.sv
1 parent 4958b35 commit 92d4c7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+5110
-215
lines changed

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright lowRISC contributors.
2+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
# SPDX-License-Identifier: Apache-2.0
4+
dv/formal/strategies/* linguist-generated

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Copyright lowRISC contributors.
2+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
# SPDX-License-Identifier: Apache-2.0
4+
15
IBEX_CONFIG ?= small
26

37
FUSESOC_CONFIG_OPTS = $(shell ./util/ibex_config.py $(IBEX_CONFIG) fusesoc_opts)

dv/formal/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
build
22
jgproject
33
jgproofs
4+
aig-manip/target

dv/formal/Makefile

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
# Copyright lowRISC contributors.
2+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
# Original author: Louis-Emile Ploix
4+
# SPDX-License-Identifier: Apache-2.0
5+
16
IBEX_ROOT=../..
27

3-
SAIL=sail
8+
SAIL=$(shell which sail)
9+
PSGEN=$(shell which psgen)
410

511
SAIL_RISCV_MODEL_DIR=${LOWRISC_SAIL_RISCV_SRC}/model
612

@@ -9,7 +15,7 @@ include sail-sources.mk
915
PSGEN_SRCS=thm/btype.proof thm/ibex.proof thm/mem.proof thm/riscv.proof
1016
PSGEN_FLAGS=-root riscv -task
1117

12-
SAIL_EXTRA_SRCS=../spec/main.sail
18+
SAIL_EXTRA_SRCS=spec/main.sail
1319

1420
# -sv, use the SystemVerilog backend
1521
# --sv-comb, generate a always_comb instead of an initial block
@@ -23,14 +29,14 @@ SAIL_SV_FLAGS=-sv --sv-comb --sv-inregs --sv-outregs --sv-nostrings --sv-nopacke
2329
--sv-unreachable translate --sv-unreachable lookup_TLB --sv-unreachable translate_tlb_miss --sv-unreachable translate_tlb_hit --sv-unreachable pt_walk \
2430
--sv-fun2wires 2:read_ram \
2531
--sv-fun2wires 2:write_ram \
26-
--sv-fun2wires wX
32+
--sv-fun2wires wX
2733

2834
# Use fusesoc to resolve the tree of components, copy all resolved source files into the build/ directory,
2935
# and then generate a filelist for jasper to ingest.
3036
# - Note. we use the 'vcs' fusesoc backend flow to generate the filelist. This is because fusesoc does not currently implement a
31-
# JasperGold backend, but this is not an issue as the file-format generated by the vcs flow is compatible with jasper.
32-
.PHONY: fusesoc
33-
fusesoc:
37+
# JasperGold backend, but this is not an issue as the file-format generated by the vcs flow is compatible with both jasper and
38+
# yosys-slang.
39+
build/fusesoc: $(IBEX_ROOT)/rtl $(IBEX_ROOT)/vendor
3440
mkdir -p build/fusesoc
3541
fusesoc \
3642
--cores-root $(IBEX_ROOT) \
@@ -39,33 +45,52 @@ fusesoc:
3945
--tool vcs \
4046
--setup \
4147
lowrisc:ibex:ibex_formal:0.1
48+
touch build/fusesoc # Fix timestamps for Makefile
49+
50+
# The sail spec module, constructed from LOWRISC_SAIL_RISCV_SRC, compiled by our fork of the sail compiler
51+
build/ibexspec.sv: $(SAIL) $(SAIL_SRCS) $(SAIL_EXTRA_SRCS) sail-sources.mk Makefile spec/fix_bugs.py
52+
mkdir -p build
53+
cd build && $(SAIL) $(SAIL_SRCS) $(addprefix ../,$(SAIL_EXTRA_SRCS)) $(SAIL_SV_FLAGS) $(addprefix -sv_unreachable execute_,$(COMPRESSED_INSTRS)) -o ibexspec
54+
python3 spec/fix_bugs.py
55+
56+
# The compiled property structure, and the associated TCL
57+
build/psgen-jg.sv: $(PSGEN) $(PSGEN_SRCS) Makefile
58+
mkdir -p build
59+
$(PSGEN) $(addprefix -path ,$(PSGEN_SRCS)) $(PSGEN_FLAGS) -sv-out build/psgen-jg.sv -tcl-out build/psgen.tcl
4260

43-
.PHONY: sv
44-
sv:
61+
# Same as above, but generate our own covers, and tweak for consumption by our tools
62+
build/psgen-yosys.sv: $(PSGEN) $(PSGEN_SRCS) Makefile
4563
mkdir -p build
46-
python3 buildspec.py header > build/ibexspec_instrs.sv
47-
cd build && $(SAIL) $(SAIL_SRCS) $(SAIL_EXTRA_SRCS) $(SAIL_SV_FLAGS) `cd .. && python3 buildspec.py unreachables` -o ibexspec
48-
python3 spec/fix_pmp_bug.py
49-
python3 buildspec.py unreachable_loc_hack
64+
$(PSGEN) $(addprefix -path ,$(PSGEN_SRCS)) $(PSGEN_FLAGS) -sv-out build/psgen-yosys.sv -clocking -covers -cover-assert -step-prefix
65+
66+
# The aiger file for the OSS flow, using the yosys_formal/* plugins. The main yosys script is in build_all.ys
67+
build/all.aig: build/psgen-yosys.sv build/fusesoc build/ibexspec.sv check build_all.ys $(LOWRISC_YOSYS_SLANG) build/yosys_formal.so
68+
yosys -m $(LOWRISC_YOSYS_SLANG) -m build/yosys_formal.so -v 1 -s <(cat ./build_all.ys | sed "s|LOWRISC_SAIL_SRC|$(LOWRISC_SAIL_SRC)|g")
5069

51-
.PHONY: psgen
52-
psgen:
70+
# Build the custom yosys plugins
71+
build/yosys_formal.so: yosys_formal/global_clock.cc yosys_formal/write_aiger.cc yosys_formal/opt_muxtree.cc
72+
yosys-config --build build/yosys_formal.so yosys_formal/global_clock.cc yosys_formal/write_aiger.cc yosys_formal/opt_muxtree.cc
73+
74+
# Build the aig-manip Rust tool
75+
build/aig-manip: aig-manip/src/main.rs
5376
mkdir -p build
54-
psgen $(addprefix -path ,$(PSGEN_SRCS)) $(PSGEN_FLAGS) -sv-out build/psgen.sv -tcl-out build/psgen.tcl
77+
cd aig-manip && cargo build --release
78+
cp aig-manip/target/release/aig-manip build/
5579

80+
# Run the jasper environment in interactive mode
5681
.PHONY: jg
57-
jg: fusesoc psgen sv
82+
jg: build/fusesoc build/psgen-jg.sv build/ibexspec.sv
5883
jg verify.tcl -allow_unsupported_OS -acquire_proj
5984

60-
# The following default target is intended for regressions / unattended runs.
85+
# Jasper environment for regression and unattended runs
6186
.PHONY: all
62-
all: fusesoc psgen sv
87+
all: build/fusesoc build/psgen-jg.sv build/ibexspec.sv
6388
jg verify.tcl -allow_unsupported_OS -acquire_proj -no_gui --- "prove_no_liveness"
6489

6590
################################################################################
6691

6792
.PHONY: clean
6893
clean:
69-
rm -rf build/
70-
rm -rf jgproject/
71-
rm -rf jgproofs/
94+
rm -rf build/ aig-manip/target
95+
rm -rf jgproject/ jgproofs/
96+

dv/formal/README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Getting started:
1212
- `cd dv/formal`
1313

1414
### Reproducible Build
15-
15+
#### With Jasper:
1616
This flow is intended for users who wish to run the formal flow as-is using the pinned external dependencies (psgen, sail, riscv-sail etc.)
1717

1818
Build instructions:
@@ -28,13 +28,22 @@ Some steps require a lot of RAM and CPU so we recommend closing any other resour
2828
A machine with 128 GiB of RAM and 32 cores was used to complete the proof.
2929
To avoid manually running each step you can also use the `prove_lemmas` command inside the TCL command interface located below your session window.
3030

31+
#### With Yosys and rIC3:
32+
This is equivalent to the above, but uses only open source tools.
33+
34+
Build instructions:
35+
- `nix develop .#oss-dev`
36+
- `make build/aig-manip` builds the Rust aig-manip tool used by conductor.py
37+
- `make build/all.aig` builds the core Aiger file
38+
- `python3 conductor.py prove` runs the proof, maximising memory usage. See `python3 conductor.py -h` for more options.
39+
3140
### Development Builds
3241

3342
Users who wish to do development on this flow should use the below steps.
3443
This will allow changes to both the local files and the external dependencies (psgen, sail, riscv-sail), and to run the intermediate build steps manually.
3544

36-
Build instructions:
37-
- Identical to the Reproducible Build steps, but use `nix develop .#formal-dev`.
45+
- For Jasper: Identical to the Reproducible Build steps, but use `nix develop .#formal-dev`.
46+
- For OSS: Identical to Reproducible Build steps.
3847

3948
Invoking `make jg` using the provided makefile would run the following steps, which can also be executed manually:
4049
- `make fusesoc` fetches the necessary RTL using the FuseSoC tool and makes a local copy inside `build/`.
@@ -44,9 +53,15 @@ Invoking `make jg` using the provided makefile would run the following steps, wh
4453
- `make sv` to build the SV translation of the Sail compiler.
4554
Will invoke `buildspec.py`, which can be configured to adjust which instructions are defined.
4655
By default all of them are, this is correct but slow.
47-
- `jg verify.tcl` invokes Jasper interactively, sourcing the configuration & run script.
56+
- `jg verify.tcl` (jasper only) invokes Jasper interactively, sourcing the configuration & run script.
4857
Requires the above two steps to be executed first.
4958

59+
Invoking `make build/all.aig` similarly does the following:
60+
- `make fusesoc`
61+
- `make psgen`
62+
- `make sv`
63+
- Invokes yosys (and a collection of plugins which may be found under `yosys_formal`, as well as our fork of yosys-slang) to build an Aiger file.
64+
5065
Local versions of the external dependencies can be modified and linked into the build via Environment Variables as follows:
5166
- psgen: (`https://github.com/mndstrmr/psgen`)
5267
- Clone the repository to a local directory \<psgen-dir\> : `git clone https://github.com/mndstrmr/psgen`
@@ -66,6 +81,11 @@ Local versions of the external dependencies can be modified and linked into the
6681
- Make local changes...
6782
- In the formal-dev shell:
6883
- Update `LOWRISC_SAIL_RISCV_SRC` to point to the source root with `export LOWRISC_SAIL_RISCV_SRC=<sail-riscv-dir>`.
84+
- yosys-slang: (`https://github.com/mndstrmr/yosys-slang/tree/formal`)
85+
- Clone the repository to a local directory \<yosys-slang-dir\> (`git clone https://github.com/mndstrmr/yosys-slang --branch formal`).
86+
- Make local changes...
87+
- In the formal-dev shell:
88+
- Update `LOWRISC_YOSYS_SLANG` to point to the source root with `export LOWRISC_YOSYS_SLANG=<yosys-slang-dir>`.
6989

7090
## Conclusivity
7191
All properties are currently known to be conclusive, with the exception of M-Types.
@@ -77,9 +97,6 @@ This means:
7797
- We do not prove that the instruction executed with a given PC was loaded with that PC.
7898
- We haven't proven that Ibex resets correctly, if it doesn't there is no trace equivalence.
7999

80-
## RTL Changes
81-
- `ResetAll = 1` is required for now (instead of `ResetAll = Lockstep`)
82-
83100
## Code Tour
84101
### Top Level Goals
85102
The top level objective is to get proofs for `Wrap`, `Live`, `Load`, `Store` and `NoMem`.

0 commit comments

Comments
 (0)