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
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sqlite3
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
import json
|
|
7
|
+
from collections import defaultdict
|
|
8
|
+
from functools import wraps
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Callable, TypeVar, Optional, Iterable
|
|
11
|
+
from sby_design import SbyProperty, pretty_path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
Fn = TypeVar("Fn", bound=Callable[..., Any])
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def transaction(method: Fn) -> Fn:
|
|
18
|
+
@wraps(method)
|
|
19
|
+
def wrapper(self: SbyStatusDb, *args: Any, **kwargs: Any) -> Any:
|
|
20
|
+
if self._transaction_active:
|
|
21
|
+
return method(self, *args, **kwargs)
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
self.log_debug(f"begin {method.__name__!r} transaction")
|
|
25
|
+
self.db.execute("begin")
|
|
26
|
+
self._transaction_active = True
|
|
27
|
+
result = method(self, *args, **kwargs)
|
|
28
|
+
self.db.execute("commit")
|
|
29
|
+
self._transaction_active = False
|
|
30
|
+
self.log_debug(f"comitted {method.__name__!r} transaction")
|
|
31
|
+
return result
|
|
32
|
+
except sqlite3.OperationalError as err:
|
|
33
|
+
self.log_debug(f"failed {method.__name__!r} transaction {err}")
|
|
34
|
+
self.db.rollback()
|
|
35
|
+
self._transaction_active = False
|
|
36
|
+
except Exception as err:
|
|
37
|
+
self.log_debug(f"failed {method.__name__!r} transaction {err}")
|
|
38
|
+
self.db.rollback()
|
|
39
|
+
self._transaction_active = False
|
|
40
|
+
raise
|
|
41
|
+
try:
|
|
42
|
+
self.log_debug(
|
|
43
|
+
f"retrying {method.__name__!r} transaction once in immediate mode"
|
|
44
|
+
)
|
|
45
|
+
self.db.execute("begin immediate")
|
|
46
|
+
self._transaction_active = True
|
|
47
|
+
result = method(self, *args, **kwargs)
|
|
48
|
+
self.db.execute("commit")
|
|
49
|
+
self._transaction_active = False
|
|
50
|
+
self.log_debug(f"comitted {method.__name__!r} transaction")
|
|
51
|
+
return result
|
|
52
|
+
except Exception as err:
|
|
53
|
+
self.log_debug(f"failed {method.__name__!r} transaction {err}")
|
|
54
|
+
self.db.rollback()
|
|
55
|
+
self._transaction_active = False
|
|
56
|
+
raise
|
|
57
|
+
|
|
58
|
+
return wrapper # type: ignore
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class SbyStatusDb:
|
|
62
|
+
def __init__(self, path: Path, task, timeout: float = 5.0):
|
|
63
|
+
self.debug = False
|
|
64
|
+
self.task = task
|
|
65
|
+
self._transaction_active = False
|
|
66
|
+
|
|
67
|
+
setup = not os.path.exists(path)
|
|
68
|
+
|
|
69
|
+
self.db = sqlite3.connect(path, isolation_level=None, timeout=timeout)
|
|
70
|
+
self.db.row_factory = sqlite3.Row
|
|
71
|
+
self.db.execute("PRAGMA journal_mode=WAL")
|
|
72
|
+
self.db.execute("PRAGMA synchronous=0")
|
|
73
|
+
|
|
74
|
+
if setup:
|
|
75
|
+
self._setup()
|
|
76
|
+
|
|
77
|
+
if task is not None:
|
|
78
|
+
self.task_id = self.create_task(workdir=task.workdir, mode=task.opt_mode)
|
|
79
|
+
|
|
80
|
+
def log_debug(self, *args):
|
|
81
|
+
if self.debug:
|
|
82
|
+
if self.task:
|
|
83
|
+
self.task.log(" ".join(str(arg) for arg in args))
|
|
84
|
+
else:
|
|
85
|
+
print(*args)
|
|
86
|
+
|
|
87
|
+
@transaction
|
|
88
|
+
def _setup(self):
|
|
89
|
+
script = """
|
|
90
|
+
CREATE TABLE task (
|
|
91
|
+
id INTEGER PRIMARY KEY,
|
|
92
|
+
workdir TEXT,
|
|
93
|
+
mode TEXT,
|
|
94
|
+
created REAL
|
|
95
|
+
);
|
|
96
|
+
CREATE TABLE task_status (
|
|
97
|
+
id INTEGER PRIMARY KEY,
|
|
98
|
+
task INTEGER,
|
|
99
|
+
status TEXT,
|
|
100
|
+
data TEXT,
|
|
101
|
+
created REAL,
|
|
102
|
+
FOREIGN KEY(task) REFERENCES task(id)
|
|
103
|
+
);
|
|
104
|
+
CREATE TABLE task_property (
|
|
105
|
+
id INTEGER PRIMARY KEY,
|
|
106
|
+
task INTEGER,
|
|
107
|
+
src TEXT,
|
|
108
|
+
name TEXT,
|
|
109
|
+
created REAL,
|
|
110
|
+
FOREIGN KEY(task) REFERENCES task(id)
|
|
111
|
+
);
|
|
112
|
+
CREATE TABLE task_property_status (
|
|
113
|
+
id INTEGER PRIMARY KEY,
|
|
114
|
+
task_property INTEGER,
|
|
115
|
+
status TEXT,
|
|
116
|
+
data TEXT,
|
|
117
|
+
created REAL,
|
|
118
|
+
FOREIGN KEY(task_property) REFERENCES task_property(id)
|
|
119
|
+
);
|
|
120
|
+
CREATE TABLE task_property_data (
|
|
121
|
+
id INTEGER PRIMARY KEY,
|
|
122
|
+
task_property INTEGER,
|
|
123
|
+
kind TEXT,
|
|
124
|
+
data TEXT,
|
|
125
|
+
created REAL,
|
|
126
|
+
FOREIGN KEY(task_property) REFERENCES task_property(id)
|
|
127
|
+
);
|
|
128
|
+
"""
|
|
129
|
+
for statement in script.split(";\n"):
|
|
130
|
+
statement = statement.strip()
|
|
131
|
+
if statement:
|
|
132
|
+
self.db.execute(statement)
|
|
133
|
+
|
|
134
|
+
@transaction
|
|
135
|
+
def create_task(self, workdir: str, mode: str) -> int:
|
|
136
|
+
return self.db.execute(
|
|
137
|
+
"""
|
|
138
|
+
INSERT INTO task (workdir, mode, created)
|
|
139
|
+
VALUES (:workdir, :mode, :now)
|
|
140
|
+
""",
|
|
141
|
+
dict(workdir=workdir, mode=mode, now=time.time()),
|
|
142
|
+
).lastrowid
|
|
143
|
+
|
|
144
|
+
@transaction
|
|
145
|
+
def create_task_properties(
|
|
146
|
+
self, properties: Iterable[SbyProperty], *, task_id: Optional[int] = None
|
|
147
|
+
):
|
|
148
|
+
if task_id is None:
|
|
149
|
+
task_id = self.task_id
|
|
150
|
+
now = time.time()
|
|
151
|
+
self.db.executemany(
|
|
152
|
+
"""
|
|
153
|
+
INSERT INTO task_property (name, src, task, created)
|
|
154
|
+
VALUES (:name, :src, :task, :now)
|
|
155
|
+
""",
|
|
156
|
+
[
|
|
157
|
+
dict(
|
|
158
|
+
name=json.dumps(prop.path),
|
|
159
|
+
src=prop.location or "",
|
|
160
|
+
task=task_id,
|
|
161
|
+
now=now,
|
|
162
|
+
)
|
|
163
|
+
for prop in properties
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
@transaction
|
|
168
|
+
def set_task_status(
|
|
169
|
+
self,
|
|
170
|
+
status: Optional[str] = None,
|
|
171
|
+
data: Any = None,
|
|
172
|
+
):
|
|
173
|
+
if status is None:
|
|
174
|
+
status = property.status
|
|
175
|
+
|
|
176
|
+
now = time.time()
|
|
177
|
+
self.db.execute(
|
|
178
|
+
"""
|
|
179
|
+
INSERT INTO task_status (
|
|
180
|
+
task, status, data, created
|
|
181
|
+
)
|
|
182
|
+
VALUES (
|
|
183
|
+
:task, :status, :data, :now
|
|
184
|
+
)
|
|
185
|
+
""",
|
|
186
|
+
dict(
|
|
187
|
+
task=self.task_id,
|
|
188
|
+
status=status,
|
|
189
|
+
data=json.dumps(data),
|
|
190
|
+
now=now,
|
|
191
|
+
),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
@transaction
|
|
195
|
+
def set_task_property_status(
|
|
196
|
+
self,
|
|
197
|
+
property: SbyProperty,
|
|
198
|
+
status: Optional[str] = None,
|
|
199
|
+
data: Any = None,
|
|
200
|
+
):
|
|
201
|
+
if status is None:
|
|
202
|
+
status = property.status
|
|
203
|
+
|
|
204
|
+
now = time.time()
|
|
205
|
+
self.db.execute(
|
|
206
|
+
"""
|
|
207
|
+
INSERT INTO task_property_status (
|
|
208
|
+
task_property, status, data, created
|
|
209
|
+
)
|
|
210
|
+
VALUES (
|
|
211
|
+
(SELECT id FROM task_property WHERE task = :task AND name = :name),
|
|
212
|
+
:status, :data, :now
|
|
213
|
+
)
|
|
214
|
+
""",
|
|
215
|
+
dict(
|
|
216
|
+
task=self.task_id,
|
|
217
|
+
name=json.dumps(property.path),
|
|
218
|
+
status=status,
|
|
219
|
+
data=json.dumps(data),
|
|
220
|
+
now=now,
|
|
221
|
+
),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
@transaction
|
|
225
|
+
def add_task_property_data(self, property: SbyProperty, kind: str, data: Any):
|
|
226
|
+
now = time.time()
|
|
227
|
+
self.db.execute(
|
|
228
|
+
"""
|
|
229
|
+
INSERT INTO task_property_data (
|
|
230
|
+
task_property, kind, data, created
|
|
231
|
+
)
|
|
232
|
+
VALUES (
|
|
233
|
+
(SELECT id FROM task_property WHERE task = :task AND name = :name),
|
|
234
|
+
:kind, :data, :now
|
|
235
|
+
)
|
|
236
|
+
""",
|
|
237
|
+
dict(
|
|
238
|
+
task=self.task_id,
|
|
239
|
+
name=json.dumps(property.path),
|
|
240
|
+
kind=kind,
|
|
241
|
+
data=json.dumps(data),
|
|
242
|
+
now=now,
|
|
243
|
+
),
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
@transaction
|
|
247
|
+
def all_tasks(self):
|
|
248
|
+
rows = self.db.execute(
|
|
249
|
+
"""
|
|
250
|
+
SELECT id, workdir, created FROM task
|
|
251
|
+
"""
|
|
252
|
+
).fetchall()
|
|
253
|
+
|
|
254
|
+
return {row["id"]: dict(row) for row in rows}
|
|
255
|
+
|
|
256
|
+
@transaction
|
|
257
|
+
def all_task_properties(self):
|
|
258
|
+
rows = self.db.execute(
|
|
259
|
+
"""
|
|
260
|
+
SELECT id, task, src, name, created FROM task_property
|
|
261
|
+
"""
|
|
262
|
+
).fetchall()
|
|
263
|
+
|
|
264
|
+
def get_result(row):
|
|
265
|
+
row = dict(row)
|
|
266
|
+
row["name"] = tuple(json.loads(row.get("name", "[]")))
|
|
267
|
+
row["data"] = json.loads(row.get("data", "null"))
|
|
268
|
+
return row
|
|
269
|
+
|
|
270
|
+
return {row["id"]: get_result(row) for row in rows}
|
|
271
|
+
|
|
272
|
+
@transaction
|
|
273
|
+
def all_task_property_statuses(self):
|
|
274
|
+
rows = self.db.execute(
|
|
275
|
+
"""
|
|
276
|
+
SELECT id, task_property, status, data, created
|
|
277
|
+
FROM task_property_status
|
|
278
|
+
"""
|
|
279
|
+
).fetchall()
|
|
280
|
+
|
|
281
|
+
def get_result(row):
|
|
282
|
+
row = dict(row)
|
|
283
|
+
row["data"] = json.loads(row.get("data", "null"))
|
|
284
|
+
return row
|
|
285
|
+
|
|
286
|
+
return {row["id"]: get_result(row) for row in rows}
|
|
287
|
+
|
|
288
|
+
@transaction
|
|
289
|
+
def all_status_data(self):
|
|
290
|
+
return (
|
|
291
|
+
self.all_tasks(),
|
|
292
|
+
self.all_task_properties(),
|
|
293
|
+
self.all_task_property_statuses(),
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
@transaction
|
|
297
|
+
def reset(self):
|
|
298
|
+
self.db.execute("""DELETE FROM task_property_status""")
|
|
299
|
+
self.db.execute("""DELETE FROM task_property_data""")
|
|
300
|
+
self.db.execute("""DELETE FROM task_property""")
|
|
301
|
+
self.db.execute("""DELETE FROM task_status""")
|
|
302
|
+
self.db.execute("""DELETE FROM task""")
|
|
303
|
+
|
|
304
|
+
def print_status_summary(self):
|
|
305
|
+
tasks, task_properties, task_property_statuses = self.all_status_data()
|
|
306
|
+
properties = defaultdict(set)
|
|
307
|
+
|
|
308
|
+
uniquify_paths = defaultdict(dict)
|
|
309
|
+
|
|
310
|
+
def add_status(task_property, status):
|
|
311
|
+
|
|
312
|
+
display_name = task_property["name"]
|
|
313
|
+
if display_name[-1].startswith("$"):
|
|
314
|
+
counters = uniquify_paths[task_property["src"]]
|
|
315
|
+
counter = counters.setdefault(display_name[-1], len(counters) + 1)
|
|
316
|
+
if task_property["src"]:
|
|
317
|
+
if counter < 2:
|
|
318
|
+
path_based = f"<unnamed at {task_property['src']}>"
|
|
319
|
+
else:
|
|
320
|
+
path_based = f"<unnamed #{counter} at {task_property['src']}>"
|
|
321
|
+
else:
|
|
322
|
+
path_based = f"<unnamed #{counter}>"
|
|
323
|
+
display_name = (*display_name[:-1], path_based)
|
|
324
|
+
|
|
325
|
+
properties[display_name].add(status)
|
|
326
|
+
|
|
327
|
+
for task_property in task_properties.values():
|
|
328
|
+
add_status(task_property, "UNKNOWN")
|
|
329
|
+
|
|
330
|
+
for status in task_property_statuses.values():
|
|
331
|
+
task_property = task_properties[status["task_property"]]
|
|
332
|
+
add_status(task_property, status["status"])
|
|
333
|
+
|
|
334
|
+
for display_name, statuses in sorted(properties.items()):
|
|
335
|
+
print(pretty_path(display_name), combine_statuses(statuses))
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def combine_statuses(statuses):
|
|
339
|
+
statuses = set(statuses)
|
|
340
|
+
|
|
341
|
+
if len(statuses) > 1:
|
|
342
|
+
statuses.discard("UNKNOWN")
|
|
343
|
+
|
|
344
|
+
return ",".join(sorted(statuses))
|
|
@@ -79,6 +79,20 @@ def except_hook(exctype, value, traceback):
|
|
|
79
79
|
sys.excepthook = except_hook
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def recursion_helper(iteration, *request):
|
|
83
|
+
stack = [iteration(*request)]
|
|
84
|
+
|
|
85
|
+
while stack:
|
|
86
|
+
top = stack.pop()
|
|
87
|
+
try:
|
|
88
|
+
request = next(top)
|
|
89
|
+
except StopIteration:
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
stack.append(top)
|
|
93
|
+
stack.append(iteration(*request))
|
|
94
|
+
|
|
95
|
+
|
|
82
96
|
hex_dict = {
|
|
83
97
|
"0": "0000", "1": "0001", "2": "0010", "3": "0011",
|
|
84
98
|
"4": "0100", "5": "0101", "6": "0110", "7": "0111",
|
|
@@ -100,6 +114,7 @@ class SmtModInfo:
|
|
|
100
114
|
self.clocks = dict()
|
|
101
115
|
self.cells = dict()
|
|
102
116
|
self.asserts = dict()
|
|
117
|
+
self.assumes = dict()
|
|
103
118
|
self.covers = dict()
|
|
104
119
|
self.maximize = set()
|
|
105
120
|
self.minimize = set()
|
|
@@ -127,6 +142,7 @@ class SmtIo:
|
|
|
127
142
|
self.recheck = False
|
|
128
143
|
self.smt2cache = [list()]
|
|
129
144
|
self.smt2_options = dict()
|
|
145
|
+
self.smt2_assumptions = dict()
|
|
130
146
|
self.p = None
|
|
131
147
|
self.p_index = solvers_index
|
|
132
148
|
solvers_index += 1
|
|
@@ -298,10 +314,22 @@ class SmtIo:
|
|
|
298
314
|
return stmt
|
|
299
315
|
|
|
300
316
|
def unroll_stmt(self, stmt):
|
|
317
|
+
result = []
|
|
318
|
+
recursion_helper(self._unroll_stmt_into, stmt, result)
|
|
319
|
+
return result.pop()
|
|
320
|
+
|
|
321
|
+
def _unroll_stmt_into(self, stmt, output, depth=128):
|
|
301
322
|
if not isinstance(stmt, list):
|
|
302
|
-
|
|
323
|
+
output.append(stmt)
|
|
324
|
+
return
|
|
303
325
|
|
|
304
|
-
|
|
326
|
+
new_stmt = []
|
|
327
|
+
for s in stmt:
|
|
328
|
+
if depth:
|
|
329
|
+
yield from self._unroll_stmt_into(s, new_stmt, depth - 1)
|
|
330
|
+
else:
|
|
331
|
+
yield s, new_stmt
|
|
332
|
+
stmt = new_stmt
|
|
305
333
|
|
|
306
334
|
if len(stmt) >= 2 and not isinstance(stmt[0], list) and stmt[0] in self.unroll_decls:
|
|
307
335
|
assert stmt[1] in self.unroll_objs
|
|
@@ -330,12 +358,19 @@ class SmtIo:
|
|
|
330
358
|
decl[2] = list()
|
|
331
359
|
|
|
332
360
|
if len(decl) > 0:
|
|
333
|
-
|
|
361
|
+
tmp = []
|
|
362
|
+
if depth:
|
|
363
|
+
yield from self._unroll_stmt_into(decl, tmp, depth - 1)
|
|
364
|
+
else:
|
|
365
|
+
yield decl, tmp
|
|
366
|
+
|
|
367
|
+
decl = tmp.pop()
|
|
334
368
|
self.write(self.unparse(decl), unroll=False)
|
|
335
369
|
|
|
336
|
-
|
|
370
|
+
output.append(self.unroll_cache[key])
|
|
371
|
+
return
|
|
337
372
|
|
|
338
|
-
|
|
373
|
+
output.append(stmt)
|
|
339
374
|
|
|
340
375
|
def p_thread_main(self):
|
|
341
376
|
while True:
|
|
@@ -569,6 +604,12 @@ class SmtIo:
|
|
|
569
604
|
else:
|
|
570
605
|
self.modinfo[self.curmod].covers["%s_c %s" % (self.curmod, fields[2])] = fields[3]
|
|
571
606
|
|
|
607
|
+
if fields[1] == "yosys-smt2-assume":
|
|
608
|
+
if len(fields) > 4:
|
|
609
|
+
self.modinfo[self.curmod].assumes["%s_u %s" % (self.curmod, fields[2])] = f'{fields[4]} ({fields[3]})'
|
|
610
|
+
else:
|
|
611
|
+
self.modinfo[self.curmod].assumes["%s_u %s" % (self.curmod, fields[2])] = fields[3]
|
|
612
|
+
|
|
572
613
|
if fields[1] == "yosys-smt2-maximize":
|
|
573
614
|
self.modinfo[self.curmod].maximize.add(fields[2])
|
|
574
615
|
|
|
@@ -752,8 +793,13 @@ class SmtIo:
|
|
|
752
793
|
return stmt
|
|
753
794
|
|
|
754
795
|
def check_sat(self, expected=["sat", "unsat", "unknown", "timeout", "interrupted"]):
|
|
796
|
+
if self.smt2_assumptions:
|
|
797
|
+
assume_exprs = " ".join(self.smt2_assumptions.values())
|
|
798
|
+
check_stmt = f"(check-sat-assuming ({assume_exprs}))"
|
|
799
|
+
else:
|
|
800
|
+
check_stmt = "(check-sat)"
|
|
755
801
|
if self.debug_print:
|
|
756
|
-
print(">
|
|
802
|
+
print(f"> {check_stmt}")
|
|
757
803
|
if self.debug_file and not self.nocomments:
|
|
758
804
|
print("; running check-sat..", file=self.debug_file)
|
|
759
805
|
self.debug_file.flush()
|
|
@@ -767,7 +813,7 @@ class SmtIo:
|
|
|
767
813
|
for cache_stmt in cache_ctx:
|
|
768
814
|
self.p_write(cache_stmt + "\n", False)
|
|
769
815
|
|
|
770
|
-
self.p_write("
|
|
816
|
+
self.p_write(f"{check_stmt}\n", True)
|
|
771
817
|
|
|
772
818
|
if self.timeinfo:
|
|
773
819
|
i = 0
|
|
@@ -835,7 +881,7 @@ class SmtIo:
|
|
|
835
881
|
|
|
836
882
|
if self.debug_file:
|
|
837
883
|
print("(set-info :status %s)" % result, file=self.debug_file)
|
|
838
|
-
print(
|
|
884
|
+
print(check_stmt, file=self.debug_file)
|
|
839
885
|
self.debug_file.flush()
|
|
840
886
|
|
|
841
887
|
if result not in expected:
|
|
@@ -912,6 +958,48 @@ class SmtIo:
|
|
|
912
958
|
def bv2int(self, v):
|
|
913
959
|
return int(self.bv2bin(v), 2)
|
|
914
960
|
|
|
961
|
+
def get_raw_unsat_assumptions(self):
|
|
962
|
+
self.write("(get-unsat-assumptions)")
|
|
963
|
+
exprs = set(self.unparse(part) for part in self.parse(self.read()))
|
|
964
|
+
unsat_assumptions = []
|
|
965
|
+
for key, value in self.smt2_assumptions.items():
|
|
966
|
+
# normalize expression
|
|
967
|
+
value = self.unparse(self.parse(value))
|
|
968
|
+
if value in exprs:
|
|
969
|
+
exprs.remove(value)
|
|
970
|
+
unsat_assumptions.append(key)
|
|
971
|
+
return unsat_assumptions
|
|
972
|
+
|
|
973
|
+
def get_unsat_assumptions(self, minimize=False):
|
|
974
|
+
if not minimize:
|
|
975
|
+
return self.get_raw_unsat_assumptions()
|
|
976
|
+
required_assumptions = {}
|
|
977
|
+
|
|
978
|
+
while True:
|
|
979
|
+
candidate_assumptions = {}
|
|
980
|
+
for key in self.get_raw_unsat_assumptions():
|
|
981
|
+
if key not in required_assumptions:
|
|
982
|
+
candidate_assumptions[key] = self.smt2_assumptions[key]
|
|
983
|
+
|
|
984
|
+
while candidate_assumptions:
|
|
985
|
+
|
|
986
|
+
candidate_key, candidate_assume = candidate_assumptions.popitem()
|
|
987
|
+
|
|
988
|
+
self.smt2_assumptions = {}
|
|
989
|
+
for key, assume in candidate_assumptions.items():
|
|
990
|
+
self.smt2_assumptions[key] = assume
|
|
991
|
+
for key, assume in required_assumptions.items():
|
|
992
|
+
self.smt2_assumptions[key] = assume
|
|
993
|
+
result = self.check_sat()
|
|
994
|
+
|
|
995
|
+
if result == 'unsat':
|
|
996
|
+
candidate_assumptions = None
|
|
997
|
+
else:
|
|
998
|
+
required_assumptions[candidate_key] = candidate_assume
|
|
999
|
+
|
|
1000
|
+
if candidate_assumptions is not None:
|
|
1001
|
+
return list(required_assumptions)
|
|
1002
|
+
|
|
915
1003
|
def get(self, expr):
|
|
916
1004
|
self.write("(get-value (%s))" % (expr))
|
|
917
1005
|
return self.parse(self.read())[0][1]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// **AUTOGENERATED FILE** **DO NOT EDIT**
|
|
2
|
-
// Generated by ../yosys-src/techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py at 2024-
|
|
2
|
+
// Generated by ../yosys-src/techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py at 2024-04-04 02:33:31.959107+00:00
|
|
3
3
|
`timescale 1ns /10ps
|
|
4
4
|
|
|
5
5
|
module TDP36K_BRAM_A_X1_B_X1_nonsplit (
|