najaeda 0.1.7__cp312-cp312-macosx_11_0_arm64.whl → 0.1.8__cp312-cp312-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.

@@ -11,18 +11,12 @@ version: 2
11
11
  # Set the OS, Python version and other tools you might need
12
12
  build:
13
13
  os: ubuntu-22.04
14
- apt_packages:
15
- - cmake
16
14
  tools:
17
15
  python: "3.12"
18
- # You can also specify other tool versions:
19
- # nodejs: "19"
20
- # rust: "1.64"
21
- # golang: "1.19"
22
16
 
23
17
  # Build documentation in the "docs/" directory with Sphinx
24
18
  sphinx:
25
- configuration: docs/conf.py
19
+ configuration: src/najaeda/najaeda/docs/source/conf.py
26
20
 
27
21
  # Optionally build your docs in additional formats such as PDF and ePub
28
22
  # formats:
@@ -34,4 +28,4 @@ sphinx:
34
28
  # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
35
29
  python:
36
30
  install:
37
- - requirements: docs/requirements.txt
31
+ - requirements: src/najaeda/najaeda/docs/requirements.txt
@@ -0,0 +1,7 @@
1
+ docutils>=0.12
2
+ Jinja2>=2.7.3
3
+ MarkupSafe>=0.23
4
+ Pygments>=1.6
5
+ Sphinx>=4.0,!=5.0.0
6
+ Breathe>=v4.35.0
7
+ sphinx_rtd_theme>=1.3.0
@@ -1,5 +1,5 @@
1
- najaeda API Documentation
2
- =========================
1
+ najaeda Complete API Documentation
2
+ ==================================
3
3
 
4
4
  .. automodule:: najaeda.netlist
5
5
  :members:
@@ -15,7 +15,7 @@ sys.path.insert(0, os.path.abspath('../../../'))
15
15
  project = 'najaeda'
16
16
  copyright = '2024, Naja authors'
17
17
  author = 'Naja authors'
18
- release = '0.1.6'
18
+ release = '0.1.8'
19
19
 
20
20
  # -- General configuration ---------------------------------------------------
21
21
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -0,0 +1,20 @@
1
+ Equipotential Class
2
+ ===================
3
+
4
+ .. automodule:: najaeda.equipotential
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
8
+
9
+ Equipotential Overview
10
+ ----------------------
11
+
12
+ The `Equipotential` class is responsible for managing equipotentials in the `najaeda` system.
13
+
14
+ Equipotential Attributes
15
+ ------------------------
16
+
17
+ .. autoclass:: najaeda.netlist.Equipotential
18
+ :members:
19
+ :undoc-members:
20
+ :show-inheritance:
@@ -10,4 +10,8 @@ najaeda documentation
10
10
  :maxdepth: 2
11
11
  :caption: Contents:
12
12
 
13
+ instance
14
+ term
15
+ net
16
+ equipotential
13
17
  api
@@ -0,0 +1,23 @@
1
+ Instance Class
2
+ ==============
3
+
4
+ .. automodule:: najaeda.instance
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
8
+
9
+ Instance Overview
10
+ -----------------
11
+
12
+ In `najaeda`, an `Instance` encapsulates the concept of an instance in its hierarchical context.
13
+
14
+ When an `Instance` is modified through editing methods,
15
+ `najaeda` will automatically manage the necessary uniquification.
16
+
17
+ Instance Attributes
18
+ -------------------
19
+
20
+ .. autoclass:: najaeda.netlist.Instance
21
+ :members:
22
+ :undoc-members:
23
+ :show-inheritance:
@@ -0,0 +1,20 @@
1
+ Net Class
2
+ =========
3
+
4
+ .. automodule:: najaeda.net
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
8
+
9
+ Net Overview
10
+ ------------
11
+
12
+ The `Net` class is responsible for managing nets in the `najaeda` system.
13
+
14
+ Net Attributes
15
+ --------------
16
+
17
+ .. autoclass:: najaeda.netlist.Net
18
+ :members:
19
+ :undoc-members:
20
+ :show-inheritance:
@@ -0,0 +1,20 @@
1
+ Term Class
2
+ ==========
3
+
4
+ .. automodule:: najaeda.term
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
8
+
9
+ Term Overview
10
+ -------------
11
+
12
+ The `Term` class is responsible for managing terms in the `najaeda` system.
13
+
14
+ Term Attributes
15
+ ---------------
16
+
17
+ .. autoclass:: najaeda.netlist.Term
18
+ :members:
19
+ :undoc-members:
20
+ :show-inheritance:
Binary file
najaeda/netlist.py CHANGED
@@ -32,7 +32,6 @@ def consistent_hash(obj):
32
32
  return b''.join(hash_object(i) for i in o)
33
33
  else:
34
34
  return hash_value(o)
35
-
36
35
  serialized_obj = default_serializer(obj)
37
36
  obj_bytes = hash_object(serialized_obj)
38
37
  return int(hashlib.sha256(obj_bytes).hexdigest(), 16)
@@ -71,6 +70,7 @@ class Equipotential:
71
70
 
72
71
  def __init__(self, term):
73
72
  snl_term = get_snl_term_for_ids(term.pathIDs, term.termIDs)
73
+ inst_term = None
74
74
  if isinstance(snl_term, snl.SNLBusTerm):
75
75
  raise ValueError("Equipotential cannot be constructed on bus term")
76
76
  if len(term.pathIDs) == 0:
@@ -82,10 +82,11 @@ class Equipotential:
82
82
  if inst_term is None:
83
83
  self.equi = None
84
84
  return
85
+ else:
86
+ snl_term = get_snl_term_for_ids(inst_term.pathIDs, inst_term.termIDs)
85
87
  else:
86
88
  inst_term = term
87
89
  path = get_snl_path_from_id_list(inst_term.pathIDs)
88
- snl_term = get_snl_term_for_ids(inst_term.pathIDs, inst_term.termIDs)
89
90
  ito = snl.SNLNetComponentOccurrence(
90
91
  path.getHeadPath(),
91
92
  path.getTailInstance().getInstTerm(snl_term)
@@ -95,6 +96,9 @@ class Equipotential:
95
96
  def __eq__(self, value):
96
97
  return self.equi == value.equi
97
98
 
99
+ def dump_dot(self, path: str):
100
+ self.equi.dumpDotFile(path)
101
+
98
102
  def get_inst_terms(self):
99
103
  if self.equi is not None:
100
104
  for term in self.equi.getInstTermOccurrences():
@@ -106,7 +110,7 @@ class Equipotential:
106
110
  def get_top_terms(self):
107
111
  if self.equi is not None:
108
112
  for term in self.equi.getTerms():
109
- yield Term(snl.SNLPath(), term)
113
+ yield Term([], term)
110
114
 
111
115
  def get_leaf_readers(self):
112
116
  if self.equi is not None:
@@ -151,10 +155,13 @@ class Net:
151
155
  raise ValueError(
152
156
  "Only one of `net` or `net_concat` should be provided, not both."
153
157
  )
154
- if path.size() > 0:
155
- self.pathIDs = path.getPathIDs()
156
- else:
157
- self.pathIDs = []
158
+ if isinstance(path, snl.SNLPath):
159
+ if path.size() > 0:
160
+ self.pathIDs = path.getPathIDs()
161
+ else:
162
+ self.pathIDs = []
163
+ elif isinstance(path, list):
164
+ self.pathIDs = path.copy()
158
165
  if net is not None:
159
166
  self.net = net
160
167
  elif net_concat is not None:
@@ -235,11 +242,10 @@ class Net:
235
242
  return sum(1 for _ in self.net_concat)
236
243
 
237
244
  def get_bits(self):
238
- path = get_snl_path_from_id_list(self.pathIDs)
239
245
  if hasattr(self, "net"):
240
246
  if isinstance(self.net, snl.SNLBusNet):
241
247
  for bit in self.net.getBits():
242
- yield Net(path, bit)
248
+ yield Net(self.pathIDs, bit)
243
249
  else:
244
250
  yield self
245
251
  else:
@@ -247,30 +253,28 @@ class Net:
247
253
  yield net
248
254
 
249
255
  def get_bit(self, index: int):
250
- path = get_snl_path_from_id_list(self.pathIDs)
251
256
  if hasattr(self, "net"):
252
257
  if isinstance(self.net, snl.SNLBusNet):
253
- return Net(path, self.net.getBit(index))
258
+ return Net(self.pathIDs, self.net.getBit(index))
254
259
  else:
255
260
  return None
256
261
  if 0 <= index < len(self.net_concat):
257
- return Net(path, self.net_concat[index])
262
+ return Net(self.pathIDs, self.net_concat[index])
258
263
  return None
259
264
 
260
265
  def get_inst_terms(self):
261
- init_path = get_snl_path_from_id_list(self.pathIDs)
262
266
  if hasattr(self, "net_concat"):
263
267
  raise ValueError("Cannot get inst terms from a net_concat")
264
268
  for term in self.net.getInstTerms():
265
- path = snl.SNLPath(init_path, term.getInstance())
269
+ path = self.pathIDs.copy()
270
+ path.append(term.getInstance().getID())
266
271
  yield Term(path, term.getBitTerm())
267
272
 
268
273
  def get_design_terms(self):
269
- path = get_snl_path_from_id_list(self.pathIDs)
270
274
  if hasattr(self, "net_concat"):
271
275
  raise ValueError("Cannot get terms from a net_concat")
272
276
  for term in self.net.getBitTerms():
273
- yield Term(path, term)
277
+ yield Term(self.pathIDs, term)
274
278
 
275
279
  def get_terms(self):
276
280
  for term in itertools.chain(self.get_design_terms(), self.get_inst_terms()):
@@ -306,10 +310,13 @@ class Term:
306
310
  else:
307
311
  self.termIDs = [term.getID(), term.getBit()]
308
312
 
309
- if path.size() > 0:
310
- self.pathIDs = path.getPathIDs()
311
- else:
312
- self.pathIDs = []
313
+ if isinstance(path, snl.SNLPath):
314
+ if path.size() > 0:
315
+ self.pathIDs = path.getPathIDs()
316
+ else:
317
+ self.pathIDs = []
318
+ elif isinstance(path, list):
319
+ self.pathIDs = path.copy()
313
320
 
314
321
  def __eq__(self, other) -> bool:
315
322
  return self.pathIDs == other.pathIDs and self.termIDs == other.termIDs
@@ -453,23 +460,21 @@ class Term:
453
460
  return None
454
461
 
455
462
  def get_lower_net(self) -> Net:
456
- path = get_snl_path_from_id_list(self.pathIDs)
457
463
  """Return the lower net of the term."""
458
- return self.__get_net(path, self.__get_snl_lower_bitnet)
464
+ return self.__get_net(self.pathIDs, self.__get_snl_lower_bitnet)
459
465
 
460
466
  def get_net(self) -> Net:
461
467
  """Return the net of the term."""
462
- path = get_snl_path_from_id_list(self.pathIDs)
463
- if path.empty():
468
+ head_path = self.pathIDs.copy()
469
+ if len(head_path) == 0:
464
470
  return None
465
471
  # path is one level up
466
- head_path = path.getHeadPath()
472
+ head_path.pop()
467
473
  return self.__get_net(head_path, self.__get_snl_bitnet)
468
474
 
469
475
  def get_instance(self):
470
- path = get_snl_path_from_id_list(self.pathIDs)
471
476
  """Return the instance of the term."""
472
- return Instance(path)
477
+ return Instance(self.pathIDs)
473
478
 
474
479
  def get_flat_fanout(self):
475
480
  return self.get_equipotential().get_leaf_readers()
@@ -488,17 +493,16 @@ class Term:
488
493
  return snlterm.getDirection() == snl.SNLTerm.Direction.Output
489
494
 
490
495
  def get_bits(self):
491
- path = get_snl_path_from_id_list(self.pathIDs)
492
496
  if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
493
497
  for bit in get_snl_term_for_ids(self.pathIDs, self.termIDs).getBits():
494
- yield Term(path, bit)
498
+ yield Term(self.pathIDs, bit)
495
499
  else:
496
500
  yield self
497
501
 
498
502
  def get_bit(self, index: int):
499
- path = get_snl_path_from_id_list(self.pathIDs)
500
503
  if isinstance(get_snl_term_for_ids(self.pathIDs, self.termIDs), snl.SNLBusTerm):
501
- return Term(path, get_snl_term_for_ids(self.pathIDs, self.termIDs).getBit(index))
504
+ return Term(self.pathIDs, get_snl_term_for_ids(
505
+ self.pathIDs, self.termIDs).getBit(index))
502
506
  return None
503
507
 
504
508
  def disconnect(self):
@@ -564,10 +568,13 @@ class Instance:
564
568
  """
565
569
 
566
570
  def __init__(self, path=snl.SNLPath()):
567
- if path.size() > 0:
568
- self.pathIDs = path.getPathIDs()
569
- else:
570
- self.pathIDs = []
571
+ if isinstance(path, snl.SNLPath):
572
+ if path.size() > 0:
573
+ self.pathIDs = path.getPathIDs()
574
+ else:
575
+ self.pathIDs = []
576
+ elif isinstance(path, list):
577
+ self.pathIDs = path.copy()
571
578
 
572
579
  def __eq__(self, other) -> bool:
573
580
  return self.pathIDs == other.pathIDs
@@ -658,17 +665,26 @@ class Instance:
658
665
  return found_model
659
666
  return None
660
667
 
668
+ def dump_full_dot(self, path: str):
669
+ """Dump the full dot file of this instance."""
670
+ self.__get_snl_model().dumpFullDotFile(path)
671
+
672
+ def dump_context_dot(self, path: str):
673
+ self.__get_snl_model().dumpContextDotFile(path)
674
+
661
675
  def get_child_instance(self, name: str):
676
+ """Return the child instance with the given name."""
662
677
  childInst = self.__get_snl_model().getInstance(name)
663
678
  if childInst is None:
664
679
  return None
665
- path = get_snl_path_from_id_list(self.pathIDs)
666
- return Instance(snl.SNLPath(path, childInst))
680
+ path = self.pathIDs.copy()
681
+ path.append(childInst.getID())
682
+ return Instance(path)
667
683
 
668
684
  def get_child_instances(self):
669
685
  for inst in self.__get_snl_model().getInstances():
670
- path_init = get_snl_path_from_id_list(self.pathIDs)
671
- path = snl.SNLPath(path_init, inst)
686
+ path = self.pathIDs.copy()
687
+ path.append(inst.getID())
672
688
  yield Instance(path)
673
689
 
674
690
  def get_number_of_child_instances(self) -> int:
@@ -691,24 +707,28 @@ class Instance:
691
707
  # stack.append([inst_child, path_child])
692
708
 
693
709
  def get_nets(self):
694
- path = get_snl_path_from_id_list(self.pathIDs)
710
+ """Return the nets of the instance.
711
+ This will iterate over all scalar nets and bus nets.
712
+ """
695
713
  for net in self.__get_snl_model().getNets():
696
- yield Net(path, net)
714
+ yield Net(self.pathIDs, net)
697
715
 
698
716
  def get_flat_nets(self):
699
- path = get_snl_path_from_id_list(self.pathIDs)
717
+ """Return the nets of the instance.
718
+ This will iterate over all scalar nets and bus net bits.
719
+ """
700
720
  for net in self.__get_snl_model().getNets():
701
721
  if isinstance(net, snl.SNLBusNet):
702
722
  for bit in net.getBits():
703
- yield Net(path, bit)
723
+ yield Net(self.pathIDs, bit)
704
724
  else:
705
- yield Net(path, net)
725
+ yield Net(self.pathIDs, net)
706
726
 
707
727
  def get_net(self, name: str) -> Net:
708
- path = get_snl_path_from_id_list(self.pathIDs)
728
+ """Return the net with the given name."""
709
729
  net = self.__get_snl_model().getNet(name)
710
730
  if net is not None:
711
- return Net(path, net)
731
+ return Net(self.pathIDs, net)
712
732
  return None
713
733
 
714
734
  def is_primitive(self) -> bool:
@@ -716,60 +736,73 @@ class Instance:
716
736
  return self.__get_snl_model().isPrimitive()
717
737
 
718
738
  def get_terms(self):
719
- path = get_snl_path_from_id_list(self.pathIDs)
739
+ """Return the terms of the instance.
740
+ This will iterate over all scalar terms and bus terms.
741
+ """
720
742
  for term in self.__get_snl_model().getTerms():
721
- yield Term(path, term)
743
+ yield Term(self.pathIDs, term)
722
744
 
723
745
  def get_flat_terms(self):
724
- path = get_snl_path_from_id_list(self.pathIDs)
746
+ """Return the flat terms of the instance.
747
+ This will iterate over all scalar terms and bus term bits.
748
+ """
725
749
  for term in self.__get_snl_model().getBitTerms():
726
- yield Term(path, term)
750
+ yield Term(self.pathIDs, term)
727
751
 
728
752
  def get_term(self, name: str) -> Term:
729
- path = get_snl_path_from_id_list(self.pathIDs)
753
+ """Return the term with the given name."""
730
754
  term = self.__get_snl_model().getTerm(name)
731
755
  if term is not None:
732
- return Term(path, self.__get_snl_model().getTerm(name))
756
+ return Term(self.pathIDs, self.__get_snl_model().getTerm(name))
733
757
  return None
734
758
 
735
759
  def get_input_terms(self):
736
- path = get_snl_path_from_id_list(self.pathIDs)
760
+ """Return the input terms of the instance.
761
+ This will iterate over all scalar input terms and bus input terms.
762
+ """
737
763
  for term in self.__get_snl_model().getTerms():
738
764
  if term.getDirection() != snl.SNLTerm.Direction.Output:
739
- yield Term(path, term)
765
+ yield Term(self.pathIDs, term)
740
766
 
741
767
  def get_flat_input_terms(self):
742
- path = get_snl_path_from_id_list(self.pathIDs)
768
+ """Return the flat input terms of the instance.
769
+ This will iterate over all scalar input terms and bus input term bits.
770
+ """
743
771
  for term in self.__get_snl_model().getTerms():
744
772
  if term.getDirection() != snl.SNLTerm.Direction.Output:
745
773
  if isinstance(term, snl.SNLBusTerm):
746
774
  for bit in term.getBits():
747
- yield Term(path, bit)
775
+ yield Term(self.pathIDs, bit)
748
776
  else:
749
- yield Term(path, term)
777
+ yield Term(self.pathIDs, term)
750
778
 
751
779
  def get_output_terms(self):
752
- path = get_snl_path_from_id_list(self.pathIDs)
780
+ """Return the output terms of the instance.
781
+ This will iterate over all scalar output terms and bus output terms.
782
+ """
753
783
  for term in self.__get_snl_model().getTerms():
754
784
  if term.getDirection() != snl.SNLTerm.Direction.Input:
755
- yield Term(path, term)
785
+ yield Term(self.pathIDs, term)
756
786
 
757
787
  def get_flat_output_terms(self):
758
- path = get_snl_path_from_id_list(self.pathIDs)
788
+ """Return the flat output terms of the instance.
789
+ This will iterate over all scalar output terms and bus output term bits.
790
+ """
759
791
  for term in self.__get_snl_model().getTerms():
760
792
  if term.getDirection() != snl.SNLTerm.Direction.Input:
761
793
  if isinstance(term, snl.SNLBusTerm):
762
794
  for bit in term.getBits():
763
- yield Term(path, bit)
795
+ yield Term(self.pathIDs, bit)
764
796
  else:
765
- yield Term(path, term)
797
+ yield Term(self.pathIDs, term)
766
798
 
767
799
  def delete_instance(self, name: str):
768
- init_path = get_snl_path_from_id_list(self.pathIDs)
800
+ """Delete the child instance with the given name."""
769
801
  if name == "":
770
802
  raise ValueError(
771
803
  "Cannot delete instance with empty name. Try delete_instance_by_id instead."
772
804
  )
805
+ init_path = get_snl_path_from_id_list(self.pathIDs)
773
806
  path = snl.SNLPath(init_path, self.__get_snl_model().getInstance(name))
774
807
  snl.SNLUniquifier(path)
775
808
  if init_path.size() > 0:
@@ -777,6 +810,7 @@ class Instance:
777
810
  self.__get_snl_model().getInstance(name).destroy()
778
811
 
779
812
  def delete_instance_by_id(self, id: str):
813
+ """Delete the child instance with the given ID."""
780
814
  init_path = get_snl_path_from_id_list(self.pathIDs)
781
815
  path = snl.SNLPath(init_path, self.__get_snl_model().getInstanceByID(id))
782
816
  snl.SNLUniquifier(path)
@@ -784,19 +818,22 @@ class Instance:
784
818
  self.__get_snl_model().getInstanceByID(id).destroy()
785
819
 
786
820
  def get_design(self):
787
- path = get_snl_path_from_id_list(self.pathIDs)
821
+ """Return the Instance containing this instance."""
822
+ path = self.pathIDs.copy()
788
823
  if len(self.pathIDs) == 1:
789
824
  return get_top()
790
- return Instance(path.getHeadPath())
825
+ path.pop()
826
+ return Instance(path)
791
827
 
792
828
  def delete(self):
829
+ """Delete this instance."""
793
830
  path = get_snl_path_from_id_list(self.pathIDs)
794
831
  snl.SNLUniquifier(path)
795
832
  self.get_design().delete_instance_by_id(path.getTailInstance().getID())
796
833
 
797
834
  def get_name(self) -> str:
798
- path = get_snl_path_from_id_list(self.pathIDs)
799
835
  """Return the name of the instance or name of the top is this is the top."""
836
+ path = get_snl_path_from_id_list(self.pathIDs)
800
837
  if self.is_top():
801
838
  return self.get_model_name()
802
839
  else:
@@ -807,10 +844,12 @@ class Instance:
807
844
  return self.__get_snl_model().getName()
808
845
 
809
846
  def get_model_id(self) -> tuple[int, int, int]:
847
+ """Return the ID of the model of the instance or ID of the top is this is the top."""
810
848
  model = self.__get_snl_model()
811
849
  return model.getDB().getID(), model.getLibrary().getID(), model.getID()
812
850
 
813
851
  def create_child_instance(self, model: str, name: str):
852
+ """Create a child instance with the given model and name."""
814
853
  path = get_snl_path_from_id_list(self.pathIDs)
815
854
  if path.size() > 0:
816
855
  snl.SNLUniquifier(path)
@@ -826,6 +865,7 @@ class Instance:
826
865
  return Instance(path)
827
866
 
828
867
  def create_term(self, name: str, direction: snl.SNLTerm.Direction) -> Term:
868
+ """Create a Term in this Instance with the given name and direction."""
829
869
  path = get_snl_path_from_id_list(self.pathIDs)
830
870
  if path.size() > 0:
831
871
  snl.SNLUniquifier(path)
@@ -835,15 +875,19 @@ class Instance:
835
875
  return Term(path, newSNLTerm)
836
876
 
837
877
  def create_output_term(self, name: str) -> Term:
878
+ """Create an output Term in this Instance with the given name."""
838
879
  return self.create_term(name, snl.SNLTerm.Direction.Output)
839
880
 
840
881
  def create_input_term(self, name: str) -> Term:
882
+ """Create an input Term in this Instance with the given name."""
841
883
  return self.create_term(name, snl.SNLTerm.Direction.Input)
842
884
 
843
885
  def create_inout_term(self, name: str) -> Term:
886
+ """Create an inout Term in this Instance with the given name."""
844
887
  return self.create_term(name, snl.SNLTerm.Direction.InOut)
845
888
 
846
889
  def create_bus_term(self, name: str, msb: int, lsb: int, direction) -> Term:
890
+ """Create a bus Term in this Instance with the given name, msb, lsb and direction."""
847
891
  path = get_snl_path_from_id_list(self.pathIDs)
848
892
  if path.size() > 0:
849
893
  snl.SNLUniquifier(path)
@@ -853,15 +897,19 @@ class Instance:
853
897
  return Term(path, newSNLTerm)
854
898
 
855
899
  def create_inout_bus_term(self, name: str, msb: int, lsb: int) -> Term:
900
+ """Create an inout bus Term in this Instance with the given name, msb and lsb."""
856
901
  return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.InOut)
857
902
 
858
903
  def create_output_bus_term(self, name: str, msb: int, lsb: int) -> Term:
904
+ """Create an output bus Term in this Instance with the given name, msb and lsb."""
859
905
  return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Output)
860
906
 
861
907
  def create_input_bus_term(self, name: str, msb: int, lsb: int) -> Term:
908
+ """Create an input bus Term in this Instance with the given name, msb and lsb."""
862
909
  return self.create_bus_term(name, msb, lsb, snl.SNLTerm.Direction.Input)
863
910
 
864
911
  def create_net(self, name: str) -> Net:
912
+ """Create a scalar Net in this Instance with the given name."""
865
913
  path = get_snl_path_from_id_list(self.pathIDs)
866
914
  if path.size() > 0:
867
915
  snl.SNLUniquifier(path)
@@ -871,6 +919,7 @@ class Instance:
871
919
  return Net(path, newSNLNet)
872
920
 
873
921
  def create_bus_net(self, name: str, msb: int, lsb: int) -> Net:
922
+ """Create a bus Net in this Instance with the given name, msb and lsb."""
874
923
  path = get_snl_path_from_id_list(self.pathIDs)
875
924
  if path.size() > 0:
876
925
  snl.SNLUniquifier(path)
@@ -880,6 +929,7 @@ class Instance:
880
929
  return Net(path, newSNLNet)
881
930
 
882
931
  def dump_verilog(self, path: str, name: str):
932
+ """Dump the verilog of this instance."""
883
933
  self.__get_snl_model().dumpVerilog(path, name)
884
934
 
885
935
 
najaeda/stats.py ADDED
@@ -0,0 +1,320 @@
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
+ from najaeda import netlist
7
+
8
+
9
+ class DesignsStats:
10
+ def __init__(self):
11
+ self.blackboxes = dict()
12
+ self.hier_designs = dict()
13
+
14
+
15
+ class DesignStats:
16
+ def __init__(self):
17
+ self.name = ""
18
+ self.assigns = 0
19
+ self.flat_assigns = 0
20
+ self.basic_primitives = dict()
21
+ self.primitives = dict()
22
+ self.flat_basic_primitives = dict()
23
+ self.flat_primitives = dict()
24
+ self.blackboxes = dict()
25
+ self.flat_blackboxes = dict()
26
+ self.ins = dict()
27
+ self.flat_ins = dict()
28
+ self.terms = dict()
29
+ self.bit_terms = dict()
30
+ self.net_stats = dict()
31
+
32
+ def add_ins_stats(self, ins_stats):
33
+ self.flat_assigns += ins_stats.flat_assigns
34
+ for ins, nb in ins_stats.flat_ins.items():
35
+ self.flat_ins[ins] = self.flat_ins.get(ins, 0) + nb
36
+ for ins, nb in ins_stats.flat_blackboxes.items():
37
+ self.flat_blackboxes[ins] = self.flat_blackboxes.get(ins, 0) + nb
38
+ for primitive, nb in ins_stats.flat_primitives.items():
39
+ self.flat_primitives[primitive] = (
40
+ self.flat_primitives.get(primitive, 0) + nb
41
+ )
42
+ for primitive, nb in ins_stats.flat_basic_primitives.items():
43
+ self.flat_basic_primitives[primitive] = (
44
+ self.flat_basic_primitives.get(primitive, 0) + nb
45
+ )
46
+
47
+
48
+ def is_basic_primitive(design):
49
+ return (
50
+ design.is_const0() or design.is_const1() or design.is_buf() or design.is_inv()
51
+ )
52
+
53
+
54
+ def compute_design_stats(design, designs_stats):
55
+ if design.get_model_id() in designs_stats.hier_designs:
56
+ return designs_stats.hier_designs.get(design.get_model_id())
57
+ design_stats = DesignStats()
58
+ design_stats.name = design.get_model_name()
59
+ for ins in design.get_child_instances():
60
+ model_id = ins.get_model_id()
61
+ if ins.is_assign():
62
+ design_stats.assigns += 1
63
+ design_stats.flat_assigns += 1
64
+ elif ins.is_primitive():
65
+ if is_basic_primitive(ins):
66
+ design_stats.basic_primitives[model_id] = (
67
+ design_stats.basic_primitives.get(model_id, 0) + 1
68
+ )
69
+ design_stats.flat_basic_primitives[model_id] = (
70
+ design_stats.flat_basic_primitives.get(model_id, 0) + 1
71
+ )
72
+ else:
73
+ design_stats.primitives[model_id] = (
74
+ design_stats.primitives.get(model_id, 0) + 1
75
+ )
76
+ design_stats.flat_primitives[model_id] = (
77
+ design_stats.flat_primitives.get(model_id, 0) + 1
78
+ )
79
+ elif ins.is_blackbox():
80
+ design_stats.blackboxes[model_id] = (
81
+ design_stats.blackboxes.get(model_id, 0) + 1
82
+ )
83
+ design_stats.flat_blackboxes[model_id] = (
84
+ design_stats.flat_blackboxes.get(model_id, 0) + 1
85
+ )
86
+ if model_id not in designs_stats.blackboxes:
87
+ designs_stats.blackboxes[model_id] = dict()
88
+ compute_design_terms(model_id, designs_stats.blackboxes[model_id])
89
+ else:
90
+ if model_id in designs_stats.hier_designs:
91
+ model_stats = designs_stats.hier_designs[model_id]
92
+ else:
93
+ model_stats = compute_design_stats(ins, designs_stats)
94
+ design_stats.ins[model_id] = design_stats.ins.get(model_id, 0) + 1
95
+ design_stats.flat_ins[model_id] = design_stats.flat_ins.get(model_id, 0) + 1
96
+ design_stats.add_ins_stats(model_stats)
97
+ compute_design_terms(design, design_stats)
98
+ compute_design_net_stats(design, design_stats)
99
+ designs_stats.hier_designs[design.get_model_id()] = design_stats
100
+ return design_stats
101
+
102
+
103
+ def compute_design_terms(design, design_stats):
104
+ for term in design.get_terms():
105
+ if term.get_direction() == netlist.Term.INPUT:
106
+ design_stats.terms["inputs"] = design_stats.terms.get("inputs", 0) + 1
107
+ bit_terms = sum(1 for _ in term.get_bits())
108
+ design_stats.bit_terms["inputs"] = (
109
+ design_stats.bit_terms.get("inputs", 0) + bit_terms
110
+ )
111
+ elif term.get_direction() == netlist.Term.OUTPUT:
112
+ design_stats.terms["outputs"] = design_stats.terms.get("outputs", 0) + 1
113
+ bit_terms = sum(1 for _ in term.get_bits())
114
+ design_stats.bit_terms["outputs"] = (
115
+ design_stats.bit_terms.get("outputs", 0) + bit_terms
116
+ )
117
+ elif term.get_direction() == netlist.Term.INOUT:
118
+ design_stats.terms["inouts"] = design_stats.terms.get("inouts", 0) + 1
119
+ bit_terms = sum(1 for _ in term.get_bits())
120
+ design_stats.bit_terms["inouts"] = (
121
+ design_stats.bit_terms.get("inouts", 0) + bit_terms
122
+ )
123
+ else:
124
+ design_stats.terms["unknowns"] = design_stats.terms.get("unknowns", 0) + 1
125
+ bit_terms = sum(1 for _ in term.get_bits())
126
+ design_stats.bit_terms["unknowns"] = (
127
+ design_stats.bit_terms.get("unknowns", 0) + bit_terms
128
+ )
129
+
130
+
131
+ def compute_design_net_stats(design, design_stats):
132
+ for net in design.get_flat_nets():
133
+ if net.is_const():
134
+ pass
135
+ nb_components = sum(1 for c in net.get_terms())
136
+ design_stats.net_stats[nb_components] = (
137
+ design_stats.net_stats.get(nb_components, 0) + 1
138
+ )
139
+ design_stats.net_stats = dict(sorted(design_stats.net_stats.items()))
140
+
141
+
142
+ def dump_instances(stats_file, title, instances):
143
+ if len(instances) == 0:
144
+ return
145
+ sorted_instances = sorted(
146
+ instances.items(), key=lambda item: netlist.get_model_name(item[0])
147
+ )
148
+ stats_file.write(title + " " + str(sum(j for i, j in sorted_instances)) + "\n")
149
+ line_char = 0
150
+ for instance in sorted_instances:
151
+ model_name = netlist.get_model_name(instance[0])
152
+ if line_char != 0:
153
+ stats_file.write(",")
154
+ line_char += 1
155
+ if line_char > 80:
156
+ stats_file.write("\n")
157
+ line_char = 0
158
+ elif line_char != 0:
159
+ stats_file.write(" ")
160
+ line_char += 1
161
+ instance_char = model_name + ":" + str(instance[1])
162
+ line_char += len(instance_char)
163
+ stats_file.write(instance_char)
164
+ stats_file.write("\n\n")
165
+
166
+
167
+ def dump_blackboxes_stats(stats_file, design_stats):
168
+ if len(design_stats.blackboxes) > 0:
169
+ stats_file.write("*** BlackBoxes ***\n")
170
+ for bbox in design_stats.blackboxes.items():
171
+ design = bbox[0]
172
+ design_terms = bbox[1]
173
+ stats_file.write("*** " + design.getName() + " ***\n")
174
+ if len(design_terms) > 0:
175
+ stats_file.write("Terms: ")
176
+ first = True
177
+ for terms in design_terms.items():
178
+ if not first:
179
+ stats_file.write(", ")
180
+ else:
181
+ first = False
182
+ stats_file.write(terms[0] + ":" + str(terms[1]))
183
+ stats_file.write("\n")
184
+ stats_file.write("\n")
185
+
186
+
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
+ # def dump_pandas(designs_stats):
239
+ # import pandas
240
+ # import matplotlib.pyplot as plt
241
+ #
242
+ # #create a figures directory erase the previous one
243
+ # if os.path.exists('figures'):
244
+ # import shutil
245
+ # shutil.rmtree('figures')
246
+ # os.makedirs('figures')
247
+ #
248
+ # data = []
249
+ # for design, design_stats in designs_stats.hier_designs.items():
250
+ # data.append([
251
+ # design.getName(),
252
+ # sum(design_stats.terms.values()),
253
+ # sum(design_stats.bit_terms.values()),
254
+ # sum(design_stats.basic_primitives.values()),
255
+ # sum(design_stats.primitives.values()),
256
+ # sum(design_stats.blackboxes.values()),
257
+ # sum(design_stats.ins.values()),
258
+ # sum(design_stats.flat_ins.values()),
259
+ # sum(design_stats.flat_blackboxes.values()),
260
+ # sum(design_stats.flat_basic_primitives.values()),
261
+ # sum(design_stats.flat_primitives.values())])
262
+ # df = pandas.DataFrame(data, columns=[
263
+ # 'Design', 'Terms', 'Bit Terms',
264
+ # 'Basic Primitives', 'Primitives', 'Blackboxes', 'Instances',
265
+ # 'Flat Instances', 'Flat Blackboxes',
266
+ # 'Flat Basic Primitives', 'Flat Primitives'])
267
+ # df.to_csv('figures/designs_stats.csv', index=False)
268
+ #
269
+ # net_series = pandas.Series(design_stats.net_stats)
270
+ # nets_plot = net_series.plot(kind='bar',
271
+ # title='Number of nets with a given number of components for\n' + design.getName(),
272
+ # xlabel='number of components', ylabel='number of nets')
273
+ # nets_plot.set_yscale('log')
274
+ # nets_plot.xaxis.set_major_locator(plt.MaxNLocator(100))
275
+ # nets_figure = nets_plot.get_figure()
276
+ # nets_figure.tight_layout()
277
+ # nets_figure.savefig('figures/nets_' + design.getName() + '.png')
278
+ #
279
+ # flat_primitives_series = pandas.Series(design_stats.flat_primitives)
280
+ # primitives_plot = flat_primitives_series.plot(kind='bar',
281
+ # title='Number of primitives for\n' + design.getName(),
282
+ # xlabel='primitive', ylabel='number of flat instances')
283
+ # primitives_plot.set_yscale('log')
284
+ # primitives_figure = primitives_plot.get_figure()
285
+ # primitives_figure.tight_layout()
286
+ # primitives_figure.savefig('figures/flat_primitives_' + design.getName() + '.png')
287
+
288
+
289
+ def compute_and_dump_design_stats(design, stats_file, with_pandas=False):
290
+ designs_stats = DesignsStats()
291
+ compute_design_stats(design, designs_stats)
292
+ dumped_models = set()
293
+ dump_stats(design, stats_file, designs_stats, dumped_models)
294
+ dump_blackboxes_stats(stats_file, designs_stats)
295
+ # if with_pandas:
296
+ # dump_pandas(designs_stats)
297
+
298
+
299
+ def dump_constants(design, analyzed_models):
300
+ if design.isPrimitive():
301
+ return
302
+ if design in analyzed_models:
303
+ return
304
+ analyzed_models.add(design)
305
+ for bitnet in design.getBitNets():
306
+ if bitnet.isConstant():
307
+ message = f"In design {design.getName()}, \
308
+ constant net {bitnet.getName()} \
309
+ of type {bitnet.getTypeAsString()}"
310
+ logging.info(message)
311
+ if all(False for _ in bitnet.getComponents()):
312
+ logging.info(" with zero connections\n")
313
+ else:
314
+ logging.info(" connected to:\n")
315
+ for component in bitnet.getComponents():
316
+ logging.info(str(component) + "\n")
317
+
318
+ for ins in design.getInstances():
319
+ model = ins.getModel()
320
+ dump_constants(model, analyzed_models)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: najaeda
3
- Version: 0.1.7
3
+ Version: 0.1.8
4
4
  Summary: Naja EDA Python package
5
5
  Author-Email: Naja Authors <contact@keplertech.io>
6
6
  License: Apache License 2.0
@@ -54,6 +54,11 @@ Install Naja EDA using pip:
54
54
 
55
55
  pip install najaeda
56
56
 
57
+ Documentation
58
+ -------------
59
+
60
+ Naja EDA online documentation is available `here <https://najaeda.readthedocs.io/en/latest/index.html>`_.
61
+
57
62
  Examples
58
63
  --------
59
64
 
@@ -92,7 +97,7 @@ easily extended in the future. Don't hesitate to reach out if you need help.
92
97
 
93
98
  netlist.load_primitives('xilinx')
94
99
  benchmarks = path.join('..','benchmarks')
95
- top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'arm_core_netlist.v')])
100
+ top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'vexriscv.v')])
96
101
 
97
102
  Print all the instances in the netlist
98
103
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -0,0 +1,25 @@
1
+ najaeda-0.1.8.dist-info/RECORD,,
2
+ najaeda-0.1.8.dist-info/WHEEL,sha256=bS2kxwU1pioFffhNQmlfvjD0H1flBf5ZtxV4jDj8Nvc,114
3
+ najaeda-0.1.8.dist-info/METADATA,sha256=Gs7f1HbI7hS--g6TbdjGTvnIa85u8WDsmFnAHdslz2g,6880
4
+ najaeda-0.1.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
5
+ najaeda-0.1.8.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377
6
+ najaeda/netlist.py,sha256=xcn-v5Vhjt1di8yDJV5T9SKpKIkyXKRnodBzP50RiCw,37044
7
+ najaeda/libnaja_snl_python.dylib,sha256=rrnm_iwb4e4P9AWHpz3mJTkIeFvAI32_okrVfZoz_0E,808208
8
+ najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ najaeda/libnaja_snl.dylib,sha256=AFqR64aX6KnzkX6lrLGCuscx2f5E07umNC_7E9cNrT0,574272
10
+ najaeda/snl.so,sha256=2vv_LPtR0B-txFyT1mZYaYoaqPw6vd42BX2UROwOR8A,97888
11
+ najaeda/stats.py,sha256=9taIJ2ns8E8W_Cm9xThq9-S6Gr6TMPb7qLTJPfx4jFk,12891
12
+ najaeda/instance_visitor.py,sha256=2HnQ5y8-0tSOKd9nS4WYiypccQWLJgKfs84wp357Tls,1781
13
+ najaeda/docs/requirements.txt,sha256=1XIBGTIplm2arC9HhDCfLuAjozGdVSXkqmOj8ybuT6U,121
14
+ najaeda/docs/Makefile,sha256=4zv3TVkTACm6JBaKgTES3ZI9cETXgM6ULbZkXZP1as8,638
15
+ najaeda/docs/make.bat,sha256=L4I5T7uDUIjwGyMRJ-y9FoT61sxIyCuaYuJyLt8c-nA,804
16
+ najaeda/docs/.readthedocs.yaml,sha256=TL2hK9gR25hw-7_gMeywIqBikAP0mVPRB-O4wGfrdPU,900
17
+ najaeda/docs/source/index.rst,sha256=nYkctDLuoue7UMQi5gV-PARChvJDb_3P4e_9NTqzJtc,367
18
+ najaeda/docs/source/instance.rst,sha256=uqyHR7dN9po3sN_APC3C8vk7W2MT0ca49memgtFpzCk,517
19
+ najaeda/docs/source/conf.py,sha256=GIJ89oFBSXucgDBXLcyyWC-cU_lC3GvfswnmLxm9pVM,1387
20
+ najaeda/docs/source/term.rst,sha256=Xh4xis6lR_Oe26Qm3vCt7ziU3PR0cKBBGO8OmCHWt0M,341
21
+ najaeda/docs/source/net.rst,sha256=QNkCZp1bp8_h_fUcf4jwPF4DByZmMtiSb56gOki0wSI,331
22
+ najaeda/docs/source/equipotential.rst,sha256=1wG1sbwexs9JhxxSY2z9XucsLE0SfopVK7VIty0r3mw,431
23
+ najaeda/docs/source/api.rst,sha256=P_-1jiVrIajvFCqP1Wx2W1l6a4T2RHXlWG00rls1qF0,159
24
+ najaeda/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ najaeda/primitives/xilinx.py,sha256=fuu4KxEIuC0ueCK4C_gds6hzgtJsLE3tjDtOHtY9McM,25947
najaeda/docs/conf.py DELETED
@@ -1,26 +0,0 @@
1
- #...
2
- #extensions = [
3
- # "breathe",
4
- # 'sphinx_rtd_theme',
5
- #]
6
- #...
7
-
8
- project = 'najaeda'
9
- copyright = '2023, The Naja authors'
10
- author = 'The Naja authors'
11
-
12
- html_theme = "sphinx_rtd_theme"
13
- html_title = "najaeda Documentation"
14
-
15
- breathe_default_project = "najaeda"
16
-
17
- #import os
18
- #if 'IN_READ_THE_DOCS' in os.environ:
19
- # import subprocess
20
- # #call doxygen from cmake
21
- # subprocess.call('mkdir build', shell=True)
22
- # subprocess.call('cd build; cmake ../.. -DBUILD_ONLY_DOC=ON', shell=True)
23
- # subprocess.call('cd build; make docs', shell=True)
24
- # subprocess.call('cd build/docs; pwd; ls -all', shell=True)
25
- #
26
- #breathe_projects = { "najaeda" : "./build/docs/xml/" }
@@ -1,20 +0,0 @@
1
- najaeda/netlist.py,sha256=_ojRBNwyvfcrsuoNRpCc1LCIo6uzFQSQcmaTR7qvOQc,34660
2
- najaeda/libnaja_snl_python.dylib,sha256=sRfycYjggRgfCbm5QgIuKf1e3Dn6aaK8c9Ny5JaziNM,741024
3
- najaeda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- najaeda/libnaja_snl.dylib,sha256=AFqR64aX6KnzkX6lrLGCuscx2f5E07umNC_7E9cNrT0,574272
5
- najaeda/snl.so,sha256=2vv_LPtR0B-txFyT1mZYaYoaqPw6vd42BX2UROwOR8A,97888
6
- najaeda/instance_visitor.py,sha256=2HnQ5y8-0tSOKd9nS4WYiypccQWLJgKfs84wp357Tls,1781
7
- najaeda/docs/Makefile,sha256=4zv3TVkTACm6JBaKgTES3ZI9cETXgM6ULbZkXZP1as8,638
8
- najaeda/docs/conf.py,sha256=XmqDjqssSJswFPmC7RhVS_dYKOjzML4UmrbhUowF78M,653
9
- najaeda/docs/make.bat,sha256=L4I5T7uDUIjwGyMRJ-y9FoT61sxIyCuaYuJyLt8c-nA,804
10
- najaeda/docs/.readthedocs.yaml,sha256=yP012ik240oBTMApJYBOvjhNzFDzsAI4vmqX1R7KDrA,988
11
- najaeda/docs/source/index.rst,sha256=VBWfJySZ9v8mWfWt3kuSCZh7Gp0zUrFjXGQH7tZZfy0,323
12
- najaeda/docs/source/conf.py,sha256=3qkykCg12ZYqawHl8VEg2Fti6rc3G-soGYM0L6zL3CU,1387
13
- najaeda/docs/source/api.rst,sha256=H2Bw0JmHS9z-NhQARepmH74wsWHzjSVPbeXppSmtgCQ,141
14
- najaeda/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- najaeda/primitives/xilinx.py,sha256=fuu4KxEIuC0ueCK4C_gds6hzgtJsLE3tjDtOHtY9McM,25947
16
- najaeda-0.1.7.dist-info/RECORD,,
17
- najaeda-0.1.7.dist-info/WHEEL,sha256=bS2kxwU1pioFffhNQmlfvjD0H1flBf5ZtxV4jDj8Nvc,114
18
- najaeda-0.1.7.dist-info/METADATA,sha256=4ac4lOScunYkRke1pZTzxQiLM3XwMGQxbekUHq2PMdw,6752
19
- najaeda-0.1.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
20
- najaeda-0.1.7.dist-info/licenses/AUTHORS,sha256=7NYEGDAX_1QZvCCHfq8YVXC5ZbwH_pbNI8DcSmm70GU,377