Add btor engine
authorClifford Wolf <clifford@clifford.at>
Sat, 8 Dec 2018 04:23:04 +0000 (05:23 +0100)
committerClifford Wolf <clifford@clifford.at>
Sat, 8 Dec 2018 04:23:04 +0000 (05:23 +0100)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
sbysrc/sby.py
sbysrc/sby_core.py
sbysrc/sby_engine_btor.py [new file with mode: 0644]
sbysrc/sby_mode_bmc.py

index 435119da7ea7c9396770386150b554cb061199d9..8bf19cf77e1c4235b56c6cb36104e8f7f501a318 100644 (file)
@@ -59,13 +59,14 @@ sby [options] [<jobname>.sby [tasknames]]
     --suprove <path_to_executable>
     --aigbmc <path_to_executable>
     --avy <path_to_executable>
+    --btormc <path_to_executable>
         configure which executable to use for the respective tool
 """)
     sys.exit(1)
 
 try:
     opts, args = getopt.getopt(sys.argv[1:], "d:btfT:E", ["yosys=",
-            "abc=", "smtbmc=", "suprove=", "aigbmc=", "avy="])
+            "abc=", "smtbmc=", "suprove=", "aigbmc=", "avy=", "btormc="])
 except:
     usage()
 
@@ -94,6 +95,8 @@ for o, a in opts:
         exe_paths["aigbmc"] = a
     elif o == "--avy":
         exe_paths["avy"] = a
+    elif o == "--btormc":
+        exe_paths["btormc"] = a
     else:
         usage()
 
index fa8052697f3422d517b1e7c2fcbed637d9e4fc84..2eea8ed613dc573fe457843dee3f64c4f00efe02 100644 (file)
@@ -153,6 +153,7 @@ class SbyJob:
             "suprove": "suprove",
             "aigbmc": "aigbmc",
             "avy": "avy",
+            "btormc": "btormc",
         }
 
         self.tasks_running = []
@@ -333,6 +334,24 @@ class SbyJob:
 
             return [task]
 
+        if re.match(r"^btor(_syn)?(_nomem)?$", model_name):
+            with open("%s/model/design_%s.ys" % (self.workdir, model_name), "w") as f:
+                print("# running in %s/model/" % (self.workdir), file=f)
+                print("read_ilang design%s.il" % ("_nomem" if "_nomem" in model_name else ""), file=f)
+                if "_syn" in model_name:
+                    print("techmap", file=f)
+                    print("opt -fast", file=f)
+                    print("abc", file=f)
+                    print("opt_clean", file=f)
+                print("stat", file=f)
+                print("write_btor design_%s.btor" % model_name, file=f)
+
+            task = SbyTask(self, model_name, self.model("nomem" if "_nomem" in model_name else "base"),
+                    "cd %s/model; %s -ql design_%s.log design_%s.ys" % (self.workdir, self.exe_paths["yosys"], model_name, model_name))
+            task.checkretcode = True
+
+            return [task]
+
         if model_name == "aig":
             with open("%s/model/design_aiger.ys" % (self.workdir), "w") as f:
                 print("# running in %s/model/" % (self.workdir), file=f)
diff --git a/sbysrc/sby_engine_btor.py b/sbysrc/sby_engine_btor.py
new file mode 100644 (file)
index 0000000..8b9a9cc
--- /dev/null
@@ -0,0 +1,137 @@
+#
+# SymbiYosys (sby) -- Front-end for Yosys-based formal verification flows
+#
+# Copyright (C) 2016  Clifford Wolf <clifford@clifford.at>
+#
+# 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.
+#
+
+import re, os, getopt
+from sby_core import SbyTask
+
+def run(mode, job, engine_idx, engine):
+    opts, solver_args = getopt.getopt(engine[1:], "", [])
+
+    if len(solver_args) == 0:
+        job.error("Missing solver command.")
+
+    for o, a in opts:
+        job.error("Unexpected BTOR engine options.")
+
+    if solver_args[0] == "btormc":
+        solver_cmd = job.exe_paths["btormc"] + " --stop-first -kmax %d" % job.opt_depth
+        if job.opt_skip is not None:
+            solver_cmd += " -kmin %d" % job.opt_skip
+        solver_cmd += " ".join([""] + solver_args[1:])
+
+    else:
+        job.error("Invalid solver command %s." % solver_args[0])
+
+    task = SbyTask(job, "engine_%d" % engine_idx, job.model("btor"),
+            "cd %s; %s model/design_btor.btor" % (job.workdir, solver_cmd),
+            logfile=open("%s/engine_%d/logfile.txt" % (job.workdir, engine_idx), "w"))
+
+    task_status = None
+    produced_cex = False
+    end_of_cex = False
+    aiw_file = open("%s/engine_%d/trace.aiw" % (job.workdir, engine_idx), "w")
+
+    def output_callback(line):
+        nonlocal task_status
+        nonlocal produced_cex
+        nonlocal end_of_cex
+
+        if task_status is not None:
+            if not end_of_cex and not produced_cex and line.isdigit():
+                produced_cex = True
+            if not end_of_cex:
+                print(line, file=aiw_file)
+            if line == ".":
+                end_of_cex = True
+            return None
+
+        if line.startswith("u"):
+            return "No CEX up to depth %d." % (int(line[1:])-1)
+
+        if line in ["0", "1", "2"]:
+            print(line, file=aiw_file)
+            if line == "0": task_status = "PASS"
+            if line == "1": task_status = "FAIL"
+            if line == "2": task_status = "UNKNOWN"
+
+        return None
+
+    def exit_callback(retcode):
+        if solver_args[0] not in ["avy"]:
+            assert retcode == 0
+        assert task_status is not None
+
+        aiw_file.close()
+
+        job.update_status(task_status)
+        job.log("engine_%d: Status returned by engine: %s" % (engine_idx, task_status))
+        job.summary.append("engine_%d (%s) returned %s" % (engine_idx, " ".join(engine), task_status))
+
+        job.terminate()
+
+        if task_status == "FAIL" and job.opt_aigsmt != "none":
+            if produced_cex:
+                if mode == "live":
+                    task2 = SbyTask(job, "engine_%d" % engine_idx, job.model("smt2"),
+                            ("cd %s; %s -g -s %s%s --noprogress --dump-vcd engine_%d/trace.vcd --dump-vlogtb engine_%d/trace_tb.v " +
+                             "--dump-smtc engine_%d/trace.smtc --aig model/design_btor.aim:engine_%d/trace.aiw model/design_smt2.smt2") %
+                                    (job.workdir, job.exe_paths["smtbmc"], job.opt_aigsmt,
+                                    "" if job.opt_tbtop is None else " --vlogtb-top %s" % job.opt_tbtop,
+                                    engine_idx, engine_idx, engine_idx, engine_idx),
+                            logfile=open("%s/engine_%d/logfile2.txt" % (job.workdir, engine_idx), "w"))
+                else:
+                    task2 = SbyTask(job, "engine_%d" % engine_idx, job.model("smt2"),
+                            ("cd %s; %s -s %s%s --noprogress --append %d --dump-vcd engine_%d/trace.vcd --dump-vlogtb engine_%d/trace_tb.v " +
+                             "--dump-smtc engine_%d/trace.smtc --aig model/design_btor.aim:engine_%d/trace.aiw model/design_smt2.smt2") %
+                                    (job.workdir, job.exe_paths["smtbmc"], job.opt_aigsmt,
+                                    "" if job.opt_tbtop is None else " --vlogtb-top %s" % job.opt_tbtop,
+                                    job.opt_append, engine_idx, engine_idx, engine_idx, engine_idx),
+                            logfile=open("%s/engine_%d/logfile2.txt" % (job.workdir, engine_idx), "w"))
+
+                task2_status = None
+
+                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"
+
+                    if os.path.exists("%s/engine_%d/trace.vcd" % (job.workdir, engine_idx)):
+                        job.summary.append("counterexample trace: %s/engine_%d/trace.vcd" % (job.workdir, engine_idx))
+
+                task2.output_callback = output_callback2
+                task2.exit_callback = exit_callback2
+
+            else:
+                job.log("engine_%d: Engine did not produce a counter example." % engine_idx)
+
+    task.output_callback = output_callback
+    task.exit_callback = exit_callback
+
index 5e6236d22da4759fa0bd58ba1872a077f95fa9a4..c3c55ea807388fb68b06e5223e74fe7567556f0c 100644 (file)
@@ -39,6 +39,10 @@ def run(job):
             import sby_engine_abc
             sby_engine_abc.run("bmc", job, engine_idx, engine)
 
+        elif engine[0] == "btor":
+            import sby_engine_btor
+            sby_engine_btor.run("bmc", job, engine_idx, engine)
+
         else:
             job.error("Invalid engine '%s' for bmc mode." % engine[0])