mirror of
https://github.com/YosysHQ/sby.git
synced 2026-03-31 20:19:03 +00:00
113 lines
No EOL
4.2 KiB
Python
113 lines
No EOL
4.2 KiB
Python
#
|
|
# SymbiYosys (sby) -- Front-end for Yosys-based formal verification flows
|
|
# ITP engine: interpolation-based model checking using Craig interpolants
|
|
#
|
|
# Contributor: Pratik Deshmukh <deshmukhpratik931@gmail.com>
|
|
#
|
|
# Permission to use, copy, modify, and/or distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
#
|
|
# Usage in .sby file:
|
|
# [engines]
|
|
# itp [bound] [skip]
|
|
#
|
|
# bound: maximum unrolling depth (default: task opt_depth or 20)
|
|
# skip: number of initial timeframes to skip before checking bad states
|
|
# (default: task opt_skip or 0)
|
|
#
|
|
# The engine uses the 'itp-bmc' binary which must be either:
|
|
# 1. Available in PATH as 'itp-bmc'
|
|
# 2. Specified via the ITP_BMC environment variable
|
|
#
|
|
# Note: This engine currently does not produce counterexample witness traces.
|
|
# When a property violation is found (FAIL), no .aiw or .yw trace file is
|
|
# generated. Trace generation support is planned for a future version.
|
|
#
|
|
|
|
import os, getopt
|
|
from sby_core import SbyProc
|
|
|
|
def run(mode, task, engine_idx, engine):
|
|
if mode not in ["prove", "bmc"]:
|
|
task.error(f"engine_{engine_idx}: The itp engine is only supported in prove and bmc modes.")
|
|
|
|
# Parse options
|
|
args = engine[1:]
|
|
|
|
# Defaults from task options
|
|
bound = task.opt_depth
|
|
skip = task.opt_skip
|
|
|
|
# Positional args override: itp [bound] [skip]
|
|
if len(args) > 0:
|
|
try:
|
|
bound = int(args[0])
|
|
except ValueError:
|
|
task.error(f"engine_{engine_idx}: Invalid bound value '{args[0]}', expected integer.")
|
|
if len(args) > 1:
|
|
try:
|
|
skip = int(args[1])
|
|
except ValueError:
|
|
task.error(f"engine_{engine_idx}: Invalid skip value '{args[1]}', expected integer.")
|
|
if len(args) > 2:
|
|
task.error(f"engine_{engine_idx}: Too many arguments to itp engine.")
|
|
|
|
if skip >= bound:
|
|
task.error(f"engine_{engine_idx}: skip ({skip}) must be less than bound ({bound}).")
|
|
|
|
# Locate binary and derive workdir (for minisat relative path)
|
|
bmc_binary = task.exe_paths["itp-bmc"]
|
|
bmc_workdir = os.path.dirname(os.path.realpath(bmc_binary))
|
|
|
|
log = task.log_prefix(f"engine_{engine_idx}")
|
|
|
|
# Input: binary AIGER model generated by sby
|
|
aig_src = f"{task.workdir}/model/design_aiger.aig"
|
|
|
|
log(f"Running interpolation-based model checker: bound={bound}, skip={skip}")
|
|
|
|
proc_status = None
|
|
|
|
def output_callback(line):
|
|
nonlocal proc_status
|
|
if "Fixpoint reached" in line:
|
|
log("Interpolation fixpoint reached — property proved SAFE")
|
|
proc_status = "PASS"
|
|
elif "Counterexample found" in line:
|
|
log("Counterexample found — property UNSAFE")
|
|
elif "Safe up to bound" in line:
|
|
log(f"Bounded safety result (fixpoint not reached): {line.strip()}")
|
|
proc_status = "PASS"
|
|
return line
|
|
|
|
def exit_callback(retcode):
|
|
nonlocal proc_status
|
|
|
|
# If output_callback already determined status (e.g. from output lines),
|
|
# trust that over the exit code
|
|
if proc_status is None:
|
|
proc_status = "PASS" if retcode == 0 else "FAIL"
|
|
|
|
task.update_status(proc_status)
|
|
task.summary.set_engine_status(engine_idx, proc_status)
|
|
task.terminate()
|
|
|
|
proc = SbyProc(
|
|
task,
|
|
f"engine_{engine_idx}",
|
|
task.model("aig"),
|
|
f"BMC_WORKDIR={bmc_workdir} {bmc_binary} {bound} {aig_src} {skip}",
|
|
logfile=open(f"{task.workdir}/engine_{engine_idx}/logfile.txt", "w"),
|
|
)
|
|
|
|
proc.output_callback = output_callback
|
|
proc.register_exit_callback(exit_callback) |