d843ec208d1d799b0b84bdf456aac2b3c196f396
2 # SymbiYosys (sby) -- Front-end for Yosys-based formal verification flows
4 # Copyright (C) 2016 Clifford Wolf <clifford@clifford.at>
6 # Permission to use, copy, modify, and/or distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 from sby_core
import SbyTask
22 def run(mode
, job
, engine_idx
, engine
):
33 induction_only
= False
35 opts
, args
= getopt
.getopt(engine
[1:], "", ["nomem", "syn", "stbv", "stdt", "presat",
36 "nopresat", "unroll", "nounroll", "dumpsmt2", "progress", "basecase", "induction"])
49 elif o
== "--nopresat":
53 elif o
== "--nounroll":
55 elif o
== "--dumpsmt2":
57 elif o
== "--progress":
59 elif o
== "--basecase":
61 job
.error("smtbmc options --basecase and --induction are exclusive.")
63 elif o
== "--induction":
65 job
.error("smtbmc options --basecase and --induction are exclusive.")
68 job
.error("Invalid smtbmc options %s." % o
)
71 for i
, a
in enumerate(args
):
72 if i
== 0 and a
== "z3" and unroll_opt
is None:
80 smtbmc_opts
+= ["-s" if i
== 0 else "-S", a
]
83 smtbmc_opts
+= ["--presat"]
85 if unroll_opt
is None or unroll_opt
:
86 smtbmc_opts
+= ["--unroll"]
88 if job
.opt_smtc
is not None:
89 smtbmc_opts
+= ["--smtc", "src/%s" % job
.opt_smtc
]
91 if job
.opt_tbtop
is not None:
92 smtbmc_opts
+= ["--vlogtb-top", job
.opt_tbtop
]
95 if syn_opt
: model_name
+= "_syn"
96 if nomem_opt
: model_name
+= "_nomem"
97 if stbv_opt
: model_name
+= "_stbv"
98 if stdt_opt
: model_name
+= "_stdt"
101 if not induction_only
:
102 run("prove_basecase", job
, engine_idx
, engine
)
103 if not basecase_only
:
104 run("prove_induction", job
, engine_idx
, engine
)
107 taskname
= "engine_%d" % engine_idx
108 trace_prefix
= "engine_%d/trace" % engine_idx
109 logfile_prefix
= "%s/engine_%d/logfile" % (job
.workdir
, engine_idx
)
111 if mode
== "prove_basecase":
112 taskname
+= ".basecase"
113 logfile_prefix
+= "_basecase"
115 if mode
== "prove_induction":
116 taskname
+= ".induction"
117 trace_prefix
+= "_induct"
118 logfile_prefix
+= "_induction"
119 smtbmc_opts
.append("-i")
122 smtbmc_opts
.append("-c")
126 smtbmc_opts
+= ["--dump-smt2", trace_prefix
.replace("%", "") + ".smt2"]
129 smtbmc_opts
.append("--noprogress")
132 if job
.opt_skip
is not None:
133 t_opt
= "%d:%d" % (job
.opt_skip
, job
.opt_depth
)
135 t_opt
= "%d" % job
.opt_depth
137 task
= SbyTask(job
, taskname
, job
.model(model_name
),
138 "cd %s; %s %s -t %s --append %d --dump-vcd %s.vcd --dump-vlogtb %s_tb.v --dump-smtc %s.smtc model/design_%s.smt2" %
139 (job
.workdir
, job
.exe_paths
["smtbmc"], " ".join(smtbmc_opts
), t_opt
, job
.opt_append
, trace_prefix
, trace_prefix
, trace_prefix
, model_name
),
140 logfile
=open(logfile_prefix
+ ".txt", "w"), logstderr
=(not progress
))
142 if mode
== "prove_basecase":
143 job
.basecase_tasks
.append(task
)
145 if mode
== "prove_induction":
146 job
.induction_tasks
.append(task
)
150 def output_callback(line
):
153 match
= re
.match(r
"^## [0-9: ]+ Status: FAILED", line
)
156 return line
.replace("FAILED", "failed")
158 match
= re
.match(r
"^## [0-9: ]+ Status: PASSED", line
)
161 return line
.replace("PASSED", "passed")
163 match
= re
.match(r
"^## [0-9: ]+ Status: PREUNSAT", line
)
165 task_status
= "ERROR"
170 def exit_callback(retcode
):
171 if task_status
is None:
172 job
.error("engine_%d: Engine terminated without status." % engine_idx
)
174 if mode
== "bmc" or mode
== "cover":
175 job
.update_status(task_status
)
176 task_status_lower
= task_status
.lower() if task_status
== "PASS" else task_status
177 job
.log("engine_%d: Status returned by engine: %s" % (engine_idx
, task_status_lower
))
178 job
.summary
.append("engine_%d (%s) returned %s" % (engine_idx
, " ".join(engine
), task_status_lower
))
180 if task_status
== "FAIL" and mode
!= "cover":
181 if os
.path
.exists("%s/engine_%d/trace.vcd" % (job
.workdir
, engine_idx
)):
182 job
.summary
.append("counterexample trace: %s/engine_%d/trace.vcd" % (job
.workdir
, engine_idx
))
186 elif mode
in ["prove_basecase", "prove_induction"]:
187 task_status_lower
= task_status
.lower() if task_status
== "PASS" else task_status
188 job
.log("engine_%d: Status returned by engine for %s: %s" % (engine_idx
, mode
.split("_")[1], task_status_lower
))
189 job
.summary
.append("engine_%d (%s) returned %s for %s" % (engine_idx
, " ".join(engine
), task_status_lower
, mode
.split("_")[1]))
191 if mode
== "prove_basecase":
192 for task
in job
.basecase_tasks
:
195 if task_status
== "PASS":
196 job
.basecase_pass
= True
199 job
.update_status(task_status
)
200 if os
.path
.exists("%s/engine_%d/trace.vcd" % (job
.workdir
, engine_idx
)):
201 job
.summary
.append("counterexample trace: %s/engine_%d/trace.vcd" % (job
.workdir
, engine_idx
))
204 elif mode
== "prove_induction":
205 for task
in job
.induction_tasks
:
208 if task_status
== "PASS":
209 job
.induction_pass
= True
214 if job
.basecase_pass
and job
.induction_pass
:
215 job
.update_status("PASS")
216 job
.summary
.append("successful proof by k-induction.")
222 task
.output_callback
= output_callback
223 task
.exit_callback
= exit_callback