Add aiger engine
authorClifford Wolf <clifford@clifford.at>
Sun, 19 Feb 2017 22:53:01 +0000 (23:53 +0100)
committerClifford Wolf <clifford@clifford.at>
Sun, 19 Feb 2017 22:53:01 +0000 (23:53 +0100)
.gitignore
sbysrc/demo.sby [deleted file]
sbysrc/demo1.sby [new file with mode: 0644]
sbysrc/demo2.sby [new file with mode: 0644]
sbysrc/sby.py
sbysrc/sby_core.py
sbysrc/sby_engine_abc.py
sbysrc/sby_engine_aiger.py [new file with mode: 0644]
sbysrc/sby_engine_smtbmc.py
sbysrc/sby_mode_prove.py

index b0f28e2ddbb150a0b35ccc66d3248d7cfa456875..e374fdc6a260dcf754cc6c0167505cab28858a1e 100644 (file)
@@ -1,4 +1,4 @@
 /docs/build
-/sbysrc/demo
+/sbysrc/demo[0-9]
 /sbysrc/__pycache__
 
diff --git a/sbysrc/demo.sby b/sbysrc/demo.sby
deleted file mode 100644 (file)
index cfd67cc..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-[options]
-mode bmc
-depth 10
-wait on
-
-[engines]
-smtbmc yices
-smtbmc boolector -ack
-smtbmc --nomem z3
-abc bmc3
-
-[script]
-read_verilog -formal -norestrict -assume-asserts picorv32.v
-read_verilog -formal axicheck.v
-prep -nordff -top testbench
-
-[files]
-picorv32.v ~/Work/picorv32/picorv32.v
-axicheck.v ~/Work/picorv32/scripts/smtbmc/axicheck.v
-
diff --git a/sbysrc/demo1.sby b/sbysrc/demo1.sby
new file mode 100644 (file)
index 0000000..cfd67cc
--- /dev/null
@@ -0,0 +1,21 @@
+
+[options]
+mode bmc
+depth 10
+wait on
+
+[engines]
+smtbmc yices
+smtbmc boolector -ack
+smtbmc --nomem z3
+abc bmc3
+
+[script]
+read_verilog -formal -norestrict -assume-asserts picorv32.v
+read_verilog -formal axicheck.v
+prep -nordff -top testbench
+
+[files]
+picorv32.v ~/Work/picorv32/picorv32.v
+axicheck.v ~/Work/picorv32/scripts/smtbmc/axicheck.v
+
diff --git a/sbysrc/demo2.sby b/sbysrc/demo2.sby
new file mode 100644 (file)
index 0000000..1d5639c
--- /dev/null
@@ -0,0 +1,21 @@
+[options]
+mode prove
+wait on
+
+[engines]
+aiger suprove
+aiger avy
+
+[script]
+read_verilog -formal demo.v
+prep -top top
+
+[file demo.v]
+module top(input clk, input up, down);
+  reg [4:0] counter = 0;
+  always @(posedge clk) begin
+    if (up && counter != 10) counter <= counter + 1;
+    if (down && counter != 0) counter <= counter - 1;
+  end
+  assert property (counter != 15);
+endmodule
index 94ec952105660dd3869a9c3d68373f9a5e5a2eca..e960240c8f910af986f925879bf8882aa5396c34 100644 (file)
@@ -43,14 +43,15 @@ sby [options] <jobname>.sby
     --yosys <path_to_executable>
     --abc <path_to_executable>
     --smtbmc <path_to_executable>
-    --sprove <path_to_executable>
+    --suprove <path_to_executable>
+    --avy <path_to_executable>
         configure which executable to use for the respective tool
 """)
     sys.exit(1)
 
 try:
     opts, args = getopt.getopt(sys.argv[1:], "d:bf", ["yosys=",
-            "abc=", "smtbmc=", "sprove="])
+            "abc=", "smtbmc=", "suprove="])
 except:
     usage()
 
@@ -67,8 +68,8 @@ for o, a in opts:
         exe_paths["abc"] = a
     elif o == "--smtbmc":
         exe_paths["smtbmc"] = a
-    elif o == "--sprove":
-        exe_paths["sprove"] = a
+    elif o == "--suprove":
+        exe_paths["suprove"] = a
     else:
         usage()
 
index a1aaec351473f9dfeca85eb4a469d2d942f064a8..dd1e380b079e8fb14f4e57a5b9e2f1b8bd3388ff 100644 (file)
@@ -52,12 +52,14 @@ class SbyTask:
             self.notify.append(next_task)
 
     def handle_output(self, line):
-        if self.terminated:
+        if self.terminated or len(line) == 0:
             return
-        if self.logfile is not None:
-            print(line, file=self.logfile)
         if self.output_callback is not None:
-            self.output_callback(line)
+            line = self.output_callback(line)
+        if line is not None and (self.noprintregex is None or not self.noprintregex.match(line)):
+            if self.logfile is not None:
+                print(line, file=self.logfile)
+            self.job.log("%s: %s" % (self.info, line))
 
     def handle_exit(self, retcode):
         if self.terminated:
@@ -101,9 +103,6 @@ class SbyTask:
                 break
             outs = (self.linebuffer + outs).strip()
             self.linebuffer = ""
-            if len(outs) == 0: continue
-            if self.noprintregex is None or not self.noprintregex.match(outs):
-                self.job.log("%s: %s" % (self.info, outs))
             self.handle_output(outs)
 
         if self.p.poll() is not None:
@@ -141,7 +140,8 @@ class SbyJob:
             "yosys": "yosys",
             "abc": "yosys-abc",
             "smtbmc": "yosys-smtbmc",
-            "sprove": "super_prove",
+            "suprove": "super_prove",
+            "avy": "avy",
         }
 
         self.tasks_running = []
@@ -254,8 +254,7 @@ class SbyJob:
                     fds.append(task.p.stdout)
 
             try:
-                while select(fds, [], [], 1.0) == ([], [], []):
-                    pass
+                select(fds, [], [], 1.0) == ([], [], [])
             except:
                 pass
 
index 4230620adb7ae49f6a928c60c18c8cad3b77ae8c..092a1766c89442a422e294549c495ab0759a1a11 100644 (file)
@@ -67,6 +67,8 @@ def run(mode, job, engine_idx, engine):
         match = re.match(r"^Property proved.", line)
         if match: task_status = "PASS"
 
+        return line
+
     def exit_callback(retcode):
         assert retcode == 0
         assert task_status is not None
@@ -95,6 +97,8 @@ def run(mode, job, engine_idx, engine):
                 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
                 assert task2_status == "FAIL"
diff --git a/sbysrc/sby_engine_aiger.py b/sbysrc/sby_engine_aiger.py
new file mode 100644 (file)
index 0000000..c1feebd
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# 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:], "", [])
+    assert len(solver_args) > 0
+
+    for o, a in opts:
+        assert False
+
+    if solver_args[0] == "suprove":
+        solver_cmd = " ".join([job.exe_paths["suprove"]] + solver_args[1:])
+
+    elif solver_args[0] == "avy":
+        solver_cmd = " ".join([job.exe_paths["avy"], "--cex", "-"] + solver_args[1:])
+
+    else:
+        assert False
+
+    task = SbyTask(job, "engine_%d" % engine_idx, job.model("aig"),
+            "cd %s; %s model/design_aiger.aig" % (job.workdir, solver_cmd),
+            logfile=open("%s/engine_%d/logfile.txt" % (job.workdir, engine_idx), "w"))
+
+    task_status = None
+    aiw_file = open("%s/engine_%d/trace.aiw" % (job.workdir, engine_idx), "w")
+
+    def output_callback(line):
+        nonlocal task_status
+
+        if task_status is not None:
+            print(line, file=aiw_file)
+            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":
+            task2 = SbyTask(job, "engine_%d" % engine_idx, job.model("smt2"),
+                    ("cd %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_aiger.aim:engine_%d/trace.aiw model/design_smt2.smt2") %
+                            (job.workdir, job.exe_paths["smtbmc"], 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
+                assert task2_status == "FAIL"
+
+                job.summary.append("counterexample trace: %s/engine_%d/trace.vcd" % (job.workdir, engine_idx))
+
+            task2.output_callback = output_callback2
+            task2.exit_callback = exit_callback2
+
+    task.output_callback = output_callback
+    task.exit_callback = exit_callback
+
index 3977f2c90abce23509462e30816b4fbca1d210e1..52ccb9cfe51fce777a2c5370f41b40910330b7bd 100644 (file)
@@ -86,6 +86,8 @@ def run(mode, job, engine_idx, engine):
         match = re.match(r"^## [0-9: ]+ Status: PASSED", line)
         if match: task_status = "PASS"
 
+        return line
+
     def exit_callback(retcode):
         assert task_status is not None
 
index 2491404b5fdbceb6d42098ff71adddc4ab9969cf..67cb7f230da25b2dea0da5e0a8e9f4d6d98fc08a 100644 (file)
@@ -43,6 +43,10 @@ def run(job):
             import sby_engine_smtbmc
             sby_engine_smtbmc.run("prove", job, engine_idx, engine)
 
+        elif engine[0] == "aiger":
+            import sby_engine_aiger
+            sby_engine_aiger.run("prove", job, engine_idx, engine)
+
         elif engine[0] == "abc":
             import sby_engine_abc
             sby_engine_abc.run("prove", job, engine_idx, engine)