mirror of
https://github.com/YosysHQ/sby.git
synced 2025-08-09 23:00:53 +00:00
Support for "abc --keep-going pdr" via new "pdr -X" mode
This commit is contained in:
parent
52184e5bf0
commit
6ba762db4c
7 changed files with 258 additions and 79 deletions
|
@ -17,32 +17,101 @@
|
|||
#
|
||||
|
||||
import re, getopt
|
||||
import json
|
||||
from sby_core import SbyProc
|
||||
from sby_engine_aiger import aigsmt_exit_callback
|
||||
from sby_engine_aiger import aigsmt_exit_callback, aigsmt_trace_callback
|
||||
|
||||
|
||||
def abc_getopt(args, long):
|
||||
long = set(long)
|
||||
output = []
|
||||
parsed = []
|
||||
toggles = set()
|
||||
pos = 0
|
||||
|
||||
while pos < len(args):
|
||||
arg = args[pos]
|
||||
pos += 1
|
||||
if not arg.startswith('-'):
|
||||
output.append(arg)
|
||||
elif arg == '--':
|
||||
output.extend(args[pos:])
|
||||
break
|
||||
elif arg.startswith('--'):
|
||||
if '=' in arg:
|
||||
prefix, param = arg.split('=', 1)
|
||||
if prefix + "=" in long:
|
||||
parsed.append(prefix, param)
|
||||
elif arg[2:] in long:
|
||||
parsed.append((arg, ''))
|
||||
elif arg[2:] + "=" in long:
|
||||
parsed.append((arg, args[pos]))
|
||||
pos += 1
|
||||
else:
|
||||
output.append(arg)
|
||||
elif arg.startswith('-'):
|
||||
output.append(arg)
|
||||
for c in arg[1:]:
|
||||
if 'A' <= c <= 'Z':
|
||||
if pos < len(args):
|
||||
output.append(args[pos])
|
||||
pos += 1
|
||||
else:
|
||||
toggles.symmetric_difference_update([c])
|
||||
|
||||
return output, parsed, toggles
|
||||
|
||||
|
||||
def run(mode, task, engine_idx, engine):
|
||||
abc_opts, abc_command = getopt.getopt(engine[1:], "", [])
|
||||
keep_going = False
|
||||
|
||||
fold_command = "fold"
|
||||
if task.opt_aigfolds:
|
||||
fold_command += " -s"
|
||||
|
||||
abc_command, custom_options, toggles = abc_getopt(engine[1:], [
|
||||
"keep-going",
|
||||
])
|
||||
|
||||
if len(abc_command) == 0:
|
||||
task.error("Missing ABC command.")
|
||||
|
||||
for o, a in abc_opts:
|
||||
task.error("Unexpected ABC engine options.")
|
||||
if abc_command[0].startswith('-'):
|
||||
task.error(f"Unexpected ABC engine option '{abc_command[0]}'.")
|
||||
|
||||
if abc_command[0] == "bmc3":
|
||||
if mode != "bmc":
|
||||
task.error("ABC command 'bmc3' is only valid in bmc mode.")
|
||||
for o, a in custom_options:
|
||||
task.error(f"Option {o} not supported by 'abc {abc_command[0]}'")
|
||||
abc_command[0] += f" -F {task.opt_depth} -v"
|
||||
|
||||
elif abc_command[0] == "sim3":
|
||||
if mode != "bmc":
|
||||
task.error("ABC command 'sim3' is only valid in bmc mode.")
|
||||
for o, a in custom_options:
|
||||
task.error(f"Option {o} not supported by 'abc {abc_command[0]}'")
|
||||
abc_command[0] += f" -F {task.opt_depth} -v"
|
||||
|
||||
elif abc_command[0] == "pdr":
|
||||
if mode != "prove":
|
||||
task.error("ABC command 'pdr' is only valid in prove mode.")
|
||||
abc_command[0] += f" -v -I engine_{engine_idx}/invariants.pla"
|
||||
|
||||
for o, a in custom_options:
|
||||
if o == '--keep-going':
|
||||
keep_going = True
|
||||
else:
|
||||
task.error(f"Option {o} not supported by 'abc {abc_command[0]}'")
|
||||
|
||||
abc_command[0] += " -v"
|
||||
|
||||
if keep_going:
|
||||
abc_command += ["-a", "-X", f"engine_{engine_idx}/trace_"]
|
||||
|
||||
if 'd' in toggles:
|
||||
abc_command += ["-I", f"engine_{engine_idx}/invariants.pla"]
|
||||
if not task.opt_aigfolds:
|
||||
fold_command += " -s"
|
||||
|
||||
else:
|
||||
task.error(f"Invalid ABC command {abc_command[0]}.")
|
||||
|
@ -66,9 +135,8 @@ def run(mode, task, engine_idx, engine):
|
|||
task,
|
||||
f"engine_{engine_idx}",
|
||||
task.model("aig"),
|
||||
f"""cd {task.workdir}; {task.exe_paths["abc"]} -c 'read_aiger model/design_aiger.aig; fold{
|
||||
" -s" if task.opt_aigfolds or (abc_command[0].startswith("pdr ") and "-d" in abc_command[1:]) else ""
|
||||
}; strash; {" ".join(abc_command)}; write_cex -a engine_{engine_idx}/trace.aiw'""",
|
||||
f"""cd {task.workdir}; {task.exe_paths["abc"]} -c 'read_aiger model/design_aiger.aig; {
|
||||
fold_command}; strash; {" ".join(abc_command)}; write_cex -a engine_{engine_idx}/trace.aiw'""",
|
||||
logfile=open(f"{task.workdir}/engine_{engine_idx}/logfile.txt", "w")
|
||||
)
|
||||
proc.checkretcode = True
|
||||
|
@ -76,11 +144,42 @@ def run(mode, task, engine_idx, engine):
|
|||
proc.noprintregex = re.compile(r"^\.+$")
|
||||
proc_status = None
|
||||
|
||||
procs_running = 1
|
||||
|
||||
aiger_props = None
|
||||
disproved = []
|
||||
|
||||
def output_callback(line):
|
||||
nonlocal proc_status
|
||||
nonlocal procs_running
|
||||
nonlocal aiger_props
|
||||
|
||||
match = re.match(r"^Output [0-9]+ of miter .* was asserted in frame [0-9]+.", line)
|
||||
if match: proc_status = "FAIL"
|
||||
if keep_going and aiger_props is None:
|
||||
with open(f"{task.workdir}/model/design_aiger.ywa") as ywa_file:
|
||||
ywa = json.load(ywa_file)
|
||||
aiger_props = []
|
||||
for path in ywa["asserts"]:
|
||||
aiger_props.append(task.design.properties_by_path[tuple(path)])
|
||||
|
||||
if keep_going:
|
||||
match = re.match(r"Writing CEX for output ([0-9]+) to engine_[0-9]+/(.*)\.aiw", line)
|
||||
if match:
|
||||
output = int(match[1])
|
||||
prop = aiger_props[output]
|
||||
prop.status = "FAIL"
|
||||
|
||||
task.status_db.set_task_property_status(prop, data=dict(source="abc pdr", engine=f"engine_{engine_idx}"))
|
||||
disproved.append(output)
|
||||
proc_status = "FAIL"
|
||||
proc = aigsmt_trace_callback(task, engine_idx, proc_status,
|
||||
run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append,
|
||||
name=match[2],
|
||||
)
|
||||
proc.register_exit_callback(exit_callback)
|
||||
procs_running += 1
|
||||
else:
|
||||
match = re.match(r"^Output [0-9]+ of miter .* was asserted in frame [0-9]+.", line)
|
||||
if match: proc_status = "FAIL"
|
||||
|
||||
match = re.match(r"^Simulation of [0-9]+ frames for [0-9]+ rounds with [0-9]+ restarts did not assert POs.", line)
|
||||
if match: proc_status = "UNKNOWN"
|
||||
|
@ -94,11 +193,38 @@ def run(mode, task, engine_idx, engine):
|
|||
match = re.match(r"^Property proved.", line)
|
||||
if match: proc_status = "PASS"
|
||||
|
||||
if keep_going:
|
||||
match = re.match(r"^Properties: All = (\d+). Proved = (\d+). Disproved = (\d+). Undecided = (\d+).", line)
|
||||
if match:
|
||||
all_count = int(match[1])
|
||||
proved_count = int(match[2])
|
||||
disproved_count = int(match[3])
|
||||
undecided_count = int(match[4])
|
||||
if (
|
||||
all_count == len(aiger_props) and
|
||||
all_count == proved_count + disproved_count + undecided_count and
|
||||
disproved_count == len(disproved) and
|
||||
not undecided_count
|
||||
):
|
||||
for i, prop in enumerate(aiger_props):
|
||||
if i not in disproved:
|
||||
prop.status = "PASS"
|
||||
|
||||
return line
|
||||
|
||||
def exit_callback(retcode):
|
||||
aigsmt_exit_callback(task, engine_idx, proc_status,
|
||||
run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append, )
|
||||
nonlocal procs_running
|
||||
if keep_going:
|
||||
procs_running -= 1
|
||||
if not procs_running:
|
||||
if proc_status == "FAIL" and mode == "bmc" and keep_going:
|
||||
task.pass_unknown_asserts(dict(source="abc pdr", keep_going=True, engine=f"engine_{engine_idx}"))
|
||||
task.update_status(proc_status)
|
||||
task.summary.set_engine_status(engine_idx, proc_status)
|
||||
task.terminate()
|
||||
else:
|
||||
aigsmt_exit_callback(task, engine_idx, proc_status,
|
||||
run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append)
|
||||
|
||||
proc.output_callback = output_callback
|
||||
proc.register_exit_callback(exit_callback)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue