@@ -444,6 +444,7 @@ def traverse(net):
444444 busy .add (net )
445445
446446 cycle = None
447+ extra_nets = []
447448 if net .is_const :
448449 pass
449450 elif net .is_late :
@@ -452,10 +453,16 @@ def traverse(net):
452453 sig , bit = self .late_to_signal [net ]
453454 cycle .path .append ((sig , bit , sig .src_loc ))
454455 else :
455- for src , src_loc in self .cells [net .cell ].comb_edges_to (net .bit ):
456+ cell = self .cells [net .cell ]
457+ if not cell .comb_edges_is_per_bit ():
458+ extra_nets = [extra_net for extra_net in cell .output_nets (net .cell ) if extra_net != net ]
459+ for extra_net in extra_nets :
460+ assert extra_net not in checked
461+ busy .add (extra_net )
462+ for src , src_loc in cell .comb_edges_to (net .bit ):
456463 cycle = traverse (src )
457464 if cycle is not None :
458- cycle .path .append ((self . cells [ net . cell ] , net .bit , src_loc ))
465+ cycle .path .append ((cell , net .bit , src_loc ))
459466 break
460467
461468 if cycle is not None and cycle .start == net :
@@ -473,6 +480,9 @@ def traverse(net):
473480
474481 busy .remove (net )
475482 checked .add (net )
483+ for extra_net in extra_nets :
484+ busy .remove (extra_net )
485+ checked .add (extra_net )
476486 return cycle
477487
478488 for cell_idx , cell in enumerate (self .cells ):
@@ -579,6 +589,10 @@ def resolve_nets(self, netlist: Netlist):
579589 def comb_edges_to (self , bit : int ) -> "Iterable[(Net, Any)]" :
580590 raise NotImplementedError
581591
592+ def comb_edges_is_per_bit (self ) -> bool :
593+ """Returns True iff ``comb_edges_to`` looks at its argument."""
594+ raise NotImplementedError
595+
582596
583597class Top (Cell ):
584598 """A special cell type representing top-level non-IO ports. Must be present in the netlist exactly
@@ -631,6 +645,9 @@ def __repr__(self):
631645 def comb_edges_to (self , bit ):
632646 return []
633647
648+ def comb_edges_is_per_bit (self ) -> bool :
649+ return False
650+
634651
635652class Operator (Cell ):
636653 """Roughly corresponds to ``hdl.ast.Operator``.
@@ -722,6 +739,15 @@ def comb_edges_to(self, bit):
722739 yield (self .inputs [1 ][bit ], self .src_loc )
723740 yield (self .inputs [2 ][bit ], self .src_loc )
724741
742+ def comb_edges_is_per_bit (self ) -> bool :
743+ if len (self .inputs ) == 1 and self .operator == "~" :
744+ return True
745+ elif len (self .inputs ) == 2 and self .operator in ("&" , "|" , "^" ):
746+ return True
747+ elif len (self .inputs ) == 3 :
748+ return True
749+ return False
750+
725751
726752class Part (Cell ):
727753 """Corresponds to ``hdl.ast.Part``.
@@ -767,6 +793,9 @@ def comb_edges_to(self, bit):
767793 for net in self .offset :
768794 yield (net , self .src_loc )
769795
796+ def comb_edges_is_per_bit (self ) -> bool :
797+ return False
798+
770799
771800class Match (Cell ):
772801 """Used to represent a single switch on the control plane of processes.
@@ -812,6 +841,9 @@ def comb_edges_to(self, bit):
812841 for net in self .value :
813842 yield (net , self .src_loc )
814843
844+ def comb_edges_is_per_bit (self ) -> bool :
845+ return False
846+
815847
816848class Assignment :
817849 """A single assignment in an ``AssignmentList``.
@@ -895,6 +927,9 @@ def comb_edges_to(self, bit):
895927 yield (assign .cond , assign .src_loc )
896928 yield (assign .value [bit - assign .start ], assign .src_loc )
897929
930+ def comb_edges_is_per_bit (self ) -> bool :
931+ return True
932+
898933
899934class FlipFlop (Cell ):
900935 """A flip-flop. ``data`` is the data input. ``init`` is the initial and async reset value.
@@ -943,6 +978,9 @@ def comb_edges_to(self, bit):
943978 yield (self .clk , self .src_loc )
944979 yield (self .arst , self .src_loc )
945980
981+ def comb_edges_is_per_bit (self ) -> bool :
982+ return False
983+
946984
947985class Memory (Cell ):
948986 """Corresponds to ``Memory``. ``init`` must have length equal to ``depth``.
@@ -1054,6 +1092,9 @@ def comb_edges_to(self, bit):
10541092 for net in self .addr :
10551093 yield (net , self .src_loc )
10561094
1095+ def comb_edges_is_per_bit (self ) -> bool :
1096+ return False
1097+
10571098
10581099class SyncReadPort (Cell ):
10591100 """A single synchronous read port of a memory. The cell output is the data port.
@@ -1101,6 +1142,9 @@ def __repr__(self):
11011142 def comb_edges_to (self , bit ):
11021143 return []
11031144
1145+ def comb_edges_is_per_bit (self ) -> bool :
1146+ return False
1147+
11041148
11051149class AsyncPrint (Cell ):
11061150 """Corresponds to ``Print`` in the "comb" domain.
@@ -1187,6 +1231,9 @@ def __repr__(self):
11871231 def comb_edges_to (self , bit ):
11881232 return []
11891233
1234+ def comb_edges_is_per_bit (self ) -> bool :
1235+ return False
1236+
11901237
11911238class AnyValue (Cell ):
11921239 """Corresponds to ``AnyConst`` or ``AnySeq``. ``kind`` must be either ``'anyconst'``
@@ -1220,6 +1267,9 @@ def __repr__(self):
12201267 def comb_edges_to (self , bit ):
12211268 return []
12221269
1270+ def comb_edges_is_per_bit (self ) -> bool :
1271+ return False
1272+
12231273
12241274class AsyncProperty (Cell ):
12251275 """Corresponds to ``Assert``, ``Assume``, or ``Cover`` in the "comb" domain.
@@ -1381,6 +1431,9 @@ def comb_edges_to(self, bit):
13811431 # don't ask me, I'm a housecat
13821432 return []
13831433
1434+ def comb_edges_is_per_bit (self ) -> bool :
1435+ return False
1436+
13841437
13851438class IOBuffer (Cell ):
13861439 """An IO buffer cell. This cell does two things:
@@ -1440,3 +1493,6 @@ def comb_edges_to(self, bit):
14401493 if self .dir is not IODirection .Input :
14411494 yield (self .o [bit ], self .src_loc )
14421495 yield (self .oe , self .src_loc )
1496+
1497+ def comb_edges_is_per_bit (self ) -> bool :
1498+ return True
0 commit comments