najaeda 0.1.0__cp311-cp311-macosx_11_0_arm64.whl → 0.1.2__cp311-cp311-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of najaeda might be problematic. Click here for more details.

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