Fixed and added a lot of tests
[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                 var bits = BitVector.parse(val_4_bit);\r
185                 A3.setToValueOf(bits.getBit(0));\r
186                 A2.setToValueOf(bits.getBit(1));\r
187                 A1.setToValueOf(bits.getBit(2));\r
188                 A0.setToValueOf(bits.getBit(3));\r
189         }\r
190 \r
191         @Override\r
192         public void setReg_B(String val_4_bit)\r
193         {\r
194                 var bits = BitVector.parse(val_4_bit);\r
195                 B3.setToValueOf(bits.getBit(0));\r
196                 B2.setToValueOf(bits.getBit(1));\r
197                 B1.setToValueOf(bits.getBit(2));\r
198                 B0.setToValueOf(bits.getBit(3));\r
199         }\r
200 \r
201         @Override\r
202         public void setCarryIn(String val_1_bit)\r
203         {\r
204                 Cn.setToValueOf(Bit.parse(val_1_bit));\r
205         }\r
206 \r
207         @Override\r
208         public void setNotOutEnable(String val_1_bit)\r
209         {\r
210                 throw new UnsupportedOperationException(); // TODO\r
211         }\r
212 \r
213         @Override\r
214         public void setD(String val_4_bit)\r
215         {\r
216                 var bits = BitVector.parse(val_4_bit);\r
217                 D4.setToValueOf(bits.getBit(0));\r
218                 D3.setToValueOf(bits.getBit(1));\r
219                 D2.setToValueOf(bits.getBit(2));\r
220                 D1.setToValueOf(bits.getBit(3));\r
221         }\r
222 \r
223         @Override\r
224         public void setQ_0(String val_1_bit)\r
225         {\r
226                 IQn.setToValueOf(Bit.parse(val_1_bit));\r
227         }\r
228 \r
229         @Override\r
230         public void setQ_3(String val_1_bit)\r
231         {\r
232                 IQn_3.setToValueOf(Bit.parse(val_1_bit));\r
233         }\r
234 \r
235         @Override\r
236         public void setRAM_0(String val_1_bit)\r
237         {\r
238                 IRAMn.setToValueOf(Bit.parse(val_1_bit));\r
239         }\r
240 \r
241         @Override\r
242         public void setRAM_3(String val_1_bit)\r
243         {\r
244                 IRAMn_3.setToValueOf(Bit.parse(val_1_bit));\r
245         }\r
246 \r
247         @Override\r
248         public void clockOn(boolean isClockOn)\r
249         {\r
250                 C.setState(isClockOn);\r
251         }\r
252 \r
253         @Override\r
254         public String getQ_0()\r
255         {\r
256                 return OQn.getDisplayedValue().toString();\r
257         }\r
258 \r
259         @Override\r
260         public String getQ_3()\r
261         {\r
262                 return OQn_3.getDisplayedValue().toString();\r
263         }\r
264 \r
265         @Override\r
266         public String getRAM_0()\r
267         {\r
268                 return ORAMn.getDisplayedValue().toString();\r
269         }\r
270 \r
271         @Override\r
272         public String getRAM_3()\r
273         {\r
274                 return ORAMn_3.getDisplayedValue().toString();\r
275         }\r
276 \r
277         @Override\r
278         public String getNotP()\r
279         {\r
280                 throw new UnsupportedOperationException(); // TODO\r
281         }\r
282 \r
283         @Override\r
284         public String getNotG()\r
285         {\r
286                 throw new UnsupportedOperationException(); // TODO\r
287         }\r
288 \r
289         @Override\r
290         public String getCarryOut()\r
291         {\r
292                 return Cn_4.getDisplayedValue().toString();\r
293         }\r
294 \r
295         @Override\r
296         public String getSign()\r
297         {\r
298                 return F3.getDisplayedValue().toString();\r
299         }\r
300 \r
301         @Override\r
302         public String getZero()\r
303         {\r
304                 return F_0.getDisplayedValue().toString();\r
305         }\r
306 \r
307         @Override\r
308         public String getOverflow()\r
309         {\r
310                 return OVR.getDisplayedValue().toString();\r
311         }\r
312 \r
313         @Override\r
314         public String getY()\r
315         {\r
316                 var y3 = Y4.getDisplayedValue();\r
317                 var y2 = Y3.getDisplayedValue();\r
318                 var y1 = Y2.getDisplayedValue();\r
319                 var y0 = Y1.getDisplayedValue();\r
320                 return y3.concat(y2).concat(y1).concat(y0).toString();\r
321         }\r
322 \r
323         private void setField(String name, Object value)\r
324         {\r
325                 try\r
326                 {\r
327                         Field f = TestableAm2901Impl.class.getDeclaredField(name);\r
328                         f.setAccessible(true);\r
329                         f.set(this, Objects.requireNonNull(value));\r
330                 }\r
331                 catch (Exception e)\r
332                 {\r
333                         fail(e);\r
334                 }\r
335         }\r
336 \r
337         private static BitVector of(int value, int length)\r
338         {\r
339                 BitVectorMutator mutator = BitVectorMutator.ofLength(length);\r
340                 int val = value;\r
341                 for (int i = length - 1; i >= 0; i--)\r
342                 {\r
343                         mutator.setBit(i, Bit.lastBitOf(val));\r
344                         val >>>= 1;\r
345                 }\r
346                 return mutator.toBitVector();\r
347         }\r
348 \r
349         @Override\r
350         public void setDirectly(Register r, String val_4_bit)\r
351         {\r
352                 am2901.setHighLevelState(regToStateID(r), BitVector.parse(val_4_bit));\r
353         }\r
354 \r
355         @Override\r
356         public String getDirectly(Register r)\r
357         {\r
358                 return am2901.getHighLevelState(regToStateID(r)).toString();\r
359         }\r
360 \r
361         private static String regToStateID(Register r)\r
362         {\r
363                 if (r == Register.Q)\r
364                         return "qreg.q";\r
365                 return "regs.c" + r.toBitString() + ".q";\r
366         }\r
367 }\r