najaeda 0.1.0__cp39-cp39-macosx_11_0_arm64.whl → 0.1.3__cp39-cp39-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 CHANGED
Binary file
Binary file
najaeda/netlist.py CHANGED
@@ -1,53 +1,181 @@
1
- # SPDX-FileCopyrightText: 2024 The Naja authors <https://github.com/najaeda/naja/blob/main/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 some of the snl occurrence API."""
11
-
12
- def __init__(self, inst_term):
13
- ito = snl.SNLNetComponentOccurrence(inst_term.path, inst_term.term)
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 InstTerm(term.getPath(), term.getInstTerm())
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 TopTerm(snl.SNLPath(), term.getBitTerm())
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
- if term.getInstTerm().getDirection() == snl.SNLTerm.Direction.Output:
27
- yield InstTerm(term.getPath(), term.getInstTerm())
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
- self.net = net
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
- return self.net.getName()
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
- yield InstTerm(self.path, term)
160
+ path = snl.SNLPath(self.path, term.getInstance())
161
+ yield Term(path, term.getBitTerm())
41
162
 
42
- def get_top_terms(self):
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 TopTerm(self.path, term)
167
+ yield Term(self.path, term)
45
168
 
46
- def __eq__(self, value):
47
- return self.net == value.net and self.path == value.path
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 TopTerm:
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 get_name(self) -> str:
76
- return self.term.getName()
77
-
78
- def get_direction(self) -> snl.SNLTerm.Direction:
79
- return self.term.getDirection()
80
-
81
- def get_net(self) -> Net:
82
- return Net(self.path, self.term.getNet())
83
-
84
- def get_equipotential(self) -> Equipotential:
85
- return Equipotential(self)
86
-
87
- def is_input(self) -> bool:
88
- return self.term.getDirection() == snl.SNLTerm.Direction.Input
89
-
90
- def is_output(self) -> bool:
91
- return self.term.getDirection() == snl.SNLTerm.Direction.Output
92
-
93
-
94
- class InstTerm:
95
- def __init__(self, path, term):
96
- self.path = path
97
- self.term = term
98
-
99
- def __eq__(self, other) -> bool:
100
- return self.path == other.path and self.term == other.term
101
-
102
- def __ne__(self, other) -> bool:
103
- return not self == other
104
-
105
- def __lt__(self, other) -> bool:
106
- if self.path != other.path:
107
- return self.path < other.path
108
- return self.term < other.term
109
-
110
- def __le__(self, other) -> bool:
111
- return self < other or self == other
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 __gt__(self, other) -> bool:
114
- return not self <= other
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 __ge__(self, other) -> bool:
117
- return not self < other
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
- return Net(self.path, self.term.getNet())
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
- inst = self.term.getInstance()
127
- path = snl.SNLPath(self.path, inst)
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) -> Equipotential:
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 get_string(self) -> str:
143
- return str(snl.SNLInstTermOccurrence(self.path, self.term))
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
- uniq = snl.SNLUniquifier(self.path)
147
- self.term.setNet(snl.SNLNet())
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
- uniq = snl.SNLUniquifier(self.path)
151
- self.term.setNet(net.net)
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 Instance(path, instance)
413
+ return path
164
414
 
165
415
 
166
416
  class Instance:
167
- """Class that represents the instance and wraps some of the snl occurrence API."""
417
+ """Class that represents the instance and wraps some
418
+ of the snl occurrence API.
419
+ """
168
420
 
169
- def __init__(self, path, inst):
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.inst == other.inst and self.path == other.path
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
- return Instance(snl.SNLPath(self.path, self.inst.getModel().getInstance(name)),
178
- self.inst.getModel().getInstance(name))
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.inst.getModel().getInstances():
496
+ for inst in self.__get_snl_model().getInstances():
182
497
  path = snl.SNLPath(self.path, inst)
183
- yield Instance(path, inst)
498
+ yield Instance(path)
184
499
 
185
500
  def get_number_of_child_instances(self) -> int:
186
- return len(tuple(self.inst.getModel().getInstances()))
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 get_inst_terms(self):
189
- if self.inst is None:
190
- return
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 get_inst_term(self, name: str) -> InstTerm:
195
- if self.inst is None:
196
- return None
197
- for term in self.inst.getInstTerms():
198
- if term.getBitTerm().getName() == name:
199
- return InstTerm(self.path.getHeadPath(), term)
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 is_primitive(self) -> bool:
203
- return self.inst.getModel().isPrimitive()
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 get_output_inst_terms(self):
206
- for term in self.inst.getInstTerms():
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
- yield InstTerm(self.path.getHeadPath(), term)
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.inst.getModel().getInstance(name))
212
- uniq = snl.SNLUniquifier(path)
213
- uniq_path = uniq.getPathUniqCollection()
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
- tuple(uniq_path)[len(tuple(uniq_path)) - 1].destroy()
589
+ self.__get_snl_model().getInstance(name).destroy()
216
590
 
217
591
  def get_name(self) -> str:
218
- return self.inst.getName()
219
-
220
- def create_child_instance(self, model, name):
221
- uniq = snl.SNLUniquifier(self.path)
222
- design = self.inst.getModel()
223
- newSNLInstance = snl.SNLInstance.create(design, model, name)
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(snl.SNLPath(self.path, newSNLInstance), newSNLInstance)
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
- class Loader:
229
- def __init__(self):
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
- def load_liberty_primitives(self, files):
261
- self.db_.loadLibertyPrimitives(files)
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 get_all_primitive_instances() -> list:
265
- top = snl.SNLUniverse.get().getTopDesign()
266
- primitives = []
267
-
268
- for inst in top.getInstances():
269
- path = snl.SNLPath(inst)
270
- stack = [[inst, path]]
271
- while stack:
272
- current = stack.pop()
273
- current_inst = current[0]
274
- current_path = current[1]
275
- for inst_child in current_inst.getModel().getInstances():
276
- path_child = snl.SNLPath(current_path, inst_child)
277
- if inst_child.getModel().isPrimitive():
278
- primitives.append(Instance(path_child, inst_child))
279
- stack.append([inst_child, path_child])
280
- return primitives
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=Qmm8uWPQTspuPJ9tUBLJdmqmcf0_LWu4zzBSlc_SSWo,112
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=KNWsrF8X9RxYBICuNtfn6azx7iZjZjmEo7MdhifbDd8,740160
8
+ najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ najaeda/libnaja_snl.dylib,sha256=8Ei7KKU0b14IqlvH_8yQSSCpH0rjbxpeRaXgyfSemMY,574112
10
+ najaeda/snl.so,sha256=aBlR-NJTWhggF83LF96jmkuxpIzloTy5XO1Z27S4C0s,97888
11
+ najaeda/.dylibs/Python,sha256=XN-3zWbVA8jmg35-eZf5_kPmM1T66HkIJXNKQKBnywc,7676144
@@ -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
@@ -1,11 +0,0 @@
1
- najaeda-0.1.0.dist-info/RECORD,,
2
- najaeda-0.1.0.dist-info/WHEEL,sha256=Qmm8uWPQTspuPJ9tUBLJdmqmcf0_LWu4zzBSlc_SSWo,112
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=fFys7m5DCN-CDA6CHeU0HLJ0uczmN4d9GvlJCR8e_QU,722256
8
- najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- najaeda/libnaja_snl.dylib,sha256=P60Bn-hOArZrLqcdQUL0J6NzPHUV4V8Jf0StrJpTXgg,573808
10
- najaeda/snl.so,sha256=W2ReoDD2lPslwcOaK53N20hur6GiwnPVPGBPZJcvjkc,97616
11
- najaeda/.dylibs/Python,sha256=XN-3zWbVA8jmg35-eZf5_kPmM1T66HkIJXNKQKBnywc,7676144