17
17
"FragmentTransformer" ,
18
18
"TransformedElaboratable" ,
19
19
"DomainCollector" , "DomainRenamer" , "DomainLowerer" ,
20
+ "LHSMaskCollector" ,
20
21
"ResetInserter" , "EnableInserter" ]
21
22
22
23
@@ -601,6 +602,71 @@ def on_fragment(self, fragment):
601
602
return super ().on_fragment (fragment )
602
603
603
604
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
+
604
670
class _ControlInserter (FragmentTransformer ):
605
671
def __init__ (self , controls ):
606
672
self .src_loc = None
@@ -615,10 +681,9 @@ def on_fragment(self, fragment):
615
681
for domain , statements in fragment .statements .items ():
616
682
if domain == "comb" or domain not in self .controls :
617
683
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 )
622
687
return new_fragment
623
688
624
689
def _insert_control (self , fragment , domain , signals ):
@@ -630,13 +695,20 @@ def __call__(self, value, *, src_loc_at=0):
630
695
631
696
632
697
class 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 ]))
635
707
fragment .add_statements (domain , Switch (self .controls [domain ], [(1 , stmts , None )], src_loc = self .src_loc ))
636
708
637
709
638
710
class EnableInserter (_ControlInserter ):
639
- def _insert_control (self , fragment , domain , signals ):
711
+ def _insert_control (self , fragment , domain , _lhs_masks ):
640
712
if domain in fragment .statements :
641
713
fragment .statements [domain ] = _StatementList ([Switch (
642
714
self .controls [domain ],
0 commit comments