najaeda 0.1.11__cp313-cp313-macosx_11_0_arm64.whl → 0.1.13__cp313-cp313-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.

Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ Common Classes
2
+ ==============
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+ :caption: Contents:
7
+
8
+ .. autoclass:: najaeda.netlist.Attribute
9
+ :members:
10
+ :undoc-members:
11
+ :show-inheritance:
@@ -11,9 +11,7 @@ najaeda documentation
11
11
  :caption: Contents:
12
12
 
13
13
  introduction
14
- instance
15
- term
16
- net
17
- equipotential
14
+ netlist_classes
15
+ common_classes
18
16
  examples
19
17
  api
@@ -0,0 +1,11 @@
1
+ Netlist Classes
2
+ ===============
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+ :caption: Contents:
7
+
8
+ instance
9
+ term
10
+ net
11
+ equipotential
najaeda/libnaja_snl.dylib CHANGED
Binary file
Binary file
najaeda/net_visitor.py ADDED
@@ -0,0 +1,53 @@
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
+ # from typing import Callable
7
+ # from najaeda import netlist
8
+ #
9
+ #
10
+ # class VisitorConfig:
11
+ # def __init__(
12
+ # self,
13
+ # enter_condition: Callable[[netlist.Instance], bool] = lambda node: True,
14
+ # callback: Callable[..., None] = lambda node, *args, **kwargs: None,
15
+ # args: tuple = (),
16
+ # kwargs: dict = None,
17
+ # ):
18
+ # """
19
+ # :param enter_condition: A callable that takes a node (dict)
20
+ # and returns True if the visitor should enter.
21
+ # :param callback: A callable that takes a node (dict) and performs an operation on it.
22
+ # :param args: Positional arguments to pass to the callback.
23
+ # :param kwargs: Keyword arguments to pass to the callback.
24
+ # """
25
+ # self.enter_condition = enter_condition
26
+ # self.callback = callback
27
+ # self.args = args
28
+ # self.kwargs = kwargs or {}
29
+ #
30
+ #
31
+ # def visit(equipotential: netlist.Equipotential, config: VisitorConfig):
32
+ # """Recursively visits nodes in the netlist hierarchy.
33
+ #
34
+ # :param instance: The current node in the netlist instance hierarchy.
35
+ # :param config: VisitorConfig object defining conditions and callbacks.
36
+ # """
37
+ # # Execute the callback
38
+ # config.callback(equipotential, *config.args, **config.kwargs)
39
+ #
40
+ # # Check if we should proceed to children
41
+ # if config.enter_condition(equipotential):
42
+ # for component in equipotential.get .get_child_instances():
43
+ # visit(child, config)
44
+ #
45
+ # def visit(term: netlist.Term, config: VisitorConfig):
46
+ # config.callback(term, *config.args, **config.kwargs)
47
+ #
48
+ # #get the corresponding iterms
49
+ # instance = term.get_instance()
50
+ # if instance is not None:
51
+ # for iterm in instance.get_iterms():
52
+ # visit(iterm, config)
53
+ #
najaeda/netlist.py CHANGED
@@ -8,11 +8,16 @@ import time
8
8
  import logging
9
9
  import hashlib
10
10
  import struct
11
+ import sys
11
12
  from enum import Enum
12
13
 
13
14
  from najaeda import snl
14
15
 
15
16
 
17
+ def get_none_existent():
18
+ return sys.maxsize
19
+
20
+
16
21
  def consistent_hash(obj):
17
22
  def default_serializer(o):
18
23
  if isinstance(o, (str, int, float, bool, type(None))):
@@ -40,14 +45,14 @@ def consistent_hash(obj):
40
45
 
41
46
 
42
47
  def get_snl_instance_from_id_list(id_list: list) -> snl.SNLInstance:
43
- top = snl.SNLUniverse.get().getTopDesign()
44
- design = top
45
- instance = None
46
- for id in id_list:
47
- instance = design.getInstanceByID(id)
48
- assert instance is not None
49
- design = instance.getModel()
50
- return instance
48
+ design = snl.SNLUniverse.get().getTopDesign()
49
+ # instance = None
50
+ # for id in id_list:
51
+ # instance = design.getInstanceByID(id)
52
+ # assert instance is not None
53
+ # design = instance.getModel()
54
+ # return instance
55
+ return design.getInstanceByIDList(id_list)
51
56
 
52
57
 
53
58
  def get_snl_path_from_id_list(id_list: list) -> snl.SNLPath:
@@ -71,7 +76,8 @@ class Equipotential:
71
76
  """
72
77
 
73
78
  def __init__(self, term):
74
- snl_term = get_snl_term_for_ids(term.pathIDs, term.termIDs)
79
+ path = get_snl_path_from_id_list(term.pathIDs)
80
+ snl_term = get_snl_term_for_ids_with_path(path, term.termIDs)
75
81
  inst_term = None
76
82
  if isinstance(snl_term, snl.SNLBusTerm):
77
83
  raise ValueError("Equipotential cannot be constructed on bus term")
@@ -85,10 +91,10 @@ class Equipotential:
85
91
  self.equi = None
86
92
  return
87
93
  else:
94
+ path = snl.SNLPath(path, get_snl_instance_from_id_list(inst_term.pathIDs))
88
95
  snl_term = get_snl_term_for_ids(inst_term.pathIDs, inst_term.termIDs)
89
96
  else:
90
97
  inst_term = term
91
- path = get_snl_path_from_id_list(inst_term.pathIDs)
92
98
  ito = snl.SNLNetComponentOccurrence(
93
99
  path.getHeadPath(), path.getTailInstance().getInstTerm(snl_term)
94
100
  )
@@ -109,10 +115,10 @@ class Equipotential:
109
115
  """
110
116
  if self.equi is not None:
111
117
  for term in self.equi.getInstTermOccurrences():
112
- yield Term(
113
- snl.SNLPath(term.getPath(), term.getInstTerm().getInstance()),
114
- term.getInstTerm().getBitTerm(),
115
- )
118
+ path = term.getPath().getPathIDs()
119
+ path.append(term.getInstTerm().getInstance().getID())
120
+ yield Term(path,
121
+ term.getInstTerm().getBitTerm())
116
122
 
117
123
  def get_top_terms(self):
118
124
  """Iterate over the top terminals of this equipotential.
@@ -130,12 +136,10 @@ class Equipotential:
130
136
  direction = term.getInstTerm().getDirection()
131
137
  if direction != snl.SNLTerm.Direction.Output:
132
138
  if term.getInstTerm().getInstance().getModel().isLeaf():
133
- yield Term(
134
- snl.SNLPath(
135
- term.getPath(), term.getInstTerm().getInstance()
136
- ),
137
- term.getInstTerm().getBitTerm(),
138
- )
139
+ path = term.getPath().getPathIDs()
140
+ path.append(term.getInstTerm().getInstance().getID())
141
+ yield Term(path,
142
+ term.getInstTerm().getBitTerm())
139
143
 
140
144
  def get_leaf_drivers(self):
141
145
  if self.equi is not None:
@@ -143,26 +147,24 @@ class Equipotential:
143
147
  direction = term.getInstTerm().getDirection()
144
148
  if direction != snl.SNLTerm.Direction.Input:
145
149
  if term.getInstTerm().getInstance().getModel().isLeaf():
146
- yield Term(
147
- snl.SNLPath(
148
- term.getPath(), term.getInstTerm().getInstance()
149
- ),
150
- term.getInstTerm().getBitTerm(),
151
- )
150
+ path = term.getPath().getPathIDs()
151
+ path.append(term.getInstTerm().getInstance().getID())
152
+ yield Term(path,
153
+ term.getInstTerm().getBitTerm())
152
154
 
153
155
  def get_top_readers(self):
154
156
  if self.equi is not None:
155
157
  for term in self.equi.getTerms():
156
158
  direction = term.getDirection()
157
159
  if direction != snl.SNLTerm.Direction.Input:
158
- yield Term(snl.SNLPath(), term)
160
+ yield Term([], term)
159
161
 
160
162
  def get_top_drivers(self):
161
163
  if self.equi is not None:
162
164
  for term in self.equi.getTerms():
163
165
  direction = term.getDirection()
164
166
  if direction != snl.SNLTerm.Direction.Output:
165
- yield Term(snl.SNLPath(), term)
167
+ yield Term([], term)
166
168
 
167
169
 
168
170
  class Net:
@@ -343,10 +345,11 @@ class Net:
343
345
  """
344
346
  if hasattr(self, "net_concat"):
345
347
  raise ValueError("Cannot get inst terms from a net_concat")
348
+ path = self.pathIDs.copy()
346
349
  for term in self.net.getInstTerms():
347
- path = self.pathIDs.copy()
348
350
  path.append(term.getInstance().getID())
349
351
  yield Term(path, term.getBitTerm())
352
+ path.pop()
350
353
 
351
354
  def get_design_terms(self):
352
355
  """
@@ -374,12 +377,28 @@ def get_snl_term_for_ids(pathIDs, termIDs):
374
377
  model = snl.SNLUniverse.get().getTopDesign()
375
378
  else:
376
379
  model = path.getTailInstance().getModel()
377
- if termIDs[1] == -1:
380
+ if termIDs[1] == get_none_existent():
378
381
  return model.getTermByID(termIDs[0])
379
382
  else:
380
383
  snlterm = model.getTermByID(termIDs[0])
381
384
  if isinstance(snlterm, snl.SNLBusTerm):
382
- return snlterm.getBit(termIDs[1])
385
+ return snlterm.getBusTermBit(termIDs[1])
386
+ else:
387
+ return snlterm
388
+
389
+
390
+ def get_snl_term_for_ids_with_path(path, termIDs):
391
+ model = None
392
+ if path.size() == 0:
393
+ model = snl.SNLUniverse.get().getTopDesign()
394
+ else:
395
+ model = path.getTailInstance().getModel()
396
+ if termIDs[1] == get_none_existent():
397
+ return model.getTermByID(termIDs[0])
398
+ else:
399
+ snlterm = model.getTermByID(termIDs[0])
400
+ if isinstance(snlterm, snl.SNLBusTerm):
401
+ return snlterm.getBusTermBit(termIDs[1])
383
402
  else:
384
403
  return snlterm
385
404
 
@@ -390,19 +409,12 @@ class Term:
390
409
  INOUT = snl.SNLTerm.Direction.InOut
391
410
 
392
411
  def __init__(self, path, term):
393
- self.termIDs = []
394
- if isinstance(term, snl.SNLBusTerm):
395
- self.termIDs = [term.getID(), -1]
396
- else:
397
- self.termIDs = [term.getID(), term.getBit()]
398
-
399
- if isinstance(path, snl.SNLPath):
400
- if path.size() > 0:
401
- self.pathIDs = path.getPathIDs()
402
- else:
403
- self.pathIDs = []
404
- elif isinstance(path, list):
405
- self.pathIDs = path.copy()
412
+ # self.termIDs = []
413
+ # if isinstance(term, snl.SNLBusTerm):
414
+ # self.termIDs = [term.getID(), -1]
415
+ # else:
416
+ self.termIDs = [term.getID(), term.getBit()]
417
+ self.pathIDs = path.copy()
406
418
 
407
419
  def __eq__(self, other) -> bool:
408
420
  return self.pathIDs == other.pathIDs and self.termIDs == other.termIDs
@@ -434,13 +446,19 @@ class Term:
434
446
  return consistent_hash((self.pathIDs, termIDs))
435
447
 
436
448
  def __str__(self):
449
+ term_str = ""
437
450
  path = get_snl_path_from_id_list(self.pathIDs)
438
451
  if path.size() == 0:
439
- return get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()
452
+ term_str = get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()
440
453
  else:
441
- return (
454
+ term_str = (
442
455
  f"{path}/{get_snl_term_for_ids(self.pathIDs, self.termIDs).getName()}"
443
456
  )
457
+ if self.is_bus:
458
+ term_str += f"[{self.get_msb()}:{self.get_lsb()}]"
459
+ elif self.is_bus_bit:
460
+ term_str += f"[{self.get_lsb()}]"
461
+ return term_str
444
462
 
445
463
  def __repr__(self) -> str:
446
464
  path = get_snl_path_from_id_list(self.pathIDs)
@@ -486,6 +504,17 @@ class Term:
486
504
  """
487
505
  return self.is_scalar() or self.is_bus_bit()
488
506
 
507
+ def get_bit_number(self):
508
+ """
509
+ :return: the bit index of the term if it is a bit.
510
+ :rtype: int or None
511
+ """
512
+ if isinstance(
513
+ get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTermBit
514
+ ):
515
+ return get_snl_term_for_ids(self.pathIDs, self.termIDs).getBit()
516
+ return None
517
+
489
518
  def get_msb(self) -> int:
490
519
  """
491
520
  :return: the most significant bit of the term if it is a bus.
@@ -651,7 +680,7 @@ class Term:
651
680
  if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
652
681
  return Term(
653
682
  self.pathIDs,
654
- get_snl_term_for_ids(self.pathIDs, self.termIDs).getBit(index),
683
+ get_snl_term_for_ids(self.pathIDs, self.termIDs).getBusTermBit(index),
655
684
  )
656
685
  return None
657
686
 
@@ -727,12 +756,24 @@ class Attribute:
727
756
  return str(self.snlAttribute)
728
757
 
729
758
  def get_name(self):
759
+ """
760
+ :return: the name of the attribute.
761
+ :rtype: str
762
+ """
730
763
  return self.snlAttribute.getName()
731
764
 
732
765
  def has_value(self):
766
+ """
767
+ :return: True if the attribute has a value.
768
+ :rtype: bool
769
+ """
733
770
  return self.snlAttribute.hasValue()
734
771
 
735
772
  def get_value(self):
773
+ """
774
+ :return: the value of the attribute.
775
+ :rtype: str
776
+ """
736
777
  return self.snlAttribute.getValue()
737
778
 
738
779
 
@@ -742,13 +783,23 @@ class Instance:
742
783
  """
743
784
 
744
785
  def __init__(self, path=snl.SNLPath()):
786
+ self.inst = None
787
+ self.revisionCount = 0
788
+ self.SNLID = [0, 0, 0, 0, 0, 0]
745
789
  if isinstance(path, snl.SNLPath):
746
790
  if path.size() > 0:
747
791
  self.pathIDs = path.getPathIDs()
792
+ self.revisionCount = path.getTailInstance().getModel().getRevisionCount()
793
+ self.inst = path.getTailInstance()
748
794
  else:
749
795
  self.pathIDs = []
750
796
  elif isinstance(path, list):
751
797
  self.pathIDs = path.copy()
798
+ if len(path) > 0:
799
+ self.inst = get_snl_instance_from_id_list(path)
800
+ self.revisionCount = self.inst.getModel().getRevisionCount()
801
+ if self.inst is not None:
802
+ self.SNLID = self.inst.getModel().getSNLID()
752
803
 
753
804
  def __eq__(self, other) -> bool:
754
805
  return self.pathIDs == other.pathIDs
@@ -774,6 +825,7 @@ class Instance:
774
825
  def get_leaf_children(self):
775
826
  """Iterate over the leaf children of this Instance.
776
827
  Equivalent to the underlying leaves of the instanciation tree.
828
+
777
829
  :return: an iterator over the leaf children Instance of this Instance.
778
830
  :rtype: Iterator[Instance]
779
831
  """
@@ -801,7 +853,7 @@ class Instance:
801
853
  return len(self.pathIDs) == 0
802
854
 
803
855
  def is_assign(self) -> bool:
804
- """Example: (assign a=b) will create an instance of assign connecting
856
+ """(assign a=b) will create an instance of assign connecting
805
857
  the wire a to the output of the assign and b to the input.
806
858
 
807
859
  :return: True if this is an assign. Assigns are represented with
@@ -859,11 +911,24 @@ class Instance:
859
911
  """
860
912
  return self.__get_snl_model().isInv()
861
913
 
914
+ def is_basic_primitive(instance):
915
+ design = instance.__get_snl_model()
916
+ return (
917
+ design.isConst0() or design.isConst1() or design.isBuf() or design.isInv()
918
+ )
919
+
862
920
  def __get_snl_model(self):
863
921
  if self.is_top():
864
922
  return snl.SNLUniverse.get().getTopDesign()
865
- instance = get_snl_instance_from_id_list(self.pathIDs)
866
- return instance.getModel()
923
+ if (
924
+ self.inst.getModel().getRevisionCount() != self.revisionCount or
925
+ self.inst.getModel().getSNLID() != self.SNLID
926
+ ):
927
+ self.inst = get_snl_instance_from_id_list(self.pathIDs)
928
+ self.revisionCount = self.inst.getModel().getRevisionCount()
929
+ self.SNLID = self.inst.getModel().getSNLID()
930
+
931
+ return self.inst.getModel()
867
932
 
868
933
  def __get_leaf_snl_object(self):
869
934
  if self.is_top():
@@ -906,10 +971,11 @@ class Instance:
906
971
  :return: an iterator over the child instances of this instance.
907
972
  :rtype: Iterator[Instance]
908
973
  """
974
+ path = get_snl_path_from_id_list(self.pathIDs)
909
975
  for inst in self.__get_snl_model().getInstances():
910
- path = self.pathIDs.copy()
911
- path.append(inst.getID())
912
- yield Instance(path)
976
+ path_child = snl.SNLPath(path, inst)
977
+ yield Instance(path_child)
978
+ # path.pop()
913
979
 
914
980
  def get_number_of_child_instances(self) -> int:
915
981
  """
@@ -1041,8 +1107,11 @@ class Instance:
1041
1107
  yield Term(self.pathIDs, term)
1042
1108
 
1043
1109
  def get_flat_output_terms(self):
1044
- """Return the flat output terms of the instance.
1045
- This will iterate over all scalar output terms and bus output term bits.
1110
+ """Iterate over all scalar output terms and bus output term bits
1111
+ of this Instance.
1112
+
1113
+ :return: the flat output terms of this Instance.
1114
+ :rtype: Iterator[Term]
1046
1115
  """
1047
1116
  for term in self.__get_snl_model().getTerms():
1048
1117
  if term.getDirection() != snl.SNLTerm.Direction.Input:
@@ -1053,6 +1122,11 @@ class Instance:
1053
1122
  yield Term(self.pathIDs, term)
1054
1123
 
1055
1124
  def get_attributes(self):
1125
+ """Iterate over the attributes of this Instance.
1126
+
1127
+ :return: the attributes of this Instance.
1128
+ :rtype: Iterator[Attribute]
1129
+ """
1056
1130
  leaf_object = self.__get_leaf_snl_object()
1057
1131
  for attribute in leaf_object.getAttributes():
1058
1132
  yield Attribute(attribute)
@@ -1160,7 +1234,7 @@ class Instance:
1160
1234
  path = get_snl_path_from_id_list(self.pathIDs)
1161
1235
  design = self.__get_snl_model()
1162
1236
  newSNLTerm = snl.SNLScalarTerm.create(design, direction, name)
1163
- return Term(path, newSNLTerm)
1237
+ return Term(path.getPathIDs(), newSNLTerm)
1164
1238
 
1165
1239
  def create_output_term(self, name: str) -> Term:
1166
1240
  """Create an output Term in this Instance with the given name.
@@ -1191,6 +1265,7 @@ class Instance:
1191
1265
 
1192
1266
  def create_bus_term(self, name: str, msb: int, lsb: int, direction) -> Term:
1193
1267
  """Create a bus Term in this Instance with the given name, msb, lsb and direction.
1268
+
1194
1269
  :param str name: the name of the Term to create.
1195
1270
  :param int msb: the most significant bit of the Term to create.
1196
1271
  :param int lsb: the least significant bit of the Term to create.
@@ -1200,10 +1275,9 @@ class Instance:
1200
1275
  path = get_snl_path_from_id_list(self.pathIDs)
1201
1276
  if path.size() > 0:
1202
1277
  snl.SNLUniquifier(path)
1203
- path = get_snl_path_from_id_list(self.pathIDs)
1204
1278
  design = self.__get_snl_model()
1205
1279
  newSNLTerm = snl.SNLBusTerm.create(design, direction, msb, lsb, name)
1206
- return Term(path, newSNLTerm)
1280
+ return Term(self.pathIDs, newSNLTerm)
1207
1281
 
1208
1282
  def create_inout_bus_term(self, name: str, msb: int, lsb: int) -> Term:
1209
1283
  """Create an inout bus Term in this Instance with the given name, msb and lsb.
@@ -1312,10 +1386,17 @@ def create_top(name: str) -> Instance:
1312
1386
  return Instance()
1313
1387
 
1314
1388
 
1315
- def load_verilog(files: list):
1389
+ class VerilogConfig:
1390
+ def __init__(self, keep_assigns=True):
1391
+ self.keep_assigns = keep_assigns
1392
+
1393
+
1394
+ def load_verilog(files: list, config: VerilogConfig = None) -> Instance:
1395
+ if config is None:
1396
+ config = VerilogConfig() # Use default settings
1316
1397
  start_time = time.time()
1317
1398
  logging.info(f"Loading verilog: {', '.join(files)}")
1318
- get_top_db().loadVerilog(files)
1399
+ get_top_db().loadVerilog(files, keep_assigns=config.keep_assigns)
1319
1400
  execution_time = time.time() - start_time
1320
1401
  logging.info(f"Loading done in {execution_time:.2f} seconds")
1321
1402
  return get_top()
@@ -1328,7 +1409,9 @@ def load_liberty(files: list):
1328
1409
 
1329
1410
  def load_primitives(name: str):
1330
1411
  """Loads a primitive library embedded in najaeda.
1412
+
1331
1413
  Currently supported libraries are:
1414
+
1332
1415
  - xilinx
1333
1416
  """
1334
1417
  if name == "xilinx":
@@ -2,6 +2,7 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ import logging
5
6
  from najaeda import snl
6
7
 
7
8
 
@@ -426,6 +427,7 @@ def constructRAMB36E1(lib):
426
427
 
427
428
 
428
429
  def load(db):
430
+ logging.info("Loading Xilinx primitives")
429
431
  lib = snl.SNLLibrary.createPrimitives(db, "xilinx")
430
432
  constructIBUF(lib)
431
433
  constructOBUF(lib)
najaeda/snl.so CHANGED
Binary file
najaeda/stats.py CHANGED
@@ -150,10 +150,8 @@ class InstanceStats:
150
150
  )
151
151
 
152
152
 
153
- def is_basic_primitive(design):
154
- return (
155
- design.is_const0() or design.is_const1() or design.is_buf() or design.is_inv()
156
- )
153
+ def is_basic_primitive(instance):
154
+ return instance.is_basic_primitive()
157
155
 
158
156
 
159
157
  def compute_instance_stats(instance, instances_stats):
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.1
2
+ Name: najaeda
3
+ Version: 0.1.13
4
+ Summary: Naja EDA Python package
5
+ Author-Email: Naja Authors <contact@keplertech.io>
6
+ License: Apache License 2.0
7
+ Project-URL: Homepage, https://github.com/najaeda/naja
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/x-rst
10
+
11
+ Naja EDA Python Package
12
+ =======================
13
+
14
+ Naja EDA is a Python package that provides data structures and APIs for developing post-synthesis Electronic Design Automation (EDA) algorithms.
15
+
16
+ Naja EDA provides a powerful yet simple framework designed to help software
17
+ and hardware developers efficiently navigate and manipulate electronic
18
+ design automation (EDA) workflows.
19
+
20
+ With Naja EDA, you can:
21
+
22
+ * Explore Netlists with Ease:
23
+
24
+ * Navigate netlist hierarchy and connectivity effortlessly.
25
+ * Browse at multiple levels of detail:
26
+
27
+ * Bit-level or bus-level granularity.
28
+ * Instance-by-instance exploration or flattened views at the primitives level.
29
+ * Localized per-instance connections or comprehensive equipotential views.
30
+
31
+ * Perform ECO (Engineering Change Order) Transformations:
32
+
33
+ * Seamlessly apply and manage changes to your designs.
34
+
35
+ * Prototype EDA Ideas Quickly:
36
+
37
+ * Use an intuitive API to experiment with new EDA concepts and workflows.
38
+
39
+ * Develop Custom EDA Tools:
40
+
41
+ * Build fast, tailored tools for solving specific challenges without relying on costly, proprietary EDA software.
42
+
43
+ Naja EDA empowers developers to innovate, adapt, and accelerate their EDA
44
+ processes with minimal overhead.
45
+
46
+ Naja EDA is the Python counterpart of the `Naja C++ project <https://github.com/najaeda/naja>`_.
47
+
48
+ If you’re interested in this project, please consider starring it on GitHub.
49
+ Feel free to reach out to us anytime at `contact@keplertech.io <mailto:contact@keplertech.io>`_.
50
+
51
+ Installation
52
+ ------------
53
+
54
+ Install Naja EDA using pip:
55
+
56
+ .. code-block:: bash
57
+
58
+ pip install najaeda
59
+
60
+ Documentation
61
+ -------------
62
+
63
+ Naja EDA online documentation is available `here <https://najaeda.readthedocs.io/en/latest/index.html>`_.
64
+
65
+ Examples
66
+ --------
67
+
68
+ A list of examples can be found in this
69
+ documentation `section <https://najaeda.readthedocs.io/en/latest/examples.html>`_.
70
+
71
+ Support
72
+ -------
73
+ If you encounter any issues or have questions, please report them on the
74
+ `Naja issue tracker <https://github.com/najaeda/naja/issues>`_.
75
+
76
+ License
77
+ -------
78
+ This project is licensed under the Apache License 2.0. \
79
+ See the `LICENSE <https://github.com/najaeda/naja/blob/main/LICENSE>`_ file for details.
@@ -1,19 +1,20 @@
1
- najaeda-0.1.11.dist-info/RECORD,,
2
- najaeda-0.1.11.dist-info/WHEEL,sha256=PJzLOGr1UQbVJ9ClJnwqiFhnlyWYjSsyNgebnLgIQKg,114
3
- najaeda-0.1.11.dist-info/METADATA,sha256=Kl445PNmMAaclhm5MqkBms6A5AmGvDpGs8aFr36wyMw,7218
4
- najaeda-0.1.11.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
5
- najaeda-0.1.11.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377
6
- najaeda/netlist.py,sha256=xutSwtSsMHtXefn8vG1JVMUm_XZMOv_6wQfxywDvF8U,46275
7
- najaeda/libnaja_snl_python.dylib,sha256=68PJlYLdLZ_ECcHT3_IIF1gTvJ6Q3hnD3h0xrm9by3g,825616
1
+ najaeda-0.1.13.dist-info/RECORD,,
2
+ najaeda-0.1.13.dist-info/WHEEL,sha256=PJzLOGr1UQbVJ9ClJnwqiFhnlyWYjSsyNgebnLgIQKg,114
3
+ najaeda-0.1.13.dist-info/METADATA,sha256=_MF_KzBJGkauW1DVSxFnM0A-0BmFqz1L3vr0WyDBeVA,2475
4
+ najaeda-0.1.13.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
5
+ najaeda-0.1.13.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377
6
+ najaeda/netlist.py,sha256=8HvicL1VCsozjMZ8Fl0SS8OQyI4XREEhSwMQ5xKqVBc,49050
7
+ najaeda/libnaja_snl_python.dylib,sha256=ArFvLzetWBUGctsNZ-Kwb6MnH1SWOyV8mbVKDXjqDQM,887360
8
8
  najaeda/pandas_stats.py,sha256=yOb4ka965U7rN4D6AwvSGmRyeT_O7Ed-5cmT8BFbfeo,1070
9
9
  najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- najaeda/libnaja_snl.dylib,sha256=Vnih_WkRfWljfXKCkqkDY43NQ7RtHgCI7-YfS7i0vQY,574176
11
- najaeda/snl.so,sha256=jLLEWjnuzaSCSJsHYEeIVir026oaLAqBs7KKty0koBA,98272
12
- najaeda/stats.py,sha256=xWiIHa-S9yCHgAjyi6fVtx9C96o9v4MkYU7x5GdRKwA,16250
10
+ najaeda/net_visitor.py,sha256=P_esjibYb-wBDuF-AyF7es9sJYw1Ha8RhTPu-qKe7G4,1940
11
+ najaeda/libnaja_snl.dylib,sha256=_W6nRABcp6q9xoBF0hTOBDWwHBUB6-n8anUoTyNkn-s,574288
12
+ najaeda/snl.so,sha256=VpKDYKLX0RzGO3gC9OGY-owFF_JRe7t9iiCFJ5fgtZE,98272
13
+ najaeda/stats.py,sha256=wackXsf0x24ic9v-UifECHj4t5yveUWssMDZp2B057A,16187
13
14
  najaeda/instance_visitor.py,sha256=JMsPSQaWNiDjxS05rxg83a0PIsrOIuTi9G35hkwdibs,1530
14
15
  najaeda/docs/requirements.txt,sha256=1XIBGTIplm2arC9HhDCfLuAjozGdVSXkqmOj8ybuT6U,121
15
16
  najaeda/docs/.readthedocs.yaml,sha256=nN_Psro-YdfPcIiueZkJcZepts68g23rqVThhKnmVRw,790
16
- najaeda/docs/source/index.rst,sha256=otNU_o72UQp2jEiF4ymADbfU8OeZqQme0K_JQz4kfSU,394
17
+ najaeda/docs/source/index.rst,sha256=80VMfeEGHObnOUXRBxIzISQsG_HNkgT-pUpsDZsCfOY,387
17
18
  najaeda/docs/source/instance.rst,sha256=7B2IBB0p32Tb4qvOCE77OlrQaYpFADvmTlq1q8eyVqw,458
18
19
  najaeda/docs/source/conf.py,sha256=iSeerg2pJlZlhtwkJ9edRRYrLEdx3R1p7GWi78dHP1o,2019
19
20
  najaeda/docs/source/preprocessor.py,sha256=TK4LsTdNbv2dxkKQaJ7cEyo9PU5v_56vlrFCJYIPKf8,2625
@@ -21,8 +22,12 @@ najaeda/docs/source/term.rst,sha256=QKWT6u1xjEjusvcZYknKQ-M83ibohO5y1EYTQnnXqak,
21
22
  najaeda/docs/source/net.rst,sha256=i6YEir8ZOldSY8-UmPxgVJ4Ot3y-Q6seRkBr2H-KmXc,732
22
23
  najaeda/docs/source/visitors.rst,sha256=KScCr7BytrhFxWfZPyYWIrr3CEJuk5Tx-LjEuDnnBaA,227
23
24
  najaeda/docs/source/examples.rst.in,sha256=4ZStOA3N5VHbKZgdn2kaEQZL7wPoJwODS2E1BO54uFY,2091
25
+ najaeda/docs/source/common_classes.rst,sha256=o20u3mcpFYINwy0sVdye90ZPMQcPqoH3V4ERKcG7SZI,181
24
26
  najaeda/docs/source/equipotential.rst,sha256=0MDi-4fPEsX7K_ezWj5DB3mCalnhqN-sicYbQKYQfNc,335
27
+ najaeda/docs/source/netlist_classes.rst,sha256=Zrha9MQVEdEwxmP2zhgC0K3iioZXXerzeFoOz5SrOXM,132
25
28
  najaeda/docs/source/introduction.rst,sha256=kE4qxEJCgcAswiT3rIJS21oBYIMg1cyT_rKmOzQgvsI,2095
26
29
  najaeda/docs/source/api.rst,sha256=47VCPyF4Py_1cklZ3q9fmOMhqqI17rxwU_VUJETfCwY,151
30
+ najaeda/.dylibs/libcapnp-1.1.0.dylib,sha256=l9SvRdxPrCI2mB_UitO7QjsaC7I5mq2R3rZjoIQKEYI,709328
31
+ najaeda/.dylibs/libkj-1.1.0.dylib,sha256=pB7dMks8b8ybJ6xKWqFR_hHjKsmpf7wzbcunZaS7gO4,578320
27
32
  najaeda/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- najaeda/primitives/xilinx.py,sha256=fuu4KxEIuC0ueCK4C_gds6hzgtJsLE3tjDtOHtY9McM,25947
33
+ najaeda/primitives/xilinx.py,sha256=_VPQfWAp3oc4EgOzW-gy96BXdFZK6E4C7aOSdCn4JRU,26008
@@ -1,203 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: najaeda
3
- Version: 0.1.11
4
- Summary: Naja EDA Python package
5
- Author-Email: Naja Authors <contact@keplertech.io>
6
- License: Apache License 2.0
7
- Project-URL: Homepage, https://github.com/najaeda/naja
8
- Requires-Python: >=3.8
9
- Description-Content-Type: text/x-rst
10
-
11
- Naja EDA Python Package
12
- =======================
13
-
14
- Naja EDA is a Python package that provides data structures and APIs for developing post-synthesis Electronic Design Automation (EDA) algorithms.
15
-
16
- Naja EDA provides a powerful yet simple framework designed to help software
17
- and hardware developers efficiently navigate and manipulate electronic
18
- design automation (EDA) workflows.
19
-
20
- With Naja EDA, you can:
21
-
22
- * Explore Netlists with Ease:
23
-
24
- * Navigate netlist hierarchy and connectivity effortlessly.
25
- * Browse at multiple levels of detail:
26
-
27
- * Bit-level or bus-level granularity.
28
- * Instance-by-instance exploration or flattened views at the primitives level.
29
- * Localized per-instance connections or comprehensive equipotential views.
30
-
31
- * Perform ECO (Engineering Change Order) Transformations:
32
-
33
- * Seamlessly apply and manage changes to your designs.
34
-
35
- * Prototype EDA Ideas Quickly:
36
-
37
- * Use an intuitive API to experiment with new EDA concepts and workflows.
38
-
39
- * Develop Custom EDA Tools:
40
-
41
- * Build fast, tailored tools for solving specific challenges without relying on costly, proprietary EDA software.
42
-
43
- Naja EDA empowers developers to innovate, adapt, and accelerate their EDA
44
- processes with minimal overhead.
45
-
46
- Naja EDA is the Python counterpart of the `Naja C++ project <https://github.com/najaeda/naja>`_.
47
-
48
- Installation
49
- ------------
50
-
51
- Install Naja EDA using pip:
52
-
53
- .. code-block:: bash
54
-
55
- pip install najaeda
56
-
57
- Documentation
58
- -------------
59
-
60
- Naja EDA online documentation is available `here <https://najaeda.readthedocs.io/en/latest/index.html>`_.
61
-
62
- Examples
63
- --------
64
-
65
- Load a design from a liberty file and a Verilog file
66
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67
- Following snippet shows how to load primitive cells from a liberty file and
68
- a netlist from a Verilog file.
69
-
70
- .. code-block:: python
71
-
72
- benchmarks = path.join('..','benchmarks')
73
- liberty_files = [
74
- 'NangateOpenCellLibrary_typical.lib',
75
- 'fakeram45_1024x32.lib',
76
- 'fakeram45_64x32.lib'
77
- ]
78
- liberty_files = list(map(lambda p:path.join(benchmarks, 'liberty', p), liberty_files))
79
-
80
- netlist.load_liberty(liberty_files)
81
- top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'tinyrocket.v')])
82
-
83
- top.dump_verilog('.', 'tinyrocket_naja.v')
84
-
85
- Load a design with pre-existing libraries
86
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87
- In FPGA design environments, Liberty files are often unavailable.
88
-
89
- To address this, the following example demonstrates how to load primitives
90
- without relying on Liberty files.
91
-
92
- Naja EDA comes with pre-configured libraries to simplify this process.
93
- Currently, it includes support for partial Xilinx primitives, but this can be
94
- easily extended in the future. Don't hesitate to reach out if you need help.
95
-
96
- .. code-block:: python
97
-
98
- netlist.load_primitives('xilinx')
99
- benchmarks = path.join('..','benchmarks')
100
- top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'vexriscv.v')])
101
-
102
- Print all the instances in the netlist
103
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104
- Next example shows how to browse all the netlist and print all its content recursively.
105
-
106
- .. code-block:: python
107
-
108
- def print_netlist(instance):
109
- for child_instance in instance.get_child_instances():
110
- print(f"{child_instance}:{child_instance.get_model_name()}")
111
- print_netlist(child_instance)
112
-
113
- Similar to the previous example, but utilizing an instance visitor.
114
- This approach allows you to perform operations on each instance while
115
- also defining conditions for stopping or continuing exploration.
116
-
117
- .. code-block:: python
118
-
119
- def print_instance(instance):
120
- print(f"{instance}:{instance.get_model_name()}")
121
- visitor_config = instance_visitor.VisitorConfig(callback=print_instance)
122
- instance_visitor.visit(top, visitor_config)
123
-
124
- Counting the Number of Leaves in a Netlist
125
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126
- The instance visitor provides a tool for collecting various types of information
127
- about a netlist.
128
-
129
- The following example demonstrates how to use the visitor’s callback
130
- function to transmit user-defined arguments, allowing for flexible data processing.
131
-
132
- This specific use case shows how to count the number of leaf instances in a netlist.
133
-
134
- .. code-block:: python
135
-
136
- leaves = {"count": 0, "assigns": 0, "constants": 0}
137
- def count_leaves(instance, leaves):
138
- if instance.is_leaf():
139
- if instance.is_assign():
140
- leaves["assigns"] += 1
141
- elif instance.is_const():
142
- leaves["constants"] += 1
143
- else:
144
- leaves["count"] += 1
145
- visitor_config = instance_visitor.VisitorConfig(callback=count_leaves, args=(leaves,))
146
- instance_visitor.visit(top, visitor_config)
147
- print(f"{top} leaves count")
148
- print(f"nb_assigns={leaves['assigns']}")
149
- print(f"nb constants={leaves['constants']}")
150
- print(f"nb other leaves={leaves['count']}")
151
-
152
- DLE (Dead Logic Elimination)
153
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154
- This example demonstrates how to perform Dead Logic Elimination (DLE) on a netlist.
155
-
156
- .. code-block:: python
157
-
158
- def apply_dle(top):
159
- # Trace back from design outputs
160
- visited = set()
161
- traced_terms = top.get_flat_output_terms()
162
- for leaf in top.get_leaf_children():
163
- atrributes = list(leaf.get_attributes())
164
- for attr in atrributes:
165
- if attr.get_name() == 'DONT_TOUCH' or attr.get_name() == 'KEEP' or attr.get_name() == 'preserve' or attr.get_name() == 'noprune':
166
- for term in leaf.get_flat_input_terms():
167
- traced_terms.append(term)
168
- for termToTrace in traced_terms:
169
- queue = deque([termToTrace])
170
- while queue:
171
- term = queue.popleft()
172
- if term in visited:
173
- continue
174
- visited.add(term)
175
- equipotential = term.get_equipotential()
176
- leaf_drivers = equipotential.get_leaf_drivers()
177
- for driver in leaf_drivers:
178
- instance = driver.get_instance()
179
- instances.add(instance)
180
- input_terms = instance.get_flat_input_terms()
181
- queue.extend(input_terms)
182
-
183
-
184
- to_delete = [leaf for leaf in top.get_leaf_children() if leaf not in instances]
185
- for leaf in to_delete:
186
- leaf.delete()
187
- return to_delete
188
-
189
- Documentation
190
- -------------
191
- Naja EDA is a work in progress, and the documentation is still under development.
192
-
193
- Naja documentation is available on the `Naja GitHub repository <https://github.com/najaeda/naja>`_.
194
-
195
- Support
196
- -------
197
- If you encounter any issues or have questions, please report them on the
198
- `Naja issue tracker <https://github.com/najaeda/naja/issues>`_.
199
-
200
- License
201
- -------
202
- This project is licensed under the Apache License 2.0. \
203
- See the `LICENSE <https://github.com/najaeda/naja/blob/main/LICENSE>`_ file for details.