najaeda 0.1.0__cp311-cp311-macosx_11_0_arm64.whl → 0.1.3__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 +605 -156
- najaeda/snl.so +0 -0
- najaeda-0.1.3.dist-info/METADATA +72 -0
- najaeda-0.1.3.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.3.dist-info}/WHEEL +0 -0
- {najaeda-0.1.0.dist-info → najaeda-0.1.3.dist-info}/licenses/AUTHORS +0 -0
- {najaeda-0.1.0.dist-info → najaeda-0.1.3.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,53 +1,181 @@
|
|
|
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
|
|
|
6
|
+
import itertools
|
|
5
7
|
import logging
|
|
8
|
+
|
|
6
9
|
from najaeda import snl
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
class Equipotential:
|
|
10
|
-
"""Class that represents the term and wraps
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
"""Class that represents the term and wraps
|
|
14
|
+
some of the snl occurrence API.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, term):
|
|
18
|
+
if isinstance(term.term, snl.SNLBusTerm):
|
|
19
|
+
raise ValueError("Equipotential cannot be constructed on bus term")
|
|
20
|
+
ito = snl.SNLNetComponentOccurrence(
|
|
21
|
+
term.path.getHeadPath(), term.path.getTailInstance().getInstTerm(term.term)
|
|
22
|
+
)
|
|
14
23
|
self.equi = snl.SNLEquipotential(ito)
|
|
15
24
|
|
|
25
|
+
def __eq__(self, value):
|
|
26
|
+
return self.equi == value.equi
|
|
27
|
+
|
|
16
28
|
def get_inst_terms(self):
|
|
17
29
|
for term in self.equi.getInstTermOccurrences():
|
|
18
|
-
yield
|
|
30
|
+
yield Term(
|
|
31
|
+
snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
|
|
32
|
+
term.getInstTerm().getBitTerm(),
|
|
33
|
+
)
|
|
19
34
|
|
|
20
35
|
def get_top_terms(self):
|
|
21
36
|
for term in self.equi.getTerms():
|
|
22
|
-
yield
|
|
37
|
+
yield Term(snl.SNLPath(), term.getBitTerm())
|
|
23
38
|
|
|
24
39
|
def get_all_leaf_readers(self):
|
|
25
40
|
for term in self.equi.getInstTermOccurrences():
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
direction = term.getInstTerm().getDirection()
|
|
42
|
+
if direction != snl.SNLTerm.Direction.Output:
|
|
43
|
+
if term.getInstTerm().getInstance().getModel().isPrimitive():
|
|
44
|
+
yield Term(
|
|
45
|
+
snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
|
|
46
|
+
term.getInstTerm().getBitTerm(),
|
|
47
|
+
)
|
|
28
48
|
|
|
29
49
|
|
|
30
50
|
class Net:
|
|
31
|
-
def __init__(self, path, net):
|
|
51
|
+
def __init__(self, path, net=None, net_concat=None):
|
|
52
|
+
if net is not None and net_concat is not None:
|
|
53
|
+
raise ValueError(
|
|
54
|
+
"Only one of `net` or `net_concat` should be provided, not both."
|
|
55
|
+
)
|
|
32
56
|
self.path = path
|
|
33
|
-
|
|
57
|
+
if net is not None:
|
|
58
|
+
self.net = net
|
|
59
|
+
elif net_concat is not None:
|
|
60
|
+
self.net_concat = net_concat
|
|
61
|
+
|
|
62
|
+
def __eq__(self, other):
|
|
63
|
+
if not isinstance(other, Net):
|
|
64
|
+
return NotImplemented
|
|
65
|
+
return vars(self) == vars(other)
|
|
66
|
+
|
|
67
|
+
def __ne__(self, other):
|
|
68
|
+
eq_result = self.__eq__(other)
|
|
69
|
+
if eq_result is NotImplemented:
|
|
70
|
+
return NotImplemented
|
|
71
|
+
return not eq_result
|
|
72
|
+
|
|
73
|
+
def __str__(self):
|
|
74
|
+
if hasattr(self, "net"):
|
|
75
|
+
net_str = str(self.net)
|
|
76
|
+
elif hasattr(self, "net_concat"):
|
|
77
|
+
net_str = "{" + ",".join(map(str, self.net_concat)) + "}"
|
|
78
|
+
if self.path.size() > 0:
|
|
79
|
+
return f"{self.path}/{net_str}"
|
|
80
|
+
return net_str
|
|
34
81
|
|
|
35
82
|
def get_name(self) -> str:
|
|
36
|
-
|
|
83
|
+
"""Return the name of the net."""
|
|
84
|
+
if hasattr(self, "net"):
|
|
85
|
+
return self.net.getName()
|
|
86
|
+
return "{" + ",".join(map(str, self.net_concat)) + "}"
|
|
87
|
+
|
|
88
|
+
def get_msb(self) -> int:
|
|
89
|
+
"""Return the most significant bit of the net if it is a bus."""
|
|
90
|
+
if hasattr(self, "net") and isinstance(self.net, snl.SNLBusNet):
|
|
91
|
+
return self.net.getMSB()
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
def get_lsb(self) -> int:
|
|
95
|
+
"""Return the least significant bit of the net if it is a bus."""
|
|
96
|
+
if hasattr(self, "net") and isinstance(self.net, snl.SNLBusNet):
|
|
97
|
+
return self.net.getLSB()
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
def is_bus(self) -> bool:
|
|
101
|
+
"""Return True if the net is a bus."""
|
|
102
|
+
return hasattr(self, "net") and isinstance(self.net, snl.SNLBusNet)
|
|
103
|
+
|
|
104
|
+
def is_bus_bit(self) -> bool:
|
|
105
|
+
"""Return True if the net is a bit of a bus."""
|
|
106
|
+
return hasattr(self, "net") and isinstance(self.net, snl.SNLBusNetBit)
|
|
107
|
+
|
|
108
|
+
def is_scalar(self) -> bool:
|
|
109
|
+
"""Return True if the net is a scalar."""
|
|
110
|
+
return hasattr(self, "net") and isinstance(self.net, snl.SNLScalarNet)
|
|
111
|
+
|
|
112
|
+
def is_bit(self) -> bool:
|
|
113
|
+
"""Return True if the net is a bit."""
|
|
114
|
+
return self.is_scalar() or self.is_bus_bit()
|
|
115
|
+
|
|
116
|
+
def is_concat(self) -> bool:
|
|
117
|
+
"""Return True if the net is a concatenation."""
|
|
118
|
+
return hasattr(self, "net_concat")
|
|
119
|
+
|
|
120
|
+
def is_const(self) -> bool:
|
|
121
|
+
"""Return True if the net is a constant generator."""
|
|
122
|
+
if hasattr(self, "net"):
|
|
123
|
+
return self.net.isConstant()
|
|
124
|
+
for net in self.net_concat:
|
|
125
|
+
if not net.isConstant():
|
|
126
|
+
return False
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
def get_width(self) -> int:
|
|
130
|
+
"""Return the width of the net."""
|
|
131
|
+
if hasattr(self, "net"):
|
|
132
|
+
return self.net.getWidth()
|
|
133
|
+
return sum(1 for _ in self.net_concat)
|
|
134
|
+
|
|
135
|
+
def get_bits(self):
|
|
136
|
+
if hasattr(self, "net"):
|
|
137
|
+
if isinstance(self.net, snl.SNLBusNet):
|
|
138
|
+
for bit in self.net.getBits():
|
|
139
|
+
yield Net(self.path, bit)
|
|
140
|
+
else:
|
|
141
|
+
yield self
|
|
142
|
+
else:
|
|
143
|
+
for net in self.net_concat:
|
|
144
|
+
yield net
|
|
145
|
+
|
|
146
|
+
def get_bit(self, index: int):
|
|
147
|
+
if hasattr(self, "net"):
|
|
148
|
+
if isinstance(self.net, snl.SNLBusNet):
|
|
149
|
+
return Net(self.path, self.net.getBit(index))
|
|
150
|
+
else:
|
|
151
|
+
return None
|
|
152
|
+
if 0 <= index < len(self.net_concat):
|
|
153
|
+
return Net(self.path, self.net_concat[index])
|
|
154
|
+
return None
|
|
37
155
|
|
|
38
156
|
def get_inst_terms(self):
|
|
157
|
+
if hasattr(self, "net_concat"):
|
|
158
|
+
raise ValueError("Cannot get inst terms from a net_concat")
|
|
39
159
|
for term in self.net.getInstTerms():
|
|
40
|
-
|
|
160
|
+
path = snl.SNLPath(self.path, term.getInstance())
|
|
161
|
+
yield Term(path, term.getBitTerm())
|
|
41
162
|
|
|
42
|
-
def
|
|
163
|
+
def get_terms(self):
|
|
164
|
+
if hasattr(self, "net_concat"):
|
|
165
|
+
raise ValueError("Cannot get terms from a net_concat")
|
|
43
166
|
for term in self.net.getBitTerms():
|
|
44
|
-
yield
|
|
167
|
+
yield Term(self.path, term)
|
|
45
168
|
|
|
46
|
-
def
|
|
47
|
-
|
|
169
|
+
def get_components(self):
|
|
170
|
+
for term in itertools.chain(self.get_terms(), self.get_inst_terms()):
|
|
171
|
+
yield term
|
|
48
172
|
|
|
49
173
|
|
|
50
|
-
class
|
|
174
|
+
class Term:
|
|
175
|
+
INPUT = snl.SNLTerm.Direction.Input
|
|
176
|
+
OUTPUT = snl.SNLTerm.Direction.Output
|
|
177
|
+
INOUT = snl.SNLTerm.Direction.InOut
|
|
178
|
+
|
|
51
179
|
def __init__(self, path, term):
|
|
52
180
|
self.path = path
|
|
53
181
|
self.term = term
|
|
@@ -72,86 +200,188 @@ class TopTerm:
|
|
|
72
200
|
def __ge__(self, other) -> bool:
|
|
73
201
|
return not self < other
|
|
74
202
|
|
|
75
|
-
def
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
def
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return self.
|
|
101
|
-
|
|
102
|
-
def
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return self.term
|
|
109
|
-
|
|
110
|
-
def
|
|
111
|
-
|
|
203
|
+
def __str__(self):
|
|
204
|
+
if self.path.size() == 0:
|
|
205
|
+
return self.term.getName()
|
|
206
|
+
else:
|
|
207
|
+
return f"{self.path}/{self.term}"
|
|
208
|
+
|
|
209
|
+
def __repr__(self) -> str:
|
|
210
|
+
return f"Term({self.path}, {self.term})"
|
|
211
|
+
|
|
212
|
+
def __make_unique(self):
|
|
213
|
+
if self.path.size() > 1:
|
|
214
|
+
path = self.path.getHeadPath()
|
|
215
|
+
snl.SNLUniquifier(path)
|
|
216
|
+
if self.is_bus_bit():
|
|
217
|
+
term = (
|
|
218
|
+
self.path.getTailInstance().getModel().getTerm(self.term.getName())
|
|
219
|
+
)
|
|
220
|
+
self.term = term.getBit(self.term.getBit())
|
|
221
|
+
else:
|
|
222
|
+
self.term = (
|
|
223
|
+
self.path.getTailInstance().getModel().getTerm(self.term.getName())
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def is_bus(self) -> bool:
|
|
227
|
+
"""Return True if the term is a bus."""
|
|
228
|
+
return isinstance(self.term, snl.SNLBusTerm)
|
|
229
|
+
|
|
230
|
+
def is_bus_bit(self) -> bool:
|
|
231
|
+
"""Return True if the term is a bit of a bus."""
|
|
232
|
+
return isinstance(self.term, snl.SNLBusTermBit)
|
|
233
|
+
|
|
234
|
+
def is_scalar(self) -> bool:
|
|
235
|
+
"""Return True if the term is a scalar."""
|
|
236
|
+
return isinstance(self.term, snl.SNLScalarTerm)
|
|
237
|
+
|
|
238
|
+
def is_bit(self) -> bool:
|
|
239
|
+
"""Return True if the term is a bit."""
|
|
240
|
+
return self.is_scalar() or self.is_bus_bit()
|
|
241
|
+
|
|
242
|
+
def get_msb(self) -> int:
|
|
243
|
+
"""Return the most significant bit of the term if it is a bus."""
|
|
244
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
245
|
+
return self.term.getMSB()
|
|
246
|
+
return None
|
|
112
247
|
|
|
113
|
-
def
|
|
114
|
-
|
|
248
|
+
def get_lsb(self) -> int:
|
|
249
|
+
"""Return the least significant bit of the term if it is a bus."""
|
|
250
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
251
|
+
return self.term.getLSB()
|
|
252
|
+
return None
|
|
115
253
|
|
|
116
|
-
def
|
|
117
|
-
|
|
254
|
+
def get_width(self) -> int:
|
|
255
|
+
"""Return the width of the term. 1 if scalar."""
|
|
256
|
+
return self.term.getWidth()
|
|
118
257
|
|
|
119
258
|
def get_name(self) -> str:
|
|
259
|
+
"""Return the name of the term."""
|
|
120
260
|
return self.term.getName()
|
|
121
261
|
|
|
262
|
+
def get_direction(self) -> snl.SNLTerm.Direction:
|
|
263
|
+
"""Return the direction of the term."""
|
|
264
|
+
if self.term.getDirection() == snl.SNLTerm.Direction.Input:
|
|
265
|
+
return Term.INPUT
|
|
266
|
+
elif self.term.getDirection() == snl.SNLTerm.Direction.Output:
|
|
267
|
+
return Term.OUTPUT
|
|
268
|
+
elif self.term.getDirection() == snl.SNLTerm.Direction.InOut:
|
|
269
|
+
return Term.INOUT
|
|
270
|
+
|
|
271
|
+
def __get_snl_bitnet(self, bit) -> Net:
|
|
272
|
+
# single bit
|
|
273
|
+
if self.path.size() > 0:
|
|
274
|
+
instTerm = self.path.getTailInstance().getInstTerm(bit)
|
|
275
|
+
return instTerm.getNet()
|
|
276
|
+
else:
|
|
277
|
+
return bit.getNet()
|
|
278
|
+
|
|
279
|
+
def __get_snl_lower_bitnet(self, bit) -> Net:
|
|
280
|
+
return bit.getNet()
|
|
281
|
+
|
|
282
|
+
def __get_snl_busnet(self, snl_nets) -> snl.SNLBusNet:
|
|
283
|
+
# iterate on all elements of the list and check if
|
|
284
|
+
# a full SNLBusNet can be reconstructed
|
|
285
|
+
snl_bus_net = None
|
|
286
|
+
for i in range(len(snl_nets)):
|
|
287
|
+
snl_net = snl_nets[i]
|
|
288
|
+
if not isinstance(snl_net, snl.SNLBusNetBit):
|
|
289
|
+
return None
|
|
290
|
+
bit_bus = snl_net.getBus()
|
|
291
|
+
if bit_bus.getWidth() != len(snl_nets):
|
|
292
|
+
return None
|
|
293
|
+
if snl_bus_net is None:
|
|
294
|
+
snl_bus_net = bit_bus
|
|
295
|
+
if snl_bus_net != bit_bus:
|
|
296
|
+
return None
|
|
297
|
+
if snl_bus_net.getBitAtPosition(i) != snl_net:
|
|
298
|
+
return None
|
|
299
|
+
return snl_bus_net
|
|
300
|
+
|
|
301
|
+
def __get_net(self, path, snl_term_net_accessor) -> Net:
|
|
302
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
303
|
+
snl_nets = []
|
|
304
|
+
for bit in self.term.getBits():
|
|
305
|
+
snl_net = snl_term_net_accessor(bit)
|
|
306
|
+
snl_nets.append(snl_net)
|
|
307
|
+
snl_bus_net = self.__get_snl_busnet(snl_nets)
|
|
308
|
+
if snl_bus_net is not None:
|
|
309
|
+
return Net(path, snl_bus_net)
|
|
310
|
+
else:
|
|
311
|
+
if all(element is not None for element in snl_nets):
|
|
312
|
+
return Net(path, net_concat=snl_nets)
|
|
313
|
+
else:
|
|
314
|
+
snl_net = snl_term_net_accessor(self.term)
|
|
315
|
+
if snl_net is not None:
|
|
316
|
+
return Net(path, snl_net)
|
|
317
|
+
return None
|
|
318
|
+
|
|
319
|
+
def get_lower_net(self) -> Net:
|
|
320
|
+
"""Return the lower net of the term."""
|
|
321
|
+
return self.__get_net(self.path, self.__get_snl_lower_bitnet)
|
|
322
|
+
|
|
122
323
|
def get_net(self) -> Net:
|
|
123
|
-
|
|
324
|
+
"""Return the net of the term."""
|
|
325
|
+
if self.path.empty():
|
|
326
|
+
return None
|
|
327
|
+
# path is one level up
|
|
328
|
+
path = self.path.getHeadPath()
|
|
329
|
+
return self.__get_net(path, self.__get_snl_bitnet)
|
|
124
330
|
|
|
125
331
|
def get_instance(self):
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return Instance(path, inst)
|
|
332
|
+
"""Return the instance of the term."""
|
|
333
|
+
return Instance(self.path)
|
|
129
334
|
|
|
130
|
-
def get_flat_fanout(self)
|
|
335
|
+
def get_flat_fanout(self):
|
|
131
336
|
return self.get_equipotential().get_all_leaf_readers()
|
|
132
337
|
|
|
133
338
|
def get_equipotential(self) -> Equipotential:
|
|
134
339
|
return Equipotential(self)
|
|
135
340
|
|
|
136
341
|
def is_input(self) -> bool:
|
|
342
|
+
"""Return True if the term is an input."""
|
|
137
343
|
return self.term.getDirection() == snl.SNLTerm.Direction.Input
|
|
138
344
|
|
|
139
345
|
def is_output(self) -> bool:
|
|
346
|
+
"""Return True if the term is an output."""
|
|
140
347
|
return self.term.getDirection() == snl.SNLTerm.Direction.Output
|
|
141
348
|
|
|
142
|
-
def
|
|
143
|
-
|
|
349
|
+
def get_bits(self):
|
|
350
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
351
|
+
for bit in self.term.getBits():
|
|
352
|
+
yield Term(self.path, bit)
|
|
353
|
+
else:
|
|
354
|
+
yield self
|
|
355
|
+
|
|
356
|
+
def get_bit(self, index: int):
|
|
357
|
+
if isinstance(self.term, snl.SNLBusTerm):
|
|
358
|
+
return Term(self.path, self.term.getBit(index))
|
|
359
|
+
return None
|
|
144
360
|
|
|
145
361
|
def disconnect(self):
|
|
146
|
-
|
|
147
|
-
self.
|
|
362
|
+
self.__make_unique()
|
|
363
|
+
inst = self.path.getTailInstance()
|
|
364
|
+
for bit in self.term.getBits():
|
|
365
|
+
iterm = inst.getInstTerm(bit)
|
|
366
|
+
iterm.setNet(None)
|
|
148
367
|
|
|
149
368
|
def connect(self, net: Net):
|
|
150
|
-
|
|
151
|
-
|
|
369
|
+
if self.get_width() != net.get_width():
|
|
370
|
+
raise ValueError("Width mismatch")
|
|
371
|
+
if self.get_instance().is_top():
|
|
372
|
+
for bterm, bnet in zip(self.term.getBits(), net.net.getBits()):
|
|
373
|
+
logging.debug(f"Connecting {bterm} to {bnet}")
|
|
374
|
+
bterm.setNet(bnet)
|
|
375
|
+
else:
|
|
376
|
+
self.__make_unique()
|
|
377
|
+
inst = self.path.getTailInstance()
|
|
378
|
+
for bterm, bnet in zip(self.term.getBits(), net.net.getBits()):
|
|
379
|
+
iterm = inst.getInstTerm(bterm)
|
|
380
|
+
iterm.setNet(bnet)
|
|
152
381
|
|
|
153
382
|
|
|
154
383
|
def get_instance_by_path(names: list):
|
|
384
|
+
assert len(names) > 0
|
|
155
385
|
path = snl.SNLPath()
|
|
156
386
|
instance = None
|
|
157
387
|
top = snl.SNLUniverse.get().getTopDesign()
|
|
@@ -159,122 +389,341 @@ def get_instance_by_path(names: list):
|
|
|
159
389
|
for name in names:
|
|
160
390
|
path = snl.SNLPath(path, design.getInstance(name))
|
|
161
391
|
instance = design.getInstance(name)
|
|
392
|
+
assert instance is not None
|
|
393
|
+
design = instance.getModel()
|
|
394
|
+
return Instance(path)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def refresh_path(path: snl.SNLPath):
|
|
398
|
+
pathlist = []
|
|
399
|
+
pathTemp = path
|
|
400
|
+
while pathTemp.size() > 0:
|
|
401
|
+
pathlist.append(pathTemp.getHeadInstance().getName())
|
|
402
|
+
pathTemp = pathTemp.getTailPath()
|
|
403
|
+
assert len(pathlist) > 0
|
|
404
|
+
path = snl.SNLPath()
|
|
405
|
+
instance = None
|
|
406
|
+
top = snl.SNLUniverse.get().getTopDesign()
|
|
407
|
+
design = top
|
|
408
|
+
for name in pathlist:
|
|
409
|
+
path = snl.SNLPath(path, design.getInstance(name))
|
|
410
|
+
instance = design.getInstance(name)
|
|
411
|
+
assert instance is not None
|
|
162
412
|
design = instance.getModel()
|
|
163
|
-
return
|
|
413
|
+
return path
|
|
164
414
|
|
|
165
415
|
|
|
166
416
|
class Instance:
|
|
167
|
-
"""Class that represents the instance and wraps some
|
|
417
|
+
"""Class that represents the instance and wraps some
|
|
418
|
+
of the snl occurrence API.
|
|
419
|
+
"""
|
|
168
420
|
|
|
169
|
-
def __init__(self, path
|
|
170
|
-
self.inst = inst
|
|
421
|
+
def __init__(self, path=snl.SNLPath()):
|
|
171
422
|
self.path = path
|
|
172
423
|
|
|
173
424
|
def __eq__(self, other) -> bool:
|
|
174
|
-
return self.
|
|
425
|
+
return self.path == other.path
|
|
426
|
+
|
|
427
|
+
def __str__(self):
|
|
428
|
+
if self.is_top():
|
|
429
|
+
top = self.__get_snl_model()
|
|
430
|
+
if top is not None:
|
|
431
|
+
return top.getName()
|
|
432
|
+
else:
|
|
433
|
+
return ""
|
|
434
|
+
else:
|
|
435
|
+
return str(self.path)
|
|
436
|
+
|
|
437
|
+
def __repr__(self) -> str:
|
|
438
|
+
return f"Instance({self.path})"
|
|
439
|
+
|
|
440
|
+
def __hash__(self):
|
|
441
|
+
return hash(self.path)
|
|
442
|
+
|
|
443
|
+
def is_top(self) -> bool:
|
|
444
|
+
"""Return True if this is the top design."""
|
|
445
|
+
return self.path.size() == 0
|
|
446
|
+
|
|
447
|
+
def is_assign(self) -> bool:
|
|
448
|
+
return self.__get_snl_model().isAssign()
|
|
449
|
+
|
|
450
|
+
def is_blackbox(self) -> bool:
|
|
451
|
+
"""Return True if this is a blackbox."""
|
|
452
|
+
return self.__get_snl_model().isBlackBox()
|
|
453
|
+
|
|
454
|
+
def is_const0(self) -> bool:
|
|
455
|
+
"""Return True if this is a constant 0 generator."""
|
|
456
|
+
return self.__get_snl_model().isConst0()
|
|
457
|
+
|
|
458
|
+
def is_const1(self) -> bool:
|
|
459
|
+
"""Return True if this is a constant 1 generator."""
|
|
460
|
+
return self.__get_snl_model().isConst1()
|
|
461
|
+
|
|
462
|
+
def is_const(self) -> bool:
|
|
463
|
+
"""Return True if this is a constant generator."""
|
|
464
|
+
return self.__get_snl_model().isConst()
|
|
465
|
+
|
|
466
|
+
def is_buf(self) -> bool:
|
|
467
|
+
"""Return True if this is a buffer."""
|
|
468
|
+
return self.__get_snl_model().isBuf()
|
|
469
|
+
|
|
470
|
+
def is_inv(self) -> bool:
|
|
471
|
+
"""Return True if this is an inverter."""
|
|
472
|
+
return self.__get_snl_model().isInv()
|
|
473
|
+
|
|
474
|
+
def __get_snl_model(self):
|
|
475
|
+
"""Return the model of the instance."""
|
|
476
|
+
if self.is_top():
|
|
477
|
+
return snl.SNLUniverse.get().getTopDesign()
|
|
478
|
+
return self.path.getTailInstance().getModel()
|
|
479
|
+
|
|
480
|
+
def __find_snl_model(self, name: str) -> snl.SNLDesign:
|
|
481
|
+
u = snl.SNLUniverse.get()
|
|
482
|
+
for db in u.getUserDBs():
|
|
483
|
+
for lib in db.getLibraries():
|
|
484
|
+
found_model = lib.getDesign(name)
|
|
485
|
+
if found_model is not None:
|
|
486
|
+
return found_model
|
|
487
|
+
return None
|
|
175
488
|
|
|
176
489
|
def get_child_instance(self, name: str):
|
|
177
|
-
|
|
178
|
-
|
|
490
|
+
childInst = self.__get_snl_model().getInstance(name)
|
|
491
|
+
if childInst is None:
|
|
492
|
+
return None
|
|
493
|
+
return Instance(snl.SNLPath(self.path, childInst))
|
|
179
494
|
|
|
180
495
|
def get_child_instances(self):
|
|
181
|
-
for inst in self.
|
|
496
|
+
for inst in self.__get_snl_model().getInstances():
|
|
182
497
|
path = snl.SNLPath(self.path, inst)
|
|
183
|
-
yield Instance(path
|
|
498
|
+
yield Instance(path)
|
|
184
499
|
|
|
185
500
|
def get_number_of_child_instances(self) -> int:
|
|
186
|
-
return
|
|
501
|
+
return sum(1 for _ in self.__get_snl_model().getInstances())
|
|
502
|
+
|
|
503
|
+
# def get_flat_primitive_instances(self):
|
|
504
|
+
# FIXME: concat first local path with the path of the instance
|
|
505
|
+
# model = self.__get_snl_model()
|
|
506
|
+
# for inst in model.getInstances():
|
|
507
|
+
# path = snl.SNLPath(inst)
|
|
508
|
+
# stack = [[inst, path]]
|
|
509
|
+
# while stack:
|
|
510
|
+
# current = stack.pop()
|
|
511
|
+
# current_inst = current[0]
|
|
512
|
+
# current_path = current[1]
|
|
513
|
+
# for inst_child in current_inst.getModel().getInstances():
|
|
514
|
+
# path_child = snl.SNLPath(current_path, inst_child)
|
|
515
|
+
# if inst_child.getModel().isPrimitive():
|
|
516
|
+
# yield Instance(path_child)
|
|
517
|
+
# stack.append([inst_child, path_child])
|
|
518
|
+
|
|
519
|
+
def get_nets(self):
|
|
520
|
+
for net in self.__get_snl_model().getNets():
|
|
521
|
+
yield Net(self.path, net)
|
|
522
|
+
|
|
523
|
+
def get_flat_nets(self):
|
|
524
|
+
for net in self.__get_snl_model().getNets():
|
|
525
|
+
if isinstance(net, snl.SNLBusNet):
|
|
526
|
+
for bit in net.getBits():
|
|
527
|
+
yield Net(self.path, bit)
|
|
528
|
+
else:
|
|
529
|
+
yield Net(self.path, net)
|
|
530
|
+
|
|
531
|
+
def get_net(self, name: str) -> Net:
|
|
532
|
+
net = self.__get_snl_model().getNet(name)
|
|
533
|
+
if net is not None:
|
|
534
|
+
return Net(self.path, net)
|
|
535
|
+
return None
|
|
187
536
|
|
|
188
|
-
def
|
|
189
|
-
if
|
|
190
|
-
|
|
191
|
-
for term in self.inst.getInstTerms():
|
|
192
|
-
yield InstTerm(self.path.getHeadPath(), term)
|
|
537
|
+
def is_primitive(self) -> bool:
|
|
538
|
+
"""Return True if this is a primitive."""
|
|
539
|
+
return self.__get_snl_model().isPrimitive()
|
|
193
540
|
|
|
194
|
-
def
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
541
|
+
def get_terms(self):
|
|
542
|
+
for term in self.__get_snl_model().getTerms():
|
|
543
|
+
yield Term(self.path, term)
|
|
544
|
+
|
|
545
|
+
def get_flat_terms(self):
|
|
546
|
+
for term in self.__get_snl_model().getBitTerms():
|
|
547
|
+
yield Term(self.path, term)
|
|
548
|
+
|
|
549
|
+
def get_term(self, name: str) -> Term:
|
|
550
|
+
term = self.__get_snl_model().getTerm(name)
|
|
551
|
+
if term is not None:
|
|
552
|
+
return Term(self.path, self.__get_snl_model().getTerm(name))
|
|
200
553
|
return None
|
|
201
554
|
|
|
202
|
-
def
|
|
203
|
-
|
|
555
|
+
def get_input_terms(self):
|
|
556
|
+
for term in self.__get_snl_model().getTerms():
|
|
557
|
+
if term.getDirection() == snl.SNLTerm.Direction.Input:
|
|
558
|
+
yield Term(self.path, term)
|
|
559
|
+
|
|
560
|
+
def get_flat_input_terms(self):
|
|
561
|
+
for term in self.__get_snl_model().getTerms():
|
|
562
|
+
if term.getDirection() == snl.SNLTerm.Direction.Input:
|
|
563
|
+
if isinstance(term, snl.SNLBusTerm):
|
|
564
|
+
for bit in term.getBits():
|
|
565
|
+
yield Term(self.path, bit)
|
|
566
|
+
else:
|
|
567
|
+
yield Term(self.path, term)
|
|
568
|
+
|
|
569
|
+
def get_output_terms(self):
|
|
570
|
+
for term in self.__get_snl_model().getTerms():
|
|
571
|
+
if term.getDirection() == snl.SNLTerm.Direction.Output:
|
|
572
|
+
yield Term(self.path, term)
|
|
204
573
|
|
|
205
|
-
def
|
|
206
|
-
for term in self.
|
|
574
|
+
def get_flat_output_terms(self):
|
|
575
|
+
for term in self.__get_snl_model().getTerms():
|
|
207
576
|
if term.getDirection() == snl.SNLTerm.Direction.Output:
|
|
208
|
-
|
|
577
|
+
if isinstance(term, snl.SNLBusTerm):
|
|
578
|
+
for bit in term.getBits():
|
|
579
|
+
yield Term(self.path, bit)
|
|
580
|
+
else:
|
|
581
|
+
yield Term(self.path, term)
|
|
209
582
|
|
|
210
583
|
def delete_instance(self, name: str):
|
|
211
|
-
path = snl.SNLPath(self.path, self.
|
|
212
|
-
|
|
213
|
-
|
|
584
|
+
path = snl.SNLPath(self.path, self.__get_snl_model().getInstance(name))
|
|
585
|
+
snl.SNLUniquifier(path)
|
|
586
|
+
if self.path.size() > 0:
|
|
587
|
+
self.path = refresh_path(self.path)
|
|
214
588
|
# Delete the last instance in uniq_path
|
|
215
|
-
|
|
589
|
+
self.__get_snl_model().getInstance(name).destroy()
|
|
216
590
|
|
|
217
591
|
def get_name(self) -> str:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
592
|
+
"""Return the name of the instance or name of the top is this is the top."""
|
|
593
|
+
if self.is_top():
|
|
594
|
+
return self.get_model_name()
|
|
595
|
+
else:
|
|
596
|
+
return self.path.getTailInstance().getName()
|
|
597
|
+
|
|
598
|
+
def get_model_name(self) -> str:
|
|
599
|
+
"""Return the name of the model of the instance or name of the top is this is the top."""
|
|
600
|
+
return self.__get_snl_model().getName()
|
|
601
|
+
|
|
602
|
+
def get_model_id(self) -> tuple[int, int, int]:
|
|
603
|
+
model = self.__get_snl_model()
|
|
604
|
+
return model.getDB().getID(), model.getLibrary().getID(), model.getID()
|
|
605
|
+
|
|
606
|
+
def create_child_instance(self, model: str, name: str):
|
|
607
|
+
if self.path.size() > 0:
|
|
608
|
+
path = self.path
|
|
609
|
+
snl.SNLUniquifier(path)
|
|
610
|
+
self.path = refresh_path(self.path)
|
|
611
|
+
design = self.__get_snl_model()
|
|
612
|
+
new_instance_model = self.__find_snl_model(model)
|
|
613
|
+
if new_instance_model is None:
|
|
614
|
+
raise ValueError(
|
|
615
|
+
f"Cannot create instance {name} in {self}: model {model} cannot be found"
|
|
616
|
+
)
|
|
617
|
+
newSNLInstance = snl.SNLInstance.create(design, new_instance_model, name)
|
|
224
618
|
path = snl.SNLPath(self.path, newSNLInstance)
|
|
225
|
-
return Instance(
|
|
619
|
+
return Instance(path)
|
|
620
|
+
|
|
621
|
+
def create_term(self, name: str, direction: snl.SNLTerm.Direction) -> Term:
|
|
622
|
+
if self.path.size() > 0:
|
|
623
|
+
path = self.path
|
|
624
|
+
snl.SNLUniquifier(path)
|
|
625
|
+
self.path = refresh_path(self.path)
|
|
626
|
+
design = self.__get_snl_model()
|
|
627
|
+
newSNLTerm = snl.SNLScalarTerm.create(design, direction, name)
|
|
628
|
+
return Term(self.path, newSNLTerm)
|
|
629
|
+
|
|
630
|
+
def create_output_term(self, name: str) -> Term:
|
|
631
|
+
return self.create_term(name, snl.SNLTerm.Direction.Output)
|
|
632
|
+
|
|
633
|
+
def create_input_term(self, name: str) -> Term:
|
|
634
|
+
return self.create_term(name, snl.SNLTerm.Direction.Input)
|
|
635
|
+
|
|
636
|
+
def create_inout_term(self, name: str) -> Term:
|
|
637
|
+
return self.create_term(name, snl.SNLTerm.Direction.InOut)
|
|
638
|
+
|
|
639
|
+
def create_bus_term(self, name: str, msb: int, lsb: int, direction) -> Term:
|
|
640
|
+
if self.path.size() > 0:
|
|
641
|
+
path = self.path
|
|
642
|
+
snl.SNLUniquifier(path)
|
|
643
|
+
self.path = refresh_path(self.path)
|
|
644
|
+
design = self.__get_snl_model()
|
|
645
|
+
newSNLTerm = snl.SNLBusTerm.create(design, direction, msb, lsb, name)
|
|
646
|
+
return Term(self.path, newSNLTerm)
|
|
647
|
+
|
|
648
|
+
def create_inout_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
649
|
+
return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.InOut)
|
|
650
|
+
|
|
651
|
+
def create_output_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
652
|
+
return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Output)
|
|
653
|
+
|
|
654
|
+
def create_input_bus_term(self, name: str, msb: int, lsb: int) -> Term:
|
|
655
|
+
return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Input)
|
|
656
|
+
|
|
657
|
+
def create_net(self, name: str) -> Net:
|
|
658
|
+
if self.path.size() > 0:
|
|
659
|
+
path = self.path
|
|
660
|
+
snl.SNLUniquifier(path)
|
|
661
|
+
self.path = refresh_path(self.path)
|
|
662
|
+
model = self.__get_snl_model()
|
|
663
|
+
newSNLNet = snl.SNLScalarNet.create(model, name)
|
|
664
|
+
return Net(self.path, newSNLNet)
|
|
665
|
+
|
|
666
|
+
def create_bus_net(self, name: str, msb: int, lsb: int) -> Net:
|
|
667
|
+
if self.path.size() > 0:
|
|
668
|
+
path = self.path
|
|
669
|
+
snl.SNLUniquifier(path)
|
|
670
|
+
self.path = refresh_path(self.path)
|
|
671
|
+
model = self.__get_snl_model()
|
|
672
|
+
newSNLNet = snl.SNLBusNet.create(model, msb, lsb, name)
|
|
673
|
+
return Net(self.path, newSNLNet)
|
|
674
|
+
|
|
675
|
+
def dump_verilog(self, path: str, name: str):
|
|
676
|
+
self.__get_snl_model().dumpVerilog(path, name)
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
def get_top_db() -> snl.SNLDB:
|
|
680
|
+
if snl.SNLUniverse.get() is None:
|
|
681
|
+
snl.SNLUniverse.create()
|
|
682
|
+
if snl.SNLUniverse.get().getTopDB() is None:
|
|
683
|
+
db = snl.SNLDB.create(snl.SNLUniverse.get())
|
|
684
|
+
snl.SNLUniverse.get().setTopDB(db)
|
|
685
|
+
return snl.SNLUniverse.get().getTopDB()
|
|
226
686
|
|
|
227
687
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
self.db_ = None
|
|
231
|
-
self.primitives_library_ = None
|
|
688
|
+
def get_top():
|
|
689
|
+
return Instance(snl.SNLPath())
|
|
232
690
|
|
|
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
691
|
|
|
260
|
-
|
|
261
|
-
|
|
692
|
+
def create_top(name: str) -> Instance:
|
|
693
|
+
# init
|
|
694
|
+
db = get_top_db()
|
|
695
|
+
# create top design
|
|
696
|
+
lib = snl.SNLLibrary.create(db)
|
|
697
|
+
top = snl.SNLDesign.create(lib, name)
|
|
698
|
+
snl.SNLUniverse.get().setTopDesign(top)
|
|
699
|
+
return Instance()
|
|
262
700
|
|
|
263
701
|
|
|
264
|
-
def
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
702
|
+
def load_verilog(files: list):
|
|
703
|
+
get_top_db().loadVerilog(files)
|
|
704
|
+
return get_top()
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def load_liberty(files: list):
|
|
708
|
+
get_top_db().loadLibertyPrimitives(files)
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def get_primitives_library() -> snl.SNLLibrary:
|
|
712
|
+
lib = get_top_db().getLibrary("PRIMS")
|
|
713
|
+
if lib is None:
|
|
714
|
+
lib = snl.SNLLibrary.createPrimitives(get_top_db())
|
|
715
|
+
return lib
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
def get_model_name(id: tuple[int, int, int]) -> str:
|
|
719
|
+
"""Return the name of the model given its id."""
|
|
720
|
+
u = snl.SNLUniverse.get()
|
|
721
|
+
if u:
|
|
722
|
+
db = u.getDB(id[0])
|
|
723
|
+
if db:
|
|
724
|
+
lib = db.getLibrary(id[1])
|
|
725
|
+
if lib:
|
|
726
|
+
model = lib.getDesign(id[2])
|
|
727
|
+
if model:
|
|
728
|
+
return model.getName()
|
|
729
|
+
return None
|
najaeda/snl.so
CHANGED
|
Binary file
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: najaeda
|
|
3
|
+
Version: 0.1.3
|
|
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.
|
|
15
|
+
It serves as the Python counterpart to the `Naja C++ project <https://github.com/najaeda/naja>`_.
|
|
16
|
+
|
|
17
|
+
Installation
|
|
18
|
+
------------
|
|
19
|
+
|
|
20
|
+
Install Naja EDA using pip:
|
|
21
|
+
|
|
22
|
+
.. code-block:: bash
|
|
23
|
+
|
|
24
|
+
pip install najaeda
|
|
25
|
+
|
|
26
|
+
Examples
|
|
27
|
+
--------
|
|
28
|
+
|
|
29
|
+
Load a design from a liberty file and a Verilog file
|
|
30
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
31
|
+
Following snippet shows how to load primitive cells from a liberty file and
|
|
32
|
+
a netlist from a Verilog file.
|
|
33
|
+
|
|
34
|
+
.. code-block:: python
|
|
35
|
+
|
|
36
|
+
from os import path
|
|
37
|
+
import sys
|
|
38
|
+
from najaeda import netlist
|
|
39
|
+
|
|
40
|
+
benchmarks = path.join('..','benchmarks')
|
|
41
|
+
liberty_files = [
|
|
42
|
+
'NangateOpenCellLibrary_typical.lib',
|
|
43
|
+
'fakeram45_1024x32.lib',
|
|
44
|
+
'fakeram45_64x32.lib'
|
|
45
|
+
]
|
|
46
|
+
liberty_files = list(map(lambda p:path.join(benchmarks, 'liberty', p), liberty_files))
|
|
47
|
+
|
|
48
|
+
netlist.load_liberty(liberty_files)
|
|
49
|
+
top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'tinyrocket.v')])
|
|
50
|
+
|
|
51
|
+
top.dump_verilog('.', 'tinyrocket_naja.v')
|
|
52
|
+
|
|
53
|
+
Print all the instances in the netlist
|
|
54
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
55
|
+
Next example shows how to browse all the netlist and print all its content.
|
|
56
|
+
|
|
57
|
+
.. code-block:: python
|
|
58
|
+
|
|
59
|
+
def print_netlist(instance):
|
|
60
|
+
for child_instance in instance.get_child_instances():
|
|
61
|
+
print(f"{child_instance}:{child_instance.get_model_name()}")
|
|
62
|
+
print_netlist(child_instance)
|
|
63
|
+
|
|
64
|
+
Documentation
|
|
65
|
+
-------------
|
|
66
|
+
|
|
67
|
+
Naja documentation is available on the `Naja GitHub repository <https://github.com/najaeda/naja>`_.
|
|
68
|
+
|
|
69
|
+
License
|
|
70
|
+
-------
|
|
71
|
+
|
|
72
|
+
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.3.dist-info/RECORD,,
|
|
2
|
+
najaeda-0.1.3.dist-info/WHEEL,sha256=vqMBchNIsmW0K9HInUQuY_xePW9YD3coNJy6G1Yfto8,114
|
|
3
|
+
najaeda-0.1.3.dist-info/METADATA,sha256=cUsTBMA9mhbFVF1WSI0wQYb3hc9-ThpBYShih2Yru6E,2147
|
|
4
|
+
najaeda-0.1.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
5
|
+
najaeda-0.1.3.dist-info/licenses/AUTHORS,sha256=e4DCPGHo6wKMyQz24V59EP7zMwalK-KBDBHHlMLFxHY,330
|
|
6
|
+
najaeda/netlist.py,sha256=sKIacJE8olG3-NxUru0ntAnzeU-enJNocnvJ3O0Jnp0,25102
|
|
7
|
+
najaeda/libnaja_snl_python.dylib,sha256=LIQrK5KTyR9DxmVTHJZHcw6-hN3i1sOlx1HHJ5fGKpQ,740160
|
|
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
|