@@ -78,17 +78,42 @@ def is_wirevector_used_elsewhere(wire, used_at_nets):
7878 for net in block .logic :
7979 if net .op == "~" :
8080 invert_destination_wires [net .dests [0 ].name ] = net
81- for net in invert_destination_wires .values ():
82- # If the argument of the net is in invert_destination_wires, then it is a double invert
83- # If the net is in net_exclude_set, then it was already removed, so we do not process it
84- if net .args [0 ].name in invert_destination_wires and net not in net_exclude_set :
85- previous_net = invert_destination_wires [net .args [0 ].name ]
86- if not is_wirevector_used_elsewhere (net .args [0 ], (net , previous_net )) \
87- and previous_net not in net_exclude_set :
88- new_logic .add (LogicNet ('w' , None , args = previous_net .args , dests = net .dests ))
89- wire_removal_set .add (net .args [0 ])
90- net_exclude_set .add (net )
91- net_exclude_set .add (previous_net )
81+ # If double invert nets are removed randomly, this may leave some double inverts behind.
82+ # Example: ~(~(~(~a)))
83+ # If we remove the middle two inverts first, we will end up with ~((~a)). These remaining
84+ # double inverts won't get removed because they aren't directly connected.
85+ # To avoid this, we remove double inverts in a chain sequentially from start to end.
86+ # For example, we first remove the two outer inverts from ~(~(~(~a))) to get ~(~a),
87+ # and then remove the remaining two inner inverts. To do this, we need iterate through
88+ # the invert_destination_wires dictionary multiple times, hence the outer while loop.
89+ repeat = True
90+ while repeat :
91+ repeat = False
92+ removed_nets = set ()
93+ for net in invert_destination_wires .values ():
94+ # If the argument of the net is in invert_destination_wires, then it is a double invert
95+ # If the net is in net_exclude_set, then it was already removed, so we do not process it
96+ if net .args [0 ].name in invert_destination_wires and net not in net_exclude_set :
97+ previous_net = invert_destination_wires [net .args [0 ].name ]
98+ if not is_wirevector_used_elsewhere (net .args [0 ], (net , previous_net )) \
99+ and previous_net not in net_exclude_set :
100+ # If previous_net is in invert_destination_wires, we have a chain of
101+ # 3 or more double inverts. To make sure we remove double inverts
102+ # in these chains sequentially, we only remove the double invert
103+ # we found if the invert net whose destination is previous_net
104+ # was not removed yet. If it was not yet removed, the for loop
105+ # needs to run again, so we set repeat to True.
106+ if previous_net .args [0 ].name in invert_destination_wires :
107+ repeat = True
108+ else :
109+ new_logic .add (LogicNet ('w' , None , args = previous_net .args , dests = net .dests ))
110+ wire_removal_set .add (net .args [0 ])
111+ removed_nets .add (net )
112+ removed_nets .add (previous_net )
113+ # remove removed_nets from invert_destination_wires to optimize the for loop
114+ for net in removed_nets :
115+ del invert_destination_wires [net .dests [0 ].name ]
116+ net_exclude_set .update (removed_nets )
92117
93118 for net in block .logic :
94119 if net not in net_exclude_set :
0 commit comments