Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
fae48b8
Merge pull request #161 from keplertech/main
nanocoh Jul 15, 2026
59cff31
reproduce with unit test
nanocoh Jul 15, 2026
df443e8
remove size nobs and fix X init
nanocoh Jul 15, 2026
1c91a01
fix unit test
nanocoh Jul 15, 2026
5f69217
strict F[0]
nanocoh Jul 15, 2026
a654311
status update and unit test fixing
nanocoh Jul 15, 2026
c1d07ae
unit test fixing
nanocoh Jul 15, 2026
9b39748
opt from PDR article + reset cache
nanocoh Jul 15, 2026
7185a43
opt from PDR article + reset cache
nanocoh Jul 15, 2026
088ed8c
flags in readme + updating workflows
nanocoh Jul 15, 2026
d81d98e
update flags
nanocoh Jul 16, 2026
96b2804
fix(sec): classify dual-rail X mismatches as inconclusive
nanocoh Jul 16, 2026
fa762f0
fix(sec): reuse exact F[0] solvers across PDR batches
nanocoh Jul 16, 2026
edcfc1e
remove timeout from tr test
nanocoh Jul 16, 2026
c9058a9
wip(sec): add initialization-aware dual-rail PDR age discovery
nanocoh Jul 17, 2026
f6fc20e
Merge origin/main into remove-internal-relations-between-designs
nanocoh Jul 17, 2026
7d7a03c
Make SEC PDR age discovery opt-in
nanocoh Jul 17, 2026
8c72d18
unit test fix
nanocoh Jul 18, 2026
62271d7
fix najaeda version
nanocoh Jul 18, 2026
8d1c5e3
speed up pdr dual rail
nanocoh Jul 18, 2026
9aebc4f
speed up dual-rail PDR with exact query caches
nanocoh Jul 19, 2026
6237d57
speed up exact dual-rail PDR query preparation
nanocoh Jul 19, 2026
ea20fc7
fix unit test
nanocoh Jul 19, 2026
c5f5b9f
Align dual-rail SEC output proof semantics
nanocoh Jul 20, 2026
d92e5e9
perf(sec): unblock exact dual-rail PDR residual proofs
nanocoh Jul 20, 2026
7a7619b
perf(sec): share exact F[0] solver across PDR queries
nanocoh Jul 20, 2026
c327e2a
perf(sec): reuse exact PDR solver state
nanocoh Jul 21, 2026
cb47217
fix(sec): preserve exact PDR predecessor solves
nanocoh Jul 21, 2026
34ba3dc
Restore exact PDR reuse and use singleton dual-rail batches
nanocoh Jul 21, 2026
f711a12
Use adaptive batching for dual-rail PDR
nanocoh Jul 21, 2026
786bd4d
fix(sec): preserve exact PDR across adaptive batches
nanocoh Jul 22, 2026
c76cdfe
fix(sec): separate dual-rail PDR mismatch and definedness proofs
nanocoh Jul 22, 2026
b8f7627
test(sec): align CLI expectations with definedness proofs
nanocoh Jul 22, 2026
5b96366
fix(sec): integrate dual-rail definedness into PDR
nanocoh Jul 22, 2026
4665539
fix(sec): use steady-state dual-rail equivalence only
nanocoh Jul 23, 2026
0c9cb77
perf(sec): reuse exact PDR frames across output batches
nanocoh Jul 23, 2026
7ee39dd
fix(sec): certify PDR invariants before cross-batch reuse
nanocoh Jul 23, 2026
67cec5b
perf(sec): reduce PDR predecessor query overhead
nanocoh Jul 23, 2026
63d9743
Speed up PDR generalization with narrow SAT probes
nanocoh Jul 23, 2026
69a7cd5
perf(sec): reuse PDR invariant certification solvers
nanocoh Jul 23, 2026
9b77f1e
fix(sec): bound PDR batch memory ownership
nanocoh Jul 24, 2026
5806fb4
fix(sec): bound dual-rail PDR singleton SAT work
nanocoh Jul 25, 2026
9541015
perf(sec): bound cumulative PDR invariant certification
nanocoh Jul 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/cva6imc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
export HPDCACHE_DIR="$PWD/core/cache_subsystem/hpdcache"
export TARGET_CFG="cv64a6_imafdc_sv39"
export LD_LIBRARY_PATH="${{github.workspace}}/stage/lib:${LD_LIBRARY_PATH}"
set +e
"${{github.workspace}}/stage/bin/kepler-formal" -systemverilog \
--compact \
-v sec \
Expand All @@ -74,4 +75,12 @@ jobs:
--sv_design1_flist "$PWD/core/Flist.cva6" \
--sv_design1_top cva6 \
--sv_design2_flist "$PWD/core/Flist.cva6" \
--sv_design2_top cva6
--sv_design2_top cva6 2>&1 | tee "${RUNNER_TEMP}/cva6-imc.log"
status=${PIPESTATUS[0]}
set -e
# Positive self-SEC accepts a proved or explicitly partial verdict.
if [[ "${status}" -eq 1 ]] &&
grep -q "SEC partially proved equivalence" "${RUNNER_TEMP}/cva6-imc.log"; then
exit 0
fi
exit "${status}"
11 changes: 10 additions & 1 deletion .github/workflows/cva6ki.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
export HPDCACHE_DIR="$PWD/core/cache_subsystem/hpdcache"
export TARGET_CFG="cv64a6_imafdc_sv39"
export LD_LIBRARY_PATH="${{github.workspace}}/stage/lib:${LD_LIBRARY_PATH}"
set +e
"${{github.workspace}}/stage/bin/kepler-formal" -systemverilog \
--compact \
-v sec \
Expand All @@ -74,4 +75,12 @@ jobs:
--sv_design1_flist "$PWD/core/Flist.cva6" \
--sv_design1_top cva6 \
--sv_design2_flist "$PWD/core/Flist.cva6" \
--sv_design2_top cva6
--sv_design2_top cva6 2>&1 | tee "${RUNNER_TEMP}/cva6-ki.log"
status=${PIPESTATUS[0]}
set -e
# Positive self-SEC accepts a proved or explicitly partial verdict.
if [[ "${status}" -eq 1 ]] &&
grep -q "SEC partially proved equivalence" "${RUNNER_TEMP}/cva6-ki.log"; then
exit 0
fi
exit "${status}"
11 changes: 10 additions & 1 deletion .github/workflows/cva6pdr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
export HPDCACHE_DIR="$PWD/core/cache_subsystem/hpdcache"
export TARGET_CFG="cv64a6_imafdc_sv39"
export LD_LIBRARY_PATH="${{github.workspace}}/stage/lib:${LD_LIBRARY_PATH}"
set +e
"${{github.workspace}}/stage/bin/kepler-formal" -systemverilog \
--compact \
-v sec \
Expand All @@ -74,4 +75,12 @@ jobs:
--sv_design1_flist "$PWD/core/Flist.cva6" \
--sv_design1_top cva6 \
--sv_design2_flist "$PWD/core/Flist.cva6" \
--sv_design2_top cva6
--sv_design2_top cva6 2>&1 | tee "${RUNNER_TEMP}/cva6-pdr.log"
status=${PIPESTATUS[0]}
set -e
# Positive self-SEC accepts a proved or explicitly partial verdict.
if [[ "${status}" -eq 1 ]] &&
grep -q "SEC partially proved equivalence" "${RUNNER_TEMP}/cva6-pdr.log"; then
exit 0
fi
exit "${status}"
2 changes: 1 addition & 1 deletion .github/workflows/regress-imc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ jobs:
sec-encoding=${{ env.SEC_ENCODING }}

- name: Install najaeda
run: pip install najaeda
run: pip install najaeda==0.7.15

- name: Generate TinyRocket edited and CSRFile SEC examples
working-directory: ${{github.workspace}}/example
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/regress-ki.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ jobs:
sec-encoding=${{ env.SEC_ENCODING }}

- name: Install najaeda
run: pip install najaeda
run: pip install najaeda==0.7.15

- name: Generate TinyRocket edited and CSRFile SEC examples
working-directory: ${{github.workspace}}/example
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/regress-lec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
regress/tinyrocket_verilog/config.yaml

- name: Install najaeda
run: pip install najaeda
run: pip install najaeda==0.7.15

- name: Execute edit.py
working-directory: ${{github.workspace}}/example
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/regress-pdr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ env:
SEC_ENGINE: pdr
SEC_ENCODING: ${{ inputs.sec_encoding || 'binary' }}
SKIP_BP_FINAL: ${{ inputs.skip_bp_final || false }}
# Binary PDR regressions allow inconclusive positive proofs and the
# reset-unanchored no-output case. Dual-rail PDR stays strict.
SEC_POSITIVE_EXPECTATION: ${{ (inputs.sec_encoding || 'binary') == 'dual_rail_steady' && 'expect-equivalent' || 'allow-unset-state-inconclusive' }}
SEC_FULL_COVERAGE_EXPECTATION: ${{ inputs.require_full_coverage && 'expect-full-coverage' || ((inputs.sec_encoding || 'binary') == 'dual_rail_steady' && 'expect-equivalent' || 'allow-unset-state-inconclusive') }}
# Binary PDR regressions also allow the reset-unanchored no-output case.
# Dual-rail positive regressions accept a partial proof, but not a fully
# inconclusive result; explicit full-coverage runs remain strict.
SEC_POSITIVE_EXPECTATION: ${{ (inputs.sec_encoding || 'binary') == 'dual_rail_steady' && 'expect-equivalent-or-partial' || 'allow-unset-state-inconclusive' }}
SEC_FULL_COVERAGE_EXPECTATION: ${{ inputs.require_full_coverage && 'expect-full-coverage' || ((inputs.sec_encoding || 'binary') == 'dual_rail_steady' && 'expect-equivalent-or-partial' || 'allow-unset-state-inconclusive') }}

jobs:
build:
Expand Down Expand Up @@ -247,7 +248,7 @@ jobs:
sec-encoding=${{ env.SEC_ENCODING }}

- name: Install najaeda
run: pip install najaeda
run: pip install najaeda==0.7.15

- name: Generate TinyRocket edited and CSRFile SEC examples
working-directory: ${{github.workspace}}/example
Expand Down
48 changes: 40 additions & 8 deletions .github/workflows/regress-sec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,26 @@ jobs:
cmake -B ${{github.workspace}}/build-sec-regress \
-GNinja \
-DPYTHON_INTERFACE=OFF \
-DENABLE_UNIT_TESTS=OFF \
-DENABLE_UNIT_TESTS=ON \
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/stage \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_CXX_FLAGS="-O3 -ffast-math -flto -DNDEBUG" \
-DCMAKE_CXX_FLAGS_RELEASE="-Ofast -ffast-math -flto -DNDEBUG" \
-DCMAKE_EXE_LINKER_FLAGS="-flto"

- name: Build and install kepler-formal runtime
- name: Build kepler-formal and unit tests
run: cmake --build ${{github.workspace}}/build-sec-regress --config Release

- name: Run unit tests
run: |
ctest --test-dir ${{github.workspace}}/build-sec-regress \
--output-on-failure \
--no-tests=error \
-E ".*[p|P]ython.*" \
-C Release

- name: Install kepler-formal runtime
run: |
cmake --build ${{github.workspace}}/build-sec-regress --target install --config Release
chmod +x ${{github.workspace}}/stage/bin/kepler-formal
Expand Down Expand Up @@ -94,14 +105,16 @@ jobs:
- name: pdr-dual-rail
engine: pdr
sec_encoding: dual_rail_steady
positive_expectation: expect-equivalent
full_coverage_expectation: expect-full-coverage
positive_expectation: expect-equivalent-or-partial
full_coverage_expectation: expect-equivalent-or-partial
case:
- name: cts_aes_asap7_base
source: regress
case_dir: kepler-formal-regress/cts_aes_asap7_base
config: objects/asap7/aes/base/4_rsz_lec_test.yml
expectation: positive
# Both dual-rail IMC and KI are inconclusive on this design.
pdr_dual_rail_expectation: allow-inconclusive
- name: sky130hd_gcd
source: regress
case_dir: kepler-formal-regress/sky130hd_gcd
Expand All @@ -122,6 +135,7 @@ jobs:
case_dir: kepler-formal-examples/nangate45_dynamic_node
config: 6_final_sec_test.yml
expectation: positive
pdr_dual_rail_expectation: allow-inconclusive
- name: asap7_jpeg_lvt
source: examples
case_dir: kepler-formal-examples/asap7_jpeg_lvt
Expand Down Expand Up @@ -167,11 +181,13 @@ jobs:
case_dir: kepler-formal-examples/asap7_mock-alu
config: 6_final_sec_test.yml
expectation: positive
pdr_dual_rail_expectation: allow-inconclusive
- name: asap7_mock_cpu
source: examples
case_dir: kepler-formal-examples/asap7_mock_cpu
config: 6_final_sec_test.yml
expectation: positive
pdr_dual_rail_expectation: allow-inconclusive
- name: nangate45_black_parrot_sec_final
source: examples
case_dir: kepler-formal-examples/nangate45_black_parrot_sec_final
Expand Down Expand Up @@ -258,7 +274,7 @@ jobs:
env:
CASE_GENERATOR: ${{ matrix.case.generator }}
run: |
pip install najaeda
pip install najaeda==0.7.15
case "${CASE_GENERATOR}" in
csrfile)
python extract_tinyrocket_csrfile_sec.py
Expand All @@ -280,6 +296,7 @@ jobs:
CASE_CONFIG: ${{ matrix.case.config }}
CASE_EXPECTATION: ${{ matrix.case.expectation }}
CASE_MAX_K: ${{ matrix.case.max_k }}
CASE_PDR_DUAL_RAIL_EXPECTATION: ${{ matrix.case.pdr_dual_rail_expectation }}
SEC_ENGINE: ${{ matrix.flow.engine }}
SEC_ENCODING: ${{ matrix.flow.sec_encoding }}
SEC_POSITIVE_EXPECTATION: ${{ matrix.flow.positive_expectation }}
Expand All @@ -297,6 +314,11 @@ jobs:
expectation="${SEC_FULL_COVERAGE_EXPECTATION}"
;;
esac
if [[ "${SEC_ENGINE}" == "pdr" &&
"${SEC_ENCODING}" == "dual_rail_steady" &&
-n "${CASE_PDR_DUAL_RAIL_EXPECTATION}" ]]; then
expectation="${CASE_PDR_DUAL_RAIL_EXPECTATION}"
fi

args=(
"${CASE_NAME}"
Expand Down Expand Up @@ -355,7 +377,7 @@ jobs:
- name: pdr-dual-rail
engine: pdr
sec_encoding: dual_rail_steady
positive_expectation: expect-equivalent
positive_expectation: expect-equivalent-or-partial
case:
# TODO: Re-enable after pending Naja SV2V frontend fixes land.
# - name: sv2v_asap7_aes_mbff
Expand Down Expand Up @@ -419,6 +441,8 @@ jobs:
case_dir: kepler-formal-examples/nangate45_black_parrot
config_prefix: sv2v
expectation: positive
# Corrected dual-rail IMC and KI have no strict output proof here.
pdr_dual_rail_expectation: allow-inconclusive
- name: sv2v_nangate45_black_parrot_sec_final
case_dir: kepler-formal-examples/nangate45_black_parrot_sec_final
config_prefix: sv2v
Expand Down Expand Up @@ -446,6 +470,8 @@ jobs:
case_dir: kepler-formal-examples/sky130hd_gcd
config_prefix: sv2v
expectation: positive
# Corrected dual-rail IMC and KI have no strict output proof here.
pdr_dual_rail_expectation: allow-inconclusive
# TODO: Re-enable after SV2V example config is fixed in regress.
# - name: sv2v_sky130hd_riscv32i
# case_dir: kepler-formal-examples/sky130hd_riscv32i
Expand All @@ -467,7 +493,7 @@ jobs:
name: pdr-dual-rail
engine: pdr
sec_encoding: dual_rail_steady
positive_expectation: expect-equivalent
positive_expectation: expect-equivalent-or-partial
case:
name: sv2v_nangate45_bp_be
case_dir: kepler-formal-examples/nangate45_bp_be
Expand Down Expand Up @@ -504,6 +530,7 @@ jobs:
CASE_DIR: ${{ matrix.case.case_dir }}
CASE_CONFIG_PREFIX: ${{ matrix.case.config_prefix }}
CASE_EXPECTATION: ${{ matrix.case.expectation }}
CASE_PDR_DUAL_RAIL_EXPECTATION: ${{ matrix.case.pdr_dual_rail_expectation }}
SEC_ENGINE: ${{ matrix.flow.engine }}
SEC_ENCODING: ${{ matrix.flow.sec_encoding }}
SEC_POSITIVE_EXPECTATION: ${{ matrix.flow.positive_expectation }}
Expand All @@ -516,6 +543,11 @@ jobs:
if [[ "${expectation}" == "positive" ]]; then
expectation="${SEC_POSITIVE_EXPECTATION}"
fi
if [[ "${SEC_ENGINE}" == "pdr" &&
"${SEC_ENCODING}" == "dual_rail_steady" &&
-n "${CASE_PDR_DUAL_RAIL_EXPECTATION}" ]]; then
expectation="${CASE_PDR_DUAL_RAIL_EXPECTATION}"
fi

if [[ "${SEC_ENGINE}" == "pdr" && "${SEC_ENCODING}" == "dual_rail_steady" ]]; then
case_config="${CASE_CONFIG_PREFIX}_sec_test.yml"
Expand Down Expand Up @@ -614,7 +646,7 @@ jobs:
set -euo pipefail
export LD_LIBRARY_PATH="${{github.workspace}}/stage/lib:${LD_LIBRARY_PATH:-}"

pip install najaeda
pip install najaeda==0.7.15

cleanup_negative_edit() {
(
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ Bazel build notes, dependency details, release flow, and the BCR publication roa

The full binary and YAML flag reference is tracked in [docs/flags-spec.md](docs/flags-spec.md). SEC-specific flags, engine behavior, encoding defaults, and skipped-output reports are documented in [docs/sec-flags-spec.md](docs/sec-flags-spec.md).

### SEC Result Codes

| Result | Exit code | Meaning |
| --- | ---: | --- |
| Proved | `0` | All checked outputs were proved equivalent. |
| Partially proved | `1` | Some outputs were proved; all remaining outputs are inconclusive. |
| Inconclusive | `2` | SEC produced neither a proof nor a counterexample. |
| Counterexample found | `3` | A definitive mismatch was found. |

These codes describe completed SEC verdicts. Configuration, input, or runtime
errors are execution failures rather than SEC verdicts.

### Binary Flags

```bash
Expand Down
20 changes: 14 additions & 6 deletions docs/sec-flags-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ liberty_files:
| CLI flag | YAML key | Default | Values | Effect |
| --- | --- | --- | --- | --- |
| `-v sec`, `--verification sec` | `verification: sec` | `lec` | `lec`, `sec` | Selects SEC instead of combinational LEC. Values are lowercase. |
| `-k <n>`, `--max-k <n>` | `max_k: <n>` | `32` | Non-negative integer | Sets the maximum SEC proof/search bound used by the selected engine. `0` is valid and only permits zero-bound checks. |
| `-k <n>`, `--max-k <n>` | `max_k: <n>` | `32` | Non-negative integer | Sets the SEC proof/search bound. |
| `--sec-engine <engine>` | `sec_engine: <engine>` | `pdr` | `k_induction`, `imc`, `pdr` | Selects the top-level SEC proof engine. Engine names are lowercase. |
| `--sec-encoding <mode>` | `sec_encoding: <mode>` | `dual_rail_steady` | `binary`, `dual_rail_steady` | Selects how SEC models unknown or reset-unanchored state values. Omit the key/flag to use the dual-rail default. |
| `--sec-uncomputable-seq-boundary` | `sec_uncomputable_seq_as_boundary: true` | `true` | boolean | Abstracts unsupported sequential instances as SEC boundaries instead of failing immediately. |
Expand Down Expand Up @@ -132,7 +132,7 @@ flows that require stable behavior should always spell out either `binary` or
| --- | --- |
| `k_induction` | Explicit classic k-induction flow: bounded base-case search followed by induction-step proof over the extracted SEC transition system. |
| `imc` | Interpolation-Based Model Checking flow over the same extracted SEC problem. It uses the shared base-case search and exact interpolant strengthening where applicable. |
| `pdr` | Property Directed Reachability flow over the extracted SEC transition system. It first accepts immediate zero-bound k-induction results, then runs PDR frames up to `max_k`. |
| `pdr` | Property Directed Reachability flow over the extracted SEC transition system. |

All engines use the same extracted SEC model: aligned environment inputs,
state bits, observed outputs, next-state formulas, initial-state information,
Expand All @@ -148,14 +148,22 @@ heuristics.

`max_k` is parsed as a non-negative integer.

In `dual_rail_steady`, `01` represents binary zero, `10` represents binary one,
and `11` represents X. All three engines prove the same steady-state property:
a bad state exists only when both designs' outputs are binary-defined and
opposite. Cycles where either output is X are outside this property. A proof in
this encoding therefore establishes equivalence under the steady-state
abstraction; it does not establish that either output becomes binary-defined.

SEC result handling is currently:

| Result | Exit code | Meaning |
| --- | --- | --- |
| Equivalent | `0` | SEC proved equivalence at the reported bound. |
| Different | `0` | SEC found a concrete counterexample at the reported bound. |
| Inconclusive | non-zero | The selected engine reached `max_k` without a proof or counterexample. |
| Unsupported | non-zero | The extracted model was incomplete or unsupported for SEC. |
| Proved | `0` | All checked outputs were proved equivalent. |
| Partially proved | `1` | Some outputs were proved; all remaining outputs are inconclusive. |
| Inconclusive | `2` | SEC produced neither a proof nor a counterexample. |
| Counterexample found | `3` | SEC found a definitive mismatch. |
| Unsupported | `2` | The extracted model was incomplete or unsupported for SEC. |

The log always prints:

Expand Down
Loading
Loading