Made WireForcingAtomicHighLevelStateHandler.getHighLevelState cleaner
[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.List;
6 import java.util.Map;
7 import java.util.function.Function;
8 import java.util.stream.Collectors;
9
10 import net.mograsim.logic.core.types.Bit;
11 import net.mograsim.logic.core.types.BitVector;
12 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
13 import net.mograsim.logic.model.model.wires.ModelWire;
14 import net.mograsim.logic.model.serializing.IdentifyParams;
15 import net.mograsim.logic.model.snippets.SnippetDefinintion;
16 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.StandardHighLevelStateHandlerSnippetSuppliers;
17
18 public class WireForcingAtomicHighLevelStateHandler implements AtomicHighLevelStateHandler
19 {
20         private final SubmodelComponent component;
21         private int logicWidth;
22         private final List<ModelWire> wiresToForce;
23         private final List<ModelWire> wiresToForceUnmodifiable;
24         private final List<ModelWire> wiresToForceInverted;
25         private final List<ModelWire> wiresToForceInvertedUnmodifiable;
26
27         public WireForcingAtomicHighLevelStateHandler(SubmodelComponent component)
28         {
29                 this(component, null);
30         }
31
32         public WireForcingAtomicHighLevelStateHandler(SubmodelComponent component, WireForcingAtomicHighLevelStateHandlerParams params)
33         {
34                 this.component = component;
35                 this.wiresToForce = new ArrayList<>();
36                 this.wiresToForceUnmodifiable = Collections.unmodifiableList(wiresToForce);
37                 this.wiresToForceInverted = new ArrayList<>();
38                 this.wiresToForceInvertedUnmodifiable = Collections.unmodifiableList(wiresToForceInverted);
39                 if (params != null)
40                 {
41                         Map<String, ModelWire> wiresByName = component.submodel.getWiresByName();
42                         setWiresToForce(params.wiresToForce.stream().map((Function<String, ModelWire>) wiresByName::get).collect(Collectors.toList()),
43                                         params.wiresToForceInverted.stream().map((Function<String, ModelWire>) wiresByName::get).collect(Collectors.toList()));
44                 }
45                 component.submodel.addWireRemovedListener(w ->
46                 {
47                         wiresToForce.removeIf(w::equals);
48                         wiresToForceInverted.removeIf(w::equals);
49                 });
50         }
51
52         public void set(List<ModelWire> wiresToForce, List<ModelWire> wiresToForceInverted)
53         {
54                 setWiresToForce(wiresToForce, wiresToForceInverted);
55         }
56
57         public void setWiresToForce(List<ModelWire> wiresToForce, List<ModelWire> wiresToForceInverted)
58         {
59                 clearWiresToForce();
60                 for (ModelWire wire : wiresToForce)
61                         addWireToForce(wire, false);
62                 for (ModelWire wire : wiresToForceInverted)
63                         addWireToForce(wire, true);
64         }
65
66         public void addWireToForce(ModelWire wire, boolean inverted)
67         {
68                 if (component.submodel.getWiresByName().get(wire.name) != wire)
69                         throw new IllegalArgumentException("Can only force wires belonging to the parent component of this handler");
70                 if (logicWidth < 1)
71                         logicWidth = wire.logicWidth;
72                 else if (wire.logicWidth != logicWidth)
73                         throw new IllegalArgumentException("Can only force wires of the same logic width");
74                 // this can add the same wire multiple times, but maybe there is a weird configuration where it is neccessary, due to race
75                 // conditions, to force the same wire twice.
76                 if (inverted)
77                         wiresToForceInverted.add(wire);
78                 else
79                         wiresToForce.add(wire);
80         }
81
82         public void clearWiresToForce()
83         {
84                 wiresToForce.clear();
85                 wiresToForceInverted.clear();
86                 logicWidth = 0;
87         }
88
89         public List<ModelWire> getWiresToForce()
90         {
91                 return wiresToForceUnmodifiable;
92         }
93
94         public List<ModelWire> getWiresToForceInverted()
95         {
96                 return wiresToForceInvertedUnmodifiable;
97         }
98
99         @Override
100         public Object getHighLevelState()
101         {
102                 BitVector result = BitVector.of(Bit.Z, logicWidth);
103
104                 if (!wiresToForceInverted.isEmpty())
105                 {
106                         for (ModelWire wire : wiresToForceInverted)
107                                 if (wire.hasCoreModelBinding())
108                                         result = result.join(wire.getWireValues());
109                         result = result.not();
110                 }
111
112                 for (ModelWire wire : wiresToForce)
113                         if (wire.hasCoreModelBinding())
114                                 result = result.join(wire.getWireValues());
115
116                 return result;
117         }
118
119         @Override
120         public void setHighLevelState(Object newState)
121         {
122                 BitVector vector;
123                 if (newState instanceof Bit)
124                         vector = BitVector.of((Bit) newState);
125                 else
126                         vector = (BitVector) newState;
127                 for (ModelWire wire : wiresToForce)
128                         if (wire.hasCoreModelBinding())
129                                 wire.forceWireValues(vector);
130                 vector = vector.not();
131                 for (ModelWire wire : wiresToForceInverted)
132                         if (wire.hasCoreModelBinding())
133                                 wire.forceWireValues(vector);
134         }
135
136         @Override
137         public String getIDForSerializing(IdentifyParams idParams)
138         {
139                 return "wireForcing";
140         }
141
142         @Override
143         public WireForcingAtomicHighLevelStateHandlerParams getParamsForSerializing(IdentifyParams idParams)
144         {
145                 WireForcingAtomicHighLevelStateHandlerParams params = new WireForcingAtomicHighLevelStateHandlerParams();
146                 params.wiresToForce = wiresToForce.stream().map(w -> w.name).collect(Collectors.toList());
147                 params.wiresToForceInverted = wiresToForceInverted.stream().map(w -> w.name).collect(Collectors.toList());
148                 return params;
149         }
150
151         public static class WireForcingAtomicHighLevelStateHandlerParams
152         {
153                 public List<String> wiresToForce;
154                 public List<String> wiresToForceInverted;
155         }
156
157         static
158         {
159                 StandardHighLevelStateHandlerSnippetSuppliers.atomicHandlerSupplier.setSnippetSupplier(
160                                 WireForcingAtomicHighLevelStateHandler.class.getCanonicalName(),
161                                 SnippetDefinintion.create(WireForcingAtomicHighLevelStateHandlerParams.class, WireForcingAtomicHighLevelStateHandler::new));
162         }
163 }