yowasp-yosys 0.38.0.92.post687.dev0__py3-none-any.whl → 0.39.0.165.post702.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- yowasp_yosys/sby.py +50 -0
- yowasp_yosys/share/include/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +107 -37
- yowasp_yosys/share/include/backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h +107 -21
- yowasp_yosys/share/include/kernel/fmt.h +17 -8
- yowasp_yosys/share/include/kernel/utils.h +3 -3
- yowasp_yosys/share/python3/sby_autotune.py +1 -0
- yowasp_yosys/share/python3/sby_cmdline.py +5 -0
- yowasp_yosys/share/python3/sby_core.py +55 -5
- yowasp_yosys/share/python3/sby_design.py +7 -0
- yowasp_yosys/share/python3/sby_engine_abc.py +156 -14
- yowasp_yosys/share/python3/sby_engine_aiger.py +100 -62
- yowasp_yosys/share/python3/sby_engine_smtbmc.py +9 -3
- yowasp_yosys/share/python3/sby_status.py +344 -0
- yowasp_yosys/share/python3/smtio.py +96 -8
- yowasp_yosys/share/quicklogic/qlf_k6n10f/bram_types_sim.v +1 -1
- yowasp_yosys/smtbmc.py +85 -10
- yowasp_yosys/yosys.wasm +0 -0
- {yowasp_yosys-0.38.0.92.post687.dev0.dist-info → yowasp_yosys-0.39.0.165.post702.dev0.dist-info}/METADATA +1 -1
- {yowasp_yosys-0.38.0.92.post687.dev0.dist-info → yowasp_yosys-0.39.0.165.post702.dev0.dist-info}/RECORD +22 -21
- {yowasp_yosys-0.38.0.92.post687.dev0.dist-info → yowasp_yosys-0.39.0.165.post702.dev0.dist-info}/WHEEL +1 -1
- {yowasp_yosys-0.38.0.92.post687.dev0.dist-info → yowasp_yosys-0.39.0.165.post702.dev0.dist-info}/entry_points.txt +0 -0
- {yowasp_yosys-0.38.0.92.post687.dev0.dist-info → yowasp_yosys-0.39.0.165.post702.dev0.dist-info}/top_level.txt +0 -0
|
@@ -27,6 +27,7 @@ from shutil import copyfile, copytree, rmtree
|
|
|
27
27
|
from select import select
|
|
28
28
|
from time import monotonic, localtime, sleep, strftime
|
|
29
29
|
from sby_design import SbyProperty, SbyModule, design_hierarchy
|
|
30
|
+
from sby_status import SbyStatusDb
|
|
30
31
|
|
|
31
32
|
all_procs_running = []
|
|
32
33
|
|
|
@@ -674,20 +675,41 @@ class SbySummary:
|
|
|
674
675
|
self.engine_summaries[engine_idx] = SbyEngineSummary(engine_idx)
|
|
675
676
|
return self.engine_summaries[engine_idx]
|
|
676
677
|
|
|
677
|
-
def add_event(self, *args, **kwargs):
|
|
678
|
+
def add_event(self, *args, update_status=True, **kwargs):
|
|
678
679
|
event = SbySummaryEvent(*args, **kwargs)
|
|
680
|
+
|
|
681
|
+
engine = self.engine_summary(event.engine_idx)
|
|
682
|
+
|
|
683
|
+
if update_status:
|
|
684
|
+
status_metadata = dict(source="summary_event", engine=engine.engine)
|
|
685
|
+
|
|
679
686
|
if event.prop:
|
|
680
687
|
if event.type == "$assert":
|
|
681
688
|
event.prop.status = "FAIL"
|
|
682
689
|
if event.path:
|
|
683
690
|
event.prop.tracefiles.append(event.path)
|
|
691
|
+
if update_status:
|
|
692
|
+
self.task.status_db.add_task_property_data(
|
|
693
|
+
event.prop,
|
|
694
|
+
"trace",
|
|
695
|
+
data=dict(path=event.path, step=event.step, **status_metadata),
|
|
696
|
+
)
|
|
684
697
|
if event.prop:
|
|
685
698
|
if event.type == "$cover":
|
|
686
699
|
event.prop.status = "PASS"
|
|
687
700
|
if event.path:
|
|
688
701
|
event.prop.tracefiles.append(event.path)
|
|
689
|
-
|
|
690
|
-
|
|
702
|
+
if update_status:
|
|
703
|
+
self.task.status_db.add_task_property_data(
|
|
704
|
+
event.prop,
|
|
705
|
+
"trace",
|
|
706
|
+
data=dict(path=event.path, step=event.step, **status_metadata),
|
|
707
|
+
)
|
|
708
|
+
if event.prop and update_status:
|
|
709
|
+
self.task.status_db.set_task_property_status(
|
|
710
|
+
event.prop,
|
|
711
|
+
data=status_metadata
|
|
712
|
+
)
|
|
691
713
|
|
|
692
714
|
if event.trace not in engine.traces:
|
|
693
715
|
engine.traces[event.trace] = SbyTraceSummary(event.trace, path=event.path, engine_case=event.engine_case)
|
|
@@ -765,8 +787,8 @@ class SbySummary:
|
|
|
765
787
|
event = same_events[0]
|
|
766
788
|
steps = sorted(e.step for e in same_events)
|
|
767
789
|
if short and len(steps) > step_limit:
|
|
768
|
-
steps = [str(step) for step in steps[:step_limit]]
|
|
769
790
|
excess = len(steps) - step_limit
|
|
791
|
+
steps = [str(step) for step in steps[:step_limit]]
|
|
770
792
|
omitted_excess = True
|
|
771
793
|
steps[-1] += f" and {excess} further step{'s' if excess != 1 else ''}"
|
|
772
794
|
|
|
@@ -1005,6 +1027,7 @@ class SbyTask(SbyConfig):
|
|
|
1005
1027
|
print("setundef -undriven -anyseq", file=f)
|
|
1006
1028
|
print("opt -fast", file=f)
|
|
1007
1029
|
if self.opt_witrename:
|
|
1030
|
+
# we need to run this a second time to handle anything added by prep
|
|
1008
1031
|
print("rename -witness", file=f)
|
|
1009
1032
|
print("opt_clean", file=f)
|
|
1010
1033
|
print(f"""write_rtlil ../model/design_prep.il""", file=f)
|
|
@@ -1026,6 +1049,9 @@ class SbyTask(SbyConfig):
|
|
|
1026
1049
|
print(cmd, file=f)
|
|
1027
1050
|
# the user must designate a top module in [script]
|
|
1028
1051
|
print("hierarchy -smtcheck", file=f)
|
|
1052
|
+
# we need to give flatten-preserved names before write_jny
|
|
1053
|
+
if self.opt_witrename:
|
|
1054
|
+
print("rename -witness", file=f)
|
|
1029
1055
|
print(f"""write_jny -no-connections ../model/design.json""", file=f)
|
|
1030
1056
|
print(f"""write_rtlil ../model/design.il""", file=f)
|
|
1031
1057
|
|
|
@@ -1041,6 +1067,10 @@ class SbyTask(SbyConfig):
|
|
|
1041
1067
|
if self.design == None:
|
|
1042
1068
|
with open(f"{self.workdir}/model/design.json") as f:
|
|
1043
1069
|
self.design = design_hierarchy(f)
|
|
1070
|
+
self.status_db.create_task_properties([
|
|
1071
|
+
prop for prop in self.design.properties_by_path.values()
|
|
1072
|
+
if not prop.type.assume_like
|
|
1073
|
+
])
|
|
1044
1074
|
|
|
1045
1075
|
def instance_hierarchy_error_callback(retcode):
|
|
1046
1076
|
self.precise_prop_status = False
|
|
@@ -1186,8 +1216,13 @@ class SbyTask(SbyConfig):
|
|
|
1186
1216
|
self.status = "ERROR"
|
|
1187
1217
|
self.terminate()
|
|
1188
1218
|
|
|
1219
|
+
def pass_unknown_asserts(self, data):
|
|
1220
|
+
for prop in self.design.pass_unknown_asserts():
|
|
1221
|
+
self.status_db.set_task_property_status(prop, data=data)
|
|
1222
|
+
|
|
1189
1223
|
def update_status(self, new_status):
|
|
1190
1224
|
assert new_status in ["PASS", "FAIL", "UNKNOWN", "ERROR"]
|
|
1225
|
+
self.status_db.set_task_status(new_status)
|
|
1191
1226
|
|
|
1192
1227
|
if new_status == "UNKNOWN":
|
|
1193
1228
|
return
|
|
@@ -1199,7 +1234,7 @@ class SbyTask(SbyConfig):
|
|
|
1199
1234
|
assert self.status != "FAIL"
|
|
1200
1235
|
self.status = "PASS"
|
|
1201
1236
|
if self.opt_mode in ("bmc", "prove") and self.design:
|
|
1202
|
-
self.
|
|
1237
|
+
self.pass_unknown_asserts(dict(source="task_status"))
|
|
1203
1238
|
|
|
1204
1239
|
elif new_status == "FAIL":
|
|
1205
1240
|
assert self.status != "PASS"
|
|
@@ -1258,6 +1293,19 @@ class SbyTask(SbyConfig):
|
|
|
1258
1293
|
|
|
1259
1294
|
self.handle_bool_option("assume_early", True)
|
|
1260
1295
|
|
|
1296
|
+
def setup_status_db(self, status_path=None):
|
|
1297
|
+
if hasattr(self, 'status_db'):
|
|
1298
|
+
return
|
|
1299
|
+
|
|
1300
|
+
if status_path is None:
|
|
1301
|
+
try:
|
|
1302
|
+
with open(f"{self.workdir}/status.path", "r") as status_path_file:
|
|
1303
|
+
status_path = f"{self.workdir}/{status_path_file.read().rstrip()}"
|
|
1304
|
+
except FileNotFoundError:
|
|
1305
|
+
status_path = f"{self.workdir}/status.sqlite"
|
|
1306
|
+
|
|
1307
|
+
self.status_db = SbyStatusDb(status_path, self)
|
|
1308
|
+
|
|
1261
1309
|
def setup_procs(self, setupmode):
|
|
1262
1310
|
self.handle_non_engine_options()
|
|
1263
1311
|
if self.opt_smtc is not None:
|
|
@@ -1285,6 +1333,8 @@ class SbyTask(SbyConfig):
|
|
|
1285
1333
|
self.retcode = 0
|
|
1286
1334
|
return
|
|
1287
1335
|
|
|
1336
|
+
self.setup_status_db()
|
|
1337
|
+
|
|
1288
1338
|
if self.opt_make_model is not None:
|
|
1289
1339
|
for name in self.opt_make_model.split(","):
|
|
1290
1340
|
self.model(name.strip())
|
|
@@ -88,6 +88,10 @@ class SbyProperty:
|
|
|
88
88
|
return c.FAIR
|
|
89
89
|
raise ValueError("Unknown property type: " + name)
|
|
90
90
|
|
|
91
|
+
@property
|
|
92
|
+
def assume_like(self):
|
|
93
|
+
return self in [self.ASSUME, self.FAIR]
|
|
94
|
+
|
|
91
95
|
name: str
|
|
92
96
|
path: Tuple[str, ...]
|
|
93
97
|
type: Type
|
|
@@ -171,9 +175,12 @@ class SbyDesign:
|
|
|
171
175
|
properties_by_path: dict = field(default_factory=dict)
|
|
172
176
|
|
|
173
177
|
def pass_unknown_asserts(self):
|
|
178
|
+
updated = []
|
|
174
179
|
for prop in self.hierarchy:
|
|
175
180
|
if prop.type == prop.Type.ASSERT and prop.status == "UNKNOWN":
|
|
176
181
|
prop.status = "PASS"
|
|
182
|
+
updated.append(prop)
|
|
183
|
+
return updated
|
|
177
184
|
|
|
178
185
|
|
|
179
186
|
def cell_path(cell):
|
|
@@ -17,32 +17,101 @@
|
|
|
17
17
|
#
|
|
18
18
|
|
|
19
19
|
import re, getopt
|
|
20
|
+
import json
|
|
20
21
|
from sby_core import SbyProc
|
|
21
|
-
from sby_engine_aiger import aigsmt_exit_callback
|
|
22
|
+
from sby_engine_aiger import aigsmt_exit_callback, aigsmt_trace_callback
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def abc_getopt(args, long):
|
|
26
|
+
long = set(long)
|
|
27
|
+
output = []
|
|
28
|
+
parsed = []
|
|
29
|
+
toggles = set()
|
|
30
|
+
pos = 0
|
|
31
|
+
|
|
32
|
+
while pos < len(args):
|
|
33
|
+
arg = args[pos]
|
|
34
|
+
pos += 1
|
|
35
|
+
if not arg.startswith('-'):
|
|
36
|
+
output.append(arg)
|
|
37
|
+
elif arg == '--':
|
|
38
|
+
output.extend(args[pos:])
|
|
39
|
+
break
|
|
40
|
+
elif arg.startswith('--'):
|
|
41
|
+
if '=' in arg:
|
|
42
|
+
prefix, param = arg.split('=', 1)
|
|
43
|
+
if prefix + "=" in long:
|
|
44
|
+
parsed.append(prefix, param)
|
|
45
|
+
elif arg[2:] in long:
|
|
46
|
+
parsed.append((arg, ''))
|
|
47
|
+
elif arg[2:] + "=" in long:
|
|
48
|
+
parsed.append((arg, args[pos]))
|
|
49
|
+
pos += 1
|
|
50
|
+
else:
|
|
51
|
+
output.append(arg)
|
|
52
|
+
elif arg.startswith('-'):
|
|
53
|
+
output.append(arg)
|
|
54
|
+
for c in arg[1:]:
|
|
55
|
+
if 'A' <= c <= 'Z':
|
|
56
|
+
if pos < len(args):
|
|
57
|
+
output.append(args[pos])
|
|
58
|
+
pos += 1
|
|
59
|
+
else:
|
|
60
|
+
toggles.symmetric_difference_update([c])
|
|
61
|
+
|
|
62
|
+
return output, parsed, toggles
|
|
63
|
+
|
|
22
64
|
|
|
23
65
|
def run(mode, task, engine_idx, engine):
|
|
24
|
-
|
|
66
|
+
keep_going = False
|
|
67
|
+
|
|
68
|
+
fold_command = "fold"
|
|
69
|
+
if task.opt_aigfolds:
|
|
70
|
+
fold_command += " -s"
|
|
71
|
+
|
|
72
|
+
abc_command, custom_options, toggles = abc_getopt(engine[1:], [
|
|
73
|
+
"keep-going",
|
|
74
|
+
])
|
|
25
75
|
|
|
26
76
|
if len(abc_command) == 0:
|
|
27
77
|
task.error("Missing ABC command.")
|
|
28
78
|
|
|
29
|
-
|
|
30
|
-
task.error("Unexpected ABC engine
|
|
79
|
+
if abc_command[0].startswith('-'):
|
|
80
|
+
task.error(f"Unexpected ABC engine option '{abc_command[0]}'.")
|
|
31
81
|
|
|
32
82
|
if abc_command[0] == "bmc3":
|
|
33
83
|
if mode != "bmc":
|
|
34
84
|
task.error("ABC command 'bmc3' is only valid in bmc mode.")
|
|
85
|
+
for o, a in custom_options:
|
|
86
|
+
task.error(f"Option {o} not supported by 'abc {abc_command[0]}'")
|
|
35
87
|
abc_command[0] += f" -F {task.opt_depth} -v"
|
|
36
88
|
|
|
37
89
|
elif abc_command[0] == "sim3":
|
|
38
90
|
if mode != "bmc":
|
|
39
91
|
task.error("ABC command 'sim3' is only valid in bmc mode.")
|
|
92
|
+
for o, a in custom_options:
|
|
93
|
+
task.error(f"Option {o} not supported by 'abc {abc_command[0]}'")
|
|
40
94
|
abc_command[0] += f" -F {task.opt_depth} -v"
|
|
41
95
|
|
|
42
96
|
elif abc_command[0] == "pdr":
|
|
43
97
|
if mode != "prove":
|
|
44
98
|
task.error("ABC command 'pdr' is only valid in prove mode.")
|
|
45
|
-
|
|
99
|
+
|
|
100
|
+
for o, a in custom_options:
|
|
101
|
+
if o == '--keep-going':
|
|
102
|
+
keep_going = True
|
|
103
|
+
else:
|
|
104
|
+
task.error(f"Option {o} not supported by 'abc {abc_command[0]}'")
|
|
105
|
+
|
|
106
|
+
abc_command[0] += " -v -l"
|
|
107
|
+
|
|
108
|
+
if keep_going:
|
|
109
|
+
abc_command += ["-a", "-X", f"engine_{engine_idx}/trace_"]
|
|
110
|
+
|
|
111
|
+
if 'd' in toggles:
|
|
112
|
+
abc_command += ["-I", f"engine_{engine_idx}/invariants.pla"]
|
|
113
|
+
if not task.opt_aigfolds:
|
|
114
|
+
fold_command += " -s"
|
|
46
115
|
|
|
47
116
|
else:
|
|
48
117
|
task.error(f"Invalid ABC command {abc_command[0]}.")
|
|
@@ -66,21 +135,61 @@ def run(mode, task, engine_idx, engine):
|
|
|
66
135
|
task,
|
|
67
136
|
f"engine_{engine_idx}",
|
|
68
137
|
task.model("aig"),
|
|
69
|
-
f"""cd {task.workdir}; {task.exe_paths["abc"]} -c 'read_aiger model/design_aiger.aig;
|
|
70
|
-
|
|
71
|
-
}; strash; {" ".join(abc_command)}; write_cex -a engine_{engine_idx}/trace.aiw'""",
|
|
138
|
+
f"""cd {task.workdir}; {task.exe_paths["abc"]} -c 'read_aiger model/design_aiger.aig; {
|
|
139
|
+
fold_command}; strash; {" ".join(abc_command)}; write_cex -a engine_{engine_idx}/trace.aiw'""",
|
|
72
140
|
logfile=open(f"{task.workdir}/engine_{engine_idx}/logfile.txt", "w")
|
|
73
141
|
)
|
|
74
142
|
proc.checkretcode = True
|
|
75
143
|
|
|
76
144
|
proc.noprintregex = re.compile(r"^\.+$")
|
|
77
|
-
proc_status =
|
|
145
|
+
proc_status = "UNKNOWN"
|
|
146
|
+
|
|
147
|
+
procs_running = 1
|
|
148
|
+
|
|
149
|
+
aiger_props = None
|
|
150
|
+
disproved = set()
|
|
151
|
+
proved = set()
|
|
78
152
|
|
|
79
153
|
def output_callback(line):
|
|
80
154
|
nonlocal proc_status
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
155
|
+
nonlocal procs_running
|
|
156
|
+
nonlocal aiger_props
|
|
157
|
+
|
|
158
|
+
if aiger_props is None:
|
|
159
|
+
with open(f"{task.workdir}/model/design_aiger.ywa") as ywa_file:
|
|
160
|
+
ywa = json.load(ywa_file)
|
|
161
|
+
aiger_props = []
|
|
162
|
+
for path in ywa["asserts"]:
|
|
163
|
+
aiger_props.append(task.design.properties_by_path.get(tuple(path)))
|
|
164
|
+
|
|
165
|
+
if keep_going:
|
|
166
|
+
match = re.match(r"Writing CEX for output ([0-9]+) to engine_[0-9]+/(.*)\.aiw", line)
|
|
167
|
+
if match:
|
|
168
|
+
output = int(match[1])
|
|
169
|
+
prop = aiger_props[output]
|
|
170
|
+
if prop:
|
|
171
|
+
prop.status = "FAIL"
|
|
172
|
+
task.status_db.set_task_property_status(prop, data=dict(source="abc pdr", engine=f"engine_{engine_idx}"))
|
|
173
|
+
disproved.add(output)
|
|
174
|
+
proc_status = "FAIL"
|
|
175
|
+
proc = aigsmt_trace_callback(task, engine_idx, proc_status,
|
|
176
|
+
run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append,
|
|
177
|
+
name=match[2],
|
|
178
|
+
)
|
|
179
|
+
proc.register_exit_callback(exit_callback)
|
|
180
|
+
procs_running += 1
|
|
181
|
+
else:
|
|
182
|
+
match = re.match(r"^Output [0-9]+ of miter .* was asserted in frame [0-9]+.", line)
|
|
183
|
+
if match: proc_status = "FAIL"
|
|
184
|
+
|
|
185
|
+
match = re.match(r"^Proved output +([0-9]+) in frame +-?[0-9]+", line)
|
|
186
|
+
if match:
|
|
187
|
+
output = int(match[1])
|
|
188
|
+
prop = aiger_props[output]
|
|
189
|
+
if prop:
|
|
190
|
+
prop.status = "PASS"
|
|
191
|
+
task.status_db.set_task_property_status(prop, data=dict(source="abc pdr", engine=f"engine_{engine_idx}"))
|
|
192
|
+
proved.add(output)
|
|
84
193
|
|
|
85
194
|
match = re.match(r"^Simulation of [0-9]+ frames for [0-9]+ rounds with [0-9]+ restarts did not assert POs.", line)
|
|
86
195
|
if match: proc_status = "UNKNOWN"
|
|
@@ -94,11 +203,44 @@ def run(mode, task, engine_idx, engine):
|
|
|
94
203
|
match = re.match(r"^Property proved.", line)
|
|
95
204
|
if match: proc_status = "PASS"
|
|
96
205
|
|
|
206
|
+
if keep_going:
|
|
207
|
+
match = re.match(r"^Properties: All = (\d+). Proved = (\d+). Disproved = (\d+). Undecided = (\d+).", line)
|
|
208
|
+
if match:
|
|
209
|
+
all_count = int(match[1])
|
|
210
|
+
proved_count = int(match[2])
|
|
211
|
+
disproved_count = int(match[3])
|
|
212
|
+
undecided_count = int(match[4])
|
|
213
|
+
if (
|
|
214
|
+
all_count != len(aiger_props) or
|
|
215
|
+
all_count != proved_count + disproved_count + undecided_count or
|
|
216
|
+
disproved_count != len(disproved) or
|
|
217
|
+
proved_count != len(proved)
|
|
218
|
+
):
|
|
219
|
+
log("WARNING: inconsistent status output")
|
|
220
|
+
proc_status = "UNKNOWN"
|
|
221
|
+
elif proved_count == all_count:
|
|
222
|
+
proc_status = "PASS"
|
|
223
|
+
elif disproved_count == 0:
|
|
224
|
+
proc_status = "UNKNOWN"
|
|
225
|
+
else:
|
|
226
|
+
proc_status = "FAIL"
|
|
227
|
+
|
|
97
228
|
return line
|
|
98
229
|
|
|
99
230
|
def exit_callback(retcode):
|
|
100
|
-
|
|
101
|
-
|
|
231
|
+
nonlocal procs_running
|
|
232
|
+
if keep_going:
|
|
233
|
+
procs_running -= 1
|
|
234
|
+
if not procs_running:
|
|
235
|
+
if proc_status == "FAIL" and mode == "bmc" and keep_going:
|
|
236
|
+
task.pass_unknown_asserts(dict(source="abc pdr", keep_going=True, engine=f"engine_{engine_idx}"))
|
|
237
|
+
task.update_status(proc_status)
|
|
238
|
+
task.summary.set_engine_status(engine_idx, proc_status)
|
|
239
|
+
if proc_status != "UNKNOWN" and not keep_going:
|
|
240
|
+
task.terminate()
|
|
241
|
+
else:
|
|
242
|
+
aigsmt_exit_callback(task, engine_idx, proc_status,
|
|
243
|
+
run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append)
|
|
102
244
|
|
|
103
245
|
proc.output_callback = output_callback
|
|
104
246
|
proc.register_exit_callback(exit_callback)
|
|
@@ -121,70 +121,108 @@ def run(mode, task, engine_idx, engine):
|
|
|
121
121
|
|
|
122
122
|
|
|
123
123
|
def aigsmt_exit_callback(task, engine_idx, proc_status, *, run_aigsmt, smtbmc_vcd, smtbmc_append, sim_append):
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
if proc_status is None:
|
|
125
|
+
task.error(f"engine_{engine_idx}: Could not determine engine status.")
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
task.update_status(proc_status)
|
|
128
|
+
task.summary.set_engine_status(engine_idx, proc_status)
|
|
129
|
+
task.terminate()
|
|
130
|
+
if proc_status == "FAIL" and (not run_aigsmt or task.opt_aigsmt != "none"):
|
|
131
|
+
aigsmt_trace_callback(task, engine_idx, proc_status, run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append)
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
trace_prefix = f"engine_{engine_idx}/trace"
|
|
133
|
+
def aigsmt_trace_callback(task, engine_idx, proc_status, *, run_aigsmt, smtbmc_vcd, smtbmc_append, sim_append, name="trace"):
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
trace_prefix = f"engine_{engine_idx}/{name}"
|
|
135
136
|
|
|
136
|
-
|
|
137
|
-
task, f"engine_{engine_idx}", [],
|
|
138
|
-
f"cd {task.workdir}; {task.exe_paths['witness']} aiw2yw engine_{engine_idx}/trace.aiw model/design_aiger.ywa engine_{engine_idx}/trace{aiw2yw_suffix}.yw",
|
|
139
|
-
)
|
|
140
|
-
yw_proc = witness_proc
|
|
137
|
+
aiw2yw_suffix = '_aiw' if run_aigsmt else ''
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
139
|
+
witness_proc = SbyProc(
|
|
140
|
+
task, f"engine_{engine_idx}", [],
|
|
141
|
+
f"cd {task.workdir}; {task.exe_paths['witness']} aiw2yw engine_{engine_idx}/{name}.aiw model/design_aiger.ywa engine_{engine_idx}/{name}{aiw2yw_suffix}.yw",
|
|
142
|
+
)
|
|
143
|
+
final_proc = witness_proc
|
|
144
|
+
|
|
145
|
+
if run_aigsmt:
|
|
146
|
+
smtbmc_opts = []
|
|
147
|
+
smtbmc_opts += ["-s", task.opt_aigsmt]
|
|
148
|
+
if task.opt_tbtop is not None:
|
|
149
|
+
smtbmc_opts += ["--vlogtb-top", task.opt_tbtop]
|
|
150
|
+
smtbmc_opts += ["--noprogress", f"--append {smtbmc_append}"]
|
|
151
|
+
if smtbmc_vcd:
|
|
152
|
+
smtbmc_opts += [f"--dump-vcd {trace_prefix}.vcd"]
|
|
153
|
+
smtbmc_opts += [f"--dump-yw {trace_prefix}.yw", f"--dump-vlogtb {trace_prefix}_tb.v", f"--dump-smtc {trace_prefix}.smtc"]
|
|
154
|
+
|
|
155
|
+
proc2 = SbyProc(
|
|
156
|
+
task,
|
|
157
|
+
f"engine_{engine_idx}",
|
|
158
|
+
[*task.model("smt2"), witness_proc],
|
|
159
|
+
f"cd {task.workdir}; {task.exe_paths['smtbmc']} {' '.join(smtbmc_opts)} --yw engine_{engine_idx}/{name}{aiw2yw_suffix}.yw model/design_smt2.smt2",
|
|
160
|
+
logfile=open(f"{task.workdir}/engine_{engine_idx}/logfile2.txt", "w"),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
proc2_status = None
|
|
164
|
+
|
|
165
|
+
last_prop = []
|
|
166
|
+
current_step = None
|
|
167
|
+
|
|
168
|
+
def output_callback2(line):
|
|
169
|
+
nonlocal proc2_status
|
|
170
|
+
nonlocal last_prop
|
|
171
|
+
nonlocal current_step
|
|
172
|
+
|
|
173
|
+
smt2_trans = {'\\':'/', '|':'/'}
|
|
174
|
+
|
|
175
|
+
match = re.match(r"^## [0-9: ]+ .* in step ([0-9]+)\.\.", line)
|
|
176
|
+
if match:
|
|
177
|
+
current_step = int(match[1])
|
|
178
|
+
return line
|
|
179
|
+
|
|
180
|
+
match = re.match(r"^## [0-9: ]+ Status: FAILED", line)
|
|
181
|
+
if match: proc2_status = "FAIL"
|
|
182
|
+
|
|
183
|
+
match = re.match(r"^## [0-9: ]+ Status: PASSED", line)
|
|
184
|
+
if match: proc2_status = "PASS"
|
|
185
|
+
|
|
186
|
+
match = re.match(r"^## [0-9: ]+ Assert failed in (\S+): (\S+)(?: \((\S+)\))?", line)
|
|
187
|
+
if match:
|
|
188
|
+
cell_name = match[3] or match[2]
|
|
189
|
+
prop = task.design.hierarchy.find_property_by_cellname(cell_name, trans_dict=smt2_trans)
|
|
190
|
+
prop.status = "FAIL"
|
|
191
|
+
task.status_db.set_task_property_status(prop, data=dict(source="aigsmt", engine=f"engine_{engine_idx}"))
|
|
192
|
+
last_prop.append(prop)
|
|
193
|
+
return line
|
|
194
|
+
|
|
195
|
+
match = re.match(r"^## [0-9: ]+ Writing trace to VCD file: (\S+)", line)
|
|
196
|
+
if match:
|
|
197
|
+
tracefile = match[1]
|
|
198
|
+
trace = os.path.basename(tracefile)[:-4]
|
|
199
|
+
task.summary.add_event(engine_idx=engine_idx, trace=trace, path=tracefile)
|
|
200
|
+
|
|
201
|
+
if match and last_prop:
|
|
202
|
+
for p in last_prop:
|
|
203
|
+
task.summary.add_event(
|
|
204
|
+
engine_idx=engine_idx, trace=trace,
|
|
205
|
+
type=p.celltype, hdlname=p.hdlname, src=p.location, step=current_step)
|
|
206
|
+
p.tracefiles.append(tracefile)
|
|
207
|
+
last_prop = []
|
|
208
|
+
return line
|
|
209
|
+
|
|
210
|
+
return line
|
|
211
|
+
|
|
212
|
+
def exit_callback2(retcode):
|
|
213
|
+
if proc2_status is None:
|
|
214
|
+
task.error(f"engine_{engine_idx}: Could not determine aigsmt status.")
|
|
215
|
+
if proc2_status != "FAIL":
|
|
216
|
+
task.error(f"engine_{engine_idx}: Unexpected aigsmt status.")
|
|
217
|
+
|
|
218
|
+
proc2.output_callback = output_callback2
|
|
219
|
+
proc2.register_exit_callback(exit_callback2)
|
|
220
|
+
|
|
221
|
+
final_proc = proc2
|
|
222
|
+
|
|
223
|
+
if task.opt_fst or (task.opt_vcd and task.opt_vcd_sim):
|
|
224
|
+
final_proc = sim_witness_trace(f"engine_{engine_idx}", task, engine_idx, f"engine_{engine_idx}/{name}.yw", append=sim_append, deps=[final_proc])
|
|
225
|
+
elif not run_aigsmt:
|
|
226
|
+
task.log(f"{click.style(f'engine_{engine_idx}', fg='magenta')}: Engine did not produce a counter example.")
|
|
227
|
+
|
|
228
|
+
return final_proc
|
|
@@ -233,6 +233,7 @@ def run(mode, task, engine_idx, engine):
|
|
|
233
233
|
cell_name = match[3] or match[2]
|
|
234
234
|
prop = task.design.hierarchy.find_property_by_cellname(cell_name, trans_dict=smt2_trans)
|
|
235
235
|
prop.status = "FAIL"
|
|
236
|
+
task.status_db.set_task_property_status(prop, data=dict(source="smtbmc", engine=f"engine_{engine_idx}"))
|
|
236
237
|
last_prop.append(prop)
|
|
237
238
|
return line
|
|
238
239
|
|
|
@@ -241,6 +242,7 @@ def run(mode, task, engine_idx, engine):
|
|
|
241
242
|
cell_name = match[2] or match[1]
|
|
242
243
|
prop = task.design.hierarchy.find_property_by_cellname(cell_name, trans_dict=smt2_trans)
|
|
243
244
|
prop.status = "PASS"
|
|
245
|
+
task.status_db.set_task_property_status(prop, data=dict(source="smtbmc", engine=f"engine_{engine_idx}"))
|
|
244
246
|
last_prop.append(prop)
|
|
245
247
|
return line
|
|
246
248
|
|
|
@@ -271,6 +273,7 @@ def run(mode, task, engine_idx, engine):
|
|
|
271
273
|
cell_name = match[2]
|
|
272
274
|
prop = task.design.hierarchy.find_property_by_cellname(cell_name, trans_dict=smt2_trans)
|
|
273
275
|
prop.status = "FAIL"
|
|
276
|
+
task.status_db.set_task_property_status(prop, data=dict(source="smtbmc", engine=f"engine_{engine_idx}"))
|
|
274
277
|
|
|
275
278
|
return line
|
|
276
279
|
|
|
@@ -288,10 +291,12 @@ def run(mode, task, engine_idx, engine):
|
|
|
288
291
|
def last_exit_callback():
|
|
289
292
|
if mode == "bmc" or mode == "cover":
|
|
290
293
|
task.update_status(proc_status)
|
|
294
|
+
if proc_status == "FAIL" and mode == "bmc" and keep_going:
|
|
295
|
+
task.pass_unknown_asserts(dict(source="smtbmc", keep_going=True, engine=f"engine_{engine_idx}"))
|
|
291
296
|
proc_status_lower = proc_status.lower() if proc_status == "PASS" else proc_status
|
|
292
297
|
task.summary.set_engine_status(engine_idx, proc_status_lower)
|
|
293
|
-
|
|
294
|
-
|
|
298
|
+
if not keep_going:
|
|
299
|
+
task.terminate()
|
|
295
300
|
|
|
296
301
|
elif mode in ["prove_basecase", "prove_induction"]:
|
|
297
302
|
proc_status_lower = proc_status.lower() if proc_status == "PASS" else proc_status
|
|
@@ -321,7 +326,8 @@ def run(mode, task, engine_idx, engine):
|
|
|
321
326
|
if task.basecase_pass and task.induction_pass:
|
|
322
327
|
task.update_status("PASS")
|
|
323
328
|
task.summary.append("successful proof by k-induction.")
|
|
324
|
-
|
|
329
|
+
if not keep_going:
|
|
330
|
+
task.terminate()
|
|
325
331
|
|
|
326
332
|
else:
|
|
327
333
|
assert False
|