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