χRVFormal is a formal verification framework for validating the instruction-level correctness of RISC-V processors implemented in Chisel.
It provides:
- A configurable reference model (
RiscvCore) that encodes the RISC-V ISA semantics - A set of checkers and helpers to connect your DUT with the reference model
- Built-in formal properties for ISA consistency checking
Read more detailed Chinese README: 中文说明.
- χRVFormal
- ✅ Supports RV32/RV64 I
- ✅ ISA extensions:
M,B,C,Zicsr,Zifencei - ✅ Privilege modes:
M,S,U - ✅ Virtual memory with Sv39
- ✅ Reg/ Memory / CSR / TLB consistency checking
- ✅ Works with ChiselTest + BMC (BtorMC)
- ✅ Optional Verilog flow (SymbiYosys)
git clone https://github.com/iscas-tis/ChiRVFormal.git
cd ChiRVFormal
sbt publishLocal -DHashId=trueThen in your build.sbt:
libraryDependencies += "cn.ac.ios.tis" %% "riscvspeccore" % "<your-version>"resolvers += Resolver.sonatypeRepo("snapshots")
libraryDependencies += "cn.ac.ios.tis" %% "riscvspeccore" % "1.3-SNAPSHOT"val rvConfig = RVConfig(
XLEN = 64,
extensions = "MCZicsrU",
fakeExtensions = "A",
initValue = Map("pc" -> "h0000_8000"),
functions = Seq("Privileged", "TLB"),
formal = Seq("CheckMem", "CheckCSRs")
)
val checker = Module(new CheckerWithState(enableReg = false)(rvConfig))Hook your pipeline commit stage:
checker.io.instCommit.valid := commit_valid
checker.io.instCommit.excp := commit_excp
checker.io.instCommit.inst := commit_inst
checker.io.instCommit.pc := commit_pc
checker.io.instCommit.npc := commit_npcInitialize helper:
ConnectHelper.setChecker(checker)(XLEN, rvConfig)val regStateWire = Wire(Vec(32, UInt(XLEN.W)))
regStateWire := rf
regStateWire(0) := 0.U
ConnectHelper.setRegSource(regStateWire)val privilegeStateWire = ConnectHelper.makePrivilegeSource(rvConfig)
// cur priviledge mode
privilegeStateWire.mode := RegNext(priviledgeMode)
// csrs
privilegeStateWire.csr.mvendorid := RegNext(mvendorid)
privilegeStateWire.csr.marchid := RegNext(marchid)
// ······Get signals in TLB of DUT.
val tlbAccessWrie = ConnectHelper.makeTLBSource(if(tlbname == "itlb") false else true)(XLEN)
// memory access in TLB
resultTLBWire.read.valid := true.B
resultTLBWire.read.addr := io.mem.req.bits.addr
resultTLBWire.read.data := io.mem.resp.bits.rdata
resultTLBWire.read.level := (level-1.U)
// ······Get the signal when DUT access memory.
val memAccessWire = ConnectHelper.makeMemSource()(XLEN)
memAccessWire.read.valid := isRead
memAccessWire.read.addr := addr
memAccessWire.read.data := backend.io.dmem.resp.bits.rdata
memAccessWire.read.memWidth := width
memAccessWire.write.valid := isWrite
memAccessWire.write.addr := addr
memAccessWire.write.data := wdata
memAccessWire.write.memWidth := widthUse assume to restrict the input space:
assume(RVI(inst))
assume(RVI.ADDI(inst))verify(new DUT(), Seq(
BoundedCheck(12),
BtormcEngineAnnotation
))Speed up debugging by focusing on one instruction:
val checker = Module(
new CheckerWithState(singleInstMode = Some(RVI.ADDI))(rvConfig)
){
"xlen": 32,
"extensions": ["I", "Zicsr", "Zba", "Zbb", "Zbc", "Zbs", "Zbkb", "Zbkc", "Zbkx"],
"fakeExtensions": [],
"initValue": {"pc": "h8000_0000", "mstatus": "h0000_1800", "mtvec": "h0000_0000"},
"functions": ["Privileged"],
"formal": ["CheckMem", "CheckNPC", "CheckCSRs"],
"regDelay": false,
"singleInstMode": null
}> sbt "svcore/runMain svcore.Main -h"
[info] running svcore.Main -h
SystemVerilog Spec Core Generator 1.3
Usage: sv-cores [options]
-c, --config <file> path to the configuration file (default: config.json)
-m, --model <model> check model to generate (default: writeback)
-t, --target-dir <directory>
directory to output the generated SystemVerilog files (default: build)
-l, --list show list of supported models
-h, --help show list of command-line optionsconfig SymbiYosys by formal.sby
[options]
mode bmc
expect pass,fail
append 0
depth 16
skip 15
[engines]
smtbmc boolector
[script]
read -sv testbench.sv
prep -flatten -nordff -top testbench
chformal -early
[files]
testbench.svrun command:
sby -f formal.sby- Use SingleInstMode first when debugging failures
- Add minimal
assumeconstraints to avoid state explosion - Run formal checks in CI (GitHub Actions) to catch regressions early
- NutShell integration: nutshell-fv
- SystemVerilog/Verilog examples: sv-core-fv
If this project is useful in your research, please cite:
SETTA 2024: Formal Verification of RISC-V Processor Chisel Designs Link | BibTex
JSA 2026: χRVFormal: Formal Verification of RISC-V Processor Chisel Designs Link | BibTex