najaeda 0.1.12__cp310-cp310-macosx_11_0_arm64.whl → 0.1.14__cp310-cp310-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
najaeda/libnaja_snl.dylib CHANGED
Binary file
Binary file
File without changes
@@ -0,0 +1,341 @@
1
+ # SPDX-FileCopyrightText: 2024 The Naja authors <https://github.com/najaeda/naja/blob/main/AUTHORS>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ import logging
6
+ import os
7
+ from naja import snl
8
+
9
+
10
+ class DesignsStats:
11
+ def __init__(self):
12
+ self.blackboxes = dict()
13
+ self.hier_designs = dict()
14
+
15
+
16
+ class DesignStats:
17
+ def __init__(self):
18
+ self.name = ""
19
+ self.assigns = 0
20
+ self.flat_assigns = 0
21
+ self.basic_primitives = dict()
22
+ self.primitives = dict()
23
+ self.flat_basic_primitives = dict()
24
+ self.flat_primitives = dict()
25
+ self.blackboxes = dict()
26
+ self.flat_blackboxes = dict()
27
+ self.ins = dict()
28
+ self.flat_ins = dict()
29
+ self.terms = dict()
30
+ self.bit_terms = dict()
31
+ self.net_stats = dict()
32
+
33
+ def add_ins_stats(self, ins_stats):
34
+ self.flat_assigns += ins_stats.flat_assigns
35
+ for ins, nb in ins_stats.flat_ins.items():
36
+ self.flat_ins[ins] = self.flat_ins.get(ins, 0) + nb
37
+ for ins, nb in ins_stats.flat_blackboxes.items():
38
+ self.flat_blackboxes[ins] = self.flat_blackboxes.get(ins, 0) + nb
39
+ for primitive, nb in ins_stats.flat_primitives.items():
40
+ self.flat_primitives[primitive] = (
41
+ self.flat_primitives.get(primitive, 0) + nb
42
+ )
43
+ for primitive, nb in ins_stats.flat_basic_primitives.items():
44
+ self.flat_basic_primitives[primitive] = (
45
+ self.flat_basic_primitives.get(primitive, 0) + nb
46
+ )
47
+
48
+
49
+ def isBasicPrimitive(design):
50
+ return design.isConst0() or design.isConst1() or design.isBuf() or design.isInv()
51
+
52
+
53
+ def compute_design_stats(design, designs_stats):
54
+ if design in designs_stats.hier_designs:
55
+ return designs_stats.hier_designs.get(design)
56
+ design_stats = DesignStats()
57
+ design_stats.name = design.getName()
58
+ for ins in design.getInstances():
59
+ model = ins.getModel()
60
+ if model.isAssign():
61
+ design_stats.assigns += 1
62
+ design_stats.flat_assigns += 1
63
+ elif model.isPrimitive():
64
+ if isBasicPrimitive(model):
65
+ design_stats.basic_primitives[model] = (
66
+ design_stats.basic_primitives.get(model, 0) + 1
67
+ )
68
+ design_stats.flat_basic_primitives[model] = (
69
+ design_stats.flat_basic_primitives.get(model, 0) + 1
70
+ )
71
+ else:
72
+ design_stats.primitives[model] = (
73
+ design_stats.primitives.get(model, 0) + 1
74
+ )
75
+ design_stats.flat_primitives[model] = (
76
+ design_stats.flat_primitives.get(model, 0) + 1
77
+ )
78
+ elif model.isBlackBox():
79
+ design_stats.blackboxes[model] = design_stats.blackboxes.get(model, 0) + 1
80
+ design_stats.flat_blackboxes[model] = (
81
+ design_stats.flat_blackboxes.get(model, 0) + 1
82
+ )
83
+ if model not in designs_stats.blackboxes:
84
+ designs_stats.blackboxes[model] = dict()
85
+ compute_design_terms(model, designs_stats.blackboxes[model])
86
+ else:
87
+ if model in designs_stats.hier_designs:
88
+ model_stats = designs_stats.hier_designs[model]
89
+ else:
90
+ model_stats = compute_design_stats(model, designs_stats)
91
+ design_stats.ins[model] = design_stats.ins.get(model, 0) + 1
92
+ design_stats.flat_ins[model] = design_stats.flat_ins.get(model, 0) + 1
93
+ design_stats.add_ins_stats(model_stats)
94
+ compute_design_terms(design, design_stats)
95
+ compute_design_net_stats(design, design_stats)
96
+ designs_stats.hier_designs[design] = design_stats
97
+ return design_stats
98
+
99
+
100
+ def compute_design_terms(design, design_stats):
101
+ for term in design.getTerms():
102
+ if term.getDirection() == snl.SNLTerm.Direction.Input:
103
+ design_stats.terms["inputs"] = design_stats.terms.get("inputs", 0) + 1
104
+ bit_terms = sum(1 for _ in term.getBits())
105
+ design_stats.bit_terms["inputs"] = (
106
+ design_stats.bit_terms.get("inputs", 0) + bit_terms
107
+ )
108
+ elif term.getDirection() == snl.SNLTerm.Direction.Output:
109
+ design_stats.terms["outputs"] = design_stats.terms.get("outputs", 0) + 1
110
+ bit_terms = sum(1 for _ in term.getBits())
111
+ design_stats.bit_terms["outputs"] = (
112
+ design_stats.bit_terms.get("outputs", 0) + bit_terms
113
+ )
114
+ elif term.getDirection() == snl.SNLTerm.Direction.InOut:
115
+ design_stats.terms["inouts"] = design_stats.terms.get("inouts", 0) + 1
116
+ bit_terms = sum(1 for _ in term.getBits())
117
+ design_stats.bit_terms["inouts"] = (
118
+ design_stats.bit_terms.get("inouts", 0) + bit_terms
119
+ )
120
+ else:
121
+ design_stats.terms["unknowns"] = design_stats.terms.get("unknowns", 0) + 1
122
+ bit_terms = sum(1 for _ in term.getBits())
123
+ design_stats.bit_terms["unknowns"] = (
124
+ design_stats.bit_terms.get("unknowns", 0) + bit_terms
125
+ )
126
+
127
+
128
+ def compute_design_net_stats(design, design_stats):
129
+ for net in design.getBitNets():
130
+ if net.isConstant():
131
+ pass
132
+ nb_components = sum(1 for c in net.getComponents())
133
+ design_stats.net_stats[nb_components] = (
134
+ design_stats.net_stats.get(nb_components, 0) + 1
135
+ )
136
+ design_stats.net_stats = dict(sorted(design_stats.net_stats.items()))
137
+
138
+
139
+ def dump_instances(stats_file, title, instances):
140
+ if len(instances) == 0:
141
+ return
142
+ sorted_instances = sorted(instances.items(), key=lambda item: item[0].getName())
143
+ stats_file.write(title + " " + str(sum(j for i, j in sorted_instances)) + "\n")
144
+ line_char = 0
145
+ for instance in sorted_instances:
146
+ if line_char != 0:
147
+ stats_file.write(",")
148
+ line_char += 1
149
+ if line_char > 80:
150
+ stats_file.write("\n")
151
+ line_char = 0
152
+ elif line_char != 0:
153
+ stats_file.write(" ")
154
+ line_char += 1
155
+ instance_char = instance[0].getName() + ":" + str(instance[1])
156
+ line_char += len(instance_char)
157
+ stats_file.write(instance_char)
158
+ stats_file.write("\n\n")
159
+
160
+
161
+ def dump_blackboxes_stats(stats_file, design_stats):
162
+ if len(design_stats.blackboxes) > 0:
163
+ stats_file.write("*** BlackBoxes ***\n")
164
+ for bbox in design_stats.blackboxes.items():
165
+ design = bbox[0]
166
+ design_terms = bbox[1]
167
+ stats_file.write("*** " + design.getName() + " ***\n")
168
+ if len(design_terms) > 0:
169
+ stats_file.write("Terms: ")
170
+ first = True
171
+ for terms in design_terms.items():
172
+ if not first:
173
+ stats_file.write(", ")
174
+ else:
175
+ first = False
176
+ stats_file.write(terms[0] + ":" + str(terms[1]))
177
+ stats_file.write("\n")
178
+ stats_file.write("\n")
179
+
180
+
181
+ def dump_stats(design, stats_file, designs_stats, dumped_models):
182
+ if design.isPrimitive() or design.isBlackBox():
183
+ return
184
+ if design in dumped_models:
185
+ return
186
+ dumped_models.add(design)
187
+ stats_file.write("*** " + design.getName() + " ***\n")
188
+ design_stats = designs_stats.hier_designs.get(design)
189
+ if design_stats is None:
190
+ print("Cannot find " + str(design) + " in design_stats")
191
+ raise
192
+ if len(design_stats.terms) > 0:
193
+ stats_file.write("Terms: ")
194
+ first = True
195
+ for terms in design_stats.terms.items():
196
+ if not first:
197
+ stats_file.write(", ")
198
+ else:
199
+ first = False
200
+ stats_file.write(terms[0] + ":" + str(terms[1]))
201
+ stats_file.write("\n")
202
+
203
+ dump_instances(stats_file, "Instances:", design_stats.ins)
204
+ nb_primitives = sum(design_stats.basic_primitives.values()) + sum(
205
+ design_stats.primitives.values()
206
+ )
207
+ if nb_primitives > 1:
208
+ stats_file.write("Primitives: " + str(nb_primitives) + "\n")
209
+ dump_instances(stats_file, "Simple Primitives:", design_stats.basic_primitives)
210
+ dump_instances(stats_file, "Other Primitives:", design_stats.primitives)
211
+ dump_instances(stats_file, "Blackboxes:", design_stats.blackboxes)
212
+ if design_stats.assigns > 0:
213
+ stats_file.write("Assigns: " + str(design_stats.assigns) + "\n")
214
+ dump_instances(stats_file, "Flat Instances:", design_stats.flat_ins)
215
+ dump_instances(stats_file, "Flat Blackboxes:", design_stats.flat_blackboxes)
216
+ nb_primitives = sum(design_stats.flat_basic_primitives.values()) + sum(
217
+ design_stats.flat_primitives.values()
218
+ )
219
+ if nb_primitives > 1:
220
+ stats_file.write("Flat Primitives: " + str(nb_primitives) + "\n")
221
+ dump_instances(
222
+ stats_file, "Flat Simple Primitives:", design_stats.flat_basic_primitives
223
+ )
224
+ dump_instances(stats_file, "Flat Other Primitives:", design_stats.flat_primitives)
225
+ if design_stats.flat_assigns > 0:
226
+ stats_file.write("Flat Assigns: " + str(design_stats.flat_assigns) + "\n")
227
+ stats_file.write("\n")
228
+ for ins in design.getInstances():
229
+ model = ins.getModel()
230
+ dump_stats(model, stats_file, designs_stats, dumped_models)
231
+
232
+
233
+ def dump_pandas(designs_stats):
234
+ import pandas
235
+ import matplotlib.pyplot as plt
236
+
237
+ # create a figures directory erase the previous one
238
+ if os.path.exists("figures"):
239
+ import shutil
240
+
241
+ shutil.rmtree("figures")
242
+ os.makedirs("figures")
243
+
244
+ data = []
245
+ for design, design_stats in designs_stats.hier_designs.items():
246
+ data.append(
247
+ [
248
+ design.getName(),
249
+ sum(design_stats.terms.values()),
250
+ sum(design_stats.bit_terms.values()),
251
+ sum(design_stats.basic_primitives.values()),
252
+ sum(design_stats.primitives.values()),
253
+ sum(design_stats.blackboxes.values()),
254
+ sum(design_stats.ins.values()),
255
+ sum(design_stats.flat_ins.values()),
256
+ sum(design_stats.flat_blackboxes.values()),
257
+ sum(design_stats.flat_basic_primitives.values()),
258
+ sum(design_stats.flat_primitives.values()),
259
+ ]
260
+ )
261
+ df = pandas.DataFrame(
262
+ data,
263
+ columns=[
264
+ "Design",
265
+ "Terms",
266
+ "Bit Terms",
267
+ "Basic Primitives",
268
+ "Primitives",
269
+ "Blackboxes",
270
+ "Instances",
271
+ "Flat Instances",
272
+ "Flat Blackboxes",
273
+ "Flat Basic Primitives",
274
+ "Flat Primitives",
275
+ ],
276
+ )
277
+ df.to_csv("figures/designs_stats.csv", index=False)
278
+
279
+ net_series = pandas.Series(design_stats.net_stats)
280
+ nets_plot = net_series.plot(
281
+ kind="bar",
282
+ title="Number of nets with a given number of components for\n"
283
+ + design.getName(),
284
+ xlabel="number of components",
285
+ ylabel="number of nets",
286
+ )
287
+ nets_plot.set_yscale("log")
288
+ nets_plot.xaxis.set_major_locator(plt.MaxNLocator(100))
289
+ nets_figure = nets_plot.get_figure()
290
+ nets_figure.tight_layout()
291
+ nets_figure.savefig("figures/nets_" + design.getName() + ".png")
292
+
293
+ flat_primitives_series = pandas.Series(design_stats.flat_primitives)
294
+ primitives_plot = flat_primitives_series.plot(
295
+ kind="bar",
296
+ title="Number of primitives for\n" + design.getName(),
297
+ xlabel="primitive",
298
+ ylabel="number of flat instances",
299
+ )
300
+ primitives_plot.set_yscale("log")
301
+ primitives_figure = primitives_plot.get_figure()
302
+ primitives_figure.tight_layout()
303
+ primitives_figure.savefig("figures/flat_primitives_" + design.getName() + ".png")
304
+
305
+
306
+ def compute_and_dump_design_stats(design, stats_file, with_pandas=False):
307
+ designs_stats = DesignsStats()
308
+ compute_design_stats(design, designs_stats)
309
+ dumped_models = set()
310
+ dump_stats(design, stats_file, designs_stats, dumped_models)
311
+ dump_blackboxes_stats(stats_file, designs_stats)
312
+ if with_pandas:
313
+ dump_pandas(designs_stats)
314
+
315
+
316
+ def dump_constants(design, analyzed_models):
317
+ if design.isPrimitive():
318
+ return
319
+ if design in analyzed_models:
320
+ return
321
+ analyzed_models.add(design)
322
+ for bitnet in design.getBitNets():
323
+ if bitnet.isConstant():
324
+ logging.info(
325
+ "In design "
326
+ + design.getName()
327
+ + ", constant net "
328
+ + bitnet.getName()
329
+ + " of type "
330
+ + bitnet.getTypeAsString()
331
+ )
332
+ if all(False for _ in bitnet.getComponents()):
333
+ logging.info(" with zero connections\n")
334
+ else:
335
+ logging.info(" connected to:\n")
336
+ for component in bitnet.getComponents():
337
+ logging.info(str(component) + "\n")
338
+
339
+ for ins in design.getInstances():
340
+ model = ins.getModel()
341
+ dump_constants(model, analyzed_models)
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():
381
+ return model.getTermByID(termIDs[0])
382
+ else:
383
+ snlterm = model.getTermByID(termIDs[0])
384
+ if isinstance(snlterm, snl.SNLBusTerm):
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():
378
397
  return model.getTermByID(termIDs[0])
379
398
  else:
380
399
  snlterm = model.getTermByID(termIDs[0])
381
400
  if isinstance(snlterm, snl.SNLBusTerm):
382
- return snlterm.getBit(termIDs[1])
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
 
@@ -754,13 +783,23 @@ class Instance:
754
783
  """
755
784
 
756
785
  def __init__(self, path=snl.SNLPath()):
786
+ self.inst = None
787
+ self.revisionCount = 0
788
+ self.SNLID = [0, 0, 0, 0, 0, 0]
757
789
  if isinstance(path, snl.SNLPath):
758
790
  if path.size() > 0:
759
791
  self.pathIDs = path.getPathIDs()
792
+ self.revisionCount = path.getTailInstance().getModel().getRevisionCount()
793
+ self.inst = path.getTailInstance()
760
794
  else:
761
795
  self.pathIDs = []
762
796
  elif isinstance(path, list):
763
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()
764
803
 
765
804
  def __eq__(self, other) -> bool:
766
805
  return self.pathIDs == other.pathIDs
@@ -872,11 +911,24 @@ class Instance:
872
911
  """
873
912
  return self.__get_snl_model().isInv()
874
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
+
875
920
  def __get_snl_model(self):
876
921
  if self.is_top():
877
922
  return snl.SNLUniverse.get().getTopDesign()
878
- instance = get_snl_instance_from_id_list(self.pathIDs)
879
- 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()
880
932
 
881
933
  def __get_leaf_snl_object(self):
882
934
  if self.is_top():
@@ -919,10 +971,11 @@ class Instance:
919
971
  :return: an iterator over the child instances of this instance.
920
972
  :rtype: Iterator[Instance]
921
973
  """
974
+ path = get_snl_path_from_id_list(self.pathIDs)
922
975
  for inst in self.__get_snl_model().getInstances():
923
- path = self.pathIDs.copy()
924
- path.append(inst.getID())
925
- yield Instance(path)
976
+ path_child = snl.SNLPath(path, inst)
977
+ yield Instance(path_child)
978
+ # path.pop()
926
979
 
927
980
  def get_number_of_child_instances(self) -> int:
928
981
  """
@@ -1181,7 +1234,7 @@ class Instance:
1181
1234
  path = get_snl_path_from_id_list(self.pathIDs)
1182
1235
  design = self.__get_snl_model()
1183
1236
  newSNLTerm = snl.SNLScalarTerm.create(design, direction, name)
1184
- return Term(path, newSNLTerm)
1237
+ return Term(path.getPathIDs(), newSNLTerm)
1185
1238
 
1186
1239
  def create_output_term(self, name: str) -> Term:
1187
1240
  """Create an output Term in this Instance with the given name.
@@ -1222,10 +1275,9 @@ class Instance:
1222
1275
  path = get_snl_path_from_id_list(self.pathIDs)
1223
1276
  if path.size() > 0:
1224
1277
  snl.SNLUniquifier(path)
1225
- path = get_snl_path_from_id_list(self.pathIDs)
1226
1278
  design = self.__get_snl_model()
1227
1279
  newSNLTerm = snl.SNLBusTerm.create(design, direction, msb, lsb, name)
1228
- return Term(path, newSNLTerm)
1280
+ return Term(self.pathIDs, newSNLTerm)
1229
1281
 
1230
1282
  def create_inout_bus_term(self, name: str, msb: int, lsb: int) -> Term:
1231
1283
  """Create an inout bus Term in this Instance with the given name, msb and lsb.
@@ -1300,6 +1352,13 @@ class Instance:
1300
1352
  """
1301
1353
  self.__get_snl_model().dumpVerilog(path, name)
1302
1354
 
1355
+ def get_truth_table(self):
1356
+ """
1357
+ :return: the truth table of the instance.
1358
+ :rtype: list[str]
1359
+ """
1360
+ return self.__get_snl_model().getTruthTable()
1361
+
1303
1362
 
1304
1363
  def get_top_db() -> snl.SNLDB:
1305
1364
  if snl.SNLUniverse.get() is None:
@@ -1334,10 +1393,17 @@ def create_top(name: str) -> Instance:
1334
1393
  return Instance()
1335
1394
 
1336
1395
 
1337
- def load_verilog(files: list):
1396
+ class VerilogConfig:
1397
+ def __init__(self, keep_assigns=True):
1398
+ self.keep_assigns = keep_assigns
1399
+
1400
+
1401
+ def load_verilog(files: list, config: VerilogConfig = None) -> Instance:
1402
+ if config is None:
1403
+ config = VerilogConfig() # Use default settings
1338
1404
  start_time = time.time()
1339
1405
  logging.info(f"Loading verilog: {', '.join(files)}")
1340
- get_top_db().loadVerilog(files)
1406
+ get_top_db().loadVerilog(files, keep_assigns=config.keep_assigns)
1341
1407
  execution_time = time.time() - start_time
1342
1408
  logging.info(f"Loading done in {execution_time:.2f} seconds")
1343
1409
  return get_top()
@@ -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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: najaeda
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: Naja EDA Python package
5
5
  Author-Email: Naja Authors <contact@keplertech.io>
6
6
  License: Apache License 2.0
@@ -1,11 +1,14 @@
1
- najaeda/netlist.py,sha256=8p0iHWDNbsMo-DndUBKLc43j7agtgb_jhlQdgkoYpvU,46750
2
- najaeda/libnaja_snl_python.dylib,sha256=cipIwCgVc5N4CO9KfFA0v8hbHfwIpB5A4wNfoQfq--Q,825616
1
+ najaeda/netlist.py,sha256=FadEyKqZMS5cGzDt-WOZRmDcDc3dFFvQSw2iJusW7Y0,49236
2
+ najaeda/libnaja_snl_python.dylib,sha256=xF5MVZMKtWkwiyvigZdTYCOsTH8M9abFn07YWx6C9Fw,887680
3
3
  najaeda/pandas_stats.py,sha256=yOb4ka965U7rN4D6AwvSGmRyeT_O7Ed-5cmT8BFbfeo,1070
4
4
  najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
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
5
+ najaeda/net_visitor.py,sha256=P_esjibYb-wBDuF-AyF7es9sJYw1Ha8RhTPu-qKe7G4,1940
6
+ najaeda/libnaja_snl.dylib,sha256=_W6nRABcp6q9xoBF0hTOBDWwHBUB6-n8anUoTyNkn-s,574288
7
+ najaeda/snl.so,sha256=lRUMHy2TG1HRdV65DPiLny314jNElZWEWcHgkg6k0co,98272
8
+ najaeda/stats.py,sha256=wackXsf0x24ic9v-UifECHj4t5yveUWssMDZp2B057A,16187
8
9
  najaeda/instance_visitor.py,sha256=JMsPSQaWNiDjxS05rxg83a0PIsrOIuTi9G35hkwdibs,1530
10
+ najaeda/native/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ najaeda/native/stats.py,sha256=3iIPr-jitdMhbHthA4BauaTXwx1ijYIQuXwtoDyCf-A,13056
9
12
  najaeda/docs/requirements.txt,sha256=1XIBGTIplm2arC9HhDCfLuAjozGdVSXkqmOj8ybuT6U,121
10
13
  najaeda/docs/.readthedocs.yaml,sha256=nN_Psro-YdfPcIiueZkJcZepts68g23rqVThhKnmVRw,790
11
14
  najaeda/docs/source/index.rst,sha256=80VMfeEGHObnOUXRBxIzISQsG_HNkgT-pUpsDZsCfOY,387
@@ -21,10 +24,12 @@ najaeda/docs/source/equipotential.rst,sha256=0MDi-4fPEsX7K_ezWj5DB3mCalnhqN-sicY
21
24
  najaeda/docs/source/netlist_classes.rst,sha256=Zrha9MQVEdEwxmP2zhgC0K3iioZXXerzeFoOz5SrOXM,132
22
25
  najaeda/docs/source/introduction.rst,sha256=kE4qxEJCgcAswiT3rIJS21oBYIMg1cyT_rKmOzQgvsI,2095
23
26
  najaeda/docs/source/api.rst,sha256=47VCPyF4Py_1cklZ3q9fmOMhqqI17rxwU_VUJETfCwY,151
27
+ najaeda/.dylibs/libcapnp-1.1.0.dylib,sha256=l9SvRdxPrCI2mB_UitO7QjsaC7I5mq2R3rZjoIQKEYI,709328
28
+ najaeda/.dylibs/libkj-1.1.0.dylib,sha256=pB7dMks8b8ybJ6xKWqFR_hHjKsmpf7wzbcunZaS7gO4,578320
24
29
  najaeda/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
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=rOJaAfyDeYqpyZcvF2uMKwvjCoDaR0tVOjIX1nCiRq8,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
30
+ najaeda/primitives/xilinx.py,sha256=_VPQfWAp3oc4EgOzW-gy96BXdFZK6E4C7aOSdCn4JRU,26008
31
+ najaeda-0.1.14.dist-info/RECORD,,
32
+ najaeda-0.1.14.dist-info/WHEEL,sha256=rOJaAfyDeYqpyZcvF2uMKwvjCoDaR0tVOjIX1nCiRq8,114
33
+ najaeda-0.1.14.dist-info/METADATA,sha256=80hWLRV3mUTPKIbrne0o4kPXICFNFUO9oPtLN6zpA7o,2475
34
+ najaeda-0.1.14.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
35
+ najaeda-0.1.14.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377