mirror of
https://github.com/YosysHQ/sby.git
synced 2025-04-05 14:04:07 +00:00
Merge pull request #210 from jix/witness_flow
Updated formal flow with new witness format
This commit is contained in:
commit
9a14f4d238
|
@ -153,6 +153,12 @@ options are:
|
|||
| ``tbtop`` | All | The top module for generated Verilog test benches, as |
|
||||
| | | hierarchical path relative to the design top module. |
|
||||
+------------------+------------+---------------------------------------------------------+
|
||||
| ``make_model`` | All | Force generation of the named formal models. Takes a |
|
||||
| | | comma-separated list of model names. For a model |
|
||||
| | | ``<name>`` this will generate the |
|
||||
| | | ``model/design_<name>.*`` files within the working |
|
||||
| | | directory, even when not required to run the task. |
|
||||
+------------------+------------+---------------------------------------------------------+
|
||||
| ``smtc`` | ``bmc``, | Pass this ``.smtc`` file to the smtbmc engine. All |
|
||||
| | ``prove``, | other engines are disabled when this option is used. |
|
||||
| | ``cover`` | Default: None |
|
||||
|
@ -340,6 +346,15 @@ solvers:
|
|||
Solver options are passed as additional arguments to the ABC command
|
||||
implementing the solver.
|
||||
|
||||
|
||||
``none`` engine
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The ``none`` engine does not run any solver. It can be used together with the
|
||||
``make_model`` option to manually generate any model supported by one of the
|
||||
other engines. This makes it easier to use the same models outside of sby.
|
||||
|
||||
|
||||
Script section
|
||||
--------------
|
||||
|
||||
|
|
|
@ -391,7 +391,7 @@ class SbyAutotune:
|
|||
else:
|
||||
self.task.copy_src()
|
||||
|
||||
self.model(None, "base")
|
||||
self.model(None, "prep")
|
||||
self.task.taskloop.run()
|
||||
|
||||
if self.task.status == "ERROR":
|
||||
|
|
|
@ -81,6 +81,7 @@ class SbyProc:
|
|||
self.linebuffer = ""
|
||||
self.logstderr = logstderr
|
||||
self.silent = silent
|
||||
self.wait = False
|
||||
|
||||
self.task.update_proc_pending(self)
|
||||
|
||||
|
@ -130,7 +131,7 @@ class SbyProc:
|
|||
self.error_callback(retcode)
|
||||
|
||||
def terminate(self, timeout=False):
|
||||
if self.task.opt_wait and not timeout:
|
||||
if (self.task.opt_wait or self.wait) and not timeout:
|
||||
return
|
||||
if self.running:
|
||||
if not self.silent:
|
||||
|
@ -585,25 +586,43 @@ class SbyTask(SbyConfig):
|
|||
if not os.path.isdir(f"{self.workdir}/model"):
|
||||
os.makedirs(f"{self.workdir}/model")
|
||||
|
||||
def print_common_prep(check):
|
||||
print("scc -select; simplemap; select -clear", file=f)
|
||||
if self.opt_multiclock:
|
||||
print("clk2fflogic", file=f)
|
||||
else:
|
||||
print("async2sync", file=f)
|
||||
print("chformal -assume -early", file=f)
|
||||
if self.opt_mode in ["bmc", "prove"]:
|
||||
print("chformal -live -fair -cover -remove", file=f)
|
||||
if self.opt_mode == "cover":
|
||||
print("chformal -live -fair -remove", file=f)
|
||||
if self.opt_mode == "live":
|
||||
print("chformal -assert2assume", file=f)
|
||||
print("chformal -cover -remove", file=f)
|
||||
print("opt_clean", file=f)
|
||||
print("setundef -anyseq", file=f)
|
||||
print("opt -keepdc -fast", file=f)
|
||||
print("check", file=f)
|
||||
print(f"hierarchy {check}", file=f)
|
||||
if model_name == "prep":
|
||||
with open(f"""{self.workdir}/model/design_prep.ys""", "w") as f:
|
||||
print(f"# running in {self.workdir}/model/", file=f)
|
||||
print(f"""read_ilang design.il""", file=f)
|
||||
print("scc -select; simplemap; select -clear", file=f)
|
||||
print("memory_nordff", file=f)
|
||||
if self.opt_multiclock:
|
||||
print("clk2fflogic", file=f)
|
||||
else:
|
||||
print("async2sync", file=f)
|
||||
print("chformal -assume -early", file=f)
|
||||
print("opt_clean", file=f)
|
||||
print("formalff -setundef -clk2ff -ff2anyinit", file=f)
|
||||
if self.opt_mode in ["bmc", "prove"]:
|
||||
print("chformal -live -fair -cover -remove", file=f)
|
||||
if self.opt_mode == "cover":
|
||||
print("chformal -live -fair -remove", file=f)
|
||||
if self.opt_mode == "live":
|
||||
print("chformal -assert2assume", file=f)
|
||||
print("chformal -cover -remove", file=f)
|
||||
print("opt_clean", file=f)
|
||||
print("check", file=f) # can't detect undriven wires past this point
|
||||
print("setundef -undriven -anyseq", file=f)
|
||||
print("opt -fast", file=f)
|
||||
print("rename -witness", file=f)
|
||||
print("opt_clean", file=f)
|
||||
print(f"""write_rtlil ../model/design_prep.il""", file=f)
|
||||
|
||||
proc = SbyProc(
|
||||
self,
|
||||
model_name,
|
||||
self.model("base"),
|
||||
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
||||
)
|
||||
proc.checkretcode = True
|
||||
|
||||
return [proc]
|
||||
|
||||
if model_name == "base":
|
||||
with open(f"""{self.workdir}/model/design.ys""", "w") as f:
|
||||
|
@ -639,12 +658,11 @@ class SbyTask(SbyConfig):
|
|||
if re.match(r"^smt2(_syn)?(_nomem)?(_stbv|_stdt)?$", model_name):
|
||||
with open(f"{self.workdir}/model/design_{model_name}.ys", "w") as f:
|
||||
print(f"# running in {self.workdir}/model/", file=f)
|
||||
print(f"""read_ilang design.il""", file=f)
|
||||
print(f"""read_ilang design_prep.il""", file=f)
|
||||
print("hierarchy -smtcheck", file=f)
|
||||
if "_nomem" in model_name:
|
||||
print("memory_map", file=f)
|
||||
else:
|
||||
print("memory_nordff", file=f)
|
||||
print_common_prep("-smtcheck")
|
||||
print("memory_map -formal", file=f)
|
||||
print("formalff -setundef -clk2ff -ff2anyinit", file=f)
|
||||
if "_syn" in model_name:
|
||||
print("techmap", file=f)
|
||||
print("opt -fast", file=f)
|
||||
|
@ -662,7 +680,7 @@ class SbyTask(SbyConfig):
|
|||
proc = SbyProc(
|
||||
self,
|
||||
model_name,
|
||||
self.model("base"),
|
||||
self.model("prep"),
|
||||
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
||||
)
|
||||
proc.checkretcode = True
|
||||
|
@ -672,12 +690,11 @@ class SbyTask(SbyConfig):
|
|||
if re.match(r"^btor(_syn)?(_nomem)?$", model_name):
|
||||
with open(f"{self.workdir}/model/design_{model_name}.ys", "w") as f:
|
||||
print(f"# running in {self.workdir}/model/", file=f)
|
||||
print(f"""read_ilang design.il""", file=f)
|
||||
print(f"""read_ilang design_prep.il""", file=f)
|
||||
print("hierarchy -simcheck", file=f)
|
||||
if "_nomem" in model_name:
|
||||
print("memory_map", file=f)
|
||||
else:
|
||||
print("memory_nordff", file=f)
|
||||
print_common_prep("-simcheck")
|
||||
print("memory_map -formal", file=f)
|
||||
print("formalff -setundef -clk2ff -ff2anyinit", file=f)
|
||||
print("flatten", file=f)
|
||||
print("setundef -undriven -anyseq", file=f)
|
||||
if "_syn" in model_name:
|
||||
|
@ -687,7 +704,7 @@ class SbyTask(SbyConfig):
|
|||
print("abc", file=f)
|
||||
print("opt_clean", file=f)
|
||||
else:
|
||||
print("opt -fast -keepdc", file=f)
|
||||
print("opt -fast", file=f)
|
||||
print("delete -output", file=f)
|
||||
print("dffunmap", file=f)
|
||||
print("stat", file=f)
|
||||
|
@ -697,7 +714,7 @@ class SbyTask(SbyConfig):
|
|||
proc = SbyProc(
|
||||
self,
|
||||
model_name,
|
||||
self.model("base"),
|
||||
self.model("prep"),
|
||||
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
||||
)
|
||||
proc.checkretcode = True
|
||||
|
@ -707,9 +724,8 @@ class SbyTask(SbyConfig):
|
|||
if model_name == "aig":
|
||||
with open(f"{self.workdir}/model/design_aiger.ys", "w") as f:
|
||||
print(f"# running in {self.workdir}/model/", file=f)
|
||||
print("read_ilang design.il", file=f)
|
||||
print("memory_map", file=f)
|
||||
print_common_prep("-simcheck")
|
||||
print("read_ilang design_prep.il", file=f)
|
||||
print("hierarchy -simcheck", file=f)
|
||||
print("flatten", file=f)
|
||||
print("setundef -undriven -anyseq", file=f)
|
||||
print("setattr -unset keep", file=f)
|
||||
|
@ -717,23 +733,26 @@ class SbyTask(SbyConfig):
|
|||
print("opt -full", file=f)
|
||||
print("techmap", file=f)
|
||||
print("opt -fast", file=f)
|
||||
print("memory_map -formal", file=f)
|
||||
print("formalff -clk2ff -ff2anyinit", file=f)
|
||||
print("simplemap", file=f)
|
||||
print("dffunmap", file=f)
|
||||
print("abc -g AND -fast", file=f)
|
||||
print("opt_clean", file=f)
|
||||
print("stat", file=f)
|
||||
print("write_aiger -I -B -zinit -no-startoffset -map design_aiger.aim design_aiger.aig", file=f)
|
||||
print("write_aiger -I -B -zinit -no-startoffset -map design_aiger.aim -ywmap design_aiger.ywa design_aiger.aig", file=f)
|
||||
|
||||
proc = SbyProc(
|
||||
self,
|
||||
"aig",
|
||||
self.model("base"),
|
||||
self.model("prep"),
|
||||
f"""cd {self.workdir}/model; {self.exe_paths["yosys"]} -ql design_aiger.log design_aiger.ys"""
|
||||
)
|
||||
proc.checkretcode = True
|
||||
|
||||
return [proc]
|
||||
|
||||
assert False
|
||||
self.error(f"Invalid model name: {model_name}")
|
||||
|
||||
def model(self, model_name):
|
||||
if model_name not in self.models:
|
||||
|
@ -811,6 +830,8 @@ class SbyTask(SbyConfig):
|
|||
self.handle_int_option("skip", None)
|
||||
self.handle_str_option("tbtop", None)
|
||||
|
||||
self.handle_str_option("make_model", None)
|
||||
|
||||
def setup_procs(self, setupmode):
|
||||
self.handle_non_engine_options()
|
||||
if self.opt_smtc is not None:
|
||||
|
@ -838,6 +859,13 @@ class SbyTask(SbyConfig):
|
|||
self.retcode = 0
|
||||
return
|
||||
|
||||
if self.opt_make_model is not None:
|
||||
for name in self.opt_make_model.split(","):
|
||||
self.model(name.strip())
|
||||
|
||||
for proc in self.procs_pending:
|
||||
proc.wait = True
|
||||
|
||||
if self.opt_mode == "bmc":
|
||||
import sby_mode_bmc
|
||||
sby_mode_bmc.run(self)
|
||||
|
@ -906,6 +934,8 @@ class SbyTask(SbyConfig):
|
|||
|
||||
def print_junit_result(self, f, junit_ts_name, junit_tc_name, junit_format_strict=False):
|
||||
junit_time = strftime('%Y-%m-%dT%H:%M:%S')
|
||||
if not self.design:
|
||||
self.precise_prop_status = False
|
||||
if self.precise_prop_status:
|
||||
checks = self.design.hierarchy.get_property_list()
|
||||
junit_tests = len(checks)
|
||||
|
|
|
@ -111,7 +111,7 @@ def run(mode, task, engine_idx, engine):
|
|||
f"engine_{engine_idx}",
|
||||
task.model("smt2"),
|
||||
("cd {}; {} -g -s {}{} --noprogress --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
|
||||
"--dump-smtc engine_{i}/trace.smtc --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
||||
"--dump-smtc engine_{i}/trace.smtc --dump-yw engine_{i}/trace.yw --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
||||
(task.workdir, task.exe_paths["smtbmc"], task.opt_aigsmt,
|
||||
"" if task.opt_tbtop is None else f" --vlogtb-top {task.opt_tbtop}",
|
||||
i=engine_idx),
|
||||
|
@ -123,7 +123,7 @@ def run(mode, task, engine_idx, engine):
|
|||
f"engine_{engine_idx}",
|
||||
task.model("smt2"),
|
||||
("cd {}; {} -s {}{} --noprogress --append {} --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
|
||||
"--dump-smtc engine_{i}/trace.smtc --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
||||
"--dump-smtc engine_{i}/trace.smtc --dump-yw engine_{i}/trace.yw --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
||||
(task.workdir, task.exe_paths["smtbmc"], task.opt_aigsmt,
|
||||
"" if task.opt_tbtop is None else f" --vlogtb-top {task.opt_tbtop}",
|
||||
task.opt_append, i=engine_idx),
|
||||
|
|
|
@ -152,7 +152,7 @@ def run(mode, task, engine_idx, engine):
|
|||
task,
|
||||
procname,
|
||||
task.model(model_name),
|
||||
f"""cd {task.workdir}; {task.exe_paths["smtbmc"]} {" ".join(smtbmc_opts)} -t {t_opt} {random_seed} --append {task.opt_append} --dump-vcd {trace_prefix}.vcd --dump-vlogtb {trace_prefix}_tb.v --dump-smtc {trace_prefix}.smtc model/design_{model_name}.smt2""",
|
||||
f"""cd {task.workdir}; {task.exe_paths["smtbmc"]} {" ".join(smtbmc_opts)} -t {t_opt} {random_seed} --append {task.opt_append} --dump-vcd {trace_prefix}.vcd --dump-yw {trace_prefix}.yw --dump-vlogtb {trace_prefix}_tb.v --dump-smtc {trace_prefix}.smtc model/design_{model_name}.smt2""",
|
||||
logfile=open(logfile_prefix + ".txt", "w"),
|
||||
logstderr=(not progress)
|
||||
)
|
||||
|
|
|
@ -46,5 +46,8 @@ def run(task):
|
|||
import sby_engine_btor
|
||||
sby_engine_btor.run("bmc", task, engine_idx, engine)
|
||||
|
||||
elif engine[0] == "none":
|
||||
pass
|
||||
|
||||
else:
|
||||
task.error(f"Invalid engine '{engine[0]}' for bmc mode.")
|
||||
|
|
|
@ -37,5 +37,8 @@ def run(task):
|
|||
import sby_engine_btor
|
||||
sby_engine_btor.run("cover", task, engine_idx, engine)
|
||||
|
||||
elif engine[0] == "none":
|
||||
pass
|
||||
|
||||
else:
|
||||
task.error(f"Invalid engine '{engine[0]}' for cover mode.")
|
||||
|
|
|
@ -34,5 +34,8 @@ def run(task):
|
|||
import sby_engine_aiger
|
||||
sby_engine_aiger.run("live", task, engine_idx, engine)
|
||||
|
||||
elif engine[0] == "none":
|
||||
pass
|
||||
|
||||
else:
|
||||
task.error(f"Invalid engine '{engine[0]}' for live mode.")
|
||||
|
|
|
@ -49,5 +49,8 @@ def run(task):
|
|||
import sby_engine_abc
|
||||
sby_engine_abc.run("prove", task, engine_idx, engine)
|
||||
|
||||
elif engine[0] == "none":
|
||||
pass
|
||||
|
||||
else:
|
||||
task.error(f"Invalid engine '{engine[0]}' for prove mode.")
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
module test (input CP, CN, CX, input A, B, output reg XP, XN, YP, YN);
|
||||
module test (input CP, CN, input A, B, output reg XP, XN);
|
||||
reg [7:0] counter = 0;
|
||||
always @* begin
|
||||
assume (A || B);
|
||||
assume (!A || !B);
|
||||
assert (A != B);
|
||||
cover (A);
|
||||
cover (B);
|
||||
cover (counter == 3 && A);
|
||||
cover (counter == 3 && B);
|
||||
end
|
||||
always @(posedge CP)
|
||||
counter <= counter + 1;
|
||||
always @(posedge CP)
|
||||
XP <= A;
|
||||
always @(negedge CN)
|
||||
XN <= B;
|
||||
always @(posedge CX)
|
||||
YP <= A;
|
||||
always @(negedge CX)
|
||||
YN <= B;
|
||||
endmodule
|
||||
|
|
Loading…
Reference in a new issue