962d58a56ff64de252c6aa7f4c30565daf15807b
[Mograsim.git] / net.mograsim.logic.ui.am2900 / test / net / mograsim / logic / ui / am2900 / TestableAm2901Impl.java
1 package net.mograsim.logic.ui.am2900;\r
2 \r
3 import static org.junit.jupiter.api.Assertions.fail;\r
4 \r
5 import java.lang.reflect.Field;\r
6 import java.util.ArrayList;\r
7 import java.util.HashMap;\r
8 import java.util.HashSet;\r
9 import java.util.LinkedList;\r
10 import java.util.List;\r
11 import java.util.Objects;\r
12 import java.util.Queue;\r
13 import java.util.Set;\r
14 import java.util.TreeSet;\r
15 \r
16 import net.mograsim.logic.core.components.BitDisplay;\r
17 import net.mograsim.logic.core.components.ManualSwitch;\r
18 import net.mograsim.logic.core.timeline.Timeline;\r
19 import net.mograsim.logic.core.types.Bit;\r
20 import net.mograsim.logic.core.types.BitVector;\r
21 import net.mograsim.logic.core.types.BitVector.BitVectorMutator;\r
22 import net.mograsim.logic.ui.model.ViewModel;\r
23 import net.mograsim.logic.ui.model.ViewModelModifiable;\r
24 import net.mograsim.logic.ui.model.components.GUIComponent;\r
25 import net.mograsim.logic.ui.model.components.atomic.GUIBitDisplay;\r
26 import net.mograsim.logic.ui.model.components.atomic.GUIManualSwitch;\r
27 import net.mograsim.logic.ui.model.components.mi.nandbased.am2901.GUIAm2901;\r
28 import net.mograsim.logic.ui.model.components.submodels.SubmodelComponent;\r
29 import net.mograsim.logic.ui.model.wires.GUIWire;\r
30 import net.mograsim.logic.ui.model.wires.Pin;\r
31 import net.mograsim.logic.ui.modeladapter.LogicModelParameters;\r
32 import net.mograsim.logic.ui.modeladapter.ViewLogicModelAdapter;\r
33 \r
34 public class TestableAm2901Impl implements TestableAm2901\r
35 {\r
36         private GUIComponent am2901;\r
37         private Timeline timeline;\r
38         private ManualSwitch I8, I7, I6, I5, I4, I3, I2, I1, I0;\r
39         private ManualSwitch C;\r
40         private ManualSwitch Cn;\r
41         private ManualSwitch D1, D2, D3, D4;\r
42         private ManualSwitch A0, A1, A2, A3;\r
43         private ManualSwitch B0, B1, B2, B3;\r
44         private ManualSwitch IRAMn, IRAMn_3, IQn, IQn_3;\r
45         private BitDisplay Y1, Y2, Y3, Y4;\r
46         private BitDisplay F_0, Cn_4, OVR, F3;\r
47         private BitDisplay ORAMn, ORAMn_3, OQn, OQn_3;\r
48 \r
49         private Set<String> wireDebugChangeSet;\r
50         private boolean debugWires = false;\r
51         public int debugEventThreshold = 10_000;\r
52         public int debugEventCount = 500;\r
53 \r
54         private int eventCounter;\r
55 \r
56         @Override\r
57         public Result run()\r
58         {\r
59                 // Normal execution until completion or eventLimit\r
60                 int eventLimit = debugEventThreshold;\r
61                 eventCounter = 0;\r
62                 debugWires = false;\r
63                 while (eventCounter < eventLimit)\r
64                 {\r
65                         timeline.executeNext();\r
66                         if (!timeline.hasNext())\r
67                         {\r
68 //                              System.out.println("run() took " + eventCounter + " events");\r
69                                 return Result.SUCCESS;\r
70                         }\r
71                 }\r
72                 // Start debugging if event limit is reached\r
73                 debugWires = true;\r
74                 wireDebugChangeSet = new TreeSet<>();\r
75                 Set<String> oldChangeSet;\r
76                 // observe wire changes to detect, if we are really stuck in an endless loop\r
77                 do\r
78                 {\r
79                         eventLimit += debugEventCount;\r
80                         oldChangeSet = wireDebugChangeSet;\r
81                         wireDebugChangeSet = new TreeSet<>();\r
82                         while (eventCounter < eventLimit)\r
83                         {\r
84                                 timeline.executeNext();\r
85                                 if (!timeline.hasNext())\r
86                                 {\r
87                                         // no endless loop, but more events needed than expected\r
88                                         System.out.println("run() took longer than expected: " + eventCounter);\r
89                                         return Result.SUCCESS;\r
90                                 }\r
91                         }\r
92                 } while (!oldChangeSet.equals(wireDebugChangeSet));\r
93                 // if stuck, abort execution and print wires\r
94                 System.err.print("Problematic Wire updates:");\r
95                 wireDebugChangeSet.forEach(System.out::println);\r
96                 System.err.println("run() failed: " + eventCounter);\r
97                 return Result.OUT_OF_TIME;\r
98         }\r
99 \r
100         @SuppressWarnings("unused")\r
101         @Override\r
102         public void setup()\r
103         {\r
104                 // Create view model\r
105                 ViewModelModifiable viewModel = new ViewModelModifiable();\r
106                 // TODO replace with deserialized version as soon as high level states work for deserialized components\r
107                 am2901 = new GUIAm2901(viewModel);\r
108 //              am2901 = IndirectGUIComponentCreator.createComponent(viewModel, "GUIAm2901");\r
109                 // guess which pins are outputs and which are inputs\r
110                 // TODO this code exists three times... but it seems too "hacky" to put it in a helper class\r
111                 List<String> inputPinNames = new ArrayList<>();\r
112                 List<String> outputPinNames = new ArrayList<>();\r
113                 for (Pin p : am2901.getPins().values())\r
114                         if (p.getRelX() == 0)\r
115                                 inputPinNames.add(p.name);\r
116                         else\r
117                                 outputPinNames.add(p.name);\r
118                 // Get switches\r
119                 HashMap<String, GUIManualSwitch> idSwitchMap = new HashMap<>();\r
120                 for (String id : inputPinNames)\r
121                 {\r
122                         GUIManualSwitch sw = new GUIManualSwitch(viewModel);\r
123                         new GUIWire(viewModel, am2901.getPin(id), sw.getOutputPin());\r
124                         idSwitchMap.put(id, sw);\r
125                 }\r
126                 // Get displays\r
127                 HashMap<String, GUIBitDisplay> idDisplayMap = new HashMap<>();\r
128                 for (String id : outputPinNames)\r
129                 {\r
130                         GUIBitDisplay bd = new GUIBitDisplay(viewModel);\r
131 //                      bd.addRedrawListener(() -> System.out.println(id + " " + bd.getBitDisplay().getDisplayedValue()));\r
132                         new GUIWire(viewModel, am2901.getPin(id), bd.getInputPin());\r
133                         idDisplayMap.put(id, bd);\r
134                 }\r
135                 // Create logic model\r
136                 LogicModelParameters params = new LogicModelParameters();\r
137                 params.gateProcessTime = 50;\r
138                 params.wireTravelTime = 10;\r
139                 timeline = ViewLogicModelAdapter.convert(viewModel, params);\r
140                 // Bind switches/displays to this test class\r
141                 for (var entry : idSwitchMap.entrySet())\r
142                         setField(entry.getKey().replaceAll("\\+|=", "_"), entry.getValue().getManualSwitch());\r
143                 for (var entry : idDisplayMap.entrySet())\r
144                         setField(entry.getKey().replaceAll("\\+|=", "_"), entry.getValue().getBitDisplay());\r
145 \r
146                 // Debug code\r
147                 HashSet<GUIWire> wiresIncludingSubmodels = new HashSet<>();\r
148                 Queue<ViewModel> modelsToIterate = new LinkedList<>();\r
149                 modelsToIterate.add(viewModel);\r
150                 while (modelsToIterate.size() > 0)\r
151                 {\r
152                         ViewModel model = modelsToIterate.poll();\r
153                         wiresIncludingSubmodels.addAll(model.getWires());\r
154                         for (GUIComponent comp : model.getComponentsByName().values())\r
155                                 if (comp instanceof SubmodelComponent)\r
156                                         modelsToIterate.offer(((SubmodelComponent) comp).submodel);\r
157                 }\r
158                 wiresIncludingSubmodels.forEach(w -> w.addRedrawListener(() ->\r
159                 {\r
160                         if (debugWires)\r
161                         {\r
162                                 wireDebugChangeSet.add(w.toString());\r
163                         }\r
164                 }));\r
165                 timeline.addEventAddedListener(te -> eventCounter++);\r
166         }\r
167 \r
168         @Override\r
169         public void setDest(Am2901_Dest dest)\r
170         {\r
171                 var bits = of(dest.ordinal(), 3);\r
172                 I8.setToValueOf(bits.getBit(0));\r
173                 I7.setToValueOf(bits.getBit(1));\r
174                 I6.setToValueOf(bits.getBit(2));\r
175         }\r
176 \r
177         @Override\r
178         public void setFunc(Am2901_Func func)\r
179         {\r
180                 var bits = of(func.ordinal(), 3);\r
181                 I5.setToValueOf(bits.getBit(0));\r
182                 I4.setToValueOf(bits.getBit(1));\r
183                 I3.setToValueOf(bits.getBit(2));\r
184         }\r
185 \r
186         @Override\r
187         public void setSrc(Am2901_Src src)\r
188         {\r
189                 var bits = of(src.ordinal(), 3);\r
190                 I2.setToValueOf(bits.getBit(0));\r
191                 I1.setToValueOf(bits.getBit(1));\r
192                 I0.setToValueOf(bits.getBit(2));\r
193         }\r
194 \r
195         @Override\r
196         public void setReg_A(String val_4_bit)\r
197         {\r
198                 var bits = BitVector.parseMSBFirst(val_4_bit);\r
199                 A3.setToValueOf(bits.getBit(3));\r
200                 A2.setToValueOf(bits.getBit(2));\r
201                 A1.setToValueOf(bits.getBit(1));\r
202                 A0.setToValueOf(bits.getBit(0));\r
203         }\r
204 \r
205         @Override\r
206         public void setReg_B(String val_4_bit)\r
207         {\r
208                 var bits = BitVector.parseMSBFirst(val_4_bit);\r
209                 B3.setToValueOf(bits.getBit(3));\r
210                 B2.setToValueOf(bits.getBit(2));\r
211                 B1.setToValueOf(bits.getBit(1));\r
212                 B0.setToValueOf(bits.getBit(0));\r
213         }\r
214 \r
215         @Override\r
216         public void setCarryIn(String val_1_bit)\r
217         {\r
218                 Cn.setToValueOf(Bit.parse(val_1_bit));\r
219         }\r
220 \r
221         @Override\r
222         public void setNotOutEnable(String val_1_bit)\r
223         {\r
224                 throw new UnsupportedOperationException(); // TODO\r
225         }\r
226 \r
227         @Override\r
228         public void setD(String val_4_bit)\r
229         {\r
230                 var bits = BitVector.parseMSBFirst(val_4_bit);\r
231                 D4.setToValueOf(bits.getBit(3));\r
232                 D3.setToValueOf(bits.getBit(2));\r
233                 D2.setToValueOf(bits.getBit(1));\r
234                 D1.setToValueOf(bits.getBit(0));\r
235         }\r
236 \r
237         @Override\r
238         public void setQ_0(String val_1_bit)\r
239         {\r
240                 IQn.setToValueOf(Bit.parse(val_1_bit));\r
241         }\r
242 \r
243         @Override\r
244         public void setQ_3(String val_1_bit)\r
245         {\r
246                 IQn_3.setToValueOf(Bit.parse(val_1_bit));\r
247         }\r
248 \r
249         @Override\r
250         public void setRAM_0(String val_1_bit)\r
251         {\r
252                 IRAMn.setToValueOf(Bit.parse(val_1_bit));\r
253         }\r
254 \r
255         @Override\r
256         public void setRAM_3(String val_1_bit)\r
257         {\r
258                 IRAMn_3.setToValueOf(Bit.parse(val_1_bit));\r
259         }\r
260 \r
261         @Override\r
262         public void clockOn(boolean isClockOn)\r
263         {\r
264                 C.setState(isClockOn);\r
265         }\r
266 \r
267         @Override\r
268         public String getQ_0()\r
269         {\r
270                 return OQn.getDisplayedValue().toString();\r
271         }\r
272 \r
273         @Override\r
274         public String getQ_3()\r
275         {\r
276                 return OQn_3.getDisplayedValue().toString();\r
277         }\r
278 \r
279         @Override\r
280         public String getRAM_0()\r
281         {\r
282                 return ORAMn.getDisplayedValue().toString();\r
283         }\r
284 \r
285         @Override\r
286         public String getRAM_3()\r
287         {\r
288                 return ORAMn_3.getDisplayedValue().toString();\r
289         }\r
290 \r
291         @Override\r
292         public String getNotP()\r
293         {\r
294                 throw new UnsupportedOperationException(); // TODO\r
295         }\r
296 \r
297         @Override\r
298         public String getNotG()\r
299         {\r
300                 throw new UnsupportedOperationException(); // TODO\r
301         }\r
302 \r
303         @Override\r
304         public String getCarryOut()\r
305         {\r
306                 return Cn_4.getDisplayedValue().toString();\r
307         }\r
308 \r
309         @Override\r
310         public String getSign()\r
311         {\r
312                 return F3.getDisplayedValue().toString();\r
313         }\r
314 \r
315         @Override\r
316         public String getZero()\r
317         {\r
318                 return F_0.getDisplayedValue().toString();\r
319         }\r
320 \r
321         @Override\r
322         public String getOverflow()\r
323         {\r
324                 return OVR.getDisplayedValue().toString();\r
325         }\r
326 \r
327         @Override\r
328         public String getY()\r
329         {\r
330                 var y3 = Y4.getDisplayedValue();\r
331                 var y2 = Y3.getDisplayedValue();\r
332                 var y1 = Y2.getDisplayedValue();\r
333                 var y0 = Y1.getDisplayedValue();\r
334                 return y0.concat(y1).concat(y2).concat(y3).toBitStringMSBFirst();\r
335         }\r
336 \r
337         private void setField(String name, Object value)\r
338         {\r
339                 try\r
340                 {\r
341                         Field f = TestableAm2901Impl.class.getDeclaredField(name);\r
342                         f.setAccessible(true);\r
343                         f.set(this, Objects.requireNonNull(value));\r
344                 }\r
345                 catch (Exception e)\r
346                 {\r
347                         fail(e);\r
348                 }\r
349         }\r
350 \r
351         private static BitVector of(int value, int length)\r
352         {\r
353                 BitVectorMutator mutator = BitVectorMutator.ofLength(length);\r
354                 int val = value;\r
355                 for (int i = length - 1; i >= 0; i--)\r
356                 {\r
357                         mutator.setBit(i, Bit.lastBitOf(val));\r
358                         val >>>= 1;\r
359                 }\r
360                 return mutator.toBitVector();\r
361         }\r
362 \r
363         @Override\r
364         public void setDirectly(Register r, String val_4_bit)\r
365         {\r
366                 am2901.setHighLevelState(regToStateID(r), BitVector.parseMSBFirst(val_4_bit));\r
367         }\r
368 \r
369         @Override\r
370         public String getDirectly(Register r)\r
371         {\r
372                 return ((BitVector) am2901.getHighLevelState(regToStateID(r))).toBitStringMSBFirst();\r
373         }\r
374 \r
375         private static String regToStateID(Register r)\r
376         {\r
377                 if (r == Register.Q)\r
378                         return "qreg.q";\r
379                 return "regs.c" + r.toBitString() + ".q";\r
380         }\r
381 }\r