najaeda 0.1.0__cp311-cp311-macosx_11_0_arm64.whl → 0.1.2__cp311-cp311-macosx_11_0_arm64.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/libnaja_snl.dylib +0 -0
- najaeda/libnaja_snl_python.dylib +0 -0
- najaeda/netlist.py +494 -134
- najaeda/snl.so +0 -0
- najaeda-0.1.2.dist-info/METADATA +68 -0
- najaeda-0.1.2.dist-info/RECORD +11 -0
- najaeda-0.1.0.dist-info/METADATA +0 -11
- najaeda-0.1.0.dist-info/RECORD +0 -11
- {najaeda-0.1.0.dist-info → najaeda-0.1.2.dist-info}/WHEEL +0 -0
- {najaeda-0.1.0.dist-info → najaeda-0.1.2.dist-info}/licenses/AUTHORS +0 -0
- {najaeda-0.1.0.dist-info → najaeda-0.1.2.dist-info}/licenses/LICENSE +0 -0
najaeda/libnaja_snl.dylib
CHANGED
|
Binary file
|
najaeda/libnaja_snl_python.dylib
CHANGED
|
Binary file
|
najaeda/netlist.py
CHANGED
|
@@ -1,30 +1,48 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2024 The Naja authors
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 The Naja authors
|
|
2
|
+
# <https://github.com/najaeda/naja/blob/main/AUTHORS>
|
|
2
3
|
#
|
|
3
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
5
|
|
|
5
|
-
import
|
|
6
|
+
import itertools
|
|
6
7
|
from najaeda import snl
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Equipotential:
|
|
10
|
-
"""Class that represents the term and wraps
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"""Class that represents the term and wraps
|
|
12
|
+
some of the snl occurrence API.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, term):
|
|
16
|
+
if isinstance(term.term, snl.SNLBusTerm):
|
|
17
|
+
raise ValueError("Equipotential cannot be constructed on bus term")
|
|
18
|
+
ito = snl.SNLNetComponentOccurrence(
|
|
19
|
+
term.path.getHeadPath(), term.path.getTailInstance().getInstTerm(term.term)
|
|
20
|
+
)
|
|
14
21
|
self.equi = snl.SNLEquipotential(ito)
|
|
15
22
|
|
|
23
|
+
def __eq__(self, value):
|
|
24
|
+
return self.equi == value.equi
|
|
25
|
+
|
|
16
26
|
def get_inst_terms(self):
|
|
17
27
|
for term in self.equi.getInstTermOccurrences():
|
|
18
|
-
yield
|
|
28
|
+
yield Term(
|
|
29
|
+
snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
|
|
30
|
+
term.getInstTerm().getBitTerm(),
|
|
31
|
+
)
|
|
19
32
|
|
|
20
33
|
def get_top_terms(self):
|
|
21
34
|
for term in self.equi.getTerms():
|
|
22
|
-
yield
|
|
35
|
+
yield Term(snl.SNLPath(), term.getBitTerm())
|
|
23
36
|
|
|
24
37
|
def get_all_leaf_readers(self):
|
|
25
38
|
for term in self.equi.getInstTermOccurrences():
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
direction = term.getInstTerm().getDirection()
|
|
40
|
+
if direction != snl.SNLTerm.Direction.Output:
|
|
41
|
+
if term.getInstTerm().getInstance().getModel().isPrimitive():
|
|
42
|
+
yield Term(
|
|
43
|
+
snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
|
|
44
|
+
term.getInstTerm().getBitTerm(),
|
|
45
|
+
)
|
|
28
46
|
|
|
29
47
|
|
|
30
48
|
class Net:
|
|
@@ -32,66 +50,111 @@ class Net:
|
|
|
32
50
|
self.path = path
|
|
33
51
|
self.net = net
|
|
34
52
|
|
|
35
|
-
def
|
|
36
|
-
return self.net.
|
|
53
|
+
def __eq__(self, value):
|
|
54
|
+
return self.net == value.net and self.path == value.path
|
|
37
55
|
|
|
38
|
-
def
|
|
39
|
-
|
|
40
|
-
yield InstTerm(self.path, term)
|
|
56
|
+
def __ne__(self, value):
|
|
57
|
+
return not self == value
|
|
41
58
|
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
59
|
+
def __lt__(self, value):
|
|
60
|
+
if self.path != value.path:
|
|
61
|
+
return self.path < value.path
|
|
62
|
+
return self.net < value.net
|
|
45
63
|
|
|
46
|
-
def
|
|
47
|
-
|
|
64
|
+
def __le__(self, value):
|
|
65
|
+
if self.path != value.path:
|
|
66
|
+
return self.path < value.path
|
|
67
|
+
return self.net <= value.net
|
|
48
68
|
|
|
69
|
+
def __gt__(self, value):
|
|
70
|
+
if self.path != value.path:
|
|
71
|
+
return self.path > value.path
|
|
72
|
+
return self.net > value.net
|
|
49
73
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
self.
|
|
74
|
+
def __ge__(self, value):
|
|
75
|
+
if self.path != value.path:
|
|
76
|
+
return self.path > value.path
|
|
77
|
+
return self.net >= value.net
|
|
54
78
|
|
|
55
|
-
def
|
|
56
|
-
|
|
79
|
+
def __str__(self):
|
|
80
|
+
if self.path.size() > 0:
|
|
81
|
+
return f"{self.path}/{self.net}"
|
|
82
|
+
return f"{self.net}"
|
|
57
83
|
|
|
58
|
-
def
|
|
59
|
-
return
|
|
84
|
+
def __repr__(self):
|
|
85
|
+
return f"Net({self.path}, {self.net})"
|
|
60
86
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return self.term < other.term
|
|
87
|
+
def get_name(self) -> str:
|
|
88
|
+
"""Return the name of the net."""
|
|
89
|
+
return self.net.getName()
|
|
65
90
|
|
|
66
|
-
def
|
|
67
|
-
|
|
91
|
+
def get_msb(self) -> int:
|
|
92
|
+
"""Return the most significant bit of the net if it is a bus."""
|
|
93
|
+
if isinstance(self.net, snl.SNLBusNet):
|
|
94
|
+
return self.net.getMSB()
|
|
95
|
+
return None
|
|
68
96
|
|
|
69
|
-
def
|
|
70
|
-
|
|
97
|
+
def get_lsb(self) -> int:
|
|
98
|
+
"""Return the least significant bit of the net if it is a bus."""
|
|
99
|
+
if isinstance(self.net, snl.SNLBusNet):
|
|
100
|
+
return self.net.getLSB()
|
|
101
|
+
return None
|
|
71
102
|
|
|
72
|
-
def
|
|
73
|
-
|
|
103
|
+
def is_bus(self) -> bool:
|
|
104
|
+
"""Return True if the net is a bus."""
|
|
105
|
+
return isinstance(self.net, snl.SNLBusNet)
|
|
74
106
|
|
|
75
|
-
def
|
|
76
|
-
|
|
107
|
+
def is_bus_bit(self) -> bool:
|
|
108
|
+
"""Return True if the net is a bit of a bus."""
|
|
109
|
+
return isinstance(self.net, snl.SNLBusNetBit)
|
|
77
110
|
|
|
78
|
-
def
|
|
79
|
-
|
|
111
|
+
def is_scalar(self) -> bool:
|
|
112
|
+
"""Return True if the net is a scalar."""
|
|
113
|
+
return isinstance(self.net, snl.SNLScalarNet)
|
|
80
114
|
|
|
81
|
-
def
|
|
82
|
-
|
|
115
|
+
def is_bit(self) -> bool:
|
|
116
|
+
"""Return True if the net is a bit."""
|
|
117
|
+
return self.is_scalar() or self.is_bus_bit()
|
|
83
118
|
|
|
84
|
-
def
|
|
85
|
-
|
|
119
|
+
def is_constant(self) -> bool:
|
|
120
|
+
"""Return True if the net is a constant generator."""
|
|
121
|
+
return self.net.isConstant()
|
|
86
122
|
|
|
87
|
-
def
|
|
88
|
-
|
|
123
|
+
def get_width(self) -> int:
|
|
124
|
+
"""Return the width of the net."""
|
|
125
|
+
return self.net.getWidth()
|
|
126
|
+
|
|
127
|
+
def get_bits(self):
|
|
128
|
+
if isinstance(self.net, snl.SNLBusNet):
|
|
129
|
+
for bit in self.net.getBits():
|
|
130
|
+
yield Net(self.path, bit)
|
|
131
|
+
else:
|
|
132
|
+
yield self
|
|
133
|
+
|
|
134
|
+
def get_bit(self, index: int):
|
|
135
|
+
if isinstance(self.net, snl.SNLBusNet):
|
|
136
|
+
return Net(self.path, self.net.getBit(index))
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
def get_inst_terms(self):
|
|
140
|
+
for term in self.net.getInstTerms():
|
|
141
|
+
path = snl.SNLPath(self.path, term.getInstance())
|
|
142
|
+
yield Term(path, term.getBitTerm())
|
|
143
|
+
|
|
144
|
+
def get_terms(self):
|
|
145
|
+
for term in self.net.getBitTerms():
|
|
146
|
+
yield Term(self.path, term)
|
|
147
|
+
|
|
148
|
+
def get_components(self):
|
|
149
|
+
for term in itertools.chain(self.get_terms(), self.get_inst_terms()):
|
|
150
|
+
yield term
|
|
89
151
|
|
|
90
|
-
def is_output(self) -> bool:
|
|
91
|
-
return self.term.getDirection() == snl.SNLTerm.Direction.Output
|
|
92
152
|
|
|
153
|
+
class Term:
|
|
154
|
+
Input = snl.SNLTerm.Direction.Input
|
|
155
|
+
Output = snl.SNLTerm.Direction.Output
|
|
156
|
+
InOut = snl.SNLTerm.Direction.InOut
|
|
93
157
|
|
|
94
|
-
class InstTerm:
|
|
95
158
|
def __init__(self, path, term):
|
|
96
159
|
self.path = path
|
|
97
160
|
self.term = term
|
|
@@ -116,42 +179,133 @@ class InstTerm:
|
|
|
116
179
|
def __ge__(self, other) -> bool:
|
|
117
180
|
return not self < other
|
|
118
181
|
|
|
182
|
+
def __str__(self) -> str:
|
|
183
|
+
return str(self.path) + "." + self.term.getName()
|
|
184
|
+
|
|
185
|
+
def __repr__(self) -> str:
|
|
186
|
+
return f"Term({self.path}, {self.term})"
|
|
187
|
+
|
|
188
|
+
def __make_unique(self):
|
|
189
|
+
if self.path.size() > 0:
|
|
190
|
+
snl.SNLUniquifier(self.path)
|
|
191
|
+
if self.is_bus_bit():
|
|
192
|
+
term = (
|
|
193
|
+
self.path.getTailInstance().getModel().getTerm(self.term.getName())
|
|
194
|
+
)
|
|
195
|
+
self.term = term.getBit(self.term.getBit())
|
|
196
|
+
else:
|
|
197
|
+
self.term = (
|
|
198
|
+
self.path.getTailInstance().getModel().getTerm(self.term.getName())
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def is_bus(self) -> bool:
|
|
202
|
+
"""Return True if the term is a bus."""
|
|
203
|
+
return isinstance(self.term, snl.SNLBusTerm)
|
|
204
|
+
|
|
205
|
+
def is_bus_bit(self) -> bool:
|
|
206
|
+
"""Return True if the term is a bit of a bus."""
|
|
207
|
+
return isinstance(self.term, snl.SNLBusTermBit)
|
|
208
|
+
|
|
209
|
+
def is_scalar(self) -> bool:
|
|
210
|
+
"""Return True if the term is a scalar."""
|
|
211
|
+
return isinstance(self.term, snl.SNLScalarTerm)
|
|
212
|
+
|
|
213
|
+
def is_bit(self) -> bool:
|
|
214
|
+
"""Return True if the term is a bit."""
|
|
215
|
+
return self.is_scalar() or self.is_bus_bit()
|
|
216
|
+
|
|
217
|
+
def get_msb(self) -> int:
|
|
218
|
+
"""Return the most significant bit of the term if it is a bus."""
|
|
219
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
220
|
+
return self.term.getMSB()
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
def get_lsb(self) -> int:
|
|
224
|
+
"""Return the least significant bit of the term if it is a bus."""
|
|
225
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
226
|
+
return self.term.getLSB()
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
def get_width(self) -> int:
|
|
230
|
+
"""Return the width of the term. 1 if scalar."""
|
|
231
|
+
return self.term.getWidth()
|
|
232
|
+
|
|
119
233
|
def get_name(self) -> str:
|
|
234
|
+
"""Return the name of the term."""
|
|
120
235
|
return self.term.getName()
|
|
121
236
|
|
|
237
|
+
def get_direction(self) -> snl.SNLTerm.Direction:
|
|
238
|
+
"""Return the direction of the term."""
|
|
239
|
+
if self.term.getDirection() == snl.SNLTerm.Direction.Input:
|
|
240
|
+
return Term.Input
|
|
241
|
+
elif self.term.getDirection() == snl.SNLTerm.Direction.Output:
|
|
242
|
+
return Term.Output
|
|
243
|
+
elif self.term.getDirection() == snl.SNLTerm.Direction.InOut:
|
|
244
|
+
return Term.InOut
|
|
245
|
+
|
|
122
246
|
def get_net(self) -> Net:
|
|
123
|
-
|
|
247
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
248
|
+
return None # FIXME xtof in the future
|
|
249
|
+
net = None
|
|
250
|
+
if self.path.size() > 0:
|
|
251
|
+
instTerm = self.path.getTailInstance().getInstTerm(self.term)
|
|
252
|
+
net = instTerm.getNet()
|
|
253
|
+
else:
|
|
254
|
+
net = get_top().model.getTerm(self.term.getName()).getNet()
|
|
255
|
+
return Net(self.path, net)
|
|
124
256
|
|
|
125
257
|
def get_instance(self):
|
|
126
|
-
|
|
127
|
-
path = snl.SNLPath(self.path, inst)
|
|
128
|
-
return Instance(path, inst)
|
|
258
|
+
return Instance(self.path)
|
|
129
259
|
|
|
130
|
-
def get_flat_fanout(self)
|
|
260
|
+
def get_flat_fanout(self):
|
|
131
261
|
return self.get_equipotential().get_all_leaf_readers()
|
|
132
262
|
|
|
133
263
|
def get_equipotential(self) -> Equipotential:
|
|
134
264
|
return Equipotential(self)
|
|
135
265
|
|
|
136
266
|
def is_input(self) -> bool:
|
|
267
|
+
"""Return True if the term is an input."""
|
|
137
268
|
return self.term.getDirection() == snl.SNLTerm.Direction.Input
|
|
138
269
|
|
|
139
270
|
def is_output(self) -> bool:
|
|
271
|
+
"""Return True if the term is an output."""
|
|
140
272
|
return self.term.getDirection() == snl.SNLTerm.Direction.Output
|
|
141
273
|
|
|
142
|
-
def
|
|
143
|
-
|
|
274
|
+
def get_bits(self):
|
|
275
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
276
|
+
for bit in self.term.getBits():
|
|
277
|
+
yield Term(self.path, bit)
|
|
278
|
+
else:
|
|
279
|
+
yield self
|
|
280
|
+
|
|
281
|
+
def get_bit(self, index: int):
|
|
282
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
283
|
+
return Term(self.path, self.term.getBit(index))
|
|
284
|
+
return None
|
|
144
285
|
|
|
145
286
|
def disconnect(self):
|
|
146
|
-
|
|
147
|
-
self.
|
|
287
|
+
self.__make_unique()
|
|
288
|
+
inst = self.path.getTailInstance()
|
|
289
|
+
for bit in self.term.getBits():
|
|
290
|
+
iterm = inst.getInstTerm(bit)
|
|
291
|
+
iterm.setNet(None)
|
|
148
292
|
|
|
149
293
|
def connect(self, net: Net):
|
|
150
|
-
|
|
151
|
-
|
|
294
|
+
if self.get_width() != net.get_width():
|
|
295
|
+
raise ValueError("Width mismatch")
|
|
296
|
+
if self.get_instance().is_top():
|
|
297
|
+
for bterm, bnet in zip(self.term.getBits(), net.net.getBits()):
|
|
298
|
+
bterm.setNet(bnet)
|
|
299
|
+
else:
|
|
300
|
+
self.__make_unique()
|
|
301
|
+
inst = self.path.getTailInstance()
|
|
302
|
+
for bterm, bnet in zip(self.term.getBits(), net.net.getBits()):
|
|
303
|
+
iterm = inst.getInstTerm(bterm)
|
|
304
|
+
iterm.setNet(bnet)
|
|
152
305
|
|
|
153
306
|
|
|
154
307
|
def get_instance_by_path(names: list):
|
|
308
|
+
assert len(names) > 0
|
|
155
309
|
path = snl.SNLPath()
|
|
156
310
|
instance = None
|
|
157
311
|
top = snl.SNLUniverse.get().getTopDesign()
|
|
@@ -159,111 +313,318 @@ def get_instance_by_path(names: list):
|
|
|
159
313
|
for name in names:
|
|
160
314
|
path = snl.SNLPath(path, design.getInstance(name))
|
|
161
315
|
instance = design.getInstance(name)
|
|
316
|
+
assert instance is not None
|
|
162
317
|
design = instance.getModel()
|
|
163
|
-
return Instance(path
|
|
318
|
+
return Instance(path)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def refresh_path(path: snl.SNLPath):
|
|
322
|
+
pathlist = []
|
|
323
|
+
pathTemp = path
|
|
324
|
+
while pathTemp.size() > 0:
|
|
325
|
+
pathlist.append(pathTemp.getHeadInstance().getName())
|
|
326
|
+
pathTemp = pathTemp.getTailPath()
|
|
327
|
+
assert len(pathlist) > 0
|
|
328
|
+
path = snl.SNLPath()
|
|
329
|
+
instance = None
|
|
330
|
+
top = snl.SNLUniverse.get().getTopDesign()
|
|
331
|
+
design = top
|
|
332
|
+
for name in pathlist:
|
|
333
|
+
path = snl.SNLPath(path, design.getInstance(name))
|
|
334
|
+
instance = design.getInstance(name)
|
|
335
|
+
assert instance is not None
|
|
336
|
+
design = instance.getModel()
|
|
337
|
+
return path
|
|
164
338
|
|
|
165
339
|
|
|
166
340
|
class Instance:
|
|
167
|
-
"""Class that represents the instance and wraps some
|
|
341
|
+
"""Class that represents the instance and wraps some
|
|
342
|
+
of the snl occurrence API.
|
|
343
|
+
"""
|
|
168
344
|
|
|
169
|
-
def __init__(self, path
|
|
170
|
-
self.inst = inst
|
|
345
|
+
def __init__(self, path=snl.SNLPath()):
|
|
171
346
|
self.path = path
|
|
172
347
|
|
|
173
348
|
def __eq__(self, other) -> bool:
|
|
174
|
-
return self.
|
|
349
|
+
return self.path == other.path
|
|
350
|
+
|
|
351
|
+
def __str__(self) -> str:
|
|
352
|
+
return str(self.path)
|
|
353
|
+
|
|
354
|
+
def __repr__(self) -> str:
|
|
355
|
+
return f"Instance({self.path})"
|
|
356
|
+
|
|
357
|
+
def __hash__(self):
|
|
358
|
+
return hash(self.path)
|
|
359
|
+
|
|
360
|
+
def is_top(self) -> bool:
|
|
361
|
+
"""Return True if this is the top design."""
|
|
362
|
+
return self.path.size() == 0
|
|
363
|
+
|
|
364
|
+
def is_assign(self) -> bool:
|
|
365
|
+
return self.__get_snl_model().isAssign()
|
|
366
|
+
|
|
367
|
+
def is_blackbox(self) -> bool:
|
|
368
|
+
"""Return True if this is a blackbox."""
|
|
369
|
+
return self.__get_snl_model().isBlackBox()
|
|
370
|
+
|
|
371
|
+
def is_const0(self) -> bool:
|
|
372
|
+
"""Return True if this is a constant 0 generator."""
|
|
373
|
+
return self.__get_snl_model().isConst0()
|
|
374
|
+
|
|
375
|
+
def is_const1(self) -> bool:
|
|
376
|
+
"""Return True if this is a constant 1 generator."""
|
|
377
|
+
return self.__get_snl_model().isConst1()
|
|
378
|
+
|
|
379
|
+
def is_const(self) -> bool:
|
|
380
|
+
"""Return True if this is a constant generator."""
|
|
381
|
+
return self.__get_snl_model().isConst()
|
|
382
|
+
|
|
383
|
+
def is_buf(self) -> bool:
|
|
384
|
+
"""Return True if this is a buffer."""
|
|
385
|
+
return self.__get_snl_model().isBuf()
|
|
386
|
+
|
|
387
|
+
def is_inv(self) -> bool:
|
|
388
|
+
"""Return True if this is an inverter."""
|
|
389
|
+
return self.__get_snl_model().isInv()
|
|
390
|
+
|
|
391
|
+
def __get_snl_model(self):
|
|
392
|
+
"""Return the model of the instance."""
|
|
393
|
+
if self.is_top():
|
|
394
|
+
return snl.SNLUniverse.get().getTopDesign()
|
|
395
|
+
return self.path.getTailInstance().getModel()
|
|
396
|
+
|
|
397
|
+
def __find_snl_model(self, name: str) -> snl.SNLDesign:
|
|
398
|
+
u = snl.SNLUniverse.get()
|
|
399
|
+
if u is None:
|
|
400
|
+
return None
|
|
401
|
+
for db in u.getUserDBs():
|
|
402
|
+
for lib in db.getLibraries():
|
|
403
|
+
found_model = lib.getDesign(name)
|
|
404
|
+
if found_model is not None:
|
|
405
|
+
return found_model
|
|
406
|
+
return None
|
|
175
407
|
|
|
176
408
|
def get_child_instance(self, name: str):
|
|
177
|
-
|
|
178
|
-
|
|
409
|
+
childInst = self.__get_snl_model().getInstance(name)
|
|
410
|
+
if childInst is None:
|
|
411
|
+
return None
|
|
412
|
+
return Instance(snl.SNLPath(self.path, childInst))
|
|
179
413
|
|
|
180
414
|
def get_child_instances(self):
|
|
181
|
-
for inst in self.
|
|
415
|
+
for inst in self.__get_snl_model().getInstances():
|
|
182
416
|
path = snl.SNLPath(self.path, inst)
|
|
183
|
-
yield Instance(path
|
|
417
|
+
yield Instance(path)
|
|
184
418
|
|
|
185
419
|
def get_number_of_child_instances(self) -> int:
|
|
186
|
-
return
|
|
420
|
+
return sum(1 for _ in self.__get_snl_model().getInstances())
|
|
187
421
|
|
|
188
|
-
def
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
for term in self.inst.getInstTerms():
|
|
192
|
-
yield InstTerm(self.path.getHeadPath(), term)
|
|
422
|
+
def get_terms(self):
|
|
423
|
+
for term in self.__get_snl_model().getTerms():
|
|
424
|
+
yield Term(self.path, term)
|
|
193
425
|
|
|
194
|
-
def
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
426
|
+
def get_term(self, name: str) -> Term:
|
|
427
|
+
term = self.__get_snl_model().getTerm(name)
|
|
428
|
+
if term is not None:
|
|
429
|
+
return Term(self.path, self.__get_snl_model().getTerm(name))
|
|
430
|
+
return None
|
|
431
|
+
|
|
432
|
+
def get_nets(self):
|
|
433
|
+
for net in self.__get_snl_model().getNets():
|
|
434
|
+
yield Net(self.path, net)
|
|
435
|
+
|
|
436
|
+
def get_flat_nets(self):
|
|
437
|
+
for net in self.__get_snl_model().getNets():
|
|
438
|
+
if isinstance(net, snl.SNLBusNet):
|
|
439
|
+
for bit in net.getBits():
|
|
440
|
+
yield Net(self.path, bit)
|
|
441
|
+
else:
|
|
442
|
+
yield Net(self.path, net)
|
|
443
|
+
|
|
444
|
+
def get_net(self, name: str) -> Net:
|
|
445
|
+
net = self.__get_snl_model().getNet(name)
|
|
446
|
+
if net is not None:
|
|
447
|
+
return Net(self.path, net)
|
|
200
448
|
return None
|
|
201
449
|
|
|
202
450
|
def is_primitive(self) -> bool:
|
|
203
|
-
return self.
|
|
451
|
+
return self.__get_snl_model().isPrimitive()
|
|
452
|
+
|
|
453
|
+
def get_input_terms(self):
|
|
454
|
+
for term in self.__get_snl_model().getTerms():
|
|
455
|
+
if term.getDirection() == snl.SNLTerm.Direction.Input:
|
|
456
|
+
yield Term(self.path, term)
|
|
457
|
+
|
|
458
|
+
def get_flat_input_terms(self):
|
|
459
|
+
for term in self.__get_snl_model().getTerms():
|
|
460
|
+
if term.getDirection() == snl.SNLTerm.Direction.Input:
|
|
461
|
+
if isinstance(term, snl.SNLBusTerm):
|
|
462
|
+
for bit in term.getBits():
|
|
463
|
+
yield Term(self.path, bit)
|
|
464
|
+
else:
|
|
465
|
+
yield Term(self.path, term)
|
|
466
|
+
|
|
467
|
+
def get_output_terms(self):
|
|
468
|
+
for term in self.__get_snl_model().getTerms():
|
|
469
|
+
if term.getDirection() == snl.SNLTerm.Direction.Output:
|
|
470
|
+
yield Term(self.path, term)
|
|
204
471
|
|
|
205
|
-
def
|
|
206
|
-
for term in self.
|
|
472
|
+
def get_flat_output_terms(self):
|
|
473
|
+
for term in self.__get_snl_model().getTerms():
|
|
207
474
|
if term.getDirection() == snl.SNLTerm.Direction.Output:
|
|
208
|
-
|
|
475
|
+
if isinstance(term, snl.SNLBusTerm):
|
|
476
|
+
for bit in term.getBits():
|
|
477
|
+
yield Term(self.path, bit)
|
|
478
|
+
else:
|
|
479
|
+
yield Term(self.path, term)
|
|
209
480
|
|
|
210
481
|
def delete_instance(self, name: str):
|
|
211
|
-
path = snl.SNLPath(self.path, self.
|
|
212
|
-
|
|
213
|
-
|
|
482
|
+
path = snl.SNLPath(self.path, self.__get_snl_model().getInstance(name))
|
|
483
|
+
snl.SNLUniquifier(path)
|
|
484
|
+
if self.path.size() > 0:
|
|
485
|
+
self.path = refresh_path(self.path)
|
|
214
486
|
# Delete the last instance in uniq_path
|
|
215
|
-
|
|
487
|
+
self.__get_snl_model().getInstance(name).destroy()
|
|
216
488
|
|
|
217
489
|
def get_name(self) -> str:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
490
|
+
"""Return the name of the instance or name of the top is this is the top."""
|
|
491
|
+
if self.is_top():
|
|
492
|
+
return self.get_model_name()
|
|
493
|
+
else:
|
|
494
|
+
return self.path.getTailInstance().getName()
|
|
495
|
+
|
|
496
|
+
def get_model_name(self) -> str:
|
|
497
|
+
"""Return the name of the model of the instance or name of the top is this is the top."""
|
|
498
|
+
return self.__get_snl_model().getName()
|
|
499
|
+
|
|
500
|
+
def get_model_id(self) -> tuple[int, int, int]:
|
|
501
|
+
model = self.__get_snl_model()
|
|
502
|
+
return model.getDB().getID(), model.getLibrary().getID(), model.getID()
|
|
503
|
+
|
|
504
|
+
def create_child_instance(self, model: str, name: str):
|
|
505
|
+
if self.path.size() > 0:
|
|
506
|
+
path = self.path
|
|
507
|
+
snl.SNLUniquifier(path)
|
|
508
|
+
self.path = refresh_path(self.path)
|
|
509
|
+
design = self.__get_snl_model()
|
|
510
|
+
new_instance_model = self.__find_snl_model(model)
|
|
511
|
+
if new_instance_model is None:
|
|
512
|
+
raise ValueError(
|
|
513
|
+
f"Cannot create instance {name} in {self}: model {model} cannot be found"
|
|
514
|
+
)
|
|
515
|
+
newSNLInstance = snl.SNLInstance.create(design, new_instance_model, name)
|
|
224
516
|
path = snl.SNLPath(self.path, newSNLInstance)
|
|
225
|
-
return Instance(
|
|
517
|
+
return Instance(path)
|
|
518
|
+
|
|
519
|
+
def create_term(self, name: str, direction: snl.SNLTerm.Direction) -> Term:
|
|
520
|
+
if self.path.size() > 0:
|
|
521
|
+
path = self.path
|
|
522
|
+
snl.SNLUniquifier(path)
|
|
523
|
+
self.path = refresh_path(self.path)
|
|
524
|
+
design = self.__get_snl_model()
|
|
525
|
+
newSNLTerm = snl.SNLScalarTerm.create(design, direction, name)
|
|
526
|
+
return Term(self.path, newSNLTerm)
|
|
527
|
+
|
|
528
|
+
def create_output_term(self, name: str) -> Term:
|
|
529
|
+
return self.create_term(name, snl.SNLTerm.Direction.Output)
|
|
530
|
+
|
|
531
|
+
def create_input_term(self, name: str) -> Term:
|
|
532
|
+
return self.create_term(name, snl.SNLTerm.Direction.Input)
|
|
533
|
+
|
|
534
|
+
def create_bus_term(
|
|
535
|
+
self, name: str, msb: int, lsb: int, direction: snl.SNLTerm.Direction
|
|
536
|
+
) -> Term:
|
|
537
|
+
if self.path.size() > 0:
|
|
538
|
+
path = self.path
|
|
539
|
+
snl.SNLUniquifier(path)
|
|
540
|
+
self.path = refresh_path(self.path)
|
|
541
|
+
design = self.__get_snl_model()
|
|
542
|
+
newSNLTerm = snl.SNLBusTerm.create(design, direction, msb, lsb, name)
|
|
543
|
+
return Term(self.path, newSNLTerm)
|
|
544
|
+
|
|
545
|
+
def create_output_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
546
|
+
return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Output)
|
|
547
|
+
|
|
548
|
+
def create_input_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
549
|
+
return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Input)
|
|
550
|
+
|
|
551
|
+
def create_net(self, name: str) -> Net:
|
|
552
|
+
if self.path.size() > 0:
|
|
553
|
+
path = self.path
|
|
554
|
+
snl.SNLUniquifier(path)
|
|
555
|
+
self.path = refresh_path(self.path)
|
|
556
|
+
model = self.__get_snl_model()
|
|
557
|
+
newSNLNet = snl.SNLScalarNet.create(model, name)
|
|
558
|
+
return Net(self.path, newSNLNet)
|
|
559
|
+
|
|
560
|
+
def create_bus_net(self, name: str, msb: int, lsb: int) -> Net:
|
|
561
|
+
if self.path.size() > 0:
|
|
562
|
+
path = self.path
|
|
563
|
+
snl.SNLUniquifier(path)
|
|
564
|
+
self.path = refresh_path(self.path)
|
|
565
|
+
model = self.__get_snl_model()
|
|
566
|
+
newSNLNet = snl.SNLBusNet.create(model, msb, lsb, name)
|
|
567
|
+
return Net(self.path, newSNLNet)
|
|
568
|
+
|
|
569
|
+
def dump_verilog(self, path: str, name: str):
|
|
570
|
+
self.__get_snl_model().dumpVerilog(path, name)
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def get_top_db() -> snl.SNLDB:
|
|
574
|
+
if snl.SNLUniverse.get() is None:
|
|
575
|
+
snl.SNLUniverse.create()
|
|
576
|
+
if snl.SNLUniverse.get().getTopDB() is None:
|
|
577
|
+
db = snl.SNLDB.create(snl.SNLUniverse.get())
|
|
578
|
+
snl.SNLUniverse.get().setTopDB(db)
|
|
579
|
+
return snl.SNLUniverse.get().getTopDB()
|
|
226
580
|
|
|
227
581
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
582
|
+
def get_top():
|
|
583
|
+
return Instance(snl.SNLPath())
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def create_top(name: str) -> Instance:
|
|
587
|
+
# init
|
|
588
|
+
db = get_top_db()
|
|
589
|
+
# create top design
|
|
590
|
+
lib = snl.SNLLibrary.create(db)
|
|
591
|
+
top = snl.SNLDesign.create(lib, name)
|
|
592
|
+
snl.SNLUniverse.get().setTopDesign(top)
|
|
593
|
+
return Instance()
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
def load_verilog(files: list):
|
|
597
|
+
get_top_db().loadVerilog(files)
|
|
598
|
+
return get_top()
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def load_liberty(files: list):
|
|
602
|
+
get_top_db().loadLibertyPrimitives(files)
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def get_primitives_library() -> snl.SNLLibrary:
|
|
606
|
+
lib = get_top_db().getLibrary("PRIMS")
|
|
607
|
+
if lib is None:
|
|
608
|
+
lib = snl.SNLLibrary.createPrimitives(get_top_db())
|
|
609
|
+
return lib
|
|
232
610
|
|
|
233
|
-
def init(self):
|
|
234
|
-
snl.SNLUniverse.create()
|
|
235
|
-
self.db_ = snl.SNLDB.create(snl.SNLUniverse.get())
|
|
236
|
-
|
|
237
|
-
def get_db(self) -> snl.SNLDB:
|
|
238
|
-
return self.db_
|
|
239
|
-
|
|
240
|
-
def get_primitives_library(self) -> snl.SNLLibrary:
|
|
241
|
-
if self.primitives_library_ is None:
|
|
242
|
-
self.primitives_library_ = snl.SNLLibrary.createPrimitives(self.db_)
|
|
243
|
-
return self.primitives_library_
|
|
244
|
-
|
|
245
|
-
def load_verilog(self, files: list):
|
|
246
|
-
self.db_.loadVerilog(files)
|
|
247
|
-
|
|
248
|
-
def verify(self):
|
|
249
|
-
universe = snl.SNLUniverse.get()
|
|
250
|
-
if universe is None:
|
|
251
|
-
logging.critical('No loaded SNLUniverse')
|
|
252
|
-
return 1
|
|
253
|
-
top = universe.getTopDesign()
|
|
254
|
-
if top is None:
|
|
255
|
-
logging.critical('SNLUniverse does not contain any top SNLDesign')
|
|
256
|
-
return 1
|
|
257
|
-
else:
|
|
258
|
-
logging.info('Found top design ' + str(top))
|
|
259
611
|
|
|
260
|
-
|
|
261
|
-
|
|
612
|
+
def get_model_name(id: tuple[int, int, int]) -> str:
|
|
613
|
+
"""Return the name of the model given its id."""
|
|
614
|
+
u = snl.SNLUniverse.get()
|
|
615
|
+
if u:
|
|
616
|
+
db = u.getDB(id[0])
|
|
617
|
+
if db:
|
|
618
|
+
lib = db.getLibrary(id[1])
|
|
619
|
+
if lib:
|
|
620
|
+
model = lib.getDesign(id[2])
|
|
621
|
+
if model:
|
|
622
|
+
return model.getName()
|
|
623
|
+
return None
|
|
262
624
|
|
|
263
625
|
|
|
264
|
-
def get_all_primitive_instances()
|
|
626
|
+
def get_all_primitive_instances():
|
|
265
627
|
top = snl.SNLUniverse.get().getTopDesign()
|
|
266
|
-
primitives = []
|
|
267
628
|
|
|
268
629
|
for inst in top.getInstances():
|
|
269
630
|
path = snl.SNLPath(inst)
|
|
@@ -275,6 +636,5 @@ def get_all_primitive_instances() -> list:
|
|
|
275
636
|
for inst_child in current_inst.getModel().getInstances():
|
|
276
637
|
path_child = snl.SNLPath(current_path, inst_child)
|
|
277
638
|
if inst_child.getModel().isPrimitive():
|
|
278
|
-
|
|
639
|
+
yield Instance(path_child)
|
|
279
640
|
stack.append([inst_child, path_child])
|
|
280
|
-
return primitives
|
najaeda/snl.so
CHANGED
|
Binary file
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: najaeda
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Naja EDA Python package
|
|
5
|
+
Author-Email: Naja Authors <contact@keplertech.io>
|
|
6
|
+
License: Apache License 2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/najaeda/naja
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/x-rst
|
|
10
|
+
|
|
11
|
+
Naja EDA Python Package
|
|
12
|
+
=======================
|
|
13
|
+
|
|
14
|
+
Naja EDA is a Python package that provides data structures and APIs for developing post-synthesis Electronic Design Automation (EDA) algorithms. It serves as the Python counterpart to the `Naja C++ project <https://github.com/najaeda/naja>`_.
|
|
15
|
+
|
|
16
|
+
Features
|
|
17
|
+
--------
|
|
18
|
+
|
|
19
|
+
- **Netlist Simplification**: Perform constant propagation and dead logic elimination.
|
|
20
|
+
- **Logic Replication**: Facilitate duplication of logic elements for optimization.
|
|
21
|
+
- **Netlist Partitioning**: Divide netlists into manageable sections.
|
|
22
|
+
- **Place and Route Support**: Assist in ASIC and FPGA design flows.
|
|
23
|
+
|
|
24
|
+
Installation
|
|
25
|
+
------------
|
|
26
|
+
|
|
27
|
+
Install Naja EDA using pip:
|
|
28
|
+
|
|
29
|
+
.. code-block:: bash
|
|
30
|
+
|
|
31
|
+
pip install najaeda
|
|
32
|
+
|
|
33
|
+
Examples
|
|
34
|
+
--------
|
|
35
|
+
Following snippet shows how to load primitive cells from a liberty file and
|
|
36
|
+
a netlist from a Verilog file.
|
|
37
|
+
.. code-block:: python
|
|
38
|
+
|
|
39
|
+
from os import path
|
|
40
|
+
from najaeda import netlist
|
|
41
|
+
|
|
42
|
+
benchmarks = path.join('..','benchmarks')
|
|
43
|
+
liberty_files = ['NangateOpenCellLibrary_typical.lib', 'fakeram45_1024x32.lib', 'fakeram45_64x32.lib']
|
|
44
|
+
liberty_files = list(map(lambda p:path.join(benchmarks, 'liberty', p), liberty_files))
|
|
45
|
+
|
|
46
|
+
netlist.load_liberty(liberty_files)
|
|
47
|
+
top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'tinyrocket.v')])
|
|
48
|
+
|
|
49
|
+
#dump verilog
|
|
50
|
+
top.dump_verilog('tinyrocket_naja.v')
|
|
51
|
+
|
|
52
|
+
Next example shows how to browse all the netlist and print all its content.
|
|
53
|
+
.. code-block:: python
|
|
54
|
+
|
|
55
|
+
def print_netlist(instance):
|
|
56
|
+
for child_instance in instance.get_child_instances():
|
|
57
|
+
print(f"{child_instance}:{child_instance.get_model_name()}")
|
|
58
|
+
print_netlist(child_instance)
|
|
59
|
+
|
|
60
|
+
Documentation
|
|
61
|
+
-------------
|
|
62
|
+
|
|
63
|
+
Comprehensive documentation is available on the `Naja GitHub repository <https://github.com/najaeda/naja>`_.
|
|
64
|
+
|
|
65
|
+
License
|
|
66
|
+
-------
|
|
67
|
+
|
|
68
|
+
This project is licensed under the Apache License 2.0. See the `LICENSE <https://github.com/najaeda/naja/blob/main/LICENSE>`_ file for details.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
najaeda-0.1.2.dist-info/RECORD,,
|
|
2
|
+
najaeda-0.1.2.dist-info/WHEEL,sha256=vqMBchNIsmW0K9HInUQuY_xePW9YD3coNJy6G1Yfto8,114
|
|
3
|
+
najaeda-0.1.2.dist-info/METADATA,sha256=agjVbL5DID69VNnjngj23q1t-TEOHBaCUhMnhIGEjZI,2267
|
|
4
|
+
najaeda-0.1.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
5
|
+
najaeda-0.1.2.dist-info/licenses/AUTHORS,sha256=e4DCPGHo6wKMyQz24V59EP7zMwalK-KBDBHHlMLFxHY,330
|
|
6
|
+
najaeda/netlist.py,sha256=usJ__3Vh_A8GFK7xUdhwJSdsTc7DWhaIF3Ptp3dfuZU,21251
|
|
7
|
+
najaeda/libnaja_snl_python.dylib,sha256=OZ222EZCWFrvmsDs6asQWMl0QP8Wqhny8kOFBjznGH4,739872
|
|
8
|
+
najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
najaeda/libnaja_snl.dylib,sha256=8Ei7KKU0b14IqlvH_8yQSSCpH0rjbxpeRaXgyfSemMY,574112
|
|
10
|
+
najaeda/snl.so,sha256=qBdtIcQsyMywHa-xUMdCJaTwG6yl189Bm6Zr96ZR6pU,97888
|
|
11
|
+
najaeda/.dylibs/Python,sha256=Gju99qyqKDZ_AHI35mL42rySLjq0Ww_yvHDxtQSu7Kw,14303584
|
najaeda-0.1.0.dist-info/METADATA
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: najaeda
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Naja EDA Python package
|
|
5
|
-
Author-Email: Naja Authors <contact@keplertech.io>
|
|
6
|
-
License: Apache License 2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/najaeda/naja
|
|
8
|
-
Requires-Python: >=3.8
|
|
9
|
-
Description-Content-Type: text/x-rst
|
|
10
|
-
|
|
11
|
-
Welcome to Naja Python package
|
najaeda-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
najaeda-0.1.0.dist-info/RECORD,,
|
|
2
|
-
najaeda-0.1.0.dist-info/WHEEL,sha256=vqMBchNIsmW0K9HInUQuY_xePW9YD3coNJy6G1Yfto8,114
|
|
3
|
-
najaeda-0.1.0.dist-info/METADATA,sha256=SIsMgouolOzryWWoChYTHcGT2-ul8f9u9mLYyIOf-VA,309
|
|
4
|
-
najaeda-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
5
|
-
najaeda-0.1.0.dist-info/licenses/AUTHORS,sha256=e4DCPGHo6wKMyQz24V59EP7zMwalK-KBDBHHlMLFxHY,330
|
|
6
|
-
najaeda/netlist.py,sha256=XyNigH-I1cKjTVcMn-eo45BgYjI7NFDhYEYlnEiOwQ8,8741
|
|
7
|
-
najaeda/libnaja_snl_python.dylib,sha256=Mbxrw8_DiVzbMF3zXfIY18KdeYoeCKyR-pmDYZtVprA,705744
|
|
8
|
-
najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
najaeda/libnaja_snl.dylib,sha256=P60Bn-hOArZrLqcdQUL0J6NzPHUV4V8Jf0StrJpTXgg,573808
|
|
10
|
-
najaeda/snl.so,sha256=K2PMfUZKoKaFA5K438t0FrM-60K7IlTYXkSQgZFaaSY,97616
|
|
11
|
-
najaeda/.dylibs/Python,sha256=Gju99qyqKDZ_AHI35mL42rySLjq0Ww_yvHDxtQSu7Kw,14303584
|
|
File without changes
|
|
File without changes
|
|
File without changes
|