3
0
Fork 0
mirror of https://github.com/YosysHQ/sby.git synced 2025-07-18 04:26:44 +00:00

add btor cover mode; use btorsim for vcd generation

Signed-off-by: N. Engelhardt <nak@symbioticeda.com>
This commit is contained in:
N. Engelhardt 2020-03-25 15:53:55 +01:00
parent 6a918fe102
commit 180e07f9c4
3 changed files with 73 additions and 68 deletions

View file

@ -29,7 +29,7 @@ def run(mode, job, engine_idx, engine):
job.error("Unexpected BTOR engine options.")
if solver_args[0] == "btormc":
solver_cmd = job.exe_paths["btormc"] + " --stop-first -v 1 -kmax {}".format(job.opt_depth - 1)
solver_cmd = job.exe_paths["btormc"] + " --stop-first {} -v 1 -kmax {}".format(0 if mode == "cover" else 1, job.opt_depth - 1)
if job.opt_skip is not None:
solver_cmd += " -kmin {}".format(job.opt_skip)
solver_cmd += " ".join([""] + solver_args[1:])
@ -41,24 +41,39 @@ def run(mode, job, engine_idx, engine):
"cd {}; {} model/design_btor.btor".format(job.workdir, solver_cmd),
logfile=open("{}/engine_{}/logfile.txt".format(job.workdir, engine_idx), "w"))
task_status = None
produced_cex = False
end_of_cex = False
wit_file = open("{}/engine_{}/trace.wit".format(job.workdir, engine_idx), "w")
solver_status = None
produced_cex = 0
expected_cex = 1
wit_file = None
def output_callback(line):
nonlocal task_status
nonlocal solver_status
nonlocal produced_cex
nonlocal end_of_cex
nonlocal expected_cex
nonlocal wit_file
if not end_of_cex and not produced_cex and line == "sat":
produced_cex = True
task_status = "FAIL"
if mode == "cover":
match = re.search(r"calling BMC on ([0-9]+) properties", line)
if match:
expected_cex = int(match[1])
assert expected_cex > 0
assert produced_cex == 0
if produced_cex and not end_of_cex:
if (produced_cex < expected_cex) and line == "sat":
assert wit_file == None
if expected_cex == 1:
wit_file = open("{}/engine_{}/trace.wit".format(job.workdir, engine_idx), "w")
else:
wit_file = open("{}/engine_{}/trace{}.wit".format(job.workdir, engine_idx, produced_cex), "w")
if wit_file:
print(line, file=wit_file)
if line == ".":
end_of_cex = True
produced_cex += 1
wit_file.close()
wit_file = None
if produced_cex == expected_cex:
solver_status = "sat"
if line.startswith("u"):
return "No CEX up to depth {}.".format(int(line[1:])-1)
@ -71,22 +86,32 @@ def run(mode, job, engine_idx, engine):
if "bad state properties at bound" in line:
return line
if "deleting model checker:" in line:
if task_status is None:
task_status = "PASS"
if solver_status is None:
solver_status = "unsat"
return line
if not produced_cex or end_of_cex:
if not wit_file:
print(line, file=task.logfile)
return None
def exit_callback(retcode):
assert retcode == 0
assert task_status is not None
assert solver_status is not None
if task_status == "PASS":
print("unsat", file=wit_file)
wit_file.close()
if solver_status == "unsat":
if expected_cex == 1:
with open("{}/engine_{}/trace.wit".format(job.workdir, engine_idx), "w") as wit_file:
print("unsat", file=wit_file)
else:
for i in range(produced_cex, expected_cex):
with open("{}/engine_{}/trace{}.wit".format(job.workdir, engine_idx, i), "w") as wit_file:
print("unsat", file=wit_file)
if mode == "cover":
task_status = "PASS" if solver_status == "sat" else "FAIL"
else:
task_status = "FAIL" if solver_status == "sat" else "PASS"
job.update_status(task_status)
job.log("engine_{}: Status returned by engine: {}".format(engine_idx, task_status))
@ -94,66 +119,42 @@ def run(mode, job, engine_idx, engine):
job.terminate()
if task_status == "FAIL" and job.opt_aigsmt != "none":
if produced_cex:
has_arrays = False
if produced_cex == 0:
job.log("engine_{}: Engine did not produce a counter example.".format(engine_idx))
elif produced_cex == 1:
task2 = SbyTask(job, "engine_{}".format(engine_idx), job.model("btor"),
"cd {dir}; btorsim -c --vcd engine_{idx}/trace.vcd --hierarchical-symbols model/design_btor.btor engine_{idx}/trace.wit".format(dir=job.workdir, idx=engine_idx),
logfile=open("{dir}/engine_{idx}/logfile2.txt".format(dir=job.workdir, idx=engine_idx), "w"))
with open("{}/model/design_btor.btor".format(job.workdir), "r") as f:
for line in f:
line = line.split()
if len(line) == 5 and line[1] == "sort" and line[2] == "array":
has_arrays = True
break
def output_callback2(line):
return line
if has_arrays:
setupcmd = "cd {};".format(job.workdir)
finalwit = "engine_{}/trace.wit".format(engine_idx)
else:
setupcmd = "cd {}; { echo sat; btorsim --states model/design_btor.btor engine_{i}/trace.wit; } > engine_{i}/simtrace.wit &&".format(job.workdir, i=engine_idx)
finalwit = "engine_{}/simtrace.wit".format(engine_idx)
def exit_callback2(line):
assert retcode == 0
if mode == "live":
task2 = SbyTask(job, "engine_{}".format(engine_idx), job.model("smt2"),
("{} {} -g -s {}{} --noprogress --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
"--dump-smtc engine_{i}/trace.smtc --btorwit {} model/design_smt2.smt2").format(setupcmd, job.exe_paths["smtbmc"], job.opt_aigsmt, "" if job.opt_tbtop is None else " --vlogtb-top {}".format(job.opt_tbtop), finalwit, i=engine_idx),
logfile=open("{}/engine_{}/logfile2.txt".format(job.workdir, engine_idx), "w"))
else:
task2 = SbyTask(job, "engine_{}".format(engine_idx), job.model("smt2"),
("{} {} -s {}{} --noprogress --append {} --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
"--dump-smtc engine_{i}/trace.smtc --btorwit {} model/design_smt2.smt2").format
(setupcmd, job.exe_paths["smtbmc"], job.opt_aigsmt,
"" if job.opt_tbtop is None else " --vlogtb-top {}".format(job.opt_tbtop),
job.opt_append, finalwit, i=engine_idx),
logfile=open("{}/engine_{}/logfile2.txt".format(job.workdir, engine_idx), "w"))
if os.path.exists("{}/engine_{}/trace.vcd".format(job.workdir, engine_idx)):
job.summary.append("counterexample trace: {}/engine_{}/trace.vcd".format(job.workdir, engine_idx))
task2_status = None
task2.output_callback = output_callback2
task2.exit_callback = exit_callback2
else:
for i in range(produced_cex):
task2 = SbyTask(job, "engine_{}".format(engine_idx), job.model("btor"),
"cd {dir}; btorsim -c --vcd engine_{idx}/trace{i}.vcd --hierarchical-symbols model/design_btor.btor engine_{idx}/trace{i}.wit".format(dir=job.workdir, idx=engine_idx, i=i),
logfile=open("{dir}/engine_{idx}/logfile{}.txt".format(i+2, dir=job.workdir, idx=engine_idx), "w"))
def output_callback2(line):
nonlocal task2_status
match = re.match(r"^## [0-9: ]+ Status: FAILED", line)
if match: task2_status = "FAIL"
match = re.match(r"^## [0-9: ]+ Status: PASSED", line)
if match: task2_status = "PASS"
return line
def exit_callback2(line):
assert task2_status is not None
if mode == "live":
assert task2_status == "PASS"
else:
assert task2_status == "FAIL"
assert retcode == 0
if os.path.exists("{}/engine_{}/trace.vcd".format(job.workdir, engine_idx)):
job.summary.append("counterexample trace: {}/engine_{}/trace.vcd".format(job.workdir, engine_idx))
if os.path.exists("{}/engine_{}/trace{}.vcd".format(job.workdir, engine_idx, i)):
job.summary.append("counterexample trace: {}/engine_{}/trace{}.vcd".format(job.workdir, engine_idx, i))
task2.output_callback = output_callback2
task2.exit_callback = exit_callback2
else:
job.log("engine_{}: Engine did not produce a counter example.".format(engine_idx))
task.output_callback = output_callback
task.exit_callback = exit_callback