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