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