najaeda 0.0.0__cp310-cp310-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.

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