MPROMEditor now calls its columns "Opcode" and "muPC"
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / snippets / highlevelstatehandlers / standard / atomic / WireForcingAtomicHighLevelStateHandler.java
1 package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Objects;
9 import java.util.concurrent.atomic.AtomicReference;
10 import java.util.function.Consumer;
11 import java.util.function.Function;
12 import java.util.stream.Collectors;
13
14 import net.mograsim.logic.core.LogicObserver;
15 import net.mograsim.logic.core.types.Bit;
16 import net.mograsim.logic.core.types.BitVector;
17 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
18 import net.mograsim.logic.model.model.wires.ModelWire;
19 import net.mograsim.logic.model.serializing.IdentifyParams;
20 import net.mograsim.logic.model.snippets.SnippetDefinintion;
21 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.StandardHighLevelStateHandlerSnippetSuppliers;
22
23 public class WireForcingAtomicHighLevelStateHandler implements AtomicHighLevelStateHandler
24 {
25         private final SubmodelComponent component;
26         private int logicWidth;
27         private final List<ModelWire> wiresToForce;
28         private final List<ModelWire> wiresToForceUnmodifiable;
29         private final List<ModelWire> wiresToForceInverted;
30         private final List<ModelWire> wiresToForceInvertedUnmodifiable;
31
32         private final Map<Consumer<Object>, LogicObserver> wireObsPerListener;
33
34         public WireForcingAtomicHighLevelStateHandler(SubmodelComponent component)
35         {
36                 this(component, null);
37         }
38
39         public WireForcingAtomicHighLevelStateHandler(SubmodelComponent component, WireForcingAtomicHighLevelStateHandlerParams params)
40         {
41                 this.component = component;
42                 this.wiresToForce = new ArrayList<>();
43                 this.wiresToForceUnmodifiable = Collections.unmodifiableList(wiresToForce);
44                 this.wiresToForceInverted = new ArrayList<>();
45                 this.wiresToForceInvertedUnmodifiable = Collections.unmodifiableList(wiresToForceInverted);
46
47                 this.wireObsPerListener = new HashMap<>();
48
49                 if (params != null)
50                 {
51                         Map<String, ModelWire> wiresByName = component.submodel.getWiresByName();
52                         setWiresToForce(params.wiresToForce.stream().map((Function<String, ModelWire>) wiresByName::get).collect(Collectors.toList()),
53                                         params.wiresToForceInverted.stream().map((Function<String, ModelWire>) wiresByName::get).collect(Collectors.toList()));
54                 }
55                 component.submodel.addWireRemovedListener(w ->
56                 {
57                         wiresToForce.removeIf(w::equals);
58                         wiresToForceInverted.removeIf(w::equals);
59                 });
60         }
61
62         public void set(List<ModelWire> wiresToForce, List<ModelWire> wiresToForceInverted)
63         {
64                 setWiresToForce(wiresToForce, wiresToForceInverted);
65         }
66
67         public void setWiresToForce(List<ModelWire> wiresToForce, List<ModelWire> wiresToForceInverted)
68         {
69                 clearWiresToForce();
70                 for (ModelWire wire : wiresToForce)
71                         addWireToForce(wire, false);
72                 for (ModelWire wire : wiresToForceInverted)
73                         addWireToForce(wire, true);
74         }
75
76         public void addWireToForce(ModelWire wire, boolean inverted)
77         {
78                 if (component.submodel.getWiresByName().get(wire.name) != wire)
79                         throw new IllegalArgumentException("Can only force wires belonging to the parent component of this handler");
80                 if (logicWidth < 1)
81                         logicWidth = wire.logicWidth;
82                 else if (wire.logicWidth != logicWidth)
83                         throw new IllegalArgumentException("Can only force wires of the same logic width");
84                 // this can add the same wire multiple times, but maybe there is a weird configuration where it is neccessary, due to race
85                 // conditions, to force the same wire twice.
86                 if (inverted)
87                         wiresToForceInverted.add(wire);
88                 else
89                         wiresToForce.add(wire);
90         }
91
92         public void clearWiresToForce()
93         {
94                 wiresToForce.clear();
95                 wiresToForceInverted.clear();
96                 logicWidth = 0;
97         }
98
99         public List<ModelWire> getWiresToForce()
100         {
101                 return wiresToForceUnmodifiable;
102         }
103
104         public List<ModelWire> getWiresToForceInverted()
105         {
106                 return wiresToForceInvertedUnmodifiable;
107         }
108
109         @Override
110         public Object getHighLevelState()
111         {
112                 BitVector result = BitVector.of(Bit.Z, logicWidth);
113
114                 if (!wiresToForceInverted.isEmpty())
115                 {
116                         for (ModelWire wire : wiresToForceInverted)
117                                 if (wire.hasCoreModelBinding())
118                                         result = result.join(wire.getWireValues());
119                         result = result.not();
120                 }
121
122                 for (ModelWire wire : wiresToForce)
123                         if (wire.hasCoreModelBinding())
124                                 result = result.join(wire.getWireValues());
125
126                 return result;
127         }
128
129         @Override
130         public void setHighLevelState(Object newState)
131         {
132                 BitVector vector;
133                 if (newState instanceof Bit)
134                         vector = BitVector.of((Bit) newState);
135                 else
136                         vector = (BitVector) newState;
137                 for (ModelWire wire : wiresToForce)
138                         if (wire.hasCoreModelBinding())
139                                 wire.forceWireValues(vector);
140                 vector = vector.not();
141                 for (ModelWire wire : wiresToForceInverted)
142                         if (wire.hasCoreModelBinding())
143                                 wire.forceWireValues(vector);
144         }
145
146         @Override
147         public void addListener(Consumer<Object> stateChanged)
148         {
149                 if (wireObsPerListener.containsKey(stateChanged))
150                         return;
151                 AtomicReference<Object> lastStateRef = new AtomicReference<>(getHighLevelState());
152                 LogicObserver obs = w ->
153                 {
154                         Object newState = getHighLevelState();
155                         if (!Objects.equals(lastStateRef.getAndSet(newState), newState))
156                                 stateChanged.accept(newState);
157                 };
158                 wireObsPerListener.put(stateChanged, obs);
159                 for (ModelWire w : wiresToForce)
160                         w.addObserver(obs);
161                 for (ModelWire w : wiresToForceInverted)
162                         w.addObserver(obs);
163         }
164
165         @Override
166         public void removeListener(Consumer<Object> stateChanged)
167         {
168                 LogicObserver obs = wireObsPerListener.remove(stateChanged);
169                 if (obs == null)
170                         return;
171                 for (ModelWire w : wiresToForce)
172                         w.removeObserver(obs);
173                 for (ModelWire w : wiresToForceInverted)
174                         w.removeObserver(obs);
175         }
176
177         @Override
178         public String getIDForSerializing(IdentifyParams idParams)
179         {
180                 return "wireForcing";
181         }
182
183         @Override
184         public WireForcingAtomicHighLevelStateHandlerParams getParamsForSerializing(IdentifyParams idParams)
185         {
186                 WireForcingAtomicHighLevelStateHandlerParams params = new WireForcingAtomicHighLevelStateHandlerParams();
187                 params.wiresToForce = wiresToForce.stream().map(w -> w.name).collect(Collectors.toList());
188                 params.wiresToForceInverted = wiresToForceInverted.stream().map(w -> w.name).collect(Collectors.toList());
189                 return params;
190         }
191
192         public static class WireForcingAtomicHighLevelStateHandlerParams
193         {
194                 public List<String> wiresToForce;
195                 public List<String> wiresToForceInverted;
196         }
197
198         static
199         {
200                 StandardHighLevelStateHandlerSnippetSuppliers.atomicHandlerSupplier.setSnippetSupplier(
201                                 WireForcingAtomicHighLevelStateHandler.class.getCanonicalName(),
202                                 SnippetDefinintion.create(WireForcingAtomicHighLevelStateHandlerParams.class, WireForcingAtomicHighLevelStateHandler::new));
203         }
204 }