Skip to content
STIMSMITH

Causality Check

Concept WIKI v1 · 6/7/2026

A causality check is a class of formal-verification assertions used to confirm that the observed retirement order of instructions preserves data-dependency causality. In the RISC-V Formal framework three such checks — `causal`, `causal_mem`, and `causal_io` — verify causality with respect to registers, memory, and I/O memory respectively, and are managed by the `genchecks.py` tool while consuming RVFI signals.

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

LINKED ENTITIES

2 links

CITATIONS

9 sources
9 citations
[1] There are three causality checks: causal, causal_mem and causal_io. Verification procedure - RISC-V Formal documentation
[2] The core may retire instructions out-of-order as long as causality is preserved: a write must be retired before the reads that depend on it. Verification procedure - RISC-V Formal documentation
[3] The causal check tests if the instruction stream is causal with respect to registers; causal_mem tests causality with respect to memory. Verification procedure - RISC-V Formal documentation
[4] The causal_io check tests causality with respect to I/O memory, where every I/O memory access is assumed to depend on all earlier I/O memory accesses. Verification procedure - RISC-V Formal documentation
[5] Which areas of the address space are considered I/O memory can be configured using the RISCV_FORMAL_IOADDR(addr) macro. Verification procedure - RISC-V Formal documentation
[6] Each causality check has a [depth] section expecting two values: the number of reset cycles and the execution depth. Verification procedure - RISC-V Formal documentation
[7] The standard checks (including the standard bus checks) are managed by genchecks.py. Verification procedure - RISC-V Formal documentation
[8] Causality checking is an application area of HyperLTL model checking, alongside information-flow control, robustness, mutation testing, and path planning. AutoHyper: Explicit-State Model Checking for HyperLTL
[9] The jMT tool constructs valid multi-execution semantics for concurrent Java programs via causality checking over single-execution graphs. jMT: Testing Correctness of Java Memory Models (Extended Version)