1717 "FragmentTransformer" ,
1818 "TransformedElaboratable" ,
1919 "DomainCollector" , "DomainRenamer" , "DomainLowerer" ,
20+ "LHSMaskCollector" ,
2021 "ResetInserter" , "EnableInserter" ]
2122
2223
@@ -601,6 +602,71 @@ def on_fragment(self, fragment):
601602 return super ().on_fragment (fragment )
602603
603604
605+ class LHSMaskCollector :
606+ def __init__ (self ):
607+ self .lhs = SignalDict ()
608+
609+ def visit_stmt (self , stmt ):
610+ if type (stmt ) is Assign :
611+ self .visit_value (stmt .lhs , ~ 0 )
612+ elif type (stmt ) is Switch :
613+ for (_ , substmt , _ ) in stmt .cases :
614+ self .visit_stmt (substmt )
615+ elif type (stmt ) in (Property , Print ):
616+ pass
617+ elif isinstance (stmt , Iterable ):
618+ for substmt in stmt :
619+ self .visit_stmt (substmt )
620+ else :
621+ assert False # :nocov:
622+
623+ def visit_value (self , value , mask ):
624+ if type (value ) in (Signal , ClockSignal , ResetSignal ):
625+ mask &= (1 << len (value )) - 1
626+ self .lhs .setdefault (value , 0 )
627+ self .lhs [value ] |= mask
628+ elif type (value ) is Operator :
629+ assert value .operator in ("s" , "u" )
630+ self .visit_value (value .operands [0 ], mask )
631+ elif type (value ) is Slice :
632+ slice_mask = (1 << value .stop ) - (1 << value .start )
633+ mask <<= value .start
634+ mask &= slice_mask
635+ self .visit_value (value .value , mask )
636+ elif type (value ) is Part :
637+ # Could be more accurate, but if you're relying on such details, you're not seeing
638+ # the Light of Heaven.
639+ self .visit_value (value .value , ~ 0 )
640+ elif type (value ) is Concat :
641+ for part in value .parts :
642+ self .visit_value (part , mask )
643+ mask >>= len (part )
644+ elif type (value ) is SwitchValue :
645+ for (_ , subvalue ) in value .cases :
646+ self .visit_value (subvalue , mask )
647+ else :
648+ assert False # :nocov:
649+
650+ def chunks (self ):
651+ for signal , mask in self .lhs .items ():
652+ if mask == (1 << len (signal )) - 1 :
653+ yield signal , 0 , None
654+ else :
655+ start = 0
656+ while start < len (signal ):
657+ if ((mask >> start ) & 1 ) == 0 :
658+ start += 1
659+ else :
660+ stop = start
661+ while stop < len (signal ) and ((mask >> stop ) & 1 ) == 1 :
662+ stop += 1
663+ yield (signal , start , stop )
664+ start = stop
665+
666+ def masks (self ):
667+ yield from self .lhs .items ()
668+
669+
604670class _ControlInserter (FragmentTransformer ):
605671 def __init__ (self , controls ):
606672 self .src_loc = None
@@ -615,10 +681,9 @@ def on_fragment(self, fragment):
615681 for domain , statements in fragment .statements .items ():
616682 if domain == "comb" or domain not in self .controls :
617683 continue
618- signals = SignalSet ()
619- for stmt in statements :
620- signals |= stmt ._lhs_signals ()
621- self ._insert_control (new_fragment , domain , signals )
684+ lhs_masks = LHSMaskCollector ()
685+ lhs_masks .visit_stmt (statements )
686+ self ._insert_control (new_fragment , domain , lhs_masks )
622687 return new_fragment
623688
624689 def _insert_control (self , fragment , domain , signals ):
@@ -630,13 +695,20 @@ def __call__(self, value, *, src_loc_at=0):
630695
631696
632697class ResetInserter (_ControlInserter ):
633- def _insert_control (self , fragment , domain , signals ):
634- stmts = [s .eq (Const (s .init , s .shape ())) for s in signals if not s .reset_less ]
698+ def _insert_control (self , fragment , domain , lhs_masks ):
699+ stmts = []
700+ for signal , start , stop in lhs_masks .chunks ():
701+ if signal .reset_less :
702+ continue
703+ if start == 0 and stop is None :
704+ stmts .append (signal .eq (Const (signal .init , signal .shape ())))
705+ else :
706+ stmts .append (signal [start :stop ].eq (Const (signal .init , signal .shape ())[start :stop ]))
635707 fragment .add_statements (domain , Switch (self .controls [domain ], [(1 , stmts , None )], src_loc = self .src_loc ))
636708
637709
638710class EnableInserter (_ControlInserter ):
639- def _insert_control (self , fragment , domain , signals ):
711+ def _insert_control (self , fragment , domain , _lhs_masks ):
640712 if domain in fragment .statements :
641713 fragment .statements [domain ] = _StatementList ([Switch (
642714 self .controls [domain ],
0 commit comments