Causality Check
Definition
A causality check is a formal-verification assertion that validates whether the order in which a processor core retires instructions preserves the data-dependency causality between them. The core rule is: a write must be retired before any read that depends on it, even when instructions are otherwise allowed to be retired out of order.
Causality Checks in the RISC-V Formal Framework
The RISC-V Formal verification procedure defines three named causality checks, all of which share a common [depth] configuration section that expects two values — first the number of reset cycles, then the execution depth (i.e. the bound for the bounded model check).
causal
The causal check tests whether the instruction stream is causal with respect to registers. It enforces that a register write is observed (via RVFI) before any register read that depends on it is retired.
causal_mem
The causal_mem check tests whether the instruction stream is causal with respect to memory. The same "write before dependent read" rule is applied to memory loads and stores tracked through RVFI memory signals.
causal_io
The causal_io check tests whether the instruction stream is causal with respect to I/O memory. For this check, every I/O memory access is assumed to depend on all earlier I/O memory accesses, so the dependency graph between I/O accesses is treated as fully connected.
Which regions of the address space count as I/O memory can be selected by the user via the RISCV_FORMAL_IOADDR(addr) macro.
Tooling
These checks are generated and managed by the genchecks.py tool, which assembles the standard checks (including causality) for cores that expose the RVFI interface. The checks consume RVFI (the RISC-V Formal Interface) signals such as rvfi_order, retire status, and memory access information to compare the core's actual retirement order against the causality-preserving order required by the formal property.
Broader Use of Causality Checking
Outside of hardware verification, the term causality checking is also used:
- In HyperLTL model checking (e.g. the AutoHyper tool), where causality checking is listed as one of the application domains that motivate hyperproperty verification, alongside information-flow control, robustness, mutation testing, and path planning.
- In Java memory model research, where the jMT tool constructs valid multi-execution semantics for concurrent Java programs by performing causality checking over well-formed single-execution graphs defined by single-execution models.
Configuration Reference
| Check | Dependency domain | [depth] arguments |
Notes |
|---|---|---|---|
causal |
Registers | reset cycles, execution depth | Basic register-level causality |
causal_mem |
Memory | reset cycles, execution depth | Causality on memory loads/stores |
causal_io |
I/O memory | reset cycles, execution depth | All I/O accesses treated as dependent on all earlier I/O accesses; I/O range configured via RISCV_FORMAL_IOADDR |