najaeda 0.1.6__cp311-cp311-macosx_11_0_arm64.whl → 0.1.8__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/netlist.py CHANGED
@@ -6,8 +6,61 @@
6
6
  import itertools
7
7
  import time
8
8
  import logging
9
-
9
+ import hashlib
10
+ # import json
10
11
  from najaeda import snl
12
+ import struct
13
+
14
+
15
+ def consistent_hash(obj):
16
+ def default_serializer(o):
17
+ if isinstance(o, (str, int, float, bool, type(None))):
18
+ return o
19
+ elif isinstance(o, (list, tuple)):
20
+ return [default_serializer(i) for i in o]
21
+ else:
22
+ return str(o)
23
+
24
+ def hash_value(value):
25
+ if isinstance(value, int):
26
+ return struct.pack('!q', value)
27
+ else:
28
+ raise TypeError(f"Unsupported type: {type(value)}")
29
+
30
+ def hash_object(o):
31
+ if isinstance(o, (list, tuple)):
32
+ return b''.join(hash_object(i) for i in o)
33
+ else:
34
+ return hash_value(o)
35
+ serialized_obj = default_serializer(obj)
36
+ obj_bytes = hash_object(serialized_obj)
37
+ return int(hashlib.sha256(obj_bytes).hexdigest(), 16)
38
+
39
+
40
+ def get_snl_instance_from_id_list(id_list: list) -> snl.SNLInstance:
41
+ top = snl.SNLUniverse.get().getTopDesign()
42
+ design = top
43
+ instance = None
44
+ for id in id_list:
45
+ instance = design.getInstanceByID(id)
46
+ assert instance is not None
47
+ design = instance.getModel()
48
+ return instance
49
+
50
+
51
+ def get_snl_path_from_id_list(id_list: list) -> snl.SNLPath:
52
+ top = snl.SNLUniverse.get().getTopDesign()
53
+ design = top
54
+ path = snl.SNLPath()
55
+ for id in id_list:
56
+ instance = design.getInstanceByID(id)
57
+ assert instance is not None
58
+ path = snl.SNLPath(path, instance)
59
+ assert path.getTailInstance() is not None
60
+ design = instance.getModel()
61
+ if len(id_list) > 0:
62
+ assert path.getTailInstance() is not None
63
+ return path
11
64
 
12
65
 
13
66
  class Equipotential:
@@ -16,36 +69,84 @@ class Equipotential:
16
69
  """
17
70
 
18
71
  def __init__(self, term):
19
- if isinstance(term.term, snl.SNLBusTerm):
72
+ snl_term = get_snl_term_for_ids(term.pathIDs, term.termIDs)
73
+ inst_term = None
74
+ if isinstance(snl_term, snl.SNLBusTerm):
20
75
  raise ValueError("Equipotential cannot be constructed on bus term")
76
+ if len(term.pathIDs) == 0:
77
+ net = term.get_lower_net()
78
+ if net is None:
79
+ self.equi = None
80
+ return
81
+ inst_term = next(net.get_inst_terms(), None)
82
+ if inst_term is None:
83
+ self.equi = None
84
+ return
85
+ else:
86
+ snl_term = get_snl_term_for_ids(inst_term.pathIDs, inst_term.termIDs)
87
+ else:
88
+ inst_term = term
89
+ path = get_snl_path_from_id_list(inst_term.pathIDs)
21
90
  ito = snl.SNLNetComponentOccurrence(
22
- term.path.getHeadPath(), term.path.getTailInstance().getInstTerm(term.term)
91
+ path.getHeadPath(),
92
+ path.getTailInstance().getInstTerm(snl_term)
23
93
  )
24
94
  self.equi = snl.SNLEquipotential(ito)
25
95
 
26
96
  def __eq__(self, value):
27
97
  return self.equi == value.equi
28
98
 
99
+ def dump_dot(self, path: str):
100
+ self.equi.dumpDotFile(path)
101
+
29
102
  def get_inst_terms(self):
30
- for term in self.equi.getInstTermOccurrences():
31
- yield Term(
32
- snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
33
- term.getInstTerm().getBitTerm(),
34
- )
103
+ if self.equi is not None:
104
+ for term in self.equi.getInstTermOccurrences():
105
+ yield Term(
106
+ snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
107
+ term.getInstTerm().getBitTerm(),
108
+ )
35
109
 
36
110
  def get_top_terms(self):
37
- for term in self.equi.getTerms():
38
- yield Term(snl.SNLPath(), term)
39
-
40
- def get_all_leaf_readers(self):
41
- for term in self.equi.getInstTermOccurrences():
42
- direction = term.getInstTerm().getDirection()
43
- if direction != snl.SNLTerm.Direction.Output:
44
- if term.getInstTerm().getInstance().getModel().isLeaf():
45
- yield Term(
46
- snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
47
- term.getInstTerm().getBitTerm(),
48
- )
111
+ if self.equi is not None:
112
+ for term in self.equi.getTerms():
113
+ yield Term([], term)
114
+
115
+ def get_leaf_readers(self):
116
+ if self.equi is not None:
117
+ for term in self.equi.getInstTermOccurrences():
118
+ direction = term.getInstTerm().getDirection()
119
+ if direction != snl.SNLTerm.Direction.Output:
120
+ if term.getInstTerm().getInstance().getModel().isLeaf():
121
+ yield Term(
122
+ snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
123
+ term.getInstTerm().getBitTerm(),
124
+ )
125
+
126
+ def get_leaf_drivers(self):
127
+ if self.equi is not None:
128
+ for term in self.equi.getInstTermOccurrences():
129
+ direction = term.getInstTerm().getDirection()
130
+ if direction != snl.SNLTerm.Direction.Input:
131
+ if term.getInstTerm().getInstance().getModel().isLeaf():
132
+ yield Term(
133
+ snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
134
+ term.getInstTerm().getBitTerm(),
135
+ )
136
+
137
+ def get_top_readers(self):
138
+ if self.equi is not None:
139
+ for term in self.equi.getTerms():
140
+ direction = term.getDirection()
141
+ if direction != snl.SNLTerm.Direction.Input:
142
+ yield Term(snl.SNLPath(), term)
143
+
144
+ def get_top_drivers(self):
145
+ if self.equi is not None:
146
+ for term in self.equi.getTerms():
147
+ direction = term.getDirection()
148
+ if direction != snl.SNLTerm.Direction.Output:
149
+ yield Term(snl.SNLPath(), term)
49
150
 
50
151
 
51
152
  class Net:
@@ -54,7 +155,13 @@ class Net:
54
155
  raise ValueError(
55
156
  "Only one of `net` or `net_concat` should be provided, not both."
56
157
  )
57
- self.path = path
158
+ if isinstance(path, snl.SNLPath):
159
+ if path.size() > 0:
160
+ self.pathIDs = path.getPathIDs()
161
+ else:
162
+ self.pathIDs = []
163
+ elif isinstance(path, list):
164
+ self.pathIDs = path.copy()
58
165
  if net is not None:
59
166
  self.net = net
60
167
  elif net_concat is not None:
@@ -76,8 +183,9 @@ class Net:
76
183
  net_str = str(self.net)
77
184
  elif hasattr(self, "net_concat"):
78
185
  net_str = "{" + ",".join(map(str, self.net_concat)) + "}"
79
- if self.path.size() > 0:
80
- return f"{self.path}/{net_str}"
186
+ path = get_snl_path_from_id_list(self.pathIDs)
187
+ if path.size() > 0:
188
+ return f"{path}/{net_str}"
81
189
  return net_str
82
190
 
83
191
  def get_name(self) -> str:
@@ -137,7 +245,7 @@ class Net:
137
245
  if hasattr(self, "net"):
138
246
  if isinstance(self.net, snl.SNLBusNet):
139
247
  for bit in self.net.getBits():
140
- yield Net(self.path, bit)
248
+ yield Net(self.pathIDs, bit)
141
249
  else:
142
250
  yield self
143
251
  else:
@@ -147,50 +255,79 @@ class Net:
147
255
  def get_bit(self, index: int):
148
256
  if hasattr(self, "net"):
149
257
  if isinstance(self.net, snl.SNLBusNet):
150
- return Net(self.path, self.net.getBit(index))
258
+ return Net(self.pathIDs, self.net.getBit(index))
151
259
  else:
152
260
  return None
153
261
  if 0 <= index < len(self.net_concat):
154
- return Net(self.path, self.net_concat[index])
262
+ return Net(self.pathIDs, self.net_concat[index])
155
263
  return None
156
264
 
157
265
  def get_inst_terms(self):
158
266
  if hasattr(self, "net_concat"):
159
267
  raise ValueError("Cannot get inst terms from a net_concat")
160
268
  for term in self.net.getInstTerms():
161
- path = snl.SNLPath(self.path, term.getInstance())
269
+ path = self.pathIDs.copy()
270
+ path.append(term.getInstance().getID())
162
271
  yield Term(path, term.getBitTerm())
163
272
 
164
273
  def get_design_terms(self):
165
274
  if hasattr(self, "net_concat"):
166
275
  raise ValueError("Cannot get terms from a net_concat")
167
276
  for term in self.net.getBitTerms():
168
- yield Term(self.path, term)
277
+ yield Term(self.pathIDs, term)
169
278
 
170
279
  def get_terms(self):
171
280
  for term in itertools.chain(self.get_design_terms(), self.get_inst_terms()):
172
281
  yield term
173
282
 
174
283
 
284
+ def get_snl_term_for_ids(pathIDs, termIDs):
285
+ path = get_snl_path_from_id_list(pathIDs)
286
+ model = None
287
+ if len(pathIDs) == 0:
288
+ model = snl.SNLUniverse.get().getTopDesign()
289
+ else:
290
+ model = path.getTailInstance().getModel()
291
+ if termIDs[1] == -1:
292
+ return model.getTermByID(termIDs[0])
293
+ else:
294
+ snlterm = model.getTermByID(termIDs[0])
295
+ if isinstance(snlterm, snl.SNLBusTerm):
296
+ return snlterm.getBit(termIDs[1])
297
+ else:
298
+ return snlterm
299
+
300
+
175
301
  class Term:
176
302
  INPUT = snl.SNLTerm.Direction.Input
177
303
  OUTPUT = snl.SNLTerm.Direction.Output
178
304
  INOUT = snl.SNLTerm.Direction.InOut
179
305
 
180
306
  def __init__(self, path, term):
181
- self.path = path
182
- self.term = term
307
+ self.termIDs = []
308
+ if isinstance(term, snl.SNLBusTerm):
309
+ self.termIDs = [term.getID(), -1]
310
+ else:
311
+ self.termIDs = [term.getID(), term.getBit()]
312
+
313
+ if isinstance(path, snl.SNLPath):
314
+ if path.size() > 0:
315
+ self.pathIDs = path.getPathIDs()
316
+ else:
317
+ self.pathIDs = []
318
+ elif isinstance(path, list):
319
+ self.pathIDs = path.copy()
183
320
 
184
321
  def __eq__(self, other) -> bool:
185
- return self.path == other.path and self.term == other.term
322
+ return self.pathIDs == other.pathIDs and self.termIDs == other.termIDs
186
323
 
187
324
  def __ne__(self, other) -> bool:
188
325
  return not self == other
189
326
 
190
327
  def __lt__(self, other) -> bool:
191
- if self.path != other.path:
192
- return self.path < other.path
193
- return self.term < other.term
328
+ if self.pathIDs != other.pathIDs:
329
+ return self.pathIDs < other.pathIDs
330
+ return self.termIDs < other.termIDs
194
331
 
195
332
  def __le__(self, other) -> bool:
196
333
  return self < other or self == other
@@ -201,40 +338,43 @@ class Term:
201
338
  def __ge__(self, other) -> bool:
202
339
  return not self < other
203
340
 
341
+ def __hash__(self):
342
+ termIDs = []
343
+ snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
344
+ if isinstance(snlterm, snl.SNLBusTerm):
345
+ termIDs = [snlterm.getID(), -1]
346
+ else:
347
+ termIDs = [snlterm.getID(), snlterm.getBit()]
348
+ return consistent_hash((self.pathIDs, termIDs))
349
+
204
350
  def __str__(self):
205
- if self.path.size() == 0:
206
- return self.term.getName()
351
+ path = get_snl_path_from_id_list(self.pathIDs)
352
+ if path.size() == 0:
353
+ return get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()
207
354
  else:
208
- return f"{self.path}/{self.term}"
355
+ return f"{path}/{get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()}"
209
356
 
210
357
  def __repr__(self) -> str:
211
- return f"Term({self.path}, {self.term})"
358
+ path = get_snl_path_from_id_list(self.pathIDs)
359
+ return f"Term({path}, {get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()})"
212
360
 
213
361
  def __make_unique(self):
214
- if self.path.size() > 1:
215
- path = self.path.getHeadPath()
362
+ path = get_snl_path_from_id_list(self.pathIDs)
363
+ if path.size() > 1:
364
+ path = path.getHeadPath()
216
365
  snl.SNLUniquifier(path)
217
- if self.is_bus_bit():
218
- term = (
219
- self.path.getTailInstance().getModel().getTerm(self.term.getName())
220
- )
221
- self.term = term.getBit(self.term.getBit())
222
- else:
223
- self.term = (
224
- self.path.getTailInstance().getModel().getTerm(self.term.getName())
225
- )
226
366
 
227
367
  def is_bus(self) -> bool:
228
368
  """Return True if the term is a bus."""
229
- return isinstance(self.term, snl.SNLBusTerm)
369
+ return isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm)
230
370
 
231
371
  def is_bus_bit(self) -> bool:
232
372
  """Return True if the term is a bit of a bus."""
233
- return isinstance(self.term, snl.SNLBusTermBit)
373
+ return isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTermBit)
234
374
 
235
375
  def is_scalar(self) -> bool:
236
376
  """Return True if the term is a scalar."""
237
- return isinstance(self.term, snl.SNLScalarTerm)
377
+ return isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLScalarTerm)
238
378
 
239
379
  def is_bit(self) -> bool:
240
380
  """Return True if the term is a bit."""
@@ -242,37 +382,39 @@ class Term:
242
382
 
243
383
  def get_msb(self) -> int:
244
384
  """Return the most significant bit of the term if it is a bus."""
245
- if isinstance(self.term, snl.SNLBusTerm):
246
- return self.term.getMSB()
385
+ if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
386
+ return get_snl_term_for_ids(self.pathIDs, self.termIDs).getMSB()
247
387
  return None
248
388
 
249
389
  def get_lsb(self) -> int:
250
390
  """Return the least significant bit of the term if it is a bus."""
251
- if isinstance(self.term, snl.SNLBusTerm):
252
- return self.term.getLSB()
391
+ if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
392
+ return get_snl_term_for_ids(self.pathIDs, self.termIDs).getLSB()
253
393
  return None
254
394
 
255
395
  def get_width(self) -> int:
256
396
  """Return the width of the term. 1 if scalar."""
257
- return self.term.getWidth()
397
+ return get_snl_term_for_ids(self.pathIDs, self.termIDs).getWidth()
258
398
 
259
399
  def get_name(self) -> str:
260
400
  """Return the name of the term."""
261
- return self.term.getName()
401
+ return get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()
262
402
 
263
403
  def get_direction(self) -> snl.SNLTerm.Direction:
264
404
  """Return the direction of the term."""
265
- if self.term.getDirection() == snl.SNLTerm.Direction.Input:
405
+ snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
406
+ if snlterm.getDirection() == snl.SNLTerm.Direction.Input:
266
407
  return Term.INPUT
267
- elif self.term.getDirection() == snl.SNLTerm.Direction.Output:
408
+ elif snlterm.getDirection() == snl.SNLTerm.Direction.Output:
268
409
  return Term.OUTPUT
269
- elif self.term.getDirection() == snl.SNLTerm.Direction.InOut:
410
+ elif snlterm.getDirection() == snl.SNLTerm.Direction.InOut:
270
411
  return Term.INOUT
271
412
 
272
413
  def __get_snl_bitnet(self, bit) -> Net:
273
414
  # single bit
274
- if self.path.size() > 0:
275
- instTerm = self.path.getTailInstance().getInstTerm(bit)
415
+ path = get_snl_path_from_id_list(self.pathIDs)
416
+ if path.size() > 0:
417
+ instTerm = path.getTailInstance().getInstTerm(bit)
276
418
  return instTerm.getNet()
277
419
  else:
278
420
  return bit.getNet()
@@ -300,9 +442,9 @@ class Term:
300
442
  return snl_bus_net
301
443
 
302
444
  def __get_net(self, path, snl_term_net_accessor) -> Net:
303
- if isinstance(self.term, snl.SNLBusTerm):
445
+ if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
304
446
  snl_nets = []
305
- for bit in self.term.getBits():
447
+ for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
306
448
  snl_net = snl_term_net_accessor(bit)
307
449
  snl_nets.append(snl_net)
308
450
  snl_bus_net = self.__get_snl_busnet(snl_nets)
@@ -312,57 +454,62 @@ class Term:
312
454
  if all(element is not None for element in snl_nets):
313
455
  return Net(path, net_concat=snl_nets)
314
456
  else:
315
- snl_net = snl_term_net_accessor(self.term)
457
+ snl_net = snl_term_net_accessor(get_snl_term_for_ids(self.pathIDs, self.termIDs))
316
458
  if snl_net is not None:
317
459
  return Net(path, snl_net)
318
460
  return None
319
461
 
320
462
  def get_lower_net(self) -> Net:
321
463
  """Return the lower net of the term."""
322
- return self.__get_net(self.path, self.__get_snl_lower_bitnet)
464
+ return self.__get_net(self.pathIDs, self.__get_snl_lower_bitnet)
323
465
 
324
466
  def get_net(self) -> Net:
325
467
  """Return the net of the term."""
326
- if self.path.empty():
468
+ head_path = self.pathIDs.copy()
469
+ if len(head_path) == 0:
327
470
  return None
328
471
  # path is one level up
329
- path = self.path.getHeadPath()
330
- return self.__get_net(path, self.__get_snl_bitnet)
472
+ head_path.pop()
473
+ return self.__get_net(head_path, self.__get_snl_bitnet)
331
474
 
332
475
  def get_instance(self):
333
476
  """Return the instance of the term."""
334
- return Instance(self.path)
477
+ return Instance(self.pathIDs)
335
478
 
336
479
  def get_flat_fanout(self):
337
- return self.get_equipotential().get_all_leaf_readers()
480
+ return self.get_equipotential().get_leaf_readers()
338
481
 
339
482
  def get_equipotential(self) -> Equipotential:
340
483
  return Equipotential(self)
341
484
 
342
485
  def is_input(self) -> bool:
343
486
  """Return True if the term is an input."""
344
- return self.term.getDirection() == snl.SNLTerm.Direction.Input
487
+ snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
488
+ return snlterm.getDirection() == snl.SNLTerm.Direction.Input
345
489
 
346
490
  def is_output(self) -> bool:
347
491
  """Return True if the term is an output."""
348
- return self.term.getDirection() == snl.SNLTerm.Direction.Output
492
+ snlterm = get_snl_term_for_ids(self.pathIDs, self.termIDs)
493
+ return snlterm.getDirection() == snl.SNLTerm.Direction.Output
349
494
 
350
495
  def get_bits(self):
351
- if isinstance(self.term, snl.SNLBusTerm):
352
- for bit in self.term.getBits():
353
- yield Term(self.path, bit)
496
+ if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
497
+ for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
498
+ yield Term(self.pathIDs, bit)
354
499
  else:
355
500
  yield self
356
501
 
357
502
  def get_bit(self, index: int):
358
- if isinstance(self.term, snl.SNLBusTerm):
359
- return Term(self.path, self.term.getBit(index))
503
+ if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
504
+ return Term(self.pathIDs, get_snl_term_for_ids(
505
+ self.pathIDs, self.termIDs).getBit(index))
360
506
  return None
361
507
 
362
508
  def disconnect(self):
509
+ path = get_snl_path_from_id_list(self.pathIDs)
363
510
  self.__make_unique()
364
- inst = self.path.getTailInstance()
365
- for bit in self.term.getBits():
511
+ inst = path.getTailInstance()
512
+ for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
366
513
  iterm = inst.getInstTerm(bit)
367
514
  iterm.setNet(None)
368
515
 
@@ -370,13 +517,18 @@ class Term:
370
517
  if self.get_width() != net.get_width():
371
518
  raise ValueError("Width mismatch")
372
519
  if self.get_instance().is_top():
373
- for bterm, bnet in zip(self.term.getBits(), net.net.getBits()):
520
+ for bterm, bnet in zip(get_snl_term_for_ids(self.pathIDs,
521
+ self.termIDs).getBits(),
522
+ net.net.getBits()):
374
523
  logging.debug(f"Connecting {bterm} to {bnet}")
375
524
  bterm.setNet(bnet)
376
525
  else:
377
526
  self.__make_unique()
378
- inst = self.path.getTailInstance()
379
- for bterm, bnet in zip(self.term.getBits(), net.net.getBits()):
527
+ path = get_snl_path_from_id_list(self.pathIDs)
528
+ inst = path.getTailInstance()
529
+ for bterm, bnet in zip(get_snl_term_for_ids(self.pathIDs,
530
+ self.termIDs).getBits(),
531
+ net.net.getBits()):
380
532
  iterm = inst.getInstTerm(bterm)
381
533
  iterm.setNet(bnet)
382
534
 
@@ -396,19 +548,15 @@ def get_instance_by_path(names: list):
396
548
 
397
549
 
398
550
  def refresh_path(path: snl.SNLPath):
399
- pathlist = []
400
- pathTemp = path
401
- while pathTemp.size() > 0:
402
- pathlist.append(pathTemp.getHeadInstance().getName())
403
- pathTemp = pathTemp.getTailPath()
551
+ pathlist = path.getPathIDs()
404
552
  assert len(pathlist) > 0
405
553
  path = snl.SNLPath()
406
554
  instance = None
407
555
  top = snl.SNLUniverse.get().getTopDesign()
408
556
  design = top
409
- for name in pathlist:
410
- path = snl.SNLPath(path, design.getInstance(name))
411
- instance = design.getInstance(name)
557
+ for id in pathlist:
558
+ path = snl.SNLPath(path, design.getInstanceByID(id))
559
+ instance = design.getInstanceByID(id)
412
560
  assert instance is not None
413
561
  design = instance.getModel()
414
562
  return path
@@ -420,10 +568,16 @@ class Instance:
420
568
  """
421
569
 
422
570
  def __init__(self, path=snl.SNLPath()):
423
- self.path = path
571
+ if isinstance(path, snl.SNLPath):
572
+ if path.size() > 0:
573
+ self.pathIDs = path.getPathIDs()
574
+ else:
575
+ self.pathIDs = []
576
+ elif isinstance(path, list):
577
+ self.pathIDs = path.copy()
424
578
 
425
579
  def __eq__(self, other) -> bool:
426
- return self.path == other.path
580
+ return self.pathIDs == other.pathIDs
427
581
 
428
582
  def __str__(self):
429
583
  if self.is_top():
@@ -433,17 +587,36 @@ class Instance:
433
587
  else:
434
588
  return ""
435
589
  else:
436
- return str(self.path)
590
+ path = get_snl_path_from_id_list(self.pathIDs)
591
+ return str(path)
437
592
 
438
593
  def __repr__(self) -> str:
439
- return f"Instance({self.path})"
594
+ path = get_snl_path_from_id_list(self.pathIDs)
595
+ return f"Instance({path})"
440
596
 
441
- # def __hash__(self):
442
- # return hash(self.path)
597
+ def __hash__(self):
598
+ return consistent_hash(self.pathIDs)
599
+
600
+ def get_leaf_children(self):
601
+ initial_path = get_snl_path_from_id_list(self.pathIDs)
602
+ for inst in self.__get_snl_model().getInstances():
603
+ if inst.getModel().isLeaf():
604
+ yield Instance(snl.SNLPath(initial_path, inst))
605
+ path = snl.SNLPath(initial_path, inst)
606
+ stack = [[inst, path]]
607
+ while stack:
608
+ current = stack.pop()
609
+ current_inst = current[0]
610
+ current_path = current[1]
611
+ for inst_child in current_inst.getModel().getInstances():
612
+ path_child = snl.SNLPath(current_path, inst_child)
613
+ if inst_child.getModel().isLeaf():
614
+ yield Instance(path_child)
615
+ stack.append([inst_child, path_child])
443
616
 
444
617
  def is_top(self) -> bool:
445
618
  """Return True if this is the top design."""
446
- return self.path.size() == 0
619
+ return len(self.pathIDs) == 0
447
620
 
448
621
  def is_assign(self) -> bool:
449
622
  return self.__get_snl_model().isAssign()
@@ -480,7 +653,8 @@ class Instance:
480
653
  """Return the model of the instance."""
481
654
  if self.is_top():
482
655
  return snl.SNLUniverse.get().getTopDesign()
483
- return self.path.getTailInstance().getModel()
656
+ instance = get_snl_instance_from_id_list(self.pathIDs)
657
+ return instance.getModel()
484
658
 
485
659
  def __find_snl_model(self, name: str) -> snl.SNLDesign:
486
660
  u = snl.SNLUniverse.get()
@@ -491,15 +665,26 @@ class Instance:
491
665
  return found_model
492
666
  return None
493
667
 
668
+ def dump_full_dot(self, path: str):
669
+ """Dump the full dot file of this instance."""
670
+ self.__get_snl_model().dumpFullDotFile(path)
671
+
672
+ def dump_context_dot(self, path: str):
673
+ self.__get_snl_model().dumpContextDotFile(path)
674
+
494
675
  def get_child_instance(self, name: str):
676
+ """Return the child instance with the given name."""
495
677
  childInst = self.__get_snl_model().getInstance(name)
496
678
  if childInst is None:
497
679
  return None
498
- return Instance(snl.SNLPath(self.path, childInst))
680
+ path = self.pathIDs.copy()
681
+ path.append(childInst.getID())
682
+ return Instance(path)
499
683
 
500
684
  def get_child_instances(self):
501
685
  for inst in self.__get_snl_model().getInstances():
502
- path = snl.SNLPath(self.path, inst)
686
+ path = self.pathIDs.copy()
687
+ path.append(inst.getID())
503
688
  yield Instance(path)
504
689
 
505
690
  def get_number_of_child_instances(self) -> int:
@@ -522,21 +707,28 @@ class Instance:
522
707
  # stack.append([inst_child, path_child])
523
708
 
524
709
  def get_nets(self):
710
+ """Return the nets of the instance.
711
+ This will iterate over all scalar nets and bus nets.
712
+ """
525
713
  for net in self.__get_snl_model().getNets():
526
- yield Net(self.path, net)
714
+ yield Net(self.pathIDs, net)
527
715
 
528
716
  def get_flat_nets(self):
717
+ """Return the nets of the instance.
718
+ This will iterate over all scalar nets and bus net bits.
719
+ """
529
720
  for net in self.__get_snl_model().getNets():
530
721
  if isinstance(net, snl.SNLBusNet):
531
722
  for bit in net.getBits():
532
- yield Net(self.path, bit)
723
+ yield Net(self.pathIDs, bit)
533
724
  else:
534
- yield Net(self.path, net)
725
+ yield Net(self.pathIDs, net)
535
726
 
536
727
  def get_net(self, name: str) -> Net:
728
+ """Return the net with the given name."""
537
729
  net = self.__get_snl_model().getNet(name)
538
730
  if net is not None:
539
- return Net(self.path, net)
731
+ return Net(self.pathIDs, net)
540
732
  return None
541
733
 
542
734
  def is_primitive(self) -> bool:
@@ -544,75 +736,124 @@ class Instance:
544
736
  return self.__get_snl_model().isPrimitive()
545
737
 
546
738
  def get_terms(self):
739
+ """Return the terms of the instance.
740
+ This will iterate over all scalar terms and bus terms.
741
+ """
547
742
  for term in self.__get_snl_model().getTerms():
548
- yield Term(self.path, term)
743
+ yield Term(self.pathIDs, term)
549
744
 
550
745
  def get_flat_terms(self):
746
+ """Return the flat terms of the instance.
747
+ This will iterate over all scalar terms and bus term bits.
748
+ """
551
749
  for term in self.__get_snl_model().getBitTerms():
552
- yield Term(self.path, term)
750
+ yield Term(self.pathIDs, term)
553
751
 
554
752
  def get_term(self, name: str) -> Term:
753
+ """Return the term with the given name."""
555
754
  term = self.__get_snl_model().getTerm(name)
556
755
  if term is not None:
557
- return Term(self.path, self.__get_snl_model().getTerm(name))
756
+ return Term(self.pathIDs, self.__get_snl_model().getTerm(name))
558
757
  return None
559
758
 
560
759
  def get_input_terms(self):
760
+ """Return the input terms of the instance.
761
+ This will iterate over all scalar input terms and bus input terms.
762
+ """
561
763
  for term in self.__get_snl_model().getTerms():
562
- if term.getDirection() == snl.SNLTerm.Direction.Input:
563
- yield Term(self.path, term)
764
+ if term.getDirection() != snl.SNLTerm.Direction.Output:
765
+ yield Term(self.pathIDs, term)
564
766
 
565
767
  def get_flat_input_terms(self):
768
+ """Return the flat input terms of the instance.
769
+ This will iterate over all scalar input terms and bus input term bits.
770
+ """
566
771
  for term in self.__get_snl_model().getTerms():
567
- if term.getDirection() == snl.SNLTerm.Direction.Input:
772
+ if term.getDirection() != snl.SNLTerm.Direction.Output:
568
773
  if isinstance(term, snl.SNLBusTerm):
569
774
  for bit in term.getBits():
570
- yield Term(self.path, bit)
775
+ yield Term(self.pathIDs, bit)
571
776
  else:
572
- yield Term(self.path, term)
777
+ yield Term(self.pathIDs, term)
573
778
 
574
779
  def get_output_terms(self):
780
+ """Return the output terms of the instance.
781
+ This will iterate over all scalar output terms and bus output terms.
782
+ """
575
783
  for term in self.__get_snl_model().getTerms():
576
- if term.getDirection() == snl.SNLTerm.Direction.Output:
577
- yield Term(self.path, term)
784
+ if term.getDirection() != snl.SNLTerm.Direction.Input:
785
+ yield Term(self.pathIDs, term)
578
786
 
579
787
  def get_flat_output_terms(self):
788
+ """Return the flat output terms of the instance.
789
+ This will iterate over all scalar output terms and bus output term bits.
790
+ """
580
791
  for term in self.__get_snl_model().getTerms():
581
- if term.getDirection() == snl.SNLTerm.Direction.Output:
792
+ if term.getDirection() != snl.SNLTerm.Direction.Input:
582
793
  if isinstance(term, snl.SNLBusTerm):
583
794
  for bit in term.getBits():
584
- yield Term(self.path, bit)
795
+ yield Term(self.pathIDs, bit)
585
796
  else:
586
- yield Term(self.path, term)
797
+ yield Term(self.pathIDs, term)
587
798
 
588
799
  def delete_instance(self, name: str):
589
- path = snl.SNLPath(self.path, self.__get_snl_model().getInstance(name))
800
+ """Delete the child instance with the given name."""
801
+ if name == "":
802
+ raise ValueError(
803
+ "Cannot delete instance with empty name. Try delete_instance_by_id instead."
804
+ )
805
+ init_path = get_snl_path_from_id_list(self.pathIDs)
806
+ path = snl.SNLPath(init_path, self.__get_snl_model().getInstance(name))
807
+ snl.SNLUniquifier(path)
808
+ if init_path.size() > 0:
809
+ # Delete the last instance in uniq_path
810
+ self.__get_snl_model().getInstance(name).destroy()
811
+
812
+ def delete_instance_by_id(self, id: str):
813
+ """Delete the child instance with the given ID."""
814
+ init_path = get_snl_path_from_id_list(self.pathIDs)
815
+ path = snl.SNLPath(init_path, self.__get_snl_model().getInstanceByID(id))
590
816
  snl.SNLUniquifier(path)
591
- if self.path.size() > 0:
592
- self.path = refresh_path(self.path)
593
817
  # Delete the last instance in uniq_path
594
- self.__get_snl_model().getInstance(name).destroy()
818
+ self.__get_snl_model().getInstanceByID(id).destroy()
819
+
820
+ def get_design(self):
821
+ """Return the Instance containing this instance."""
822
+ path = self.pathIDs.copy()
823
+ if len(self.pathIDs) == 1:
824
+ return get_top()
825
+ path.pop()
826
+ return Instance(path)
827
+
828
+ def delete(self):
829
+ """Delete this instance."""
830
+ path = get_snl_path_from_id_list(self.pathIDs)
831
+ snl.SNLUniquifier(path)
832
+ self.get_design().delete_instance_by_id(path.getTailInstance().getID())
595
833
 
596
834
  def get_name(self) -> str:
597
835
  """Return the name of the instance or name of the top is this is the top."""
836
+ path = get_snl_path_from_id_list(self.pathIDs)
598
837
  if self.is_top():
599
838
  return self.get_model_name()
600
839
  else:
601
- return self.path.getTailInstance().getName()
840
+ return path.getTailInstance().getName()
602
841
 
603
842
  def get_model_name(self) -> str:
604
843
  """Return the name of the model of the instance or name of the top is this is the top."""
605
844
  return self.__get_snl_model().getName()
606
845
 
607
846
  def get_model_id(self) -> tuple[int, int, int]:
847
+ """Return the ID of the model of the instance or ID of the top is this is the top."""
608
848
  model = self.__get_snl_model()
609
849
  return model.getDB().getID(), model.getLibrary().getID(), model.getID()
610
850
 
611
851
  def create_child_instance(self, model: str, name: str):
612
- if self.path.size() > 0:
613
- path = self.path
852
+ """Create a child instance with the given model and name."""
853
+ path = get_snl_path_from_id_list(self.pathIDs)
854
+ if path.size() > 0:
614
855
  snl.SNLUniquifier(path)
615
- self.path = refresh_path(self.path)
856
+ path = get_snl_path_from_id_list(self.pathIDs)
616
857
  design = self.__get_snl_model()
617
858
  new_instance_model = self.__find_snl_model(model)
618
859
  if new_instance_model is None:
@@ -620,64 +861,75 @@ class Instance:
620
861
  f"Cannot create instance {name} in {self}: model {model} cannot be found"
621
862
  )
622
863
  newSNLInstance = snl.SNLInstance.create(design, new_instance_model, name)
623
- path = snl.SNLPath(self.path, newSNLInstance)
864
+ path = snl.SNLPath(path, newSNLInstance)
624
865
  return Instance(path)
625
866
 
626
867
  def create_term(self, name: str, direction: snl.SNLTerm.Direction) -> Term:
627
- if self.path.size() > 0:
628
- path = self.path
868
+ """Create a Term in this Instance with the given name and direction."""
869
+ path = get_snl_path_from_id_list(self.pathIDs)
870
+ if path.size() > 0:
629
871
  snl.SNLUniquifier(path)
630
- self.path = refresh_path(self.path)
872
+ path = get_snl_path_from_id_list(self.pathIDs)
631
873
  design = self.__get_snl_model()
632
874
  newSNLTerm = snl.SNLScalarTerm.create(design, direction, name)
633
- return Term(self.path, newSNLTerm)
875
+ return Term(path, newSNLTerm)
634
876
 
635
877
  def create_output_term(self, name: str) -> Term:
878
+ """Create an output Term in this Instance with the given name."""
636
879
  return self.create_term(name, snl.SNLTerm.Direction.Output)
637
880
 
638
881
  def create_input_term(self, name: str) -> Term:
882
+ """Create an input Term in this Instance with the given name."""
639
883
  return self.create_term(name, snl.SNLTerm.Direction.Input)
640
884
 
641
885
  def create_inout_term(self, name: str) -> Term:
886
+ """Create an inout Term in this Instance with the given name."""
642
887
  return self.create_term(name, snl.SNLTerm.Direction.InOut)
643
888
 
644
889
  def create_bus_term(self, name: str, msb: int, lsb: int, direction) -> Term:
645
- if self.path.size() > 0:
646
- path = self.path
890
+ """Create a bus Term in this Instance with the given name, msb, lsb and direction."""
891
+ path = get_snl_path_from_id_list(self.pathIDs)
892
+ if path.size() > 0:
647
893
  snl.SNLUniquifier(path)
648
- self.path = refresh_path(self.path)
894
+ path = get_snl_path_from_id_list(self.pathIDs)
649
895
  design = self.__get_snl_model()
650
896
  newSNLTerm = snl.SNLBusTerm.create(design, direction, msb, lsb, name)
651
- return Term(self.path, newSNLTerm)
897
+ return Term(path, newSNLTerm)
652
898
 
653
899
  def create_inout_bus_term(self, name: str, msb: int, lsb: int) -> Term:
900
+ """Create an inout bus Term in this Instance with the given name, msb and lsb."""
654
901
  return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.InOut)
655
902
 
656
903
  def create_output_bus_term(self, name: str, msb: int, lsb: int) -> Term:
904
+ """Create an output bus Term in this Instance with the given name, msb and lsb."""
657
905
  return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Output)
658
906
 
659
907
  def create_input_bus_term(self, name: str, msb: int, lsb: int) -> Term:
908
+ """Create an input bus Term in this Instance with the given name, msb and lsb."""
660
909
  return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Input)
661
910
 
662
911
  def create_net(self, name: str) -> Net:
663
- if self.path.size() > 0:
664
- path = self.path
912
+ """Create a scalar Net in this Instance with the given name."""
913
+ path = get_snl_path_from_id_list(self.pathIDs)
914
+ if path.size() > 0:
665
915
  snl.SNLUniquifier(path)
666
- self.path = refresh_path(self.path)
916
+ path = get_snl_path_from_id_list(self.pathIDs)
667
917
  model = self.__get_snl_model()
668
918
  newSNLNet = snl.SNLScalarNet.create(model, name)
669
- return Net(self.path, newSNLNet)
919
+ return Net(path, newSNLNet)
670
920
 
671
921
  def create_bus_net(self, name: str, msb: int, lsb: int) -> Net:
672
- if self.path.size() > 0:
673
- path = self.path
922
+ """Create a bus Net in this Instance with the given name, msb and lsb."""
923
+ path = get_snl_path_from_id_list(self.pathIDs)
924
+ if path.size() > 0:
674
925
  snl.SNLUniquifier(path)
675
- self.path = refresh_path(self.path)
926
+ path = get_snl_path_from_id_list(self.pathIDs)
676
927
  model = self.__get_snl_model()
677
928
  newSNLNet = snl.SNLBusNet.create(model, msb, lsb, name)
678
- return Net(self.path, newSNLNet)
929
+ return Net(path, newSNLNet)
679
930
 
680
931
  def dump_verilog(self, path: str, name: str):
932
+ """Dump the verilog of this instance."""
681
933
  self.__get_snl_model().dumpVerilog(path, name)
682
934
 
683
935
 
@@ -731,7 +983,7 @@ def load_primitives(name: str):
731
983
  def get_primitives_library() -> snl.SNLLibrary:
732
984
  lib = get_top_db().getLibrary("PRIMS")
733
985
  if lib is None:
734
- lib = snl.SNLLibrary.createPrimitives(get_top_db())
986
+ lib = snl.SNLLibrary.createPrimitives(get_top_db(), "PRIMS")
735
987
  return lib
736
988
 
737
989