276f5415c5302da08de79b5dc50e891afa56e700
[Mograsim.git] / 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.ZERO, logicWidth);
103                 for (ModelWire wire : wiresToForceInverted)
104                         if (wire.hasCoreModelBinding())
105                                 result = result.or(wire.getWireValues());
106                 result = result.not();
107                 for (ModelWire wire : wiresToForce)
108                         if (wire.hasCoreModelBinding())
109                                 result = result.and(wire.getWireValues());
110                 return result;
111         }
112
113         @Override
114         public void setHighLevelState(Object newState)
115         {
116                 BitVector vector;
117                 if (newState instanceof Bit)
118                         vector = BitVector.of((Bit) newState);
119                 else
120                         vector = (BitVector) newState;
121                 for (ModelWire wire : wiresToForce)
122                         if (wire.hasCoreModelBinding())
123                                 wire.forceWireValues(vector);
124                 vector = vector.not();
125                 for (ModelWire wire : wiresToForceInverted)
126                         if (wire.hasCoreModelBinding())
127                                 wire.forceWireValues(vector);
128         }
129
130         @Override
131         public String getIDForSerializing(IdentifyParams idParams)
132         {
133                 return "wireForcing";
134         }
135
136         @Override
137         public WireForcingAtomicHighLevelStateHandlerParams getParamsForSerializing(IdentifyParams idParams)
138         {
139                 WireForcingAtomicHighLevelStateHandlerParams params = new WireForcingAtomicHighLevelStateHandlerParams();
140                 params.wiresToForce = wiresToForce.stream().map(w -> w.name).collect(Collectors.toList());
141                 params.wiresToForceInverted = wiresToForceInverted.stream().map(w -> w.name).collect(Collectors.toList());
142                 return params;
143         }
144
145         public static class WireForcingAtomicHighLevelStateHandlerParams
146         {
147                 public List<String> wiresToForce;
148                 public List<String> wiresToForceInverted;
149         }
150
151         static
152         {
153                 StandardHighLevelStateHandlerSnippetSuppliers.atomicHandlerSupplier.setSnippetSupplier(
154                                 WireForcingAtomicHighLevelStateHandler.class.getCanonicalName(),
155                                 SnippetDefinintion.create(WireForcingAtomicHighLevelStateHandlerParams.class, WireForcingAtomicHighLevelStateHandler::new));
156         }
157 }