najaeda 0.1.9__cp311-cp311-macosx_11_0_arm64.whl → 0.1.12__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/docs/source/common_classes.rst +11 -0
- najaeda/docs/source/index.rst +2 -4
- najaeda/docs/source/netlist_classes.rst +11 -0
- najaeda/libnaja_snl.dylib +0 -0
- najaeda/libnaja_snl_python.dylib +0 -0
- najaeda/netlist.py +91 -21
- najaeda/pandas_stats.py +32 -0
- najaeda/snl.so +0 -0
- najaeda/stats.py +211 -116
- najaeda-0.1.12.dist-info/METADATA +79 -0
- {najaeda-0.1.9.dist-info → najaeda-0.1.12.dist-info}/RECORD +14 -11
- najaeda-0.1.9.dist-info/METADATA +0 -197
- {najaeda-0.1.9.dist-info → najaeda-0.1.12.dist-info}/WHEEL +0 -0
- {najaeda-0.1.9.dist-info → najaeda-0.1.12.dist-info}/licenses/AUTHORS +0 -0
- {najaeda-0.1.9.dist-info → najaeda-0.1.12.dist-info}/licenses/LICENSE +0 -0
najaeda/docs/source/index.rst
CHANGED
najaeda/libnaja_snl.dylib
CHANGED
|
Binary file
|
najaeda/libnaja_snl_python.dylib
CHANGED
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
1004
|
-
|
|
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":
|
najaeda/pandas_stats.py
ADDED
|
@@ -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
|
|
11
|
+
class InstancesStats:
|
|
10
12
|
def __init__(self):
|
|
11
13
|
self.blackboxes = dict()
|
|
12
|
-
self.
|
|
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
|
-
|
|
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
|
|
55
|
-
if
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for ins in
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
67
|
-
|
|
171
|
+
instance_stats.basic_primitives[model_id] = (
|
|
172
|
+
instance_stats.basic_primitives.get(model_id, 0) + 1
|
|
68
173
|
)
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
74
|
-
|
|
178
|
+
instance_stats.primitives[model_id] = (
|
|
179
|
+
instance_stats.primitives.get(model_id, 0) + 1
|
|
75
180
|
)
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
81
|
-
|
|
185
|
+
instance_stats.blackboxes[model_id] = (
|
|
186
|
+
instance_stats.blackboxes.get(model_id, 0) + 1
|
|
82
187
|
)
|
|
83
|
-
|
|
84
|
-
|
|
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
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
91
|
-
model_stats =
|
|
195
|
+
if model_id in instances_stats.hier_instances:
|
|
196
|
+
model_stats = instances_stats.hier_instances[model_id]
|
|
92
197
|
else:
|
|
93
|
-
model_stats =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
213
|
+
instance_stats.terms["inputs"] = instance_stats.terms.get("inputs", 0) + 1
|
|
107
214
|
bit_terms = sum(1 for _ in term.get_bits())
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
219
|
+
instance_stats.terms["outputs"] = instance_stats.terms.get("outputs", 0) + 1
|
|
113
220
|
bit_terms = sum(1 for _ in term.get_bits())
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
225
|
+
instance_stats.terms["inouts"] = instance_stats.terms.get("inouts", 0) + 1
|
|
119
226
|
bit_terms = sum(1 for _ in term.get_bits())
|
|
120
|
-
|
|
121
|
-
|
|
227
|
+
instance_stats.bit_terms["inouts"] = (
|
|
228
|
+
instance_stats.bit_terms.get("inouts", 0) + bit_terms
|
|
122
229
|
)
|
|
123
230
|
else:
|
|
124
|
-
|
|
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
|
-
|
|
127
|
-
|
|
235
|
+
instance_stats.bit_terms["unknowns"] = (
|
|
236
|
+
instance_stats.bit_terms.get("unknowns", 0) + bit_terms
|
|
128
237
|
)
|
|
129
238
|
|
|
130
239
|
|
|
131
|
-
def
|
|
132
|
-
for net in
|
|
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
|
-
|
|
137
|
-
|
|
245
|
+
instance_stats.net_stats[nb_components] = (
|
|
246
|
+
instance_stats.net_stats.get(nb_components, 0) + 1
|
|
138
247
|
)
|
|
139
|
-
|
|
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
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
|
2
|
-
najaeda
|
|
3
|
-
najaeda
|
|
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=poDVm41oO4Iz7JkvlW_2ZVa8poCzOV92BmJVupVpd0U,808208
|
|
1
|
+
najaeda/netlist.py,sha256=8p0iHWDNbsMo-DndUBKLc43j7agtgb_jhlQdgkoYpvU,46750
|
|
2
|
+
najaeda/libnaja_snl_python.dylib,sha256=cipIwCgVc5N4CO9KfFA0v8hbHfwIpB5A4wNfoQfq--Q,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=
|
|
10
|
-
najaeda/snl.so,sha256=
|
|
11
|
-
najaeda/stats.py,sha256=
|
|
5
|
+
najaeda/libnaja_snl.dylib,sha256=T76kBcwP4dGXUXS5aD1mcNr5hBAL8ou-nJGQNg7tXIA,574160
|
|
6
|
+
najaeda/snl.so,sha256=DjnPH0vqcGKKdGaZDmeDq9r6_8m9w2AwxODv0LTcDqE,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=
|
|
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=vqMBchNIsmW0K9HInUQuY_xePW9YD3coNJy6G1Yfto8,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
|
najaeda-0.1.9.dist-info/METADATA
DELETED
|
@@ -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.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|