yowasp-yosys 0.55.0.3.post946.dev0__py3-none-any.whl → 0.56.0.0.post964__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 +39 -8
- yowasp_yosys/share/include/kernel/constids.inc +1 -0
- yowasp_yosys/share/include/kernel/io.h +382 -8
- yowasp_yosys/share/include/kernel/json.h +2 -2
- yowasp_yosys/share/include/kernel/register.h +42 -4
- yowasp_yosys/share/include/kernel/rtlil.h +5 -1
- yowasp_yosys/share/include/kernel/satgen.h +3 -1
- yowasp_yosys/share/include/kernel/yosys_common.h +9 -0
- yowasp_yosys/share/include/passes/techmap/libparse.h +235 -0
- yowasp_yosys/share/python3/sby_autotune.py +1 -1
- yowasp_yosys/share/python3/sby_cmdline.py +13 -0
- yowasp_yosys/share/python3/sby_core.py +208 -85
- yowasp_yosys/share/python3/sby_design.py +4 -0
- yowasp_yosys/share/python3/sby_engine_abc.py +15 -4
- yowasp_yosys/share/python3/sby_engine_aiger.py +14 -9
- yowasp_yosys/share/python3/sby_engine_btor.py +15 -4
- yowasp_yosys/share/python3/sby_engine_smtbmc.py +40 -27
- yowasp_yosys/share/python3/sby_status.py +388 -115
- yowasp_yosys/yosys.wasm +0 -0
- {yowasp_yosys-0.55.0.3.post946.dev0.dist-info → yowasp_yosys-0.56.0.0.post964.dist-info}/METADATA +1 -1
- {yowasp_yosys-0.55.0.3.post946.dev0.dist-info → yowasp_yosys-0.56.0.0.post964.dist-info}/RECORD +24 -23
- {yowasp_yosys-0.55.0.3.post946.dev0.dist-info → yowasp_yosys-0.56.0.0.post964.dist-info}/WHEEL +0 -0
- {yowasp_yosys-0.55.0.3.post946.dev0.dist-info → yowasp_yosys-0.56.0.0.post964.dist-info}/entry_points.txt +0 -0
- {yowasp_yosys-0.55.0.3.post946.dev0.dist-info → yowasp_yosys-0.56.0.0.post964.dist-info}/top_level.txt +0 -0
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
#
|
|
18
18
|
|
|
19
19
|
import os, re, sys, signal, platform, click
|
|
20
|
+
import time
|
|
20
21
|
if os.name == "posix":
|
|
21
22
|
import resource, fcntl
|
|
22
23
|
import subprocess
|
|
24
|
+
from pathlib import Path
|
|
23
25
|
from dataclasses import dataclass, field
|
|
24
26
|
from collections import defaultdict
|
|
25
27
|
from typing import Optional
|
|
@@ -43,12 +45,8 @@ signal.signal(signal.SIGINT, force_shutdown)
|
|
|
43
45
|
signal.signal(signal.SIGTERM, force_shutdown)
|
|
44
46
|
|
|
45
47
|
def process_filename(filename):
|
|
46
|
-
if filename.startswith("~/"):
|
|
47
|
-
filename = os.environ['HOME'] + filename[1:]
|
|
48
|
-
|
|
49
48
|
filename = os.path.expandvars(filename)
|
|
50
|
-
|
|
51
|
-
return filename
|
|
49
|
+
return Path(filename).expanduser()
|
|
52
50
|
|
|
53
51
|
def dress_message(workdir, logmessage):
|
|
54
52
|
tm = localtime()
|
|
@@ -97,6 +95,7 @@ class SbyProc:
|
|
|
97
95
|
self.silent = silent
|
|
98
96
|
self.wait = False
|
|
99
97
|
self.job_lease = None
|
|
98
|
+
self.next_db = 0.0
|
|
100
99
|
|
|
101
100
|
self.task.update_proc_pending(self)
|
|
102
101
|
|
|
@@ -148,8 +147,8 @@ class SbyProc:
|
|
|
148
147
|
if self.error_callback is not None:
|
|
149
148
|
self.error_callback(retcode)
|
|
150
149
|
|
|
151
|
-
def terminate(self,
|
|
152
|
-
if (self.task.opt_wait or self.wait) and not
|
|
150
|
+
def terminate(self, force=False):
|
|
151
|
+
if (self.task.opt_wait or self.wait) and not force:
|
|
153
152
|
return
|
|
154
153
|
if self.running:
|
|
155
154
|
if not self.silent:
|
|
@@ -175,6 +174,36 @@ class SbyProc:
|
|
|
175
174
|
if self.finished or self.terminated or self.exited:
|
|
176
175
|
return
|
|
177
176
|
|
|
177
|
+
for task in self.task.taskloop.tasks_done:
|
|
178
|
+
if task.name in self.task.cancelledby:
|
|
179
|
+
if not self.silent:
|
|
180
|
+
self.task.log(f"Cancelled by {task.name!r} task")
|
|
181
|
+
self.task.cancel()
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
if self.task.status_cancels and time.time() >= self.next_db:
|
|
185
|
+
tasks_status = self.task.status_db.all_tasks_status()
|
|
186
|
+
for task_status in tasks_status.values():
|
|
187
|
+
if (task_status["status"] in ["PASS", "FAIL", "CANCELLED"] and
|
|
188
|
+
task_status["name"] in self.task.cancelledby):
|
|
189
|
+
if not self.silent:
|
|
190
|
+
status_time = time.localtime(task_status["status_created"])
|
|
191
|
+
if status_time.tm_yday == time.localtime().tm_yday:
|
|
192
|
+
# same day, format time only
|
|
193
|
+
time_format = r"%H:%M:%S"
|
|
194
|
+
else:
|
|
195
|
+
time_format = r"%x %H:%M:%S"
|
|
196
|
+
self.task.log(
|
|
197
|
+
f'Cancelled by {task_status["name"]!r} task '
|
|
198
|
+
f'with status {task_status["status"]!r} '
|
|
199
|
+
f'at {time.strftime(time_format, status_time)} '
|
|
200
|
+
'(consider calling sby with --statusreset if this seems wrong)'
|
|
201
|
+
)
|
|
202
|
+
self.task.cancel()
|
|
203
|
+
return
|
|
204
|
+
# don't hit the database every poll
|
|
205
|
+
self.next_db = time.time() + 10
|
|
206
|
+
|
|
178
207
|
if not self.running:
|
|
179
208
|
for dep in self.deps:
|
|
180
209
|
if not dep.finished:
|
|
@@ -218,6 +247,10 @@ class SbyProc:
|
|
|
218
247
|
if self.job_lease:
|
|
219
248
|
self.job_lease.done()
|
|
220
249
|
|
|
250
|
+
if self.terminated:
|
|
251
|
+
# task already terminated, do not finish
|
|
252
|
+
return
|
|
253
|
+
|
|
221
254
|
if not self.silent:
|
|
222
255
|
self.task.log(f"{click.style(self.info, fg='magenta')}: finished (returncode={self.p.returncode})")
|
|
223
256
|
|
|
@@ -282,6 +315,7 @@ class SbyConfig:
|
|
|
282
315
|
self.autotune_config = None
|
|
283
316
|
self.files = dict()
|
|
284
317
|
self.verbatim_files = dict()
|
|
318
|
+
self.cancelledby = list()
|
|
285
319
|
pass
|
|
286
320
|
|
|
287
321
|
def parse_config(self, f):
|
|
@@ -402,6 +436,12 @@ class SbyConfig:
|
|
|
402
436
|
import sby_autotune
|
|
403
437
|
self.autotune_config = sby_autotune.SbyAutotuneConfig()
|
|
404
438
|
continue
|
|
439
|
+
|
|
440
|
+
if section == "cancelledby":
|
|
441
|
+
mode = "cancelledby"
|
|
442
|
+
if args is not None:
|
|
443
|
+
self.error(f"sby file syntax error: '[cancelledby]' section does not accept any arguments. got {args}")
|
|
444
|
+
continue
|
|
405
445
|
|
|
406
446
|
if section == "file":
|
|
407
447
|
mode = "file"
|
|
@@ -436,6 +476,12 @@ class SbyConfig:
|
|
|
436
476
|
if mode == "autotune":
|
|
437
477
|
self.autotune_config.config_line(self, line)
|
|
438
478
|
continue
|
|
479
|
+
|
|
480
|
+
if mode == "cancelledby":
|
|
481
|
+
taskname = line.strip()
|
|
482
|
+
if taskname:
|
|
483
|
+
self.cancelledby.append(taskname)
|
|
484
|
+
continue
|
|
439
485
|
|
|
440
486
|
if mode == "engines":
|
|
441
487
|
args = line.strip().split()
|
|
@@ -529,7 +575,7 @@ class SbyConfig:
|
|
|
529
575
|
self.error(f"sby file syntax error: '[files]' section entry expects up to 2 arguments, {len(entries)} specified")
|
|
530
576
|
|
|
531
577
|
if len(entries) == 1:
|
|
532
|
-
self.files[
|
|
578
|
+
self.files[Path(entries[0]).name] = entries[0]
|
|
533
579
|
elif len(entries) == 2:
|
|
534
580
|
self.files[entries[0]] = entries[1]
|
|
535
581
|
|
|
@@ -553,6 +599,7 @@ class SbyTaskloop:
|
|
|
553
599
|
self.procs_pending = []
|
|
554
600
|
self.procs_running = []
|
|
555
601
|
self.tasks = []
|
|
602
|
+
self.tasks_done = []
|
|
556
603
|
self.poll_now = False
|
|
557
604
|
self.jobclient = jobclient
|
|
558
605
|
|
|
@@ -605,6 +652,7 @@ class SbyTaskloop:
|
|
|
605
652
|
self.tasks.append(task)
|
|
606
653
|
else:
|
|
607
654
|
task.exit_callback()
|
|
655
|
+
self.tasks_done.append(task)
|
|
608
656
|
|
|
609
657
|
for task in self.tasks:
|
|
610
658
|
task.exit_callback()
|
|
@@ -631,6 +679,8 @@ class SbyTraceSummary:
|
|
|
631
679
|
path: Optional[str] = field(default=None)
|
|
632
680
|
engine_case: Optional[str] = field(default=None)
|
|
633
681
|
events: dict = field(default_factory=lambda: defaultdict(lambda: defaultdict(list)))
|
|
682
|
+
trace_ids: dict[str, int] = field(default_factory=lambda: dict())
|
|
683
|
+
last_ext: Optional[str] = field(default=None)
|
|
634
684
|
|
|
635
685
|
@property
|
|
636
686
|
def kind(self):
|
|
@@ -682,42 +732,62 @@ class SbySummary:
|
|
|
682
732
|
|
|
683
733
|
if update_status:
|
|
684
734
|
status_metadata = dict(source="summary_event", engine=engine.engine)
|
|
735
|
+
if event.step:
|
|
736
|
+
status_metadata["step"] = event.step
|
|
685
737
|
|
|
738
|
+
add_trace = False
|
|
686
739
|
if event.prop:
|
|
687
|
-
if event.type
|
|
740
|
+
if event.type is None:
|
|
741
|
+
event.type = event.prop.celltype
|
|
742
|
+
elif event.type == "$assert":
|
|
688
743
|
event.prop.status = "FAIL"
|
|
689
|
-
|
|
690
|
-
|
|
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
|
-
)
|
|
697
|
-
if event.prop:
|
|
698
|
-
if event.type == "$cover":
|
|
744
|
+
add_trace = True
|
|
745
|
+
elif event.type == "$cover":
|
|
699
746
|
event.prop.status = "PASS"
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
747
|
+
add_trace = True
|
|
748
|
+
|
|
749
|
+
trace_id = None
|
|
750
|
+
trace_path = None
|
|
751
|
+
if event.trace:
|
|
752
|
+
# get or create trace summary
|
|
753
|
+
try:
|
|
754
|
+
trace_summary = engine.traces[event.trace]
|
|
755
|
+
except KeyError:
|
|
756
|
+
trace_summary = SbyTraceSummary(event.trace, path=event.path, engine_case=event.engine_case)
|
|
757
|
+
engine.traces[event.trace] = trace_summary
|
|
758
|
+
|
|
759
|
+
if event.path:
|
|
760
|
+
trace_path = Path(event.path)
|
|
761
|
+
trace_ext = trace_path.suffix
|
|
762
|
+
trace_summary.last_ext = trace_ext
|
|
763
|
+
try:
|
|
764
|
+
# use existing tracefile for this extension
|
|
765
|
+
trace_id = trace_summary.trace_ids[trace_ext]
|
|
766
|
+
except KeyError:
|
|
767
|
+
# add tracefile to database
|
|
768
|
+
trace_id = self.task.status_db.add_task_trace(event.trace, event.path, trace_ext[1:], event.engine_case)
|
|
769
|
+
trace_summary.trace_ids[trace_ext] = trace_id
|
|
770
|
+
elif trace_summary.path:
|
|
771
|
+
# use existing tracefile for last extension
|
|
772
|
+
trace_path = Path(trace_summary.path)
|
|
773
|
+
trace_ext = trace_summary.last_ext
|
|
774
|
+
trace_id = trace_summary.trace_ids[trace_ext]
|
|
775
|
+
|
|
776
|
+
if event.type:
|
|
777
|
+
by_type = trace_summary.events[event.type]
|
|
778
|
+
if event.hdlname:
|
|
779
|
+
by_type[event.hdlname].append(event)
|
|
780
|
+
|
|
708
781
|
if event.prop and update_status:
|
|
782
|
+
# update property status in database
|
|
709
783
|
self.task.status_db.set_task_property_status(
|
|
710
784
|
event.prop,
|
|
711
|
-
|
|
785
|
+
trace_id=trace_id,
|
|
786
|
+
data=status_metadata,
|
|
712
787
|
)
|
|
713
788
|
|
|
714
|
-
if
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if event.type:
|
|
718
|
-
by_type = engine.traces[event.trace].events[event.type]
|
|
719
|
-
if event.hdlname:
|
|
720
|
-
by_type[event.hdlname].append(event)
|
|
789
|
+
if trace_path and add_trace:
|
|
790
|
+
event.prop.tracefiles.append(str(trace_path))
|
|
721
791
|
|
|
722
792
|
def set_engine_status(self, engine_idx, status, case=None):
|
|
723
793
|
engine_summary = self.engine_summary(engine_idx)
|
|
@@ -759,10 +829,21 @@ class SbySummary:
|
|
|
759
829
|
break
|
|
760
830
|
case_suffix = f" [{trace.engine_case}]" if trace.engine_case else ""
|
|
761
831
|
if trace.path:
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
832
|
+
# print single preferred trace
|
|
833
|
+
preferred_exts = [".fst", ".vcd"]
|
|
834
|
+
if trace.last_ext not in preferred_exts: preferred_exts.append(trace.last_ext)
|
|
835
|
+
for ext in trace.trace_ids.keys():
|
|
836
|
+
if ext not in preferred_exts: preferred_exts.append(ext)
|
|
837
|
+
for ext in preferred_exts:
|
|
838
|
+
if ext not in trace.trace_ids:
|
|
839
|
+
continue
|
|
840
|
+
if short:
|
|
841
|
+
path = Path(self.task.workdir) / trace.path
|
|
842
|
+
else:
|
|
843
|
+
path = Path(trace.path)
|
|
844
|
+
yield f"{trace.kind}{case_suffix}: {path.with_suffix(ext)}"
|
|
845
|
+
if short:
|
|
846
|
+
break
|
|
766
847
|
else:
|
|
767
848
|
yield f"{trace.kind}{case_suffix}: <{trace.trace}>"
|
|
768
849
|
produced_traces = True
|
|
@@ -785,15 +866,18 @@ class SbySummary:
|
|
|
785
866
|
break
|
|
786
867
|
|
|
787
868
|
event = same_events[0]
|
|
788
|
-
steps
|
|
869
|
+
# uniquify steps and ignore events with missing steps
|
|
870
|
+
steps = sorted(set(e.step for e in same_events if e.step))
|
|
789
871
|
if short and len(steps) > step_limit:
|
|
790
872
|
excess = len(steps) - step_limit
|
|
791
873
|
steps = [str(step) for step in steps[:step_limit]]
|
|
792
874
|
omitted_excess = True
|
|
793
875
|
steps[-1] += f" and {excess} further step{'s' if excess != 1 else ''}"
|
|
794
876
|
|
|
795
|
-
|
|
796
|
-
|
|
877
|
+
event_string = f" {desc} {hdlname} at {event.src}"
|
|
878
|
+
if steps:
|
|
879
|
+
event_string += f" step{'s' if len(steps) > 1 else ''} {', '.join(map(str, steps))}"
|
|
880
|
+
yield event_string
|
|
797
881
|
|
|
798
882
|
if not produced_traces:
|
|
799
883
|
yield f"{engine.engine} did not produce any traces"
|
|
@@ -801,7 +885,7 @@ class SbySummary:
|
|
|
801
885
|
if self.unreached_covers is None and self.task.opt_mode == 'cover' and self.task.status != "PASS" and self.task.design:
|
|
802
886
|
self.unreached_covers = []
|
|
803
887
|
for prop in self.task.design.hierarchy:
|
|
804
|
-
if prop.type == prop.Type.COVER and prop.status
|
|
888
|
+
if prop.type == prop.Type.COVER and prop.status in ["UNKNOWN", "FAIL"]:
|
|
805
889
|
self.unreached_covers.append(prop)
|
|
806
890
|
|
|
807
891
|
if self.unreached_covers:
|
|
@@ -825,12 +909,15 @@ class SbySummary:
|
|
|
825
909
|
|
|
826
910
|
|
|
827
911
|
class SbyTask(SbyConfig):
|
|
828
|
-
def __init__(self, sbyconfig, workdir, early_logs, reusedir, taskloop=None, logfile=None):
|
|
912
|
+
def __init__(self, sbyconfig, workdir, early_logs, reusedir, status_cancels=False, taskloop=None, logfile=None, name=None, live_formats=[]):
|
|
829
913
|
super().__init__()
|
|
830
914
|
self.used_options = set()
|
|
831
915
|
self.models = dict()
|
|
832
916
|
self.workdir = workdir
|
|
833
917
|
self.reusedir = reusedir
|
|
918
|
+
self.status_cancels = status_cancels
|
|
919
|
+
self.name = name
|
|
920
|
+
self.live_formats = live_formats
|
|
834
921
|
self.status = "UNKNOWN"
|
|
835
922
|
self.total_time = 0
|
|
836
923
|
self.expect = list()
|
|
@@ -942,35 +1029,44 @@ class SbyTask(SbyConfig):
|
|
|
942
1029
|
raise SbyAbort(logmessage)
|
|
943
1030
|
|
|
944
1031
|
def makedirs(self, path):
|
|
945
|
-
|
|
1032
|
+
path = Path(path)
|
|
1033
|
+
if self.reusedir and path.is_dir():
|
|
946
1034
|
rmtree(path, ignore_errors=True)
|
|
947
|
-
|
|
948
|
-
os.makedirs(path)
|
|
1035
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
949
1036
|
|
|
950
|
-
def copy_src(self):
|
|
951
|
-
|
|
1037
|
+
def copy_src(self, linkmode=False):
|
|
1038
|
+
outdir = Path(self.workdir) / "src"
|
|
1039
|
+
self.makedirs(outdir)
|
|
952
1040
|
|
|
953
1041
|
for dstfile, lines in self.verbatim_files.items():
|
|
954
|
-
dstfile =
|
|
955
|
-
self.log(f"Writing '{dstfile}'.")
|
|
1042
|
+
dstfile = outdir / dstfile
|
|
1043
|
+
self.log(f"Writing '{dstfile.absolute()}'.")
|
|
1044
|
+
dstfile.parent.mkdir(parents=True, exist_ok=True)
|
|
956
1045
|
|
|
957
1046
|
with open(dstfile, "w") as f:
|
|
958
1047
|
for line in lines:
|
|
959
1048
|
f.write(line)
|
|
960
1049
|
|
|
961
1050
|
for dstfile, srcfile in self.files.items():
|
|
962
|
-
|
|
1051
|
+
dstfile = Path(dstfile)
|
|
1052
|
+
if dstfile.is_absolute() or ".." in dstfile.parts:
|
|
963
1053
|
self.error(f"destination filename must be a relative path without /../: {dstfile}")
|
|
964
|
-
dstfile =
|
|
1054
|
+
dstfile = outdir / dstfile
|
|
965
1055
|
|
|
966
1056
|
srcfile = process_filename(srcfile)
|
|
967
1057
|
|
|
968
|
-
basedir =
|
|
969
|
-
|
|
970
|
-
|
|
1058
|
+
basedir = dstfile.parent
|
|
1059
|
+
basedir.mkdir(parents=True, exist_ok=True)
|
|
1060
|
+
|
|
1061
|
+
if linkmode:
|
|
1062
|
+
verb = "Link"
|
|
1063
|
+
else:
|
|
1064
|
+
verb = "Copy"
|
|
1065
|
+
self.log(f"{verb} '{srcfile.absolute()}' to '{dstfile.absolute()}'.")
|
|
971
1066
|
|
|
972
|
-
|
|
973
|
-
|
|
1067
|
+
if linkmode:
|
|
1068
|
+
os.symlink(srcfile.resolve(), dstfile)
|
|
1069
|
+
elif srcfile.is_dir():
|
|
974
1070
|
copytree(srcfile, dstfile, dirs_exist_ok=True)
|
|
975
1071
|
else:
|
|
976
1072
|
copyfile(srcfile, dstfile)
|
|
@@ -999,12 +1095,12 @@ class SbyTask(SbyConfig):
|
|
|
999
1095
|
self.__dict__["opt_" + option_name] = default_value
|
|
1000
1096
|
|
|
1001
1097
|
def make_model(self, model_name):
|
|
1002
|
-
|
|
1003
|
-
|
|
1098
|
+
modeldir = Path(self.workdir) / "model"
|
|
1099
|
+
modeldir.mkdir(exist_ok=True)
|
|
1004
1100
|
|
|
1005
1101
|
if model_name == "prep":
|
|
1006
|
-
with open(
|
|
1007
|
-
print(f"# running in {
|
|
1102
|
+
with open(modeldir / "design_prep.ys", "w") as f:
|
|
1103
|
+
print(f"# running in {modeldir}/", file=f)
|
|
1008
1104
|
print(f"""read_rtlil design.il""", file=f)
|
|
1009
1105
|
if not self.opt_skip_prep:
|
|
1010
1106
|
print("scc -select; simplemap; select -clear", file=f)
|
|
@@ -1020,7 +1116,10 @@ class SbyTask(SbyConfig):
|
|
|
1020
1116
|
if self.opt_mode in ["bmc", "prove"]:
|
|
1021
1117
|
print("chformal -live -fair -cover -remove", file=f)
|
|
1022
1118
|
if self.opt_mode == "cover":
|
|
1023
|
-
|
|
1119
|
+
if self.opt_cover_assert:
|
|
1120
|
+
print("chformal -live -fair -remove", file=f)
|
|
1121
|
+
else:
|
|
1122
|
+
print("chformal -live -fair -assert -remove", file=f)
|
|
1024
1123
|
if self.opt_mode == "live":
|
|
1025
1124
|
print("chformal -assert2assume", file=f)
|
|
1026
1125
|
print("chformal -cover -remove", file=f)
|
|
@@ -1045,7 +1144,7 @@ class SbyTask(SbyConfig):
|
|
|
1045
1144
|
return [proc]
|
|
1046
1145
|
|
|
1047
1146
|
if model_name == "base":
|
|
1048
|
-
with open(
|
|
1147
|
+
with open(modeldir / "design.ys", "w") as f:
|
|
1049
1148
|
print(f"# running in {self.workdir}/src/", file=f)
|
|
1050
1149
|
for cmd in self.script:
|
|
1051
1150
|
print(cmd, file=f)
|
|
@@ -1067,7 +1166,7 @@ class SbyTask(SbyConfig):
|
|
|
1067
1166
|
|
|
1068
1167
|
def instance_hierarchy_callback(retcode):
|
|
1069
1168
|
if self.design == None:
|
|
1070
|
-
with open(
|
|
1169
|
+
with open(modeldir / "design.json") as f:
|
|
1071
1170
|
self.design = design_hierarchy(f)
|
|
1072
1171
|
self.status_db.create_task_properties([
|
|
1073
1172
|
prop for prop in self.design.properties_by_path.values()
|
|
@@ -1083,8 +1182,8 @@ class SbyTask(SbyConfig):
|
|
|
1083
1182
|
return [proc]
|
|
1084
1183
|
|
|
1085
1184
|
if re.match(r"^smt2(_syn)?(_nomem)?(_stbv|_stdt)?$", model_name):
|
|
1086
|
-
with open(f"
|
|
1087
|
-
print(f"# running in {
|
|
1185
|
+
with open(modeldir / f"design_{model_name}.ys", "w") as f:
|
|
1186
|
+
print(f"# running in {modeldir}/", file=f)
|
|
1088
1187
|
print(f"""read_rtlil design_prep.il""", file=f)
|
|
1089
1188
|
print("hierarchy -smtcheck", file=f)
|
|
1090
1189
|
print("delete */t:$print", file=f)
|
|
@@ -1117,8 +1216,8 @@ class SbyTask(SbyConfig):
|
|
|
1117
1216
|
return [proc]
|
|
1118
1217
|
|
|
1119
1218
|
if re.match(r"^btor(_syn)?(_nomem)?$", model_name):
|
|
1120
|
-
with open(f"
|
|
1121
|
-
print(f"# running in {
|
|
1219
|
+
with open(modeldir / f"design_{model_name}.ys", "w") as f:
|
|
1220
|
+
print(f"# running in {modeldir}/", file=f)
|
|
1122
1221
|
print(f"""read_rtlil design_prep.il""", file=f)
|
|
1123
1222
|
print("hierarchy -simcheck", file=f)
|
|
1124
1223
|
print("delete */t:$print", file=f)
|
|
@@ -1153,8 +1252,8 @@ class SbyTask(SbyConfig):
|
|
|
1153
1252
|
return [proc]
|
|
1154
1253
|
|
|
1155
1254
|
if model_name == "aig":
|
|
1156
|
-
with open(
|
|
1157
|
-
print(f"# running in {
|
|
1255
|
+
with open(modeldir / "design_aiger.ys", "w") as f:
|
|
1256
|
+
print(f"# running in {modeldir}/", file=f)
|
|
1158
1257
|
print("read_rtlil design_prep.il", file=f)
|
|
1159
1258
|
print("delete */t:$print", file=f)
|
|
1160
1259
|
print("hierarchy -simcheck", file=f)
|
|
@@ -1180,7 +1279,7 @@ class SbyTask(SbyConfig):
|
|
|
1180
1279
|
self,
|
|
1181
1280
|
"aig",
|
|
1182
1281
|
self.model("prep"),
|
|
1183
|
-
f"""cd {
|
|
1282
|
+
f"""cd {modeldir}; {self.exe_paths["yosys"]} -ql design_aiger.log design_aiger.ys"""
|
|
1184
1283
|
)
|
|
1185
1284
|
proc.checkretcode = True
|
|
1186
1285
|
|
|
@@ -1191,8 +1290,8 @@ class SbyTask(SbyConfig):
|
|
|
1191
1290
|
self,
|
|
1192
1291
|
model_name,
|
|
1193
1292
|
self.model("aig"),
|
|
1194
|
-
f"""cd {
|
|
1195
|
-
logfile=open(f"{
|
|
1293
|
+
f"""cd {modeldir}; {self.exe_paths["abc"]} -c 'read_aiger design_aiger.aig; fold{" -s" if self.opt_aigfolds else ""}; strash; write_aiger design_aiger_fold.aig'""",
|
|
1294
|
+
logfile=open(f"{modeldir}/design_aiger_fold.log", "w")
|
|
1196
1295
|
)
|
|
1197
1296
|
proc.checkretcode = True
|
|
1198
1297
|
|
|
@@ -1205,25 +1304,39 @@ class SbyTask(SbyConfig):
|
|
|
1205
1304
|
self.models[model_name] = self.make_model(model_name)
|
|
1206
1305
|
return self.models[model_name]
|
|
1207
1306
|
|
|
1208
|
-
def terminate(self, timeout=False):
|
|
1307
|
+
def terminate(self, timeout=False, cancel=False):
|
|
1209
1308
|
if timeout:
|
|
1210
1309
|
self.timeout_reached = True
|
|
1211
1310
|
for proc in list(self.procs_running):
|
|
1212
|
-
proc.terminate(timeout
|
|
1311
|
+
proc.terminate(timeout or cancel)
|
|
1213
1312
|
for proc in list(self.procs_pending):
|
|
1214
|
-
proc.terminate(timeout
|
|
1313
|
+
proc.terminate(timeout or cancel)
|
|
1314
|
+
if timeout:
|
|
1315
|
+
self.update_unknown_props(dict(source="timeout"))
|
|
1316
|
+
|
|
1317
|
+
def cancel(self):
|
|
1318
|
+
self.terminate(cancel=True)
|
|
1319
|
+
self.update_status("CANCELLED")
|
|
1215
1320
|
|
|
1216
1321
|
def proc_failed(self, proc):
|
|
1217
1322
|
# proc parameter used by autotune override
|
|
1218
1323
|
self.status = "ERROR"
|
|
1219
1324
|
self.terminate()
|
|
1220
1325
|
|
|
1326
|
+
def update_unknown_props(self, data):
|
|
1327
|
+
for prop in self.design.hierarchy:
|
|
1328
|
+
if prop.status != "UNKNOWN":
|
|
1329
|
+
continue
|
|
1330
|
+
if ((prop.type == prop.Type.ASSERT and self.opt_mode in ["bmc", "prove"]) or
|
|
1331
|
+
(prop.type == prop.Type.COVER and self.opt_mode == "cover")):
|
|
1332
|
+
self.status_db.set_task_property_status(prop, data=data)
|
|
1333
|
+
|
|
1221
1334
|
def pass_unknown_asserts(self, data):
|
|
1222
1335
|
for prop in self.design.pass_unknown_asserts():
|
|
1223
1336
|
self.status_db.set_task_property_status(prop, data=data)
|
|
1224
1337
|
|
|
1225
|
-
def update_status(self, new_status):
|
|
1226
|
-
assert new_status in ["PASS", "FAIL", "UNKNOWN", "ERROR"]
|
|
1338
|
+
def update_status(self, new_status, step = None):
|
|
1339
|
+
assert new_status in ["PASS", "FAIL", "UNKNOWN", "ERROR", "CANCELLED"]
|
|
1227
1340
|
self.status_db.set_task_status(new_status)
|
|
1228
1341
|
|
|
1229
1342
|
if new_status == "UNKNOWN":
|
|
@@ -1236,7 +1349,10 @@ class SbyTask(SbyConfig):
|
|
|
1236
1349
|
assert self.status != "FAIL"
|
|
1237
1350
|
self.status = "PASS"
|
|
1238
1351
|
if self.opt_mode in ("bmc", "prove") and self.design:
|
|
1239
|
-
|
|
1352
|
+
data = {"source": "task_status"}
|
|
1353
|
+
if step:
|
|
1354
|
+
data["step"] = step
|
|
1355
|
+
self.pass_unknown_asserts(data)
|
|
1240
1356
|
|
|
1241
1357
|
elif new_status == "FAIL":
|
|
1242
1358
|
assert self.status != "PASS"
|
|
@@ -1245,6 +1361,9 @@ class SbyTask(SbyConfig):
|
|
|
1245
1361
|
elif new_status == "ERROR":
|
|
1246
1362
|
self.status = "ERROR"
|
|
1247
1363
|
|
|
1364
|
+
elif new_status == "CANCELLED":
|
|
1365
|
+
self.status = "CANCELLED"
|
|
1366
|
+
|
|
1248
1367
|
else:
|
|
1249
1368
|
assert 0
|
|
1250
1369
|
|
|
@@ -1263,7 +1382,7 @@ class SbyTask(SbyConfig):
|
|
|
1263
1382
|
self.used_options.add("expect")
|
|
1264
1383
|
|
|
1265
1384
|
for s in self.expect:
|
|
1266
|
-
if s not in ["PASS", "FAIL", "UNKNOWN", "ERROR", "TIMEOUT"]:
|
|
1385
|
+
if s not in ["PASS", "FAIL", "UNKNOWN", "ERROR", "TIMEOUT", "CANCELLED"]:
|
|
1267
1386
|
self.error(f"Invalid expect value: {s}")
|
|
1268
1387
|
|
|
1269
1388
|
if self.opt_mode != "live":
|
|
@@ -1294,6 +1413,9 @@ class SbyTask(SbyConfig):
|
|
|
1294
1413
|
self.handle_bool_option("skip_prep", False)
|
|
1295
1414
|
|
|
1296
1415
|
self.handle_bool_option("assume_early", True)
|
|
1416
|
+
|
|
1417
|
+
if self.opt_mode == "cover":
|
|
1418
|
+
self.handle_bool_option("cover_assert", False)
|
|
1297
1419
|
|
|
1298
1420
|
def setup_status_db(self, status_path=None):
|
|
1299
1421
|
if hasattr(self, 'status_db'):
|
|
@@ -1306,9 +1428,9 @@ class SbyTask(SbyConfig):
|
|
|
1306
1428
|
except FileNotFoundError:
|
|
1307
1429
|
status_path = f"{self.workdir}/status.sqlite"
|
|
1308
1430
|
|
|
1309
|
-
self.status_db = SbyStatusDb(status_path, self)
|
|
1431
|
+
self.status_db = SbyStatusDb(status_path, self, live_formats=self.live_formats)
|
|
1310
1432
|
|
|
1311
|
-
def setup_procs(self, setupmode):
|
|
1433
|
+
def setup_procs(self, setupmode, linkmode=False):
|
|
1312
1434
|
self.handle_non_engine_options()
|
|
1313
1435
|
if self.opt_smtc is not None:
|
|
1314
1436
|
for engine_idx, engine in self.engine_list():
|
|
@@ -1329,7 +1451,7 @@ class SbyTask(SbyConfig):
|
|
|
1329
1451
|
if self.reusedir:
|
|
1330
1452
|
rmtree(f"{self.workdir}/model", ignore_errors=True)
|
|
1331
1453
|
else:
|
|
1332
|
-
self.copy_src()
|
|
1454
|
+
self.copy_src(linkmode)
|
|
1333
1455
|
|
|
1334
1456
|
if setupmode:
|
|
1335
1457
|
self.retcode = 0
|
|
@@ -1400,7 +1522,7 @@ class SbyTask(SbyConfig):
|
|
|
1400
1522
|
else:
|
|
1401
1523
|
self.log("summary: " + click.style(line, fg="green" if self.status in self.expect else "red", bold=True))
|
|
1402
1524
|
|
|
1403
|
-
assert self.status in ["PASS", "FAIL", "UNKNOWN", "ERROR", "TIMEOUT"]
|
|
1525
|
+
assert self.status in ["PASS", "FAIL", "UNKNOWN", "ERROR", "TIMEOUT", "CANCELLED"]
|
|
1404
1526
|
|
|
1405
1527
|
if self.status in self.expect:
|
|
1406
1528
|
self.retcode = 0
|
|
@@ -1410,6 +1532,7 @@ class SbyTask(SbyConfig):
|
|
|
1410
1532
|
if self.status == "UNKNOWN": self.retcode = 4
|
|
1411
1533
|
if self.status == "TIMEOUT": self.retcode = 8
|
|
1412
1534
|
if self.status == "ERROR": self.retcode = 16
|
|
1535
|
+
if self.status == "CANCELLED": self.retcode = 32
|
|
1413
1536
|
|
|
1414
1537
|
def write_summary_file(self):
|
|
1415
1538
|
with open(f"{self.workdir}/{self.status}", "w") as f:
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import re, getopt
|
|
20
20
|
import json
|
|
21
|
+
import os
|
|
21
22
|
from sby_core import SbyProc
|
|
22
23
|
from sby_engine_aiger import aigsmt_exit_callback, aigsmt_trace_callback
|
|
23
24
|
|
|
@@ -173,18 +174,25 @@ def run(mode, task, engine_idx, engine):
|
|
|
173
174
|
aiger_props.append(task.design.properties_by_path.get(tuple(path)))
|
|
174
175
|
|
|
175
176
|
if keep_going:
|
|
176
|
-
match = re.match(r"Writing CEX for output ([0-9]+) to engine_[0-9]+/(.*)\.aiw", line)
|
|
177
|
+
match = re.match(r"Writing CEX for output ([0-9]+) to (engine_[0-9]+/(.*)\.aiw)", line)
|
|
177
178
|
if match:
|
|
178
179
|
output = int(match[1])
|
|
180
|
+
tracefile = match[2]
|
|
181
|
+
name = match[3]
|
|
182
|
+
trace, _ = os.path.splitext(name)
|
|
183
|
+
task.summary.add_event(engine_idx=engine_idx, trace=trace, path=tracefile)
|
|
179
184
|
prop = aiger_props[output]
|
|
180
185
|
if prop:
|
|
181
186
|
prop.status = "FAIL"
|
|
182
|
-
task.
|
|
187
|
+
task.summary.add_event(
|
|
188
|
+
engine_idx=engine_idx, trace=trace,
|
|
189
|
+
hdlname=prop.hdlname, src=prop.location, prop=prop,
|
|
190
|
+
)
|
|
183
191
|
disproved.add(output)
|
|
184
192
|
proc_status = "FAIL"
|
|
185
193
|
proc = aigsmt_trace_callback(task, engine_idx, proc_status,
|
|
186
194
|
run_aigsmt=run_aigsmt, smtbmc_vcd=smtbmc_vcd, smtbmc_append=smtbmc_append, sim_append=sim_append,
|
|
187
|
-
name=
|
|
195
|
+
name=name,
|
|
188
196
|
)
|
|
189
197
|
proc.register_exit_callback(exit_callback)
|
|
190
198
|
procs_running += 1
|
|
@@ -198,7 +206,10 @@ def run(mode, task, engine_idx, engine):
|
|
|
198
206
|
prop = aiger_props[output]
|
|
199
207
|
if prop:
|
|
200
208
|
prop.status = "PASS"
|
|
201
|
-
task.
|
|
209
|
+
task.summary.add_event(
|
|
210
|
+
engine_idx=engine_idx, trace=None,
|
|
211
|
+
hdlname=prop.hdlname, src=prop.location, prop=prop,
|
|
212
|
+
)
|
|
202
213
|
proved.add(output)
|
|
203
214
|
|
|
204
215
|
match = re.match(r"^Simulation of [0-9]+ frames for [0-9]+ rounds with [0-9]+ restarts did not assert POs.", line)
|