najaeda 0.1.22__cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
Potentially problematic release.
This version of najaeda might be problematic. Click here for more details.
- najaeda/__init__.py +0 -0
- najaeda/docs/.readthedocs.yaml +26 -0
- najaeda/docs/requirements.txt +7 -0
- najaeda/docs/source/api.rst +7 -0
- najaeda/docs/source/common_classes.rst +11 -0
- najaeda/docs/source/conf.py +57 -0
- najaeda/docs/source/equipotential.rst +15 -0
- najaeda/docs/source/examples.rst.in +66 -0
- najaeda/docs/source/index.rst +17 -0
- najaeda/docs/source/instance.rst +19 -0
- najaeda/docs/source/introduction.rst +53 -0
- najaeda/docs/source/net.rst +20 -0
- najaeda/docs/source/netlist_classes.rst +11 -0
- najaeda/docs/source/preprocessor.py +73 -0
- najaeda/docs/source/term.rst +20 -0
- najaeda/docs/source/visitors.rst +13 -0
- najaeda/instance_visitor.py +43 -0
- najaeda/libnaja_bne.so +0 -0
- najaeda/libnaja_dnl.so +0 -0
- najaeda/libnaja_nl.so +0 -0
- najaeda/libnaja_opt.so +0 -0
- najaeda/libnaja_python.so +0 -0
- najaeda/naja.so +0 -0
- najaeda/native/__init__.py +0 -0
- najaeda/native/stats.py +341 -0
- najaeda/net_visitor.py +53 -0
- najaeda/netlist.py +1576 -0
- najaeda/pandas_stats.py +32 -0
- najaeda/primitives/__init__.py +0 -0
- najaeda/primitives/xilinx.py +454 -0
- najaeda/stats.py +413 -0
- najaeda-0.1.22.dist-info/METADATA +79 -0
- najaeda-0.1.22.dist-info/RECORD +40 -0
- najaeda-0.1.22.dist-info/WHEEL +6 -0
- najaeda-0.1.22.dist-info/licenses/AUTHORS +7 -0
- najaeda-0.1.22.dist-info/licenses/LICENSE +201 -0
- najaeda.libs/libcapnp-1-d562dcbf.1.0.so +0 -0
- najaeda.libs/libkj-1-fe2e75c4.1.0.so +0 -0
- najaeda.libs/libtbb-58378cc2.so.12.15 +0 -0
- najaeda.libs/libtbbmalloc-8bd2c113.so.2.15 +0 -0
najaeda/netlist.py
ADDED
|
@@ -0,0 +1,1576 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 The Naja authors
|
|
2
|
+
# <https://github.com/najaeda/naja/blob/main/AUTHORS>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
import itertools
|
|
7
|
+
import time
|
|
8
|
+
import logging
|
|
9
|
+
import hashlib
|
|
10
|
+
import struct
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from typing import Union, List
|
|
15
|
+
|
|
16
|
+
from najaeda import naja
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_none_existent():
|
|
20
|
+
return sys.maxsize
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def consistent_hash(obj):
|
|
24
|
+
def default_serializer(o):
|
|
25
|
+
if isinstance(o, (str, int, float, bool, type(None))):
|
|
26
|
+
return o
|
|
27
|
+
elif isinstance(o, (list, tuple)):
|
|
28
|
+
return [default_serializer(i) for i in o]
|
|
29
|
+
else:
|
|
30
|
+
return str(o)
|
|
31
|
+
|
|
32
|
+
def hash_value(value):
|
|
33
|
+
if isinstance(value, int):
|
|
34
|
+
return struct.pack("!q", value)
|
|
35
|
+
else:
|
|
36
|
+
raise TypeError(f"Unsupported type: {type(value)}")
|
|
37
|
+
|
|
38
|
+
def hash_object(o):
|
|
39
|
+
if isinstance(o, (list, tuple)):
|
|
40
|
+
return b"".join(hash_object(i) for i in o)
|
|
41
|
+
else:
|
|
42
|
+
return hash_value(o)
|
|
43
|
+
|
|
44
|
+
serialized_obj = default_serializer(obj)
|
|
45
|
+
obj_bytes = hash_object(serialized_obj)
|
|
46
|
+
return int(hashlib.sha256(obj_bytes).hexdigest(), 16)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_snl_instance_from_id_list(id_list: list) -> naja.SNLInstance:
|
|
50
|
+
design = naja.NLUniverse.get().getTopDesign()
|
|
51
|
+
# instance = None
|
|
52
|
+
# for id in id_list:
|
|
53
|
+
# instance = design.getInstanceByID(id)
|
|
54
|
+
# assert instance is not None
|
|
55
|
+
# design = instance.getModel()
|
|
56
|
+
# return instance
|
|
57
|
+
return design.getInstanceByIDList(id_list)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_snl_path_from_id_list(id_list: list) -> naja.SNLPath:
|
|
61
|
+
top = naja.NLUniverse.get().getTopDesign()
|
|
62
|
+
design = top
|
|
63
|
+
path = naja.SNLPath()
|
|
64
|
+
for id in id_list:
|
|
65
|
+
instance = design.getInstanceByID(id)
|
|
66
|
+
assert instance is not None
|
|
67
|
+
path = naja.SNLPath(path, instance)
|
|
68
|
+
assert path.getTailInstance() is not None
|
|
69
|
+
design = instance.getModel()
|
|
70
|
+
if len(id_list) > 0:
|
|
71
|
+
assert path.getTailInstance() is not None
|
|
72
|
+
return path
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class Equipotential:
|
|
76
|
+
"""Class that represents the term and wraps
|
|
77
|
+
some of the snl occurrence API.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, term):
|
|
81
|
+
path = get_snl_path_from_id_list(term.pathIDs)
|
|
82
|
+
snl_term = get_snl_term_for_ids_with_path(path, term.termIDs)
|
|
83
|
+
inst_term = None
|
|
84
|
+
if isinstance(snl_term, naja.SNLBusTerm):
|
|
85
|
+
raise ValueError("Equipotential cannot be constructed on bus term")
|
|
86
|
+
if len(term.pathIDs) == 0:
|
|
87
|
+
net = term.get_lower_net()
|
|
88
|
+
if net is None:
|
|
89
|
+
self.equi = None
|
|
90
|
+
return
|
|
91
|
+
inst_term = next(net.get_inst_terms(), None)
|
|
92
|
+
if inst_term is None:
|
|
93
|
+
self.equi = None
|
|
94
|
+
return
|
|
95
|
+
else:
|
|
96
|
+
path = naja.SNLPath(path, get_snl_instance_from_id_list(inst_term.pathIDs))
|
|
97
|
+
snl_term = get_snl_term_for_ids(inst_term.pathIDs, inst_term.termIDs)
|
|
98
|
+
else:
|
|
99
|
+
inst_term = term
|
|
100
|
+
ito = naja.SNLNetComponentOccurrence(
|
|
101
|
+
path.getHeadPath(), path.getTailInstance().getInstTerm(snl_term)
|
|
102
|
+
)
|
|
103
|
+
self.equi = naja.SNLEquipotential(ito)
|
|
104
|
+
|
|
105
|
+
def __eq__(self, value):
|
|
106
|
+
return self.equi == value.equi
|
|
107
|
+
|
|
108
|
+
def dump_dot(self, path: str):
|
|
109
|
+
"""Dump the dot file of this equipotential."""
|
|
110
|
+
self.equi.dumpDotFile(path)
|
|
111
|
+
|
|
112
|
+
def get_inst_terms(self):
|
|
113
|
+
"""Iterate over the instance terminals of this equipotential.
|
|
114
|
+
|
|
115
|
+
:return: an iterator over the instance terminals of this equipotential.
|
|
116
|
+
:rtype: Iterator[Term]
|
|
117
|
+
"""
|
|
118
|
+
if self.equi is not None:
|
|
119
|
+
for term in self.equi.getInstTermOccurrences():
|
|
120
|
+
path = term.getPath().getPathIDs()
|
|
121
|
+
path.append(term.getInstTerm().getInstance().getID())
|
|
122
|
+
yield Term(path,
|
|
123
|
+
term.getInstTerm().getBitTerm())
|
|
124
|
+
|
|
125
|
+
def get_top_terms(self):
|
|
126
|
+
"""Iterate over the top terminals of this equipotential.
|
|
127
|
+
|
|
128
|
+
:return: an iterator over the top terminals of this equipotential.
|
|
129
|
+
:rtype: Iterator[Term]
|
|
130
|
+
"""
|
|
131
|
+
if self.equi is not None:
|
|
132
|
+
for term in self.equi.getTerms():
|
|
133
|
+
yield Term([], term)
|
|
134
|
+
|
|
135
|
+
def get_leaf_readers(self):
|
|
136
|
+
if self.equi is not None:
|
|
137
|
+
for term in self.equi.getInstTermOccurrences():
|
|
138
|
+
direction = term.getInstTerm().getDirection()
|
|
139
|
+
if direction != naja.SNLTerm.Direction.Output:
|
|
140
|
+
if term.getInstTerm().getInstance().getModel().isLeaf():
|
|
141
|
+
path = term.getPath().getPathIDs()
|
|
142
|
+
path.append(term.getInstTerm().getInstance().getID())
|
|
143
|
+
yield Term(path,
|
|
144
|
+
term.getInstTerm().getBitTerm())
|
|
145
|
+
|
|
146
|
+
def get_leaf_drivers(self):
|
|
147
|
+
if self.equi is not None:
|
|
148
|
+
for term in self.equi.getInstTermOccurrences():
|
|
149
|
+
direction = term.getInstTerm().getDirection()
|
|
150
|
+
if direction != naja.SNLTerm.Direction.Input:
|
|
151
|
+
if term.getInstTerm().getInstance().getModel().isLeaf():
|
|
152
|
+
path = term.getPath().getPathIDs()
|
|
153
|
+
path.append(term.getInstTerm().getInstance().getID())
|
|
154
|
+
yield Term(path,
|
|
155
|
+
term.getInstTerm().getBitTerm())
|
|
156
|
+
|
|
157
|
+
def get_top_readers(self):
|
|
158
|
+
if self.equi is not None:
|
|
159
|
+
for term in self.equi.getTerms():
|
|
160
|
+
direction = term.getDirection()
|
|
161
|
+
if direction != naja.SNLTerm.Direction.Input:
|
|
162
|
+
yield Term([], term)
|
|
163
|
+
|
|
164
|
+
def get_top_drivers(self):
|
|
165
|
+
if self.equi is not None:
|
|
166
|
+
for term in self.equi.getTerms():
|
|
167
|
+
direction = term.getDirection()
|
|
168
|
+
if direction != naja.SNLTerm.Direction.Output:
|
|
169
|
+
yield Term([], term)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class Net:
|
|
173
|
+
class Type(Enum):
|
|
174
|
+
STANDARD = naja.SNLNet.Type.Standard
|
|
175
|
+
ASSIGN0 = naja.SNLNet.Type.Assign0
|
|
176
|
+
ASSIGN1 = naja.SNLNet.Type.Assign1
|
|
177
|
+
SUPPLY0 = naja.SNLNet.Type.Supply0
|
|
178
|
+
SUPPLY1 = naja.SNLNet.Type.Supply1
|
|
179
|
+
|
|
180
|
+
def __init__(self, path, net=None, net_concat=None):
|
|
181
|
+
if net is not None and net_concat is not None:
|
|
182
|
+
raise ValueError(
|
|
183
|
+
"Only one of `net` or `net_concat` should be provided, not both."
|
|
184
|
+
)
|
|
185
|
+
if isinstance(path, naja.SNLPath):
|
|
186
|
+
if path.size() > 0:
|
|
187
|
+
self.pathIDs = path.getPathIDs()
|
|
188
|
+
else:
|
|
189
|
+
self.pathIDs = []
|
|
190
|
+
elif isinstance(path, list):
|
|
191
|
+
self.pathIDs = path.copy()
|
|
192
|
+
if net is not None:
|
|
193
|
+
self.net = net
|
|
194
|
+
elif net_concat is not None:
|
|
195
|
+
self.net_concat = net_concat
|
|
196
|
+
|
|
197
|
+
def __eq__(self, other):
|
|
198
|
+
if not isinstance(other, Net):
|
|
199
|
+
return NotImplemented
|
|
200
|
+
return vars(self) == vars(other)
|
|
201
|
+
|
|
202
|
+
def __ne__(self, other):
|
|
203
|
+
eq_result = self.__eq__(other)
|
|
204
|
+
if eq_result is NotImplemented:
|
|
205
|
+
return NotImplemented
|
|
206
|
+
return not eq_result
|
|
207
|
+
|
|
208
|
+
def __str__(self):
|
|
209
|
+
if hasattr(self, "net"):
|
|
210
|
+
net_str = str(self.net)
|
|
211
|
+
elif hasattr(self, "net_concat"):
|
|
212
|
+
net_str = "{" + ",".join(map(str, self.net_concat)) + "}"
|
|
213
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
214
|
+
if path.size() > 0:
|
|
215
|
+
return f"{path}/{net_str}"
|
|
216
|
+
return net_str
|
|
217
|
+
|
|
218
|
+
def get_name(self) -> str:
|
|
219
|
+
"""
|
|
220
|
+
:return: the name of this Net.
|
|
221
|
+
:rtype: str
|
|
222
|
+
"""
|
|
223
|
+
if hasattr(self, "net"):
|
|
224
|
+
return self.net.getName()
|
|
225
|
+
return "{" + ",".join(map(str, self.net_concat)) + "}"
|
|
226
|
+
|
|
227
|
+
def get_msb(self) -> int:
|
|
228
|
+
"""
|
|
229
|
+
:return: the most significant bit of the net if it is a bus.
|
|
230
|
+
:rtype: int
|
|
231
|
+
"""
|
|
232
|
+
if hasattr(self, "net") and isinstance(self.net, naja.SNLBusNet):
|
|
233
|
+
return self.net.getMSB()
|
|
234
|
+
return None
|
|
235
|
+
|
|
236
|
+
def get_lsb(self) -> int:
|
|
237
|
+
"""
|
|
238
|
+
:return: the least significant bit of the net if it is a bus.
|
|
239
|
+
:rtype: int
|
|
240
|
+
"""
|
|
241
|
+
if hasattr(self, "net") and isinstance(self.net, naja.SNLBusNet):
|
|
242
|
+
return self.net.getLSB()
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
def is_bus(self) -> bool:
|
|
246
|
+
"""
|
|
247
|
+
:return: True if the net is a bus.
|
|
248
|
+
:rtype: bool
|
|
249
|
+
"""
|
|
250
|
+
return hasattr(self, "net") and isinstance(self.net, naja.SNLBusNet)
|
|
251
|
+
|
|
252
|
+
def is_bus_bit(self) -> bool:
|
|
253
|
+
"""
|
|
254
|
+
:return: True if the net is a bit of a bus.
|
|
255
|
+
:rtype: bool
|
|
256
|
+
"""
|
|
257
|
+
return hasattr(self, "net") and isinstance(self.net, naja.SNLBusNetBit)
|
|
258
|
+
|
|
259
|
+
def is_scalar(self) -> bool:
|
|
260
|
+
"""
|
|
261
|
+
:return: True if the net is a scalar.
|
|
262
|
+
:rtype: bool
|
|
263
|
+
"""
|
|
264
|
+
return hasattr(self, "net") and isinstance(self.net, naja.SNLScalarNet)
|
|
265
|
+
|
|
266
|
+
def is_bit(self) -> bool:
|
|
267
|
+
"""
|
|
268
|
+
:return: True if the net is a bit.
|
|
269
|
+
:rtype: bool
|
|
270
|
+
"""
|
|
271
|
+
return self.is_scalar() or self.is_bus_bit()
|
|
272
|
+
|
|
273
|
+
def is_concat(self) -> bool:
|
|
274
|
+
"""
|
|
275
|
+
:return: True if the net is a concatenation.
|
|
276
|
+
:rtype: bool
|
|
277
|
+
"""
|
|
278
|
+
return hasattr(self, "net_concat")
|
|
279
|
+
|
|
280
|
+
def is_const(self) -> bool:
|
|
281
|
+
"""
|
|
282
|
+
:return: True if the net is a constant generator.
|
|
283
|
+
:rtype: bool
|
|
284
|
+
"""
|
|
285
|
+
if hasattr(self, "net"):
|
|
286
|
+
return self.net.isConstant()
|
|
287
|
+
else:
|
|
288
|
+
for net in self.net_concat:
|
|
289
|
+
if not net.isConstant():
|
|
290
|
+
return False
|
|
291
|
+
return True
|
|
292
|
+
|
|
293
|
+
def set_type(self, net_type: Type):
|
|
294
|
+
"""
|
|
295
|
+
:param Type net_type: the type of the net.
|
|
296
|
+
"""
|
|
297
|
+
if hasattr(self, "net"):
|
|
298
|
+
self.net.setType(net_type.value)
|
|
299
|
+
else:
|
|
300
|
+
for net in self.net_concat:
|
|
301
|
+
net.setType(net_type.value)
|
|
302
|
+
|
|
303
|
+
def get_width(self) -> int:
|
|
304
|
+
"""
|
|
305
|
+
:return: the width of the net.
|
|
306
|
+
:rtype: int
|
|
307
|
+
"""
|
|
308
|
+
if hasattr(self, "net"):
|
|
309
|
+
return self.net.getWidth()
|
|
310
|
+
return sum(1 for _ in self.net_concat)
|
|
311
|
+
|
|
312
|
+
def get_bits(self):
|
|
313
|
+
"""Iterate over the bits of this Net.
|
|
314
|
+
The iterator will return itself if the Net is scalar.
|
|
315
|
+
:return: an iterator over the bits of this Net.
|
|
316
|
+
:rtype: Iterator[Net]
|
|
317
|
+
"""
|
|
318
|
+
if hasattr(self, "net"):
|
|
319
|
+
if isinstance(self.net, naja.SNLBusNet):
|
|
320
|
+
for bit in self.net.getBits():
|
|
321
|
+
yield Net(self.pathIDs, bit)
|
|
322
|
+
else:
|
|
323
|
+
yield self
|
|
324
|
+
else:
|
|
325
|
+
for net in self.net_concat:
|
|
326
|
+
yield Net(net)
|
|
327
|
+
|
|
328
|
+
def get_bit(self, index: int):
|
|
329
|
+
"""
|
|
330
|
+
:param int index: the index of the bit to get.
|
|
331
|
+
:return: the Net bit at the given index or None if it does not exist.
|
|
332
|
+
:rtype: Net
|
|
333
|
+
"""
|
|
334
|
+
if hasattr(self, "net"):
|
|
335
|
+
if isinstance(self.net, naja.SNLBusNet):
|
|
336
|
+
return Net(self.pathIDs, self.net.getBit(index))
|
|
337
|
+
else:
|
|
338
|
+
return None
|
|
339
|
+
if 0 <= index < len(self.net_concat):
|
|
340
|
+
return Net(self.pathIDs, self.net_concat[index])
|
|
341
|
+
return None
|
|
342
|
+
|
|
343
|
+
def get_inst_terms(self):
|
|
344
|
+
"""
|
|
345
|
+
:return: an iterator over the instance terminals of the net.
|
|
346
|
+
:rtype: Iterator[Term]
|
|
347
|
+
"""
|
|
348
|
+
if hasattr(self, "net_concat"):
|
|
349
|
+
raise ValueError("Cannot get inst terms from a net_concat")
|
|
350
|
+
path = self.pathIDs.copy()
|
|
351
|
+
for term in self.net.getInstTerms():
|
|
352
|
+
path.append(term.getInstance().getID())
|
|
353
|
+
yield Term(path, term.getBitTerm())
|
|
354
|
+
path.pop()
|
|
355
|
+
|
|
356
|
+
def get_design_terms(self):
|
|
357
|
+
"""
|
|
358
|
+
:return: an iterator over the design terminals of the net.
|
|
359
|
+
:rtype: Iterator[Term]
|
|
360
|
+
"""
|
|
361
|
+
if hasattr(self, "net_concat"):
|
|
362
|
+
raise ValueError("Cannot get terms from a net_concat")
|
|
363
|
+
for term in self.net.getBitTerms():
|
|
364
|
+
yield Term(self.pathIDs, term)
|
|
365
|
+
|
|
366
|
+
def get_terms(self):
|
|
367
|
+
"""
|
|
368
|
+
:return: an iterator over the terminals of the net.
|
|
369
|
+
:rtype: Iterator[Term]
|
|
370
|
+
"""
|
|
371
|
+
for term in itertools.chain(self.get_design_terms(), self.get_inst_terms()):
|
|
372
|
+
yield term
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def get_snl_term_for_ids(pathIDs, termIDs):
|
|
376
|
+
path = get_snl_path_from_id_list(pathIDs)
|
|
377
|
+
model = None
|
|
378
|
+
if len(pathIDs) == 0:
|
|
379
|
+
model = naja.NLUniverse.get().getTopDesign()
|
|
380
|
+
else:
|
|
381
|
+
model = path.getTailInstance().getModel()
|
|
382
|
+
if termIDs[1] == get_none_existent():
|
|
383
|
+
return model.getTermByID(termIDs[0])
|
|
384
|
+
else:
|
|
385
|
+
snlterm = model.getTermByID(termIDs[0])
|
|
386
|
+
if isinstance(snlterm, naja.SNLBusTerm):
|
|
387
|
+
return snlterm.getBusTermBit(termIDs[1])
|
|
388
|
+
else:
|
|
389
|
+
return snlterm
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def get_snl_term_for_ids_with_path(path, termIDs):
|
|
393
|
+
model = None
|
|
394
|
+
if path.size() == 0:
|
|
395
|
+
model = naja.NLUniverse.get().getTopDesign()
|
|
396
|
+
else:
|
|
397
|
+
model = path.getTailInstance().getModel()
|
|
398
|
+
if termIDs[1] == get_none_existent():
|
|
399
|
+
return model.getTermByID(termIDs[0])
|
|
400
|
+
else:
|
|
401
|
+
snlterm = model.getTermByID(termIDs[0])
|
|
402
|
+
if isinstance(snlterm, naja.SNLBusTerm):
|
|
403
|
+
return snlterm.getBusTermBit(termIDs[1])
|
|
404
|
+
else:
|
|
405
|
+
return snlterm
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class Term:
|
|
409
|
+
INPUT = naja.SNLTerm.Direction.Input
|
|
410
|
+
OUTPUT = naja.SNLTerm.Direction.Output
|
|
411
|
+
INOUT = naja.SNLTerm.Direction.InOut
|
|
412
|
+
|
|
413
|
+
def __init__(self, path, term):
|
|
414
|
+
# self.termIDs = []
|
|
415
|
+
# if isinstance(term, naja.SNLBusTerm):
|
|
416
|
+
# self.termIDs = [term.getID(), -1]
|
|
417
|
+
# else:
|
|
418
|
+
self.termIDs = [term.getID(), term.getBit()]
|
|
419
|
+
self.pathIDs = path.copy()
|
|
420
|
+
|
|
421
|
+
def __eq__(self, other) -> bool:
|
|
422
|
+
return self.pathIDs == other.pathIDs and self.termIDs == other.termIDs
|
|
423
|
+
|
|
424
|
+
def __ne__(self, other) -> bool:
|
|
425
|
+
return not self == other
|
|
426
|
+
|
|
427
|
+
def __lt__(self, other) -> bool:
|
|
428
|
+
if self.pathIDs != other.pathIDs:
|
|
429
|
+
return self.pathIDs < other.pathIDs
|
|
430
|
+
return self.termIDs < other.termIDs
|
|
431
|
+
|
|
432
|
+
def __le__(self, other) -> bool:
|
|
433
|
+
return self < other or self == other
|
|
434
|
+
|
|
435
|
+
def __gt__(self, other) -> bool:
|
|
436
|
+
return not self <= other
|
|
437
|
+
|
|
438
|
+
def __ge__(self, other) -> bool:
|
|
439
|
+
return not self < other
|
|
440
|
+
|
|
441
|
+
def __hash__(self):
|
|
442
|
+
termIDs = []
|
|
443
|
+
snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
|
|
444
|
+
if isinstance(snlterm, naja.SNLBusTerm):
|
|
445
|
+
termIDs = [snlterm.getID(), -1]
|
|
446
|
+
else:
|
|
447
|
+
termIDs = [snlterm.getID(), snlterm.getBit()]
|
|
448
|
+
return consistent_hash((self.pathIDs, termIDs))
|
|
449
|
+
|
|
450
|
+
def __str__(self):
|
|
451
|
+
term_str = ""
|
|
452
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
453
|
+
if path.size() == 0:
|
|
454
|
+
term_str = get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()
|
|
455
|
+
else:
|
|
456
|
+
term_str = (
|
|
457
|
+
f"{path}/{get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()}"
|
|
458
|
+
)
|
|
459
|
+
if self.is_bus():
|
|
460
|
+
term_str += f"[{self.get_msb()}:{self.get_lsb()}]"
|
|
461
|
+
elif self.is_bus_bit():
|
|
462
|
+
term_str += f"[{self.get_lsb()}]"
|
|
463
|
+
return term_str
|
|
464
|
+
|
|
465
|
+
def __repr__(self) -> str:
|
|
466
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
467
|
+
return f"Term({path}, {get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()})"
|
|
468
|
+
|
|
469
|
+
def __make_unique(self):
|
|
470
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
471
|
+
if path.size() > 1:
|
|
472
|
+
path = path.getHeadPath()
|
|
473
|
+
naja.SNLUniquifier(path)
|
|
474
|
+
|
|
475
|
+
def is_bus(self) -> bool:
|
|
476
|
+
"""
|
|
477
|
+
:return: True if the term is a bus.
|
|
478
|
+
:rtype: bool
|
|
479
|
+
"""
|
|
480
|
+
return isinstance(
|
|
481
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTerm
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
def is_bus_bit(self) -> bool:
|
|
485
|
+
"""
|
|
486
|
+
:return: True if the term is a bit of a bus.
|
|
487
|
+
:rtype: bool
|
|
488
|
+
"""
|
|
489
|
+
return isinstance(
|
|
490
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTermBit
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
def is_scalar(self) -> bool:
|
|
494
|
+
"""
|
|
495
|
+
:return: True if the term is a scalar.
|
|
496
|
+
:rtype: bool
|
|
497
|
+
"""
|
|
498
|
+
return isinstance(
|
|
499
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLScalarTerm
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
def is_bit(self) -> bool:
|
|
503
|
+
"""
|
|
504
|
+
:return: True if the term is a bit.
|
|
505
|
+
:rtype: bool
|
|
506
|
+
"""
|
|
507
|
+
return self.is_scalar() or self.is_bus_bit()
|
|
508
|
+
|
|
509
|
+
def get_bit_number(self):
|
|
510
|
+
"""
|
|
511
|
+
:return: the bit index of the term if it is a bit.
|
|
512
|
+
:rtype: int or None
|
|
513
|
+
"""
|
|
514
|
+
if isinstance(
|
|
515
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTermBit
|
|
516
|
+
):
|
|
517
|
+
return get_snl_term_for_ids(self.pathIDs, self.termIDs).getBit()
|
|
518
|
+
return None
|
|
519
|
+
|
|
520
|
+
def get_msb(self) -> int:
|
|
521
|
+
"""
|
|
522
|
+
:return: the most significant bit of the term if it is a bus.
|
|
523
|
+
:rtype: int or None
|
|
524
|
+
"""
|
|
525
|
+
if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTerm):
|
|
526
|
+
return get_snl_term_for_ids(self.pathIDs, self.termIDs).getMSB()
|
|
527
|
+
return None
|
|
528
|
+
|
|
529
|
+
def get_lsb(self) -> int:
|
|
530
|
+
"""
|
|
531
|
+
:return: the least significant bit of the term if it is a bus.
|
|
532
|
+
:rtype: int or None
|
|
533
|
+
"""
|
|
534
|
+
if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTerm):
|
|
535
|
+
return get_snl_term_for_ids(self.pathIDs, self.termIDs).getLSB()
|
|
536
|
+
return None
|
|
537
|
+
|
|
538
|
+
def get_width(self) -> int:
|
|
539
|
+
"""
|
|
540
|
+
:return: the width of the term. 1 if scalar.
|
|
541
|
+
:rtype: int
|
|
542
|
+
"""
|
|
543
|
+
return get_snl_term_for_ids(self.pathIDs, self.termIDs).getWidth()
|
|
544
|
+
|
|
545
|
+
def get_name(self) -> str:
|
|
546
|
+
"""
|
|
547
|
+
:return: the name of the term.
|
|
548
|
+
:rtype: str
|
|
549
|
+
"""
|
|
550
|
+
return get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()
|
|
551
|
+
|
|
552
|
+
def get_direction(self) -> naja.SNLTerm.Direction:
|
|
553
|
+
"""
|
|
554
|
+
:return: the direction of the term.
|
|
555
|
+
:rtype: naja.SNLTerm.Direction
|
|
556
|
+
"""
|
|
557
|
+
snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
|
|
558
|
+
if snlterm.getDirection() == naja.SNLTerm.Direction.Input:
|
|
559
|
+
return Term.INPUT
|
|
560
|
+
elif snlterm.getDirection() == naja.SNLTerm.Direction.Output:
|
|
561
|
+
return Term.OUTPUT
|
|
562
|
+
elif snlterm.getDirection() == naja.SNLTerm.Direction.InOut:
|
|
563
|
+
return Term.INOUT
|
|
564
|
+
|
|
565
|
+
def __get_snl_bitnet(self, bit) -> Net:
|
|
566
|
+
# single bit
|
|
567
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
568
|
+
if path.size() > 0:
|
|
569
|
+
instTerm = path.getTailInstance().getInstTerm(bit)
|
|
570
|
+
return instTerm.getNet()
|
|
571
|
+
else:
|
|
572
|
+
return bit.getNet()
|
|
573
|
+
|
|
574
|
+
def __get_snl_lower_bitnet(self, bit) -> Net:
|
|
575
|
+
return bit.getNet()
|
|
576
|
+
|
|
577
|
+
def __get_snl_busnet(self, snl_nets) -> naja.SNLBusNet:
|
|
578
|
+
# iterate on all elements of the list and check if
|
|
579
|
+
# a full SNLBusNet can be reconstructed
|
|
580
|
+
snl_bus_net = None
|
|
581
|
+
for i in range(len(snl_nets)):
|
|
582
|
+
snl_net = snl_nets[i]
|
|
583
|
+
if not isinstance(snl_net, naja.SNLBusNetBit):
|
|
584
|
+
return None
|
|
585
|
+
bit_bus = snl_net.getBus()
|
|
586
|
+
if bit_bus.getWidth() != len(snl_nets):
|
|
587
|
+
return None
|
|
588
|
+
if snl_bus_net is None:
|
|
589
|
+
snl_bus_net = bit_bus
|
|
590
|
+
if snl_bus_net != bit_bus:
|
|
591
|
+
return None
|
|
592
|
+
if snl_bus_net.getBitAtPosition(i) != snl_net:
|
|
593
|
+
return None
|
|
594
|
+
return snl_bus_net
|
|
595
|
+
|
|
596
|
+
def __get_net(self, path, snl_term_net_accessor) -> Net:
|
|
597
|
+
if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTerm):
|
|
598
|
+
snl_nets = []
|
|
599
|
+
for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
|
|
600
|
+
snl_net = snl_term_net_accessor(bit)
|
|
601
|
+
snl_nets.append(snl_net)
|
|
602
|
+
snl_bus_net = self.__get_snl_busnet(snl_nets)
|
|
603
|
+
if snl_bus_net is not None:
|
|
604
|
+
return Net(path, snl_bus_net)
|
|
605
|
+
else:
|
|
606
|
+
if all(element is not None for element in snl_nets):
|
|
607
|
+
return Net(path, net_concat=snl_nets)
|
|
608
|
+
else:
|
|
609
|
+
snl_net = snl_term_net_accessor(
|
|
610
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs)
|
|
611
|
+
)
|
|
612
|
+
if snl_net is not None:
|
|
613
|
+
return Net(path, snl_net)
|
|
614
|
+
return None
|
|
615
|
+
|
|
616
|
+
def get_lower_net(self) -> Net:
|
|
617
|
+
"""
|
|
618
|
+
:return: the lower net of the term.
|
|
619
|
+
:rtype: Net
|
|
620
|
+
"""
|
|
621
|
+
return self.__get_net(self.pathIDs, self.__get_snl_lower_bitnet)
|
|
622
|
+
|
|
623
|
+
def get_net(self) -> Net:
|
|
624
|
+
"""
|
|
625
|
+
:return: the net of the term.
|
|
626
|
+
:rtype: Net
|
|
627
|
+
"""
|
|
628
|
+
head_path = self.pathIDs.copy()
|
|
629
|
+
if len(head_path) == 0:
|
|
630
|
+
return None
|
|
631
|
+
# path is one level up
|
|
632
|
+
head_path.pop()
|
|
633
|
+
return self.__get_net(head_path, self.__get_snl_bitnet)
|
|
634
|
+
|
|
635
|
+
def get_instance(self):
|
|
636
|
+
"""
|
|
637
|
+
:return: the instance of this Term.
|
|
638
|
+
:rtype: Instance
|
|
639
|
+
"""
|
|
640
|
+
return Instance(self.pathIDs)
|
|
641
|
+
|
|
642
|
+
def get_flat_fanout(self):
|
|
643
|
+
return self.get_equipotential().get_leaf_readers()
|
|
644
|
+
|
|
645
|
+
def get_equipotential(self) -> Equipotential:
|
|
646
|
+
return Equipotential(self)
|
|
647
|
+
|
|
648
|
+
def is_input(self) -> bool:
|
|
649
|
+
"""
|
|
650
|
+
:return: True if the term is an input.
|
|
651
|
+
:rtype: bool
|
|
652
|
+
"""
|
|
653
|
+
snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
|
|
654
|
+
return snlterm.getDirection() == naja.SNLTerm.Direction.Input
|
|
655
|
+
|
|
656
|
+
def is_output(self) -> bool:
|
|
657
|
+
"""
|
|
658
|
+
:return: True if the term is an output.
|
|
659
|
+
:rtype: bool
|
|
660
|
+
"""
|
|
661
|
+
snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
|
|
662
|
+
return snlterm.getDirection() == naja.SNLTerm.Direction.Output
|
|
663
|
+
|
|
664
|
+
def get_bits(self):
|
|
665
|
+
"""
|
|
666
|
+
:return: an iterator over the bits of the term.
|
|
667
|
+
If the term is scalar, it will return an iterator over itself.
|
|
668
|
+
:rtype: Iterator[Term]
|
|
669
|
+
"""
|
|
670
|
+
if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTerm):
|
|
671
|
+
for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
|
|
672
|
+
yield Term(self.pathIDs, bit)
|
|
673
|
+
else:
|
|
674
|
+
yield self
|
|
675
|
+
|
|
676
|
+
def get_bit(self, index: int):
|
|
677
|
+
"""
|
|
678
|
+
:param int index: the index of the bit to get.
|
|
679
|
+
:return: the Term bit at the given index or None if it does not exist.
|
|
680
|
+
:rtype: Term or None
|
|
681
|
+
"""
|
|
682
|
+
if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), naja.SNLBusTerm):
|
|
683
|
+
return Term(
|
|
684
|
+
self.pathIDs,
|
|
685
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs).getBusTermBit(index),
|
|
686
|
+
)
|
|
687
|
+
return None
|
|
688
|
+
|
|
689
|
+
def disconnect(self):
|
|
690
|
+
"""Disconnect this term from its net."""
|
|
691
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
692
|
+
self.__make_unique()
|
|
693
|
+
inst = path.getTailInstance()
|
|
694
|
+
for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
|
|
695
|
+
iterm = inst.getInstTerm(bit)
|
|
696
|
+
iterm.setNet(None)
|
|
697
|
+
|
|
698
|
+
def connect(self, net: Net):
|
|
699
|
+
"""Connect this term to the given Net.
|
|
700
|
+
|
|
701
|
+
:param Net net: the Net to connect to.
|
|
702
|
+
"""
|
|
703
|
+
if self.get_width() != net.get_width():
|
|
704
|
+
raise ValueError("Width mismatch")
|
|
705
|
+
if self.get_instance().is_top():
|
|
706
|
+
for bterm, bnet in zip(
|
|
707
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits(),
|
|
708
|
+
net.net.getBits(),
|
|
709
|
+
):
|
|
710
|
+
logging.debug(f"Connecting {bterm} to {bnet}")
|
|
711
|
+
bterm.setNet(bnet)
|
|
712
|
+
else:
|
|
713
|
+
self.__make_unique()
|
|
714
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
715
|
+
inst = path.getTailInstance()
|
|
716
|
+
for bterm, bnet in zip(
|
|
717
|
+
get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits(),
|
|
718
|
+
net.net.getBits(),
|
|
719
|
+
):
|
|
720
|
+
iterm = inst.getInstTerm(bterm)
|
|
721
|
+
iterm.setNet(bnet)
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
def get_instance_by_path(names: list):
|
|
725
|
+
assert len(names) > 0
|
|
726
|
+
path = naja.SNLPath()
|
|
727
|
+
instance = None
|
|
728
|
+
top = naja.NLUniverse.get().getTopDesign()
|
|
729
|
+
design = top
|
|
730
|
+
for name in names:
|
|
731
|
+
path = naja.SNLPath(path, design.getInstance(name))
|
|
732
|
+
instance = design.getInstance(name)
|
|
733
|
+
assert instance is not None
|
|
734
|
+
design = instance.getModel()
|
|
735
|
+
return Instance(path)
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
# def refresh_path(path: naja.SNLPath):
|
|
739
|
+
# pathlist = path.getPathIDs()
|
|
740
|
+
# assert len(pathlist) > 0
|
|
741
|
+
# path = naja.SNLPath()
|
|
742
|
+
# instance = None
|
|
743
|
+
# top = naja.NLUniverse.get().getTopDesign()
|
|
744
|
+
# design = top
|
|
745
|
+
# for id in pathlist:
|
|
746
|
+
# path = naja.SNLPath(path, design.getInstanceByID(id))
|
|
747
|
+
# instance = design.getInstanceByID(id)
|
|
748
|
+
# assert instance is not None
|
|
749
|
+
# design = instance.getModel()
|
|
750
|
+
# return path
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
class Attribute:
|
|
754
|
+
def __init__(self, snlAttribute):
|
|
755
|
+
self.snlAttribute = snlAttribute
|
|
756
|
+
|
|
757
|
+
def __str__(self):
|
|
758
|
+
return str(self.snlAttribute)
|
|
759
|
+
|
|
760
|
+
def get_name(self):
|
|
761
|
+
"""
|
|
762
|
+
:return: the name of the attribute.
|
|
763
|
+
:rtype: str
|
|
764
|
+
"""
|
|
765
|
+
return self.snlAttribute.getName()
|
|
766
|
+
|
|
767
|
+
def has_value(self):
|
|
768
|
+
"""
|
|
769
|
+
:return: True if the attribute has a value.
|
|
770
|
+
:rtype: bool
|
|
771
|
+
"""
|
|
772
|
+
return self.snlAttribute.hasValue()
|
|
773
|
+
|
|
774
|
+
def get_value(self):
|
|
775
|
+
"""
|
|
776
|
+
:return: the value of the attribute.
|
|
777
|
+
:rtype: str
|
|
778
|
+
"""
|
|
779
|
+
return self.snlAttribute.getValue()
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
class Instance:
|
|
783
|
+
"""Class that represents the instance and wraps some
|
|
784
|
+
of the snl occurrence API.
|
|
785
|
+
"""
|
|
786
|
+
|
|
787
|
+
def __init__(self, path=naja.SNLPath()):
|
|
788
|
+
self.inst = None
|
|
789
|
+
self.revisionCount = 0
|
|
790
|
+
self.SNLID = [0, 0, 0, 0, 0, 0]
|
|
791
|
+
if isinstance(path, naja.SNLPath):
|
|
792
|
+
if path.size() > 0:
|
|
793
|
+
self.pathIDs = path.getPathIDs()
|
|
794
|
+
self.revisionCount = path.getTailInstance().getModel().getRevisionCount()
|
|
795
|
+
self.inst = path.getTailInstance()
|
|
796
|
+
else:
|
|
797
|
+
self.pathIDs = []
|
|
798
|
+
elif isinstance(path, list):
|
|
799
|
+
self.pathIDs = path.copy()
|
|
800
|
+
if len(path) > 0:
|
|
801
|
+
self.inst = get_snl_instance_from_id_list(path)
|
|
802
|
+
self.revisionCount = self.inst.getModel().getRevisionCount()
|
|
803
|
+
if self.inst is not None:
|
|
804
|
+
self.SNLID = self.inst.getModel().getNLID()
|
|
805
|
+
|
|
806
|
+
def __eq__(self, other) -> bool:
|
|
807
|
+
return self.pathIDs == other.pathIDs
|
|
808
|
+
|
|
809
|
+
def __str__(self):
|
|
810
|
+
if self.is_top():
|
|
811
|
+
top = self.__get_snl_model()
|
|
812
|
+
if top is not None:
|
|
813
|
+
return top.getName()
|
|
814
|
+
else:
|
|
815
|
+
return ""
|
|
816
|
+
else:
|
|
817
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
818
|
+
return str(path)
|
|
819
|
+
|
|
820
|
+
def __repr__(self) -> str:
|
|
821
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
822
|
+
return f"Instance({path})"
|
|
823
|
+
|
|
824
|
+
def __hash__(self):
|
|
825
|
+
return consistent_hash(self.pathIDs)
|
|
826
|
+
|
|
827
|
+
def get_leaf_children(self):
|
|
828
|
+
"""Iterate over the leaf children of this Instance.
|
|
829
|
+
Equivalent to the underlying leaves of the instanciation tree.
|
|
830
|
+
|
|
831
|
+
:return: an iterator over the leaf children Instance of this Instance.
|
|
832
|
+
:rtype: Iterator[Instance]
|
|
833
|
+
"""
|
|
834
|
+
initial_path = get_snl_path_from_id_list(self.pathIDs)
|
|
835
|
+
for inst in self.__get_snl_model().getInstances():
|
|
836
|
+
if inst.getModel().isLeaf():
|
|
837
|
+
yield Instance(naja.SNLPath(initial_path, inst))
|
|
838
|
+
path = naja.SNLPath(initial_path, inst)
|
|
839
|
+
stack = [[inst, path]]
|
|
840
|
+
while stack:
|
|
841
|
+
current = stack.pop()
|
|
842
|
+
current_inst = current[0]
|
|
843
|
+
current_path = current[1]
|
|
844
|
+
for inst_child in current_inst.getModel().getInstances():
|
|
845
|
+
path_child = naja.SNLPath(current_path, inst_child)
|
|
846
|
+
if inst_child.getModel().isLeaf():
|
|
847
|
+
yield Instance(path_child)
|
|
848
|
+
stack.append([inst_child, path_child])
|
|
849
|
+
|
|
850
|
+
def is_top(self) -> bool:
|
|
851
|
+
"""
|
|
852
|
+
:return: True if this is the top design.
|
|
853
|
+
:rtype: bool
|
|
854
|
+
"""
|
|
855
|
+
return len(self.pathIDs) == 0
|
|
856
|
+
|
|
857
|
+
def is_assign(self) -> bool:
|
|
858
|
+
"""(assign a=b) will create an instance of assign connecting
|
|
859
|
+
the wire a to the output of the assign and b to the input.
|
|
860
|
+
|
|
861
|
+
:return: True if this is an assign. Assigns are represented with
|
|
862
|
+
anonymous Assign instances.
|
|
863
|
+
:rtype: bool
|
|
864
|
+
"""
|
|
865
|
+
return self.__get_snl_model().isAssign()
|
|
866
|
+
|
|
867
|
+
def is_blackbox(self) -> bool:
|
|
868
|
+
"""
|
|
869
|
+
:return: True if this is a blackbox.
|
|
870
|
+
:rtype: bool
|
|
871
|
+
"""
|
|
872
|
+
return self.__get_snl_model().isBlackBox()
|
|
873
|
+
|
|
874
|
+
def is_leaf(self) -> bool:
|
|
875
|
+
"""
|
|
876
|
+
:return: True if this is a leaf.
|
|
877
|
+
:rtype: bool
|
|
878
|
+
"""
|
|
879
|
+
return self.__get_snl_model().isLeaf()
|
|
880
|
+
|
|
881
|
+
def is_const0(self) -> bool:
|
|
882
|
+
"""
|
|
883
|
+
:return: True if this is a constant 0 generator.
|
|
884
|
+
:rtype: bool
|
|
885
|
+
"""
|
|
886
|
+
return self.__get_snl_model().isConst0()
|
|
887
|
+
|
|
888
|
+
def is_const1(self) -> bool:
|
|
889
|
+
"""
|
|
890
|
+
:return: True if this is a constant 1 generator.
|
|
891
|
+
:rtype: bool
|
|
892
|
+
"""
|
|
893
|
+
return self.__get_snl_model().isConst1()
|
|
894
|
+
|
|
895
|
+
def is_const(self) -> bool:
|
|
896
|
+
"""
|
|
897
|
+
:return: True if this is a constant generator.
|
|
898
|
+
:rtype: bool
|
|
899
|
+
"""
|
|
900
|
+
return self.__get_snl_model().isConst()
|
|
901
|
+
|
|
902
|
+
def is_buf(self) -> bool:
|
|
903
|
+
"""
|
|
904
|
+
:return: True if this is a buffer.
|
|
905
|
+
:rtype: bool
|
|
906
|
+
"""
|
|
907
|
+
return self.__get_snl_model().isBuf()
|
|
908
|
+
|
|
909
|
+
def is_inv(self) -> bool:
|
|
910
|
+
"""
|
|
911
|
+
:return: True if this is an inverter.
|
|
912
|
+
:rtype: bool
|
|
913
|
+
"""
|
|
914
|
+
return self.__get_snl_model().isInv()
|
|
915
|
+
|
|
916
|
+
def is_basic_primitive(instance):
|
|
917
|
+
design = instance.__get_snl_model()
|
|
918
|
+
return (
|
|
919
|
+
design.isConst0() or design.isConst1() or design.isBuf() or design.isInv()
|
|
920
|
+
)
|
|
921
|
+
|
|
922
|
+
def __get_snl_model(self):
|
|
923
|
+
if self.is_top():
|
|
924
|
+
return naja.NLUniverse.get().getTopDesign()
|
|
925
|
+
if (
|
|
926
|
+
self.inst.getModel().getRevisionCount() != self.revisionCount or
|
|
927
|
+
self.inst.getModel().getNLID() != self.SNLID
|
|
928
|
+
):
|
|
929
|
+
self.inst = get_snl_instance_from_id_list(self.pathIDs)
|
|
930
|
+
self.revisionCount = self.inst.getModel().getRevisionCount()
|
|
931
|
+
self.SNLID = self.inst.getModel().getNLID()
|
|
932
|
+
|
|
933
|
+
return self.inst.getModel()
|
|
934
|
+
|
|
935
|
+
def __get_leaf_snl_object(self):
|
|
936
|
+
if self.is_top():
|
|
937
|
+
return naja.NLUniverse.get().getTopDesign()
|
|
938
|
+
return get_snl_instance_from_id_list(self.pathIDs)
|
|
939
|
+
|
|
940
|
+
def __find_snl_model(self, name: str) -> naja.SNLDesign:
|
|
941
|
+
u = naja.NLUniverse.get()
|
|
942
|
+
for db in u.getUserDBs():
|
|
943
|
+
for lib in db.getLibraries():
|
|
944
|
+
found_model = lib.getSNLDesign(name)
|
|
945
|
+
if found_model is not None:
|
|
946
|
+
return found_model
|
|
947
|
+
return None
|
|
948
|
+
|
|
949
|
+
def dump_full_dot(self, path: str):
|
|
950
|
+
"""Dump the full dot file of this instance."""
|
|
951
|
+
self.__get_snl_model().dumpFullDotFile(path)
|
|
952
|
+
|
|
953
|
+
def dump_context_dot(self, path: str):
|
|
954
|
+
self.__get_snl_model().dumpContextDotFile(path)
|
|
955
|
+
|
|
956
|
+
def get_child_instance(self, name: str):
|
|
957
|
+
"""
|
|
958
|
+
:param str name: the name of the child Instance to get.
|
|
959
|
+
:return: the child Instance with the given name or None if it does not exist.
|
|
960
|
+
:rtype: Instance or None
|
|
961
|
+
"""
|
|
962
|
+
childInst = self.__get_snl_model().getInstance(name)
|
|
963
|
+
if childInst is None:
|
|
964
|
+
return None
|
|
965
|
+
path = self.pathIDs.copy()
|
|
966
|
+
path.append(childInst.getID())
|
|
967
|
+
return Instance(path)
|
|
968
|
+
|
|
969
|
+
def get_child_instances(self):
|
|
970
|
+
"""Iterate over the child instances of this instance.
|
|
971
|
+
Equivalent to go down one level in hierarchy.
|
|
972
|
+
|
|
973
|
+
:return: an iterator over the child instances of this instance.
|
|
974
|
+
:rtype: Iterator[Instance]
|
|
975
|
+
"""
|
|
976
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
977
|
+
for inst in self.__get_snl_model().getInstances():
|
|
978
|
+
path_child = naja.SNLPath(path, inst)
|
|
979
|
+
yield Instance(path_child)
|
|
980
|
+
# path.pop()
|
|
981
|
+
|
|
982
|
+
def count_child_instances(self) -> int:
|
|
983
|
+
"""
|
|
984
|
+
:return: the number of child instances of this instance.
|
|
985
|
+
:rtype: int
|
|
986
|
+
"""
|
|
987
|
+
return sum(1 for _ in self.__get_snl_model().getInstances())
|
|
988
|
+
|
|
989
|
+
# def get_flat_primitive_instances(self):
|
|
990
|
+
# FIXME: concat first local path with the path of the instance
|
|
991
|
+
# model = self.__get_snl_model()
|
|
992
|
+
# for inst in model.getInstances():
|
|
993
|
+
# path = naja.SNLPath(inst)
|
|
994
|
+
# stack = [[inst, path]]
|
|
995
|
+
# while stack:
|
|
996
|
+
# current = stack.pop()
|
|
997
|
+
# current_inst = current[0]
|
|
998
|
+
# current_path = current[1]
|
|
999
|
+
# for inst_child in current_inst.getModel().getInstances():
|
|
1000
|
+
# path_child = naja.SNLPath(current_path, inst_child)
|
|
1001
|
+
# if inst_child.getModel().isPrimitive():
|
|
1002
|
+
# yield Instance(path_child)
|
|
1003
|
+
# stack.append([inst_child, path_child])
|
|
1004
|
+
|
|
1005
|
+
def get_nets(self):
|
|
1006
|
+
"""Iterate over all scalar nets and bus nets.
|
|
1007
|
+
|
|
1008
|
+
:return: an iterator over the nets of this Instance.
|
|
1009
|
+
:rtype: Iterator[Net]
|
|
1010
|
+
"""
|
|
1011
|
+
for net in self.__get_snl_model().getNets():
|
|
1012
|
+
yield Net(self.pathIDs, net)
|
|
1013
|
+
|
|
1014
|
+
def count_nets(self) -> int:
|
|
1015
|
+
"""Count the number of scalar nets and bus nets of this Instance.
|
|
1016
|
+
|
|
1017
|
+
:return: the number of nets of this Instance.
|
|
1018
|
+
:rtype: int
|
|
1019
|
+
"""
|
|
1020
|
+
return sum(1 for _ in self.get_nets())
|
|
1021
|
+
|
|
1022
|
+
def get_flat_nets(self):
|
|
1023
|
+
"""Iterate over all scalar nets and bus net bits.
|
|
1024
|
+
|
|
1025
|
+
:return: an iterator over the flat nets of this Instance.
|
|
1026
|
+
:rtype: Iterator[Net]
|
|
1027
|
+
"""
|
|
1028
|
+
for net in self.__get_snl_model().getNets():
|
|
1029
|
+
if isinstance(net, naja.SNLBusNet):
|
|
1030
|
+
for bit in net.getBits():
|
|
1031
|
+
yield Net(self.pathIDs, bit)
|
|
1032
|
+
else:
|
|
1033
|
+
yield Net(self.pathIDs, net)
|
|
1034
|
+
|
|
1035
|
+
def count_flat_nets(self) -> int:
|
|
1036
|
+
"""Count the number of scalar nets and bus net bits of this Instance.
|
|
1037
|
+
|
|
1038
|
+
:return: the number of flat nets of this Instance.
|
|
1039
|
+
:rtype: int
|
|
1040
|
+
"""
|
|
1041
|
+
return sum(1 for _ in self.get_flat_nets())
|
|
1042
|
+
|
|
1043
|
+
def get_net(self, name: str) -> Net:
|
|
1044
|
+
"""
|
|
1045
|
+
:param str name: the name of the Net to get.
|
|
1046
|
+
:return: the Net with the given name or None if it does not exist.
|
|
1047
|
+
:rtype: Net or None
|
|
1048
|
+
"""
|
|
1049
|
+
net = self.__get_snl_model().getNet(name)
|
|
1050
|
+
if net is not None:
|
|
1051
|
+
return Net(self.pathIDs, net)
|
|
1052
|
+
return None
|
|
1053
|
+
|
|
1054
|
+
def is_primitive(self) -> bool:
|
|
1055
|
+
"""
|
|
1056
|
+
:return: True if this is a primitive.
|
|
1057
|
+
:rtype: bool
|
|
1058
|
+
"""
|
|
1059
|
+
return self.__get_snl_model().isPrimitive()
|
|
1060
|
+
|
|
1061
|
+
def get_terms(self):
|
|
1062
|
+
"""Iterate over all scalar terms and bus terms of this Instance.
|
|
1063
|
+
|
|
1064
|
+
:return: the terms of this Instance.
|
|
1065
|
+
:rtype: Iterator[Term]
|
|
1066
|
+
"""
|
|
1067
|
+
for term in self.__get_snl_model().getTerms():
|
|
1068
|
+
yield Term(self.pathIDs, term)
|
|
1069
|
+
|
|
1070
|
+
def count_terms(self) -> int:
|
|
1071
|
+
"""Count the number of scalar terms and bus terms of this Instance.
|
|
1072
|
+
|
|
1073
|
+
:return: the number of terms of this Instance.
|
|
1074
|
+
:rtype: int
|
|
1075
|
+
"""
|
|
1076
|
+
return sum(1 for _ in self.get_terms())
|
|
1077
|
+
|
|
1078
|
+
def get_flat_terms(self):
|
|
1079
|
+
"""Iterate over all scalar terms and bus term bits.
|
|
1080
|
+
|
|
1081
|
+
:return: the flat terms of this Instance.
|
|
1082
|
+
:rtype: Iterator[Term]
|
|
1083
|
+
"""
|
|
1084
|
+
for term in self.__get_snl_model().getBitTerms():
|
|
1085
|
+
yield Term(self.pathIDs, term)
|
|
1086
|
+
|
|
1087
|
+
def count_flat_terms(self) -> int:
|
|
1088
|
+
"""Count the number of scalar terms and bus term bits of this Instance.
|
|
1089
|
+
|
|
1090
|
+
:return: the number of flat terms of this Instance.
|
|
1091
|
+
:rtype: int
|
|
1092
|
+
"""
|
|
1093
|
+
return sum(1 for _ in self.get_flat_terms())
|
|
1094
|
+
|
|
1095
|
+
def get_term(self, name: str) -> Term:
|
|
1096
|
+
"""
|
|
1097
|
+
:param str name: the name of the Term to get.
|
|
1098
|
+
:return: the Term with the given name.
|
|
1099
|
+
:rtype: Term or None
|
|
1100
|
+
"""
|
|
1101
|
+
term = self.__get_snl_model().getTerm(name)
|
|
1102
|
+
if term is not None:
|
|
1103
|
+
return Term(self.pathIDs, self.__get_snl_model().getTerm(name))
|
|
1104
|
+
return None
|
|
1105
|
+
|
|
1106
|
+
def get_input_terms(self):
|
|
1107
|
+
"""Iterate over all scalar input terms and bus input terms
|
|
1108
|
+
of this Instance.
|
|
1109
|
+
|
|
1110
|
+
:return: the input terms of this Instance.
|
|
1111
|
+
:rtype: Iterator[Term]
|
|
1112
|
+
"""
|
|
1113
|
+
for term in self.__get_snl_model().getTerms():
|
|
1114
|
+
if term.getDirection() != naja.SNLTerm.Direction.Output:
|
|
1115
|
+
yield Term(self.pathIDs, term)
|
|
1116
|
+
|
|
1117
|
+
def count_input_terms(self) -> int:
|
|
1118
|
+
"""Count the number of scalar input terms and bus input terms
|
|
1119
|
+
of this Instance.
|
|
1120
|
+
|
|
1121
|
+
:return: the number of input terms of this Instance.
|
|
1122
|
+
:rtype: int
|
|
1123
|
+
"""
|
|
1124
|
+
return sum(1 for _ in self.get_input_terms())
|
|
1125
|
+
|
|
1126
|
+
def get_flat_input_terms(self):
|
|
1127
|
+
"""Iterate over all scalar input terms and bus input term bits
|
|
1128
|
+
of this Instance.
|
|
1129
|
+
|
|
1130
|
+
:return: the flat input terms of this Instance.
|
|
1131
|
+
:rtype: Iterator[Term]
|
|
1132
|
+
"""
|
|
1133
|
+
for term in self.__get_snl_model().getTerms():
|
|
1134
|
+
if term.getDirection() != naja.SNLTerm.Direction.Output:
|
|
1135
|
+
if isinstance(term, naja.SNLBusTerm):
|
|
1136
|
+
for bit in term.getBits():
|
|
1137
|
+
yield Term(self.pathIDs, bit)
|
|
1138
|
+
else:
|
|
1139
|
+
yield Term(self.pathIDs, term)
|
|
1140
|
+
|
|
1141
|
+
def count_flat_input_terms(self) -> int:
|
|
1142
|
+
"""Count the number of scalar input terms and bus input term bits
|
|
1143
|
+
of this Instance.
|
|
1144
|
+
|
|
1145
|
+
:return: the number of flat input terms of this Instance.
|
|
1146
|
+
:rtype: int
|
|
1147
|
+
"""
|
|
1148
|
+
return sum(1 for _ in self.get_flat_input_terms())
|
|
1149
|
+
|
|
1150
|
+
def get_output_terms(self):
|
|
1151
|
+
"""Iterate over all scalar output terms and bus output terms
|
|
1152
|
+
of this Instance.
|
|
1153
|
+
|
|
1154
|
+
:return: the output terms of this Instance.
|
|
1155
|
+
:rtype: Iterator[Term]
|
|
1156
|
+
"""
|
|
1157
|
+
for term in self.__get_snl_model().getTerms():
|
|
1158
|
+
if term.getDirection() != naja.SNLTerm.Direction.Input:
|
|
1159
|
+
yield Term(self.pathIDs, term)
|
|
1160
|
+
|
|
1161
|
+
def count_output_terms(self) -> int:
|
|
1162
|
+
"""Count the number of scalar output terms and bus output terms
|
|
1163
|
+
of this Instance.
|
|
1164
|
+
|
|
1165
|
+
:return: the number of output terms of this Instance.
|
|
1166
|
+
:rtype: int
|
|
1167
|
+
"""
|
|
1168
|
+
return sum(1 for _ in self.get_output_terms())
|
|
1169
|
+
|
|
1170
|
+
def get_flat_output_terms(self):
|
|
1171
|
+
"""Iterate over all scalar output terms and bus output term bits
|
|
1172
|
+
of this Instance.
|
|
1173
|
+
|
|
1174
|
+
:return: the flat output terms of this Instance.
|
|
1175
|
+
:rtype: Iterator[Term]
|
|
1176
|
+
"""
|
|
1177
|
+
for term in self.__get_snl_model().getTerms():
|
|
1178
|
+
if term.getDirection() != naja.SNLTerm.Direction.Input:
|
|
1179
|
+
if isinstance(term, naja.SNLBusTerm):
|
|
1180
|
+
for bit in term.getBits():
|
|
1181
|
+
yield Term(self.pathIDs, bit)
|
|
1182
|
+
else:
|
|
1183
|
+
yield Term(self.pathIDs, term)
|
|
1184
|
+
|
|
1185
|
+
def count_flat_output_terms(self) -> int:
|
|
1186
|
+
"""Count the number of scalar output terms and bus output term bits
|
|
1187
|
+
of this Instance.
|
|
1188
|
+
|
|
1189
|
+
:return: the number of flat output terms of this Instance.
|
|
1190
|
+
:rtype: int
|
|
1191
|
+
"""
|
|
1192
|
+
return sum(1 for _ in self.get_flat_output_terms())
|
|
1193
|
+
|
|
1194
|
+
def get_attributes(self):
|
|
1195
|
+
"""Iterate over the attributes of this Instance.
|
|
1196
|
+
|
|
1197
|
+
:return: the attributes of this Instance.
|
|
1198
|
+
:rtype: Iterator[Attribute]
|
|
1199
|
+
"""
|
|
1200
|
+
leaf_object = self.__get_leaf_snl_object()
|
|
1201
|
+
for attribute in leaf_object.getAttributes():
|
|
1202
|
+
yield Attribute(attribute)
|
|
1203
|
+
|
|
1204
|
+
def delete_instance(self, name: str):
|
|
1205
|
+
"""Delete the child instance with the given name."""
|
|
1206
|
+
if name == "":
|
|
1207
|
+
raise ValueError(
|
|
1208
|
+
"Cannot delete instance with empty name. Try delete_instance_by_id instead."
|
|
1209
|
+
)
|
|
1210
|
+
init_path = get_snl_path_from_id_list(self.pathIDs)
|
|
1211
|
+
path = naja.SNLPath(init_path, self.__get_snl_model().getInstance(name))
|
|
1212
|
+
naja.SNLUniquifier(path)
|
|
1213
|
+
if init_path.size() > 0:
|
|
1214
|
+
# Delete the last instance in uniq_path
|
|
1215
|
+
self.__get_snl_model().getInstance(name).destroy()
|
|
1216
|
+
|
|
1217
|
+
def delete_instance_by_id(self, id: str):
|
|
1218
|
+
"""Delete the child instance with the given ID.
|
|
1219
|
+
|
|
1220
|
+
:param str id: the ID of the Instance to delete.
|
|
1221
|
+
"""
|
|
1222
|
+
init_path = get_snl_path_from_id_list(self.pathIDs)
|
|
1223
|
+
path = naja.SNLPath(init_path, self.__get_snl_model().getInstanceByID(id))
|
|
1224
|
+
naja.SNLUniquifier(path)
|
|
1225
|
+
# Delete the last instance in uniq_path
|
|
1226
|
+
self.__get_snl_model().getInstanceByID(id).destroy()
|
|
1227
|
+
|
|
1228
|
+
def get_design(self):
|
|
1229
|
+
"""
|
|
1230
|
+
:return: the Instance containing this instance.
|
|
1231
|
+
:rtype: Instance
|
|
1232
|
+
"""
|
|
1233
|
+
path = self.pathIDs.copy()
|
|
1234
|
+
if len(self.pathIDs) == 1:
|
|
1235
|
+
return get_top()
|
|
1236
|
+
path.pop()
|
|
1237
|
+
return Instance(path)
|
|
1238
|
+
|
|
1239
|
+
def delete(self):
|
|
1240
|
+
"""Delete this instance."""
|
|
1241
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1242
|
+
naja.SNLUniquifier(path)
|
|
1243
|
+
self.get_design().delete_instance_by_id(path.getTailInstance().getID())
|
|
1244
|
+
|
|
1245
|
+
def get_name(self) -> str:
|
|
1246
|
+
"""
|
|
1247
|
+
:return: the name of the instance or name of the top is this is the top.
|
|
1248
|
+
:rtype: str
|
|
1249
|
+
"""
|
|
1250
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1251
|
+
if self.is_top():
|
|
1252
|
+
return self.get_model_name()
|
|
1253
|
+
else:
|
|
1254
|
+
return path.getTailInstance().getName()
|
|
1255
|
+
|
|
1256
|
+
def get_model_name(self) -> str:
|
|
1257
|
+
"""
|
|
1258
|
+
:return: the name of the model of the instance
|
|
1259
|
+
or name of the top is this is the top.
|
|
1260
|
+
:rtype: str
|
|
1261
|
+
"""
|
|
1262
|
+
return self.__get_snl_model().getName()
|
|
1263
|
+
|
|
1264
|
+
def get_model_id(self) -> tuple[int, int, int]:
|
|
1265
|
+
"""
|
|
1266
|
+
:return: the ID of the model of this Instance
|
|
1267
|
+
or ID of the top if this is the top.
|
|
1268
|
+
"""
|
|
1269
|
+
model = self.__get_snl_model()
|
|
1270
|
+
return model.getDB().getID(), model.getLibrary().getID(), model.getID()
|
|
1271
|
+
|
|
1272
|
+
def create_child_instance(self, model: str, name: str):
|
|
1273
|
+
"""Create a child instance with the given model and name.
|
|
1274
|
+
|
|
1275
|
+
:param str model: the name of the model of the instance to create.
|
|
1276
|
+
:param str name: the name of the instance to create.
|
|
1277
|
+
:return: the created Instance.
|
|
1278
|
+
:rtype: Instance
|
|
1279
|
+
"""
|
|
1280
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1281
|
+
if path.size() > 0:
|
|
1282
|
+
naja.SNLUniquifier(path)
|
|
1283
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1284
|
+
design = self.__get_snl_model()
|
|
1285
|
+
new_instance_model = self.__find_snl_model(model)
|
|
1286
|
+
if new_instance_model is None:
|
|
1287
|
+
raise ValueError(
|
|
1288
|
+
f"Cannot create instance {name} in {self}: model {model} cannot be found"
|
|
1289
|
+
)
|
|
1290
|
+
newSNLInstance = naja.SNLInstance.create(design, new_instance_model, name)
|
|
1291
|
+
path = naja.SNLPath(path, newSNLInstance)
|
|
1292
|
+
return Instance(path)
|
|
1293
|
+
|
|
1294
|
+
def create_term(self, name: str, direction: naja.SNLTerm.Direction) -> Term:
|
|
1295
|
+
"""Create a Term in this Instance with the given name and direction.
|
|
1296
|
+
|
|
1297
|
+
:param str name: the name of the Term to create.
|
|
1298
|
+
:param naja.SNLTerm.Direction direction: the direction of the Term to create.
|
|
1299
|
+
:return: the created Term.
|
|
1300
|
+
"""
|
|
1301
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1302
|
+
if path.size() > 0:
|
|
1303
|
+
naja.SNLUniquifier(path)
|
|
1304
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1305
|
+
design = self.__get_snl_model()
|
|
1306
|
+
newSNLTerm = naja.SNLScalarTerm.create(design, direction, name)
|
|
1307
|
+
return Term(path.getPathIDs(), newSNLTerm)
|
|
1308
|
+
|
|
1309
|
+
def create_output_term(self, name: str) -> Term:
|
|
1310
|
+
"""Create an output Term in this Instance with the given name.
|
|
1311
|
+
|
|
1312
|
+
:param str name: the name of the Term to create.
|
|
1313
|
+
:return: the created Term.
|
|
1314
|
+
:rtype: Term
|
|
1315
|
+
"""
|
|
1316
|
+
return self.create_term(name, naja.SNLTerm.Direction.Output)
|
|
1317
|
+
|
|
1318
|
+
def create_input_term(self, name: str) -> Term:
|
|
1319
|
+
"""Create an input Term in this Instance with the given name.
|
|
1320
|
+
|
|
1321
|
+
:param str name: the name of the Term to create.
|
|
1322
|
+
:return: the created Term.
|
|
1323
|
+
:rtype: Term
|
|
1324
|
+
"""
|
|
1325
|
+
return self.create_term(name, naja.SNLTerm.Direction.Input)
|
|
1326
|
+
|
|
1327
|
+
def create_inout_term(self, name: str) -> Term:
|
|
1328
|
+
"""Create an inout Term in this Instance with the given name.
|
|
1329
|
+
|
|
1330
|
+
:param str name: the name of the Term to create.
|
|
1331
|
+
:return: the created Term.
|
|
1332
|
+
:rtype: Term
|
|
1333
|
+
"""
|
|
1334
|
+
return self.create_term(name, naja.SNLTerm.Direction.InOut)
|
|
1335
|
+
|
|
1336
|
+
def create_bus_term(self, name: str, msb: int, lsb: int, direction) -> Term:
|
|
1337
|
+
"""Create a bus Term in this Instance with the given name, msb, lsb and direction.
|
|
1338
|
+
|
|
1339
|
+
:param str name: the name of the Term to create.
|
|
1340
|
+
:param int msb: the most significant bit of the Term to create.
|
|
1341
|
+
:param int lsb: the least significant bit of the Term to create.
|
|
1342
|
+
:param naja.SNLTerm.Direction direction: the direction of the Term to create.
|
|
1343
|
+
:return: the created Term.
|
|
1344
|
+
"""
|
|
1345
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1346
|
+
if path.size() > 0:
|
|
1347
|
+
naja.SNLUniquifier(path)
|
|
1348
|
+
design = self.__get_snl_model()
|
|
1349
|
+
newSNLTerm = naja.SNLBusTerm.create(design, direction, msb, lsb, name)
|
|
1350
|
+
return Term(self.pathIDs, newSNLTerm)
|
|
1351
|
+
|
|
1352
|
+
def create_inout_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
1353
|
+
"""Create an inout bus Term in this Instance with the given name, msb and lsb.
|
|
1354
|
+
|
|
1355
|
+
:param str name: the name of the Term to create.
|
|
1356
|
+
:param int msb: the most significant bit of the Term to create.
|
|
1357
|
+
:param int lsb: the least significant bit of the Term to create.
|
|
1358
|
+
:return: the created Term.
|
|
1359
|
+
:rtype: Term
|
|
1360
|
+
"""
|
|
1361
|
+
return self.create_bus_term(name, msb, lsb, naja.SNLTerm.Direction.InOut)
|
|
1362
|
+
|
|
1363
|
+
def create_output_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
1364
|
+
"""Create an output bus Term in this Instance with the given name, msb and lsb.
|
|
1365
|
+
|
|
1366
|
+
:param str name: the name of the Term to create.
|
|
1367
|
+
:param int msb: the most significant bit of the Term to create.
|
|
1368
|
+
:param int lsb: the least significant bit of the Term to create.
|
|
1369
|
+
:return: the created Term.
|
|
1370
|
+
:rtype: Term
|
|
1371
|
+
"""
|
|
1372
|
+
return self.create_bus_term(name, msb, lsb, naja.SNLTerm.Direction.Output)
|
|
1373
|
+
|
|
1374
|
+
def create_input_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
1375
|
+
"""Create an input bus Term in this Instance with the given name, msb and lsb.
|
|
1376
|
+
|
|
1377
|
+
:param str name: the name of the Term to create.
|
|
1378
|
+
:param int msb: the most significant bit of the Term to create.
|
|
1379
|
+
:param int lsb: the least significant bit of the Term to create.
|
|
1380
|
+
:return: the created Term.
|
|
1381
|
+
:rtype: Term
|
|
1382
|
+
"""
|
|
1383
|
+
return self.create_bus_term(name, msb, lsb, naja.SNLTerm.Direction.Input)
|
|
1384
|
+
|
|
1385
|
+
def create_net(self, name: str) -> Net:
|
|
1386
|
+
"""Create a scalar Net in this Instance with the given name.
|
|
1387
|
+
|
|
1388
|
+
:param str name: the name of the Net to create.
|
|
1389
|
+
:return: the created Net.
|
|
1390
|
+
:rtype: Net
|
|
1391
|
+
"""
|
|
1392
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1393
|
+
if path.size() > 0:
|
|
1394
|
+
naja.SNLUniquifier(path)
|
|
1395
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1396
|
+
model = self.__get_snl_model()
|
|
1397
|
+
newSNLNet = naja.SNLScalarNet.create(model, name)
|
|
1398
|
+
return Net(path, newSNLNet)
|
|
1399
|
+
|
|
1400
|
+
def create_bus_net(self, name: str, msb: int, lsb: int) -> Net:
|
|
1401
|
+
"""Create a bus Net in this Instance with the given name, msb and lsb.
|
|
1402
|
+
|
|
1403
|
+
:param str name: the name of the Net to create.
|
|
1404
|
+
:param int msb: the most significant bit of the Net to create.
|
|
1405
|
+
:param int lsb: the least significant bit of the Net to create.
|
|
1406
|
+
:return: the created Net.
|
|
1407
|
+
:rtype: Net
|
|
1408
|
+
"""
|
|
1409
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1410
|
+
if path.size() > 0:
|
|
1411
|
+
naja.SNLUniquifier(path)
|
|
1412
|
+
path = get_snl_path_from_id_list(self.pathIDs)
|
|
1413
|
+
model = self.__get_snl_model()
|
|
1414
|
+
newSNLNet = naja.SNLBusNet.create(model, msb, lsb, name)
|
|
1415
|
+
return Net(path, newSNLNet)
|
|
1416
|
+
|
|
1417
|
+
def dump_verilog(self, path: str, name: str):
|
|
1418
|
+
"""Dump the verilog of this instance.
|
|
1419
|
+
|
|
1420
|
+
:param str path: the path where to dump the verilog.
|
|
1421
|
+
:param str name: the name of the verilog file.
|
|
1422
|
+
"""
|
|
1423
|
+
self.__get_snl_model().dumpVerilog(path, name)
|
|
1424
|
+
|
|
1425
|
+
def get_truth_table(self):
|
|
1426
|
+
"""
|
|
1427
|
+
:return: the truth table of the instance.
|
|
1428
|
+
:rtype: list[str]
|
|
1429
|
+
"""
|
|
1430
|
+
return self.__get_snl_model().getTruthTable()
|
|
1431
|
+
|
|
1432
|
+
|
|
1433
|
+
def __get_top_db() -> naja.NLDB:
|
|
1434
|
+
if naja.NLUniverse.get() is None:
|
|
1435
|
+
naja.NLUniverse.create()
|
|
1436
|
+
if naja.NLUniverse.get().getTopDB() is None:
|
|
1437
|
+
db = naja.NLDB.create(naja.NLUniverse.get())
|
|
1438
|
+
naja.NLUniverse.get().setTopDB(db)
|
|
1439
|
+
return naja.NLUniverse.get().getTopDB()
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
def get_top():
|
|
1443
|
+
"""
|
|
1444
|
+
:return: the top Instance.
|
|
1445
|
+
:rtype: Instance
|
|
1446
|
+
"""
|
|
1447
|
+
return Instance(naja.SNLPath())
|
|
1448
|
+
|
|
1449
|
+
|
|
1450
|
+
def create_top(name: str) -> Instance:
|
|
1451
|
+
"""Create a top instance with the given name.
|
|
1452
|
+
|
|
1453
|
+
:param str name: the name of the top instance to create.
|
|
1454
|
+
:return: the created top Instance.
|
|
1455
|
+
:rtype: Instance
|
|
1456
|
+
"""
|
|
1457
|
+
# init
|
|
1458
|
+
db = __get_top_db()
|
|
1459
|
+
# create top design
|
|
1460
|
+
lib = naja.NLLibrary.create(db)
|
|
1461
|
+
top = naja.SNLDesign.create(lib, name)
|
|
1462
|
+
naja.NLUniverse.get().setTopDesign(top)
|
|
1463
|
+
return Instance()
|
|
1464
|
+
|
|
1465
|
+
|
|
1466
|
+
class VerilogConfig:
|
|
1467
|
+
def __init__(self, keep_assigns=True):
|
|
1468
|
+
self.keep_assigns = keep_assigns
|
|
1469
|
+
|
|
1470
|
+
|
|
1471
|
+
def load_verilog(files: Union[str, List[str]], config: VerilogConfig = None) -> Instance:
|
|
1472
|
+
"""Load verilog files into the top design.
|
|
1473
|
+
:param files: a list of verilog files to load or a single file.
|
|
1474
|
+
:param config: the configuration to use when loading the files.
|
|
1475
|
+
:return: the top Instance.
|
|
1476
|
+
"""
|
|
1477
|
+
if isinstance(files, str):
|
|
1478
|
+
files = [files]
|
|
1479
|
+
if not files or len(files) == 0:
|
|
1480
|
+
raise Exception("No verilog files provided")
|
|
1481
|
+
if config is None:
|
|
1482
|
+
config = VerilogConfig() # Use default settings
|
|
1483
|
+
start_time = time.time()
|
|
1484
|
+
logging.info(f"Loading verilog: {', '.join(files)}")
|
|
1485
|
+
__get_top_db().loadVerilog(files, keep_assigns=config.keep_assigns)
|
|
1486
|
+
execution_time = time.time() - start_time
|
|
1487
|
+
logging.info(f"Loading done in {execution_time:.2f} seconds")
|
|
1488
|
+
return get_top()
|
|
1489
|
+
|
|
1490
|
+
|
|
1491
|
+
def load_liberty(files: Union[str, List[str]]):
|
|
1492
|
+
"""Load liberty files.
|
|
1493
|
+
:param files: a list of liberty files to load or a single file.
|
|
1494
|
+
"""
|
|
1495
|
+
if isinstance(files, str):
|
|
1496
|
+
files = [files]
|
|
1497
|
+
if not files or len(files) == 0:
|
|
1498
|
+
raise Exception("No liberty files provided")
|
|
1499
|
+
logging.info(f"Loading liberty files: {', '.join(files)}")
|
|
1500
|
+
__get_top_db().loadLibertyPrimitives(files)
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
def load_primitives(name: str):
|
|
1504
|
+
"""Loads a primitive library embedded in najaeda.
|
|
1505
|
+
|
|
1506
|
+
Currently supported libraries are:
|
|
1507
|
+
|
|
1508
|
+
- xilinx
|
|
1509
|
+
"""
|
|
1510
|
+
if name == "xilinx":
|
|
1511
|
+
from najaeda.primitives import xilinx
|
|
1512
|
+
|
|
1513
|
+
xilinx.load(__get_top_db())
|
|
1514
|
+
else:
|
|
1515
|
+
raise ValueError(f"Unknown primitives library: {name}")
|
|
1516
|
+
|
|
1517
|
+
|
|
1518
|
+
def load_primitives_from_file(file: str):
|
|
1519
|
+
"""Loads a primitives library from a file.
|
|
1520
|
+
|
|
1521
|
+
:param str file: the path to the primitives library file.
|
|
1522
|
+
The file must define a function `load(db)`.
|
|
1523
|
+
"""
|
|
1524
|
+
logging.info(f"Loading primitives from file: {file}")
|
|
1525
|
+
if not os.path.isfile(file):
|
|
1526
|
+
raise FileNotFoundError(f"Cannot load primitives from non existing file: {file}")
|
|
1527
|
+
import importlib.util
|
|
1528
|
+
spec = importlib.util.spec_from_file_location("user_module", file)
|
|
1529
|
+
module = importlib.util.module_from_spec(spec)
|
|
1530
|
+
sys.modules["user_module"] = module
|
|
1531
|
+
spec.loader.exec_module(module)
|
|
1532
|
+
|
|
1533
|
+
if not hasattr(module, "load"):
|
|
1534
|
+
raise RuntimeError(f"The file {file} must define a function named `load(db)`")
|
|
1535
|
+
|
|
1536
|
+
db = __get_top_db()
|
|
1537
|
+
module.load(db)
|
|
1538
|
+
|
|
1539
|
+
|
|
1540
|
+
def get_primitives_library() -> naja.NLLibrary:
|
|
1541
|
+
lib = __get_top_db().getLibrary("PRIMS")
|
|
1542
|
+
if lib is None:
|
|
1543
|
+
lib = naja.NLLibrary.createPrimitives(__get_top_db(), "PRIMS")
|
|
1544
|
+
return lib
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
def get_model_name(id: tuple[int, int, int]) -> str:
|
|
1548
|
+
"""
|
|
1549
|
+
:param tuple[int, int, int] id: the id of the model.
|
|
1550
|
+
:return: the name of the model given its id or None if it does not exist.
|
|
1551
|
+
:rtype: str or None
|
|
1552
|
+
"""
|
|
1553
|
+
u = naja.NLUniverse.get()
|
|
1554
|
+
if u:
|
|
1555
|
+
db = u.getDB(id[0])
|
|
1556
|
+
if db:
|
|
1557
|
+
lib = db.getLibrary(id[1])
|
|
1558
|
+
if lib:
|
|
1559
|
+
model = lib.getSNLDesign(id[2])
|
|
1560
|
+
if model:
|
|
1561
|
+
return model.getName()
|
|
1562
|
+
return None
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
def apply_dle():
|
|
1566
|
+
"""Apply the DLE (Dead Logic Elimination) to the top design."""
|
|
1567
|
+
top = naja.NLUniverse.get().getTopDesign()
|
|
1568
|
+
if top is not None:
|
|
1569
|
+
naja.NLUniverse.get().applyDLE()
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
def apply_constant_propagation():
|
|
1573
|
+
"""Apply constant propagation to the top design."""
|
|
1574
|
+
top = naja.NLUniverse.get().getTopDesign()
|
|
1575
|
+
if top is not None:
|
|
1576
|
+
naja.NLUniverse.get().applyConstantPropagation()
|