najaeda 0.1.9__cp313-cp313-macosx_11_0_arm64.whl → 0.1.12__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.

@@ -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/netlist.py CHANGED
@@ -8,6 +8,7 @@ import time
8
8
  import logging
9
9
  import hashlib
10
10
  import struct
11
+ from enum import Enum
11
12
 
12
13
  from najaeda import snl
13
14
 
@@ -165,6 +166,13 @@ class Equipotential:
165
166
 
166
167
 
167
168
  class Net:
169
+ class Type(Enum):
170
+ STANDARD = snl.SNLNet.Type.Standard
171
+ ASSIGN0 = snl.SNLNet.Type.Assign0
172
+ ASSIGN1 = snl.SNLNet.Type.Assign1
173
+ SUPPLY0 = snl.SNLNet.Type.Supply0
174
+ SUPPLY1 = snl.SNLNet.Type.Supply1
175
+
168
176
  def __init__(self, path, net=None, net_concat=None):
169
177
  if net is not None and net_concat is not None:
170
178
  raise ValueError(
@@ -272,10 +280,21 @@ class Net:
272
280
  """
273
281
  if hasattr(self, "net"):
274
282
  return self.net.isConstant()
275
- for net in self.net_concat:
276
- if not net.isConstant():
277
- return False
278
- return True
283
+ else:
284
+ for net in self.net_concat:
285
+ if not net.isConstant():
286
+ return False
287
+ return True
288
+
289
+ def set_type(self, net_type: Type):
290
+ """
291
+ :param Type net_type: the type of the net.
292
+ """
293
+ if hasattr(self, "net"):
294
+ self.net.setType(net_type.value)
295
+ else:
296
+ for net in self.net_concat:
297
+ net.setType(net_type.value)
279
298
 
280
299
  def get_width(self) -> int:
281
300
  """
@@ -300,7 +319,7 @@ class Net:
300
319
  yield self
301
320
  else:
302
321
  for net in self.net_concat:
303
- yield net
322
+ yield Net(net)
304
323
 
305
324
  def get_bit(self, index: int):
306
325
  """
@@ -685,19 +704,48 @@ def get_instance_by_path(names: list):
685
704
  return Instance(path)
686
705
 
687
706
 
688
- def refresh_path(path: snl.SNLPath):
689
- pathlist = path.getPathIDs()
690
- assert len(pathlist) > 0
691
- path = snl.SNLPath()
692
- instance = None
693
- top = snl.SNLUniverse.get().getTopDesign()
694
- design = top
695
- for id in pathlist:
696
- path = snl.SNLPath(path, design.getInstanceByID(id))
697
- instance = design.getInstanceByID(id)
698
- assert instance is not None
699
- design = instance.getModel()
700
- return path
707
+ # def refresh_path(path: snl.SNLPath):
708
+ # pathlist = path.getPathIDs()
709
+ # assert len(pathlist) > 0
710
+ # path = snl.SNLPath()
711
+ # instance = None
712
+ # top = snl.SNLUniverse.get().getTopDesign()
713
+ # design = top
714
+ # for id in pathlist:
715
+ # path = snl.SNLPath(path, design.getInstanceByID(id))
716
+ # instance = design.getInstanceByID(id)
717
+ # assert instance is not None
718
+ # design = instance.getModel()
719
+ # return path
720
+
721
+
722
+ class Attribute:
723
+ def __init__(self, snlAttribute):
724
+ self.snlAttribute = snlAttribute
725
+
726
+ def __str__(self):
727
+ return str(self.snlAttribute)
728
+
729
+ def get_name(self):
730
+ """
731
+ :return: the name of the attribute.
732
+ :rtype: str
733
+ """
734
+ return self.snlAttribute.getName()
735
+
736
+ def has_value(self):
737
+ """
738
+ :return: True if the attribute has a value.
739
+ :rtype: bool
740
+ """
741
+ return self.snlAttribute.hasValue()
742
+
743
+ def get_value(self):
744
+ """
745
+ :return: the value of the attribute.
746
+ :rtype: str
747
+ """
748
+ return self.snlAttribute.getValue()
701
749
 
702
750
 
703
751
  class Instance:
@@ -738,6 +786,7 @@ class Instance:
738
786
  def get_leaf_children(self):
739
787
  """Iterate over the leaf children of this Instance.
740
788
  Equivalent to the underlying leaves of the instanciation tree.
789
+
741
790
  :return: an iterator over the leaf children Instance of this Instance.
742
791
  :rtype: Iterator[Instance]
743
792
  """
@@ -765,7 +814,7 @@ class Instance:
765
814
  return len(self.pathIDs) == 0
766
815
 
767
816
  def is_assign(self) -> bool:
768
- """Example: (assign a=b) will create an instance of assign connecting
817
+ """(assign a=b) will create an instance of assign connecting
769
818
  the wire a to the output of the assign and b to the input.
770
819
 
771
820
  :return: True if this is an assign. Assigns are represented with
@@ -829,6 +878,11 @@ class Instance:
829
878
  instance = get_snl_instance_from_id_list(self.pathIDs)
830
879
  return instance.getModel()
831
880
 
881
+ def __get_leaf_snl_object(self):
882
+ if self.is_top():
883
+ return snl.SNLUniverse.get().getTopDesign()
884
+ return get_snl_instance_from_id_list(self.pathIDs)
885
+
832
886
  def __find_snl_model(self, name: str) -> snl.SNLDesign:
833
887
  u = snl.SNLUniverse.get()
834
888
  for db in u.getUserDBs():
@@ -1000,8 +1054,11 @@ class Instance:
1000
1054
  yield Term(self.pathIDs, term)
1001
1055
 
1002
1056
  def get_flat_output_terms(self):
1003
- """Return the flat output terms of the instance.
1004
- This will iterate over all scalar output terms and bus output term bits.
1057
+ """Iterate over all scalar output terms and bus output term bits
1058
+ of this Instance.
1059
+
1060
+ :return: the flat output terms of this Instance.
1061
+ :rtype: Iterator[Term]
1005
1062
  """
1006
1063
  for term in self.__get_snl_model().getTerms():
1007
1064
  if term.getDirection() != snl.SNLTerm.Direction.Input:
@@ -1011,6 +1068,16 @@ class Instance:
1011
1068
  else:
1012
1069
  yield Term(self.pathIDs, term)
1013
1070
 
1071
+ def get_attributes(self):
1072
+ """Iterate over the attributes of this Instance.
1073
+
1074
+ :return: the attributes of this Instance.
1075
+ :rtype: Iterator[Attribute]
1076
+ """
1077
+ leaf_object = self.__get_leaf_snl_object()
1078
+ for attribute in leaf_object.getAttributes():
1079
+ yield Attribute(attribute)
1080
+
1014
1081
  def delete_instance(self, name: str):
1015
1082
  """Delete the child instance with the given name."""
1016
1083
  if name == "":
@@ -1145,6 +1212,7 @@ class Instance:
1145
1212
 
1146
1213
  def create_bus_term(self, name: str, msb: int, lsb: int, direction) -> Term:
1147
1214
  """Create a bus Term in this Instance with the given name, msb, lsb and direction.
1215
+
1148
1216
  :param str name: the name of the Term to create.
1149
1217
  :param int msb: the most significant bit of the Term to create.
1150
1218
  :param int lsb: the least significant bit of the Term to create.
@@ -1282,7 +1350,9 @@ def load_liberty(files: list):
1282
1350
 
1283
1351
  def load_primitives(name: str):
1284
1352
  """Loads a primitive library embedded in najaeda.
1353
+
1285
1354
  Currently supported libraries are:
1355
+
1286
1356
  - xilinx
1287
1357
  """
1288
1358
  if name == "xilinx":
@@ -0,0 +1,32 @@
1
+ # SPDX-FileCopyrightText: 2023 The Naja authors <https://github.com/najaeda/naja/blob/main/AUTHORS>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import argparse
6
+ import pandas as pd
7
+
8
+ if __name__ == "__main__":
9
+ parser = argparse.ArgumentParser(
10
+ description="Load JSON and generate statistics using Pandas."
11
+ )
12
+ parser.add_argument("json_file", type=str, help="Path to the input JSON file.")
13
+ parser.add_argument(
14
+ "--output",
15
+ type=str,
16
+ default="design_stats.png",
17
+ help="Optional: Save computed statistics to this JSON file.",
18
+ )
19
+ args = parser.parse_args()
20
+
21
+ df = pd.read_json(args.json_file)
22
+ pandas_data = pd.DataFrame(df.set_index("Name"))
23
+ plot = pandas_data.plot.bar(y=["terms", "nets", "instances"], stacked=True)
24
+
25
+ # Customize plot
26
+ plot.set_title("Design Statistics", fontsize=16, fontweight="bold")
27
+ plot.set_xlabel("Design Name", fontsize=12)
28
+ plot.set_ylabel("Count", fontsize=12)
29
+
30
+ plot_figure = plot.get_figure()
31
+ plot_figure.tight_layout()
32
+ plot_figure.savefig(args.output)
najaeda/snl.so CHANGED
Binary file
najaeda/stats.py CHANGED
@@ -3,16 +3,121 @@
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
5
  import logging
6
+ import json
7
+
6
8
  from najaeda import netlist
7
9
 
8
10
 
9
- class DesignsStats:
11
+ class InstancesStats:
10
12
  def __init__(self):
11
13
  self.blackboxes = dict()
12
- self.hier_designs = dict()
14
+ self.hier_instances = dict()
15
+
16
+ def dump_instance_stats_text(self, instance, stats_files):
17
+ dumped_models = set()
18
+ self.__dump_instance_stats_text(instance, stats_files, dumped_models)
19
+
20
+ def __dump_stats(self, file, value_name, value):
21
+ file.write(f"{value_name}: {value} \n")
22
+
23
+ def __dump_terms_stats_text(self, instance_stats, file):
24
+ file.write("Terms: ")
25
+ first = True
26
+ for terms in instance_stats.terms.items():
27
+ if not first:
28
+ file.write(", ")
29
+ else:
30
+ first = False
31
+ file.write(terms[0] + ":" + str(terms[1]))
32
+ file.write("\n")
33
+
34
+ def __dump_instances(self, stats_file, title, instances):
35
+ if len(instances) == 0:
36
+ return
37
+ sorted_instances = sorted(
38
+ instances.items(), key=lambda item: netlist.get_model_name(item[0])
39
+ )
40
+ stats_file.write(title + " " + str(sum(j for i, j in sorted_instances)) + "\n")
41
+ line_char = 0
42
+ for instance in sorted_instances:
43
+ model_name = netlist.get_model_name(instance[0])
44
+ if line_char != 0:
45
+ stats_file.write(",")
46
+ line_char += 1
47
+ if line_char > 80:
48
+ stats_file.write("\n")
49
+ line_char = 0
50
+ elif line_char != 0:
51
+ stats_file.write(" ")
52
+ line_char += 1
53
+ instance_char = model_name + ":" + str(instance[1])
54
+ line_char += len(instance_char)
55
+ stats_file.write(instance_char)
56
+ stats_file.write("\n\n")
57
+
58
+ def __dump_instance_stats_text(self, instance, file, dumped_models):
59
+ if instance.is_primitive() or instance.is_blackbox():
60
+ return
61
+ # Only dump once each model
62
+ model_id = instance.get_model_id()
63
+ if model_id in dumped_models:
64
+ return
65
+ dumped_models.add(model_id)
66
+
67
+ file.write("*** " + instance.get_name() + " ***\n")
13
68
 
69
+ instance_stats = self.hier_instances.get(model_id)
70
+ if instance_stats is None:
71
+ print(
72
+ "Cannot find " + str(instance.get_model_name()) + " in instance_stats"
73
+ )
74
+ raise
75
+
76
+ if len(instance_stats.terms) > 0:
77
+ self.__dump_terms_stats_text(instance_stats, file)
78
+
79
+ # self.__dump_instances(stats_file, "Instances:", design_stats.ins)
80
+ nb_primitives = sum(instance_stats.basic_primitives.values()) + sum(
81
+ instance_stats.primitives.values()
82
+ )
83
+ if nb_primitives > 1:
84
+ self.__dump_stats(file, "Primitives", nb_primitives)
85
+
86
+ self.__dump_instances(
87
+ file, "Simple Primitives:", instance_stats.basic_primitives
88
+ )
89
+ self.__dump_instances(file, "Other Primitives:", instance_stats.primitives)
90
+ self.__dump_instances(file, "Blackboxes:", instance_stats.blackboxes)
91
+
92
+ if instance_stats.assigns > 0:
93
+ self.__dump_stats(file, "Assigns", instance_stats.assigns)
94
+
95
+ self.__dump_instances(file, "Flat Instances:", instance_stats.flat_ins)
96
+ self.__dump_instances(file, "Flat Blackboxes:", instance_stats.flat_blackboxes)
97
+
98
+ nb_primitives = sum(instance_stats.flat_basic_primitives.values()) + sum(
99
+ instance_stats.flat_primitives.values()
100
+ )
101
+ if nb_primitives > 1:
102
+ self.__dump_stats(file, "Flat Primitives", nb_primitives)
103
+
104
+ self.__dump_instances(
105
+ file, "Flat Simple Primitives:", instance_stats.flat_basic_primitives
106
+ )
107
+ self.__dump_instances(
108
+ file, "Flat Other Primitives:", instance_stats.flat_primitives
109
+ )
14
110
 
15
- class DesignStats:
111
+ if instance_stats.flat_assigns > 0:
112
+ self.__dump_stats(file, "Flat Assigns", instance_stats.flat_assigns)
113
+
114
+ file.write("\n")
115
+
116
+ for child_instance in instance.get_child_instances():
117
+ self.__dump_instance_stats_text(child_instance, file, dumped_models)
118
+
119
+
120
+ class InstanceStats:
16
121
  def __init__(self):
17
122
  self.name = ""
18
123
  self.assigns = 0
@@ -51,92 +156,96 @@ def is_basic_primitive(design):
51
156
  )
52
157
 
53
158
 
54
- def compute_design_stats(design, designs_stats):
55
- if design.get_model_id() in designs_stats.hier_designs:
56
- return designs_stats.hier_designs.get(design.get_model_id())
57
- design_stats = DesignStats()
58
- design_stats.name = design.get_model_name()
59
- for ins in design.get_child_instances():
159
+ def compute_instance_stats(instance, instances_stats):
160
+ if instance.get_model_id() in instances_stats.hier_instances:
161
+ return instances_stats.hier_instances.get(instance.get_model_id())
162
+ instance_stats = InstanceStats()
163
+ instance_stats.name = instance.get_model_name()
164
+ for ins in instance.get_child_instances():
60
165
  model_id = ins.get_model_id()
61
166
  if ins.is_assign():
62
- design_stats.assigns += 1
63
- design_stats.flat_assigns += 1
167
+ instance_stats.assigns += 1
168
+ instance_stats.flat_assigns += 1
64
169
  elif ins.is_primitive():
65
170
  if is_basic_primitive(ins):
66
- design_stats.basic_primitives[model_id] = (
67
- design_stats.basic_primitives.get(model_id, 0) + 1
171
+ instance_stats.basic_primitives[model_id] = (
172
+ instance_stats.basic_primitives.get(model_id, 0) + 1
68
173
  )
69
- design_stats.flat_basic_primitives[model_id] = (
70
- design_stats.flat_basic_primitives.get(model_id, 0) + 1
174
+ instance_stats.flat_basic_primitives[model_id] = (
175
+ instance_stats.flat_basic_primitives.get(model_id, 0) + 1
71
176
  )
72
177
  else:
73
- design_stats.primitives[model_id] = (
74
- design_stats.primitives.get(model_id, 0) + 1
178
+ instance_stats.primitives[model_id] = (
179
+ instance_stats.primitives.get(model_id, 0) + 1
75
180
  )
76
- design_stats.flat_primitives[model_id] = (
77
- design_stats.flat_primitives.get(model_id, 0) + 1
181
+ instance_stats.flat_primitives[model_id] = (
182
+ instance_stats.flat_primitives.get(model_id, 0) + 1
78
183
  )
79
184
  elif ins.is_blackbox():
80
- design_stats.blackboxes[model_id] = (
81
- design_stats.blackboxes.get(model_id, 0) + 1
185
+ instance_stats.blackboxes[model_id] = (
186
+ instance_stats.blackboxes.get(model_id, 0) + 1
82
187
  )
83
- design_stats.flat_blackboxes[model_id] = (
84
- design_stats.flat_blackboxes.get(model_id, 0) + 1
188
+ instance_stats.flat_blackboxes[model_id] = (
189
+ instance_stats.flat_blackboxes.get(model_id, 0) + 1
85
190
  )
86
- if model_id not in designs_stats.blackboxes:
87
- designs_stats.blackboxes[model_id] = dict()
88
- compute_design_terms(model_id, designs_stats.blackboxes[model_id])
191
+ if model_id not in instance_stats.blackboxes:
192
+ instance_stats.blackboxes[model_id] = dict()
193
+ compute_instance_terms(model_id, instance_stats.blackboxes[model_id])
89
194
  else:
90
- if model_id in designs_stats.hier_designs:
91
- model_stats = designs_stats.hier_designs[model_id]
195
+ if model_id in instances_stats.hier_instances:
196
+ model_stats = instances_stats.hier_instances[model_id]
92
197
  else:
93
- model_stats = compute_design_stats(ins, designs_stats)
94
- design_stats.ins[model_id] = design_stats.ins.get(model_id, 0) + 1
95
- design_stats.flat_ins[model_id] = design_stats.flat_ins.get(model_id, 0) + 1
96
- design_stats.add_ins_stats(model_stats)
97
- compute_design_terms(design, design_stats)
98
- compute_design_net_stats(design, design_stats)
99
- designs_stats.hier_designs[design.get_model_id()] = design_stats
100
- return design_stats
101
-
102
-
103
- def compute_design_terms(design, design_stats):
104
- for term in design.get_terms():
198
+ model_stats = compute_instance_stats(ins, instances_stats)
199
+ instance_stats.ins[model_id] = instance_stats.ins.get(model_id, 0) + 1
200
+ instance_stats.flat_ins[model_id] = (
201
+ instance_stats.flat_ins.get(model_id, 0) + 1
202
+ )
203
+ instance_stats.add_ins_stats(model_stats)
204
+ compute_instance_terms(instance, instance_stats)
205
+ compute_instance_net_stats(instance, instance_stats)
206
+ instances_stats.hier_instances[instance.get_model_id()] = instance_stats
207
+ return instance_stats
208
+
209
+
210
+ def compute_instance_terms(instance, instance_stats):
211
+ for term in instance.get_terms():
105
212
  if term.get_direction() == netlist.Term.INPUT:
106
- design_stats.terms["inputs"] = design_stats.terms.get("inputs", 0) + 1
213
+ instance_stats.terms["inputs"] = instance_stats.terms.get("inputs", 0) + 1
107
214
  bit_terms = sum(1 for _ in term.get_bits())
108
- design_stats.bit_terms["inputs"] = (
109
- design_stats.bit_terms.get("inputs", 0) + bit_terms
215
+ instance_stats.bit_terms["inputs"] = (
216
+ instance_stats.bit_terms.get("inputs", 0) + bit_terms
110
217
  )
111
218
  elif term.get_direction() == netlist.Term.OUTPUT:
112
- design_stats.terms["outputs"] = design_stats.terms.get("outputs", 0) + 1
219
+ instance_stats.terms["outputs"] = instance_stats.terms.get("outputs", 0) + 1
113
220
  bit_terms = sum(1 for _ in term.get_bits())
114
- design_stats.bit_terms["outputs"] = (
115
- design_stats.bit_terms.get("outputs", 0) + bit_terms
221
+ instance_stats.bit_terms["outputs"] = (
222
+ instance_stats.bit_terms.get("outputs", 0) + bit_terms
116
223
  )
117
224
  elif term.get_direction() == netlist.Term.INOUT:
118
- design_stats.terms["inouts"] = design_stats.terms.get("inouts", 0) + 1
225
+ instance_stats.terms["inouts"] = instance_stats.terms.get("inouts", 0) + 1
119
226
  bit_terms = sum(1 for _ in term.get_bits())
120
- design_stats.bit_terms["inouts"] = (
121
- design_stats.bit_terms.get("inouts", 0) + bit_terms
227
+ instance_stats.bit_terms["inouts"] = (
228
+ instance_stats.bit_terms.get("inouts", 0) + bit_terms
122
229
  )
123
230
  else:
124
- design_stats.terms["unknowns"] = design_stats.terms.get("unknowns", 0) + 1
231
+ instance_stats.terms["unknowns"] = (
232
+ instance_stats.terms.get("unknowns", 0) + 1
233
+ )
125
234
  bit_terms = sum(1 for _ in term.get_bits())
126
- design_stats.bit_terms["unknowns"] = (
127
- design_stats.bit_terms.get("unknowns", 0) + bit_terms
235
+ instance_stats.bit_terms["unknowns"] = (
236
+ instance_stats.bit_terms.get("unknowns", 0) + bit_terms
128
237
  )
129
238
 
130
239
 
131
- def compute_design_net_stats(design, design_stats):
132
- for net in design.get_flat_nets():
240
+ def compute_instance_net_stats(instance, instance_stats):
241
+ for net in instance.get_flat_nets():
133
242
  if net.is_const():
134
243
  pass
135
244
  nb_components = sum(1 for c in net.get_terms())
136
- design_stats.net_stats[nb_components] = (
137
- design_stats.net_stats.get(nb_components, 0) + 1
245
+ instance_stats.net_stats[nb_components] = (
246
+ instance_stats.net_stats.get(nb_components, 0) + 1
138
247
  )
139
- design_stats.net_stats = dict(sorted(design_stats.net_stats.items()))
248
+ instance_stats.net_stats = dict(sorted(instance_stats.net_stats.items()))
140
249
 
141
250
 
142
251
  def dump_instances(stats_file, title, instances):
@@ -184,57 +293,6 @@ def dump_blackboxes_stats(stats_file, design_stats):
184
293
  stats_file.write("\n")
185
294
 
186
295
 
187
- def dump_stats(design, stats_file, designs_stats, dumped_models):
188
- if design.is_primitive() or design.is_blackbox():
189
- return
190
- if design in dumped_models:
191
- return
192
- dumped_models.add(design)
193
- stats_file.write("*** " + design.get_name() + " ***\n")
194
- design_stats = designs_stats.hier_designs.get(design.get_model_id())
195
- if design_stats is None:
196
- print("Cannot find " + str(design) + " in design_stats")
197
- raise
198
- if len(design_stats.terms) > 0:
199
- stats_file.write("Terms: ")
200
- first = True
201
- for terms in design_stats.terms.items():
202
- if not first:
203
- stats_file.write(", ")
204
- else:
205
- first = False
206
- stats_file.write(terms[0] + ":" + str(terms[1]))
207
- stats_file.write("\n")
208
-
209
- dump_instances(stats_file, "Instances:", design_stats.ins)
210
- nb_primitives = sum(design_stats.basic_primitives.values()) + sum(
211
- design_stats.primitives.values()
212
- )
213
- if nb_primitives > 1:
214
- stats_file.write("Primitives: " + str(nb_primitives) + "\n")
215
- dump_instances(stats_file, "Simple Primitives:", design_stats.basic_primitives)
216
- dump_instances(stats_file, "Other Primitives:", design_stats.primitives)
217
- dump_instances(stats_file, "Blackboxes:", design_stats.blackboxes)
218
- if design_stats.assigns > 0:
219
- stats_file.write("Assigns: " + str(design_stats.assigns) + "\n")
220
- dump_instances(stats_file, "Flat Instances:", design_stats.flat_ins)
221
- dump_instances(stats_file, "Flat Blackboxes:", design_stats.flat_blackboxes)
222
- nb_primitives = sum(design_stats.flat_basic_primitives.values()) + sum(
223
- design_stats.flat_primitives.values()
224
- )
225
- if nb_primitives > 1:
226
- stats_file.write("Flat Primitives: " + str(nb_primitives) + "\n")
227
- dump_instances(
228
- stats_file, "Flat Simple Primitives:", design_stats.flat_basic_primitives
229
- )
230
- dump_instances(stats_file, "Flat Other Primitives:", design_stats.flat_primitives)
231
- if design_stats.flat_assigns > 0:
232
- stats_file.write("Flat Assigns: " + str(design_stats.flat_assigns) + "\n")
233
- stats_file.write("\n")
234
- for ins in design.get_child_instances():
235
- dump_stats(ins, stats_file, designs_stats, dumped_models)
236
-
237
-
238
296
  # def dump_pandas(designs_stats):
239
297
  # import pandas
240
298
  # import matplotlib.pyplot as plt
@@ -286,14 +344,51 @@ def dump_stats(design, stats_file, designs_stats, dumped_models):
286
344
  # primitives_figure.savefig('figures/flat_primitives_' + design.getName() + '.png')
287
345
 
288
346
 
289
- def dump_design_stats(design, stats_file, with_pandas=False):
290
- designs_stats = DesignsStats()
291
- compute_design_stats(design, designs_stats)
292
- dumped_models = set()
293
- dump_stats(design, stats_file, designs_stats, dumped_models)
294
- dump_blackboxes_stats(stats_file, designs_stats)
295
- # if with_pandas:
296
- # dump_pandas(designs_stats)
347
+ def convert_instance_stats_to_json(instance_stats):
348
+ json_top = list()
349
+ for _, value in instance_stats.hier_instances.items():
350
+ nb_primitives = sum(value.basic_primitives.values())
351
+ +sum(value.primitives.values())
352
+ nb_terms = sum(value.terms.values())
353
+ nb_nets = sum(value.net_stats.keys())
354
+ nb_ins = sum(value.ins.values()) + nb_primitives
355
+ json_top.append(
356
+ {
357
+ "Name": value.name,
358
+ "primitives": nb_primitives,
359
+ "instances": nb_ins,
360
+ "terms": nb_terms,
361
+ "nets": nb_nets,
362
+ # "primitives": value.primitives,
363
+ # "flat_basic_primitives": value.flat_basic_primitives,
364
+ # "flat_primitives": value.flat_primitives,
365
+ # "blackboxes": value.blackboxes,
366
+ # "flat_blackboxes": value.flat_blackboxes,
367
+ # "ins": value.ins,
368
+ # "flat_ins": value.flat_ins,
369
+ # "terms": value.terms,
370
+ # "bit_terms": value.bit_terms,
371
+ # "net_stats": value.net_stats,
372
+ }
373
+ )
374
+ return json_top
375
+
376
+
377
+ def dump_instance_stats_json(instance, stats_file):
378
+ # stats_files = [(InstanceStats.ReportType.JSON, stats_file)]
379
+ # stats_file.write("[\n")
380
+ # dump_instance_stats(design, stats_files)
381
+ # stats_file.write("]")
382
+ instances_stats = InstancesStats()
383
+ compute_instance_stats(instance, instances_stats)
384
+ json_dict = convert_instance_stats_to_json(instances_stats)
385
+ json.dump(json_dict, stats_file, indent=4)
386
+
387
+
388
+ def dump_instance_stats_text(instance, file):
389
+ instances_stats = InstancesStats()
390
+ compute_instance_stats(instance, instances_stats)
391
+ instances_stats.dump_instance_stats_text(instance, file)
297
392
 
298
393
 
299
394
  def dump_constants(design, analyzed_models):
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.1
2
+ Name: najaeda
3
+ Version: 0.1.12
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,18 +1,14 @@
1
- najaeda-0.1.9.dist-info/RECORD,,
2
- najaeda-0.1.9.dist-info/WHEEL,sha256=PJzLOGr1UQbVJ9ClJnwqiFhnlyWYjSsyNgebnLgIQKg,114
3
- najaeda-0.1.9.dist-info/METADATA,sha256=mLCLaVsZwtrgbmzHBHz5w9mjqDzjNev79QSgW4VD9I0,6854
4
- najaeda-0.1.9.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
5
- najaeda-0.1.9.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377
6
- najaeda/netlist.py,sha256=SYVF3z_koUwaRczDTVeDsVo9fT1OMw77R-1U3cLahk0,44955
7
- najaeda/libnaja_snl_python.dylib,sha256=L1wX3e5lmPyqhN1rkKPGyV7lj4E_kHqk0z2DMujk4ek,808208
1
+ najaeda/netlist.py,sha256=8p0iHWDNbsMo-DndUBKLc43j7agtgb_jhlQdgkoYpvU,46750
2
+ najaeda/libnaja_snl_python.dylib,sha256=HE3O04AAj9qVLJN0DWRC1sp27t3vaZJy2Q0qNvsPInA,825616
3
+ najaeda/pandas_stats.py,sha256=yOb4ka965U7rN4D6AwvSGmRyeT_O7Ed-5cmT8BFbfeo,1070
8
4
  najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- najaeda/libnaja_snl.dylib,sha256=AFqR64aX6KnzkX6lrLGCuscx2f5E07umNC_7E9cNrT0,574272
10
- najaeda/snl.so,sha256=nwbhD_k8zYEQZh-LsCexOj9j2uSibNAeUnWTxwUy1iM,97888
11
- najaeda/stats.py,sha256=FoNdmu7bf-Iy1RW1WO-4Ue-i7O7CRqEDbGAuyhfVxf4,12879
5
+ najaeda/libnaja_snl.dylib,sha256=T76kBcwP4dGXUXS5aD1mcNr5hBAL8ou-nJGQNg7tXIA,574160
6
+ najaeda/snl.so,sha256=jLLEWjnuzaSCSJsHYEeIVir026oaLAqBs7KKty0koBA,98272
7
+ najaeda/stats.py,sha256=xWiIHa-S9yCHgAjyi6fVtx9C96o9v4MkYU7x5GdRKwA,16250
12
8
  najaeda/instance_visitor.py,sha256=JMsPSQaWNiDjxS05rxg83a0PIsrOIuTi9G35hkwdibs,1530
13
9
  najaeda/docs/requirements.txt,sha256=1XIBGTIplm2arC9HhDCfLuAjozGdVSXkqmOj8ybuT6U,121
14
10
  najaeda/docs/.readthedocs.yaml,sha256=nN_Psro-YdfPcIiueZkJcZepts68g23rqVThhKnmVRw,790
15
- najaeda/docs/source/index.rst,sha256=otNU_o72UQp2jEiF4ymADbfU8OeZqQme0K_JQz4kfSU,394
11
+ najaeda/docs/source/index.rst,sha256=80VMfeEGHObnOUXRBxIzISQsG_HNkgT-pUpsDZsCfOY,387
16
12
  najaeda/docs/source/instance.rst,sha256=7B2IBB0p32Tb4qvOCE77OlrQaYpFADvmTlq1q8eyVqw,458
17
13
  najaeda/docs/source/conf.py,sha256=iSeerg2pJlZlhtwkJ9edRRYrLEdx3R1p7GWi78dHP1o,2019
18
14
  najaeda/docs/source/preprocessor.py,sha256=TK4LsTdNbv2dxkKQaJ7cEyo9PU5v_56vlrFCJYIPKf8,2625
@@ -20,8 +16,15 @@ najaeda/docs/source/term.rst,sha256=QKWT6u1xjEjusvcZYknKQ-M83ibohO5y1EYTQnnXqak,
20
16
  najaeda/docs/source/net.rst,sha256=i6YEir8ZOldSY8-UmPxgVJ4Ot3y-Q6seRkBr2H-KmXc,732
21
17
  najaeda/docs/source/visitors.rst,sha256=KScCr7BytrhFxWfZPyYWIrr3CEJuk5Tx-LjEuDnnBaA,227
22
18
  najaeda/docs/source/examples.rst.in,sha256=4ZStOA3N5VHbKZgdn2kaEQZL7wPoJwODS2E1BO54uFY,2091
19
+ najaeda/docs/source/common_classes.rst,sha256=o20u3mcpFYINwy0sVdye90ZPMQcPqoH3V4ERKcG7SZI,181
23
20
  najaeda/docs/source/equipotential.rst,sha256=0MDi-4fPEsX7K_ezWj5DB3mCalnhqN-sicYbQKYQfNc,335
21
+ najaeda/docs/source/netlist_classes.rst,sha256=Zrha9MQVEdEwxmP2zhgC0K3iioZXXerzeFoOz5SrOXM,132
24
22
  najaeda/docs/source/introduction.rst,sha256=kE4qxEJCgcAswiT3rIJS21oBYIMg1cyT_rKmOzQgvsI,2095
25
23
  najaeda/docs/source/api.rst,sha256=47VCPyF4Py_1cklZ3q9fmOMhqqI17rxwU_VUJETfCwY,151
26
24
  najaeda/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
25
  najaeda/primitives/xilinx.py,sha256=fuu4KxEIuC0ueCK4C_gds6hzgtJsLE3tjDtOHtY9McM,25947
26
+ najaeda-0.1.12.dist-info/RECORD,,
27
+ najaeda-0.1.12.dist-info/WHEEL,sha256=PJzLOGr1UQbVJ9ClJnwqiFhnlyWYjSsyNgebnLgIQKg,114
28
+ najaeda-0.1.12.dist-info/METADATA,sha256=SlRgiK7xMLvNflXb_hKnXr7WamPV2wijr-qtmyqUH20,2475
29
+ najaeda-0.1.12.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
30
+ najaeda-0.1.12.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377
@@ -1,197 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: najaeda
3
- Version: 0.1.9
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
- output_terms = top.get_flat_output_terms()
162
- for termToTrace in output_terms:
163
- queue = deque([termToTrace])
164
- while queue:
165
- term = queue.popleft()
166
- if term in visited:
167
- continue
168
- visited.add(term)
169
- equipotential = term.get_equipotential()
170
- leaf_drivers = equipotential.get_leaf_drivers()
171
- for driver in leaf_drivers:
172
- instance = driver.get_instance()
173
- instances.add(instance)
174
- input_terms = instance.get_flat_input_terms()
175
- queue.extend(input_terms)
176
-
177
- leaf_children = top.get_leaf_children()
178
- to_delete = [leaf for leaf in leaf_children if leaf not in instances]
179
- for leaf in to_delete:
180
- leaf.delete()
181
- return to_delete
182
-
183
- Documentation
184
- -------------
185
- Naja EDA is a work in progress, and the documentation is still under development.
186
-
187
- Naja documentation is available on the `Naja GitHub repository <https://github.com/najaeda/naja>`_.
188
-
189
- Support
190
- -------
191
- If you encounter any issues or have questions, please report them on the
192
- `Naja issue tracker <https://github.com/najaeda/naja/issues>`_.
193
-
194
- License
195
- -------
196
- This project is licensed under the Apache License 2.0. \
197
- See the `LICENSE <https://github.com/najaeda/naja/blob/main/LICENSE>`_ file for details.