1 package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic;
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.HashMap;
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;
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;
23 public class WireForcingAtomicHighLevelStateHandler implements AtomicHighLevelStateHandler
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;
32 private final Map<Consumer<Object>, LogicObserver> wireObsPerListener;
34 public WireForcingAtomicHighLevelStateHandler(SubmodelComponent component)
36 this(component, null);
39 public WireForcingAtomicHighLevelStateHandler(SubmodelComponent component, WireForcingAtomicHighLevelStateHandlerParams params)
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);
47 this.wireObsPerListener = new HashMap<>();
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()));
55 component.submodel.addWireRemovedListener(w ->
57 wiresToForce.removeIf(w::equals);
58 wiresToForceInverted.removeIf(w::equals);
62 public void set(List<ModelWire> wiresToForce, List<ModelWire> wiresToForceInverted)
64 setWiresToForce(wiresToForce, wiresToForceInverted);
67 public void setWiresToForce(List<ModelWire> wiresToForce, List<ModelWire> wiresToForceInverted)
70 for (ModelWire wire : wiresToForce)
71 addWireToForce(wire, false);
72 for (ModelWire wire : wiresToForceInverted)
73 addWireToForce(wire, true);
76 public void addWireToForce(ModelWire wire, boolean inverted)
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");
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.
87 wiresToForceInverted.add(wire);
89 wiresToForce.add(wire);
92 public void clearWiresToForce()
95 wiresToForceInverted.clear();
99 public List<ModelWire> getWiresToForce()
101 return wiresToForceUnmodifiable;
104 public List<ModelWire> getWiresToForceInverted()
106 return wiresToForceInvertedUnmodifiable;
110 public Object getHighLevelState()
112 BitVector result = BitVector.of(Bit.Z, logicWidth);
114 if (!wiresToForceInverted.isEmpty())
116 for (ModelWire wire : wiresToForceInverted)
117 if (wire.hasCoreModelBinding())
118 result = result.join(wire.getWireValues());
119 result = result.not();
122 for (ModelWire wire : wiresToForce)
123 if (wire.hasCoreModelBinding())
124 result = result.join(wire.getWireValues());
130 public void setHighLevelState(Object newState)
133 if (newState instanceof Bit)
134 vector = BitVector.of((Bit) newState);
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);
147 public void addListener(Consumer<Object> stateChanged)
149 if (wireObsPerListener.containsKey(stateChanged))
151 AtomicReference<Object> lastStateRef = new AtomicReference<>(getHighLevelState());
152 LogicObserver obs = w ->
154 Object newState = getHighLevelState();
155 if (!Objects.equals(lastStateRef.getAndSet(newState), newState))
156 stateChanged.accept(newState);
158 wireObsPerListener.put(stateChanged, obs);
159 for (ModelWire w : wiresToForce)
161 for (ModelWire w : wiresToForceInverted)
166 public void removeListener(Consumer<Object> stateChanged)
168 LogicObserver obs = wireObsPerListener.remove(stateChanged);
171 for (ModelWire w : wiresToForce)
172 w.removeObserver(obs);
173 for (ModelWire w : wiresToForceInverted)
174 w.removeObserver(obs);
178 public String getIDForSerializing(IdentifyParams idParams)
180 return "wireForcing";
184 public WireForcingAtomicHighLevelStateHandlerParams getParamsForSerializing(IdentifyParams idParams)
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());
192 public static class WireForcingAtomicHighLevelStateHandlerParams
194 public List<String> wiresToForce;
195 public List<String> wiresToForceInverted;
200 StandardHighLevelStateHandlerSnippetSuppliers.atomicHandlerSupplier.setSnippetSupplier(
201 WireForcingAtomicHighLevelStateHandler.class.getCanonicalName(),
202 SnippetDefinintion.create(WireForcingAtomicHighLevelStateHandlerParams.class, WireForcingAtomicHighLevelStateHandler::new));