+++ /dev/null
-package net.mograsim.logic.model.am2900;
-
-import static net.mograsim.logic.model.am2900.TestUtil.*;
-import static net.mograsim.logic.model.am2900.TestableAm2901.Am2901_Dest.*;
-import static net.mograsim.logic.model.am2900.TestableAm2901.Am2901_Func.*;
-import static net.mograsim.logic.model.am2900.TestableAm2901.Am2901_Src.*;
-import static net.mograsim.logic.model.am2900.TestableAm2901.Register.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.awt.Point;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
-
-import net.mograsim.logic.model.am2900.TestableAm2901.Register;
-
-@DisplayName("Am2901 Tests")
-@TestMethodOrder(OrderAnnotation.class)
-public class Am2901Test
-{
- private TestableAm2901 am2901;
-
- @BeforeEach
- void initialize()
- {
- createAndSetup();
- setInputsToZero();
- }
-
- void createAndSetup()
- {
- am2901 = new TestableAm2901Impl();
- am2901.setup();
- }
-
- void setRegistersToZero()
- {
- setInputsToZero();
- for (Register r : Register.values())
- {
- setRegisterToZero(r);
- }
- }
-
- void setRegisterToZero(Register r)
- {
- am2901.setD("0000");
- am2901.setSrc(DZ);
- am2901.setFunc(AND);
- setRegOutput(r);
-
- am2901.assertFullCycleSuccess();
- }
-
- void setRegOutput(Register r)
- {
- if (r == Q)
- {
- am2901.setDest(QREG);
- } else
- {
- am2901.setReg_B(r.toBitString());
- am2901.setDest(RAMF);
- }
- }
-
- void setInputsToZero()
- {
- am2901.setCarryIn("0");
- am2901.setQ_0("0");
- am2901.setQ_3("0");
- am2901.setRAM_0("0");
- am2901.setRAM_3("0");
- am2901.setReg_A("0000");
- am2901.setReg_B("0000");
- am2901.setD("0000");
- am2901.setSrc(AB);
- am2901.setFunc(ADD);
- am2901.setDest(QREG);
-// am2901.setNotOutEnable("0"); TODO
- am2901.clockOn(true);
- am2901.assertRunSuccess();
- }
-
- @ParameterizedTest(name = "{0}")
- @Order(1)
- @DisplayName("Direct / high level access")
- @EnumSource(Register.class)
- void testDirectAccess(Register r)
- {
- assertEquals("UUUU", am2901.getDirectly(r));
-
- am2901.setDirectly(r, "1011");
-
- assertEquals("1011", am2901.getDirectly(r));
- }
-
- @ParameterizedTest(name = "{0}")
- @Order(2)
- @DisplayName("Setting each register to 0")
- @EnumSource(Register.class)
- void testSetToZero(Register r)
- {
- assertEquals("UUUU", am2901.getDirectly(r));
-
- setRegisterToZero(r);
-
- assertEquals("0000", am2901.getDirectly(r));
- assertEquals("0000", am2901.getY());
- assertEquals("0", am2901.getCarryOut());
- assertEquals("0", am2901.getOverflow());
- assertEquals("0", am2901.getSign());
- assertEquals("1", am2901.getZero());
- }
-
- @Test
- @Order(3)
- @DisplayName("Setting all registers to 0")
- void testSetAllToZero()
- {
- setRegistersToZero();
-
- assertEquals("0000", am2901.getY());
- assertEquals("0", am2901.getCarryOut());
- assertEquals("0", am2901.getOverflow());
- assertEquals("0", am2901.getSign());
- assertEquals("1", am2901.getZero());
- assertEquals("0", am2901.getQ_0());
- assertEquals("0", am2901.getQ_3());
- assertEquals("0", am2901.getRAM_0());
- assertEquals("0", am2901.getRAM_3());
-
- assertAll("register values", Register.stream().map(r -> () ->
- {
- assertEquals("0000", am2901.getDirectly(r), r.name());
- }));
- }
-
- @Test
- @Order(4)
- @DisplayName("ADD operation")
- void testADD()
- {
- am2901.setSrc(DA);
- am2901.setFunc(ADD);
- am2901.setDest(NOP);
- am2901.setReg_A(r0.toBitString());
-
- assertAll(getAll4BitPairs().map(xy -> () ->
- {
- am2901.setDirectly(r0, to4bitBin(xy.x));
- am2901.setD(to4bitBin(xy.y));
-
- am2901.assertFullCycleSuccess();
-
- int res32Bit = xy.x + xy.y;
- int res4Bit = res32Bit & 0b1111;
- int res32Bit_sgn = signed4ToSigned32(xy.x) + signed4ToSigned32(xy.y);
- int res4Bit_sgn = signed4ToSigned32(res32Bit_sgn);
-
- assertAll("Result of " + xy.x + " + " + xy.y + " = " + res32Bit,
- () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
- () -> assertEquals(to1bitBin(res4Bit == 0), am2901.getZero(), " F=0"),
- () -> assertEquals(to1bitBin(res4Bit & 0b1000), am2901.getSign(), " F3"),
- () -> assertEquals(to1bitBin(res32Bit > 15), am2901.getCarryOut(), " Cn+4"),
- () -> assertEquals(to1bitBin(res4Bit_sgn != res32Bit_sgn), am2901.getOverflow(), " OVR"));
- }));
- }
-
- @Test
- @Order(4)
- @DisplayName("AND operation")
- void testAND()
- {
- am2901.setSrc(DA);
- am2901.setFunc(AND);
- am2901.setDest(NOP);
- am2901.setReg_A(r0.toBitString());
-
- assertAll(getAll4BitPairs().map(xy -> () ->
- {
- am2901.setDirectly(r0, to4bitBin(xy.x));
- am2901.setD(to4bitBin(xy.y));
-
- am2901.assertFullCycleSuccess();
-
- int res32Bit = xy.x & xy.y;
-
- assertAll("Result of " + xy.x + " & " + xy.y + " = " + res32Bit,
- () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
- () -> assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), " F=0"),
- () -> assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), " F3")
-// () -> assertEquals(to1bitBin(res32Bit), am2901.getCarryOut(), " Cn+4"), // TODO
-// () -> assertEquals(to1bitBin(res32Bit), am2901.getOverflow(), " OVR") // TODO
- );
- }));
- }
-
- @Test
- @Order(4)
- @DisplayName("OR operation")
- void testOR()
- {
- am2901.setSrc(DA);
- am2901.setFunc(OR);
- am2901.setDest(NOP);
- am2901.setReg_A(r0.toBitString());
-
- assertAll(getAll4BitPairs().map(xy -> () ->
- {
- am2901.setDirectly(r0, to4bitBin(xy.x));
- am2901.setD(to4bitBin(xy.y));
-
- am2901.assertFullCycleSuccess();
-
- int res32Bit = xy.x | xy.y;
-
- assertAll("Result of " + xy.x + " | " + xy.y + " = " + res32Bit,
- () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
- () -> assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), " F=0"),
- () -> assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), " F3")
-// () -> assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getCarryOut(), " Cn+4"), // TODO
-// () -> assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getOverflow(), " OVR") // TODO
- );
- }));
- }
-
- @Test
- @Order(4)
- @DisplayName("XOR operation")
- void testXOR()
- {
- am2901.setSrc(DA);
- am2901.setFunc(EXOR);
- am2901.setDest(NOP);
- am2901.setReg_A(r0.toBitString());
-
- assertAll(getAll4BitPairs().map(xy -> () ->
- {
- am2901.setDirectly(r0, to4bitBin(xy.x));
- am2901.setD(to4bitBin(xy.y));
-
- am2901.assertFullCycleSuccess();
-
- int res32Bit = xy.x ^ xy.y;
-
- assertAll("Result of " + xy.x + " ^ " + xy.y + " = " + res32Bit,
- () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
- () -> assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), " F=0"),
- () -> assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), " F3"));
- }));
- }
-
- @Test
- @Order(4)
- @DisplayName("SUB operation")
- void testSUB()
- {
- am2901.setSrc(DA);
- am2901.setCarryIn("1");
- am2901.setFunc(SUBR);
- am2901.setDest(NOP);
- am2901.setReg_A(r0.toBitString());
-
- assertAll(getAll4BitPairs().map(xy -> () ->
- {
- am2901.setDirectly(r0, to4bitBin(xy.x));
- am2901.setD(to4bitBin(xy.y));
-
- am2901.assertFullCycleSuccess();
-
- int res32Bit = xy.x - xy.y;
- int res4Bit = res32Bit & 0b1111;
- int res32Bit_sgn = signed4ToSigned32(xy.x) - signed4ToSigned32(xy.y);
- int res4Bit_sgn = signed4ToSigned32(res32Bit_sgn);
-
- assertAll("Result of " + xy.x + " - " + xy.y + " = " + res32Bit,
- () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
- () -> assertEquals(to1bitBin(res4Bit == 0), am2901.getZero(), " F=0"),
- () -> assertEquals(to1bitBin(res4Bit & 0b1000), am2901.getSign(), " F3"),
- () -> assertEquals(to1bitBin(xy.x >= xy.y), am2901.getCarryOut(), " Cn+4"),
- () -> assertEquals(to1bitBin(res4Bit_sgn != res32Bit_sgn), am2901.getOverflow(), " OVR"));
- }));
- }
-
- static Stream<Point> getAll4BitPairs()
- {
- return IntStream.range(0, 16).boxed().flatMap(x -> IntStream.range(0, 16).mapToObj(y -> new Point(x, y)));
- }
-}
+++ /dev/null
-package net.mograsim.logic.model.am2900;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-
-import net.mograsim.logic.model.SimpleLogicUIStandalone;
-import net.mograsim.logic.model.model.ViewModelModifiable;
-import net.mograsim.logic.model.model.components.GUIComponent;
-import net.mograsim.logic.model.model.components.atomic.GUIAndGate;
-import net.mograsim.logic.model.model.components.atomic.GUIBitDisplay;
-import net.mograsim.logic.model.model.components.atomic.GUIManualSwitch;
-import net.mograsim.logic.model.model.components.atomic.GUINotGate;
-import net.mograsim.logic.model.model.components.atomic.TextComponent;
-import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.model.wires.WireCrossPoint;
-import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
-import net.mograsim.logic.model.util.ModellingTool;
-
-public class Am2901Testbench
-{
- public static void main(String[] args)
- {
- SimpleLogicUIStandalone.executeVisualisation(Am2901Testbench::createTestbench);
- }
-
- public static void createTestbench(ViewModelModifiable model)
- {
- GUIComponent comp = IndirectGUIComponentCreator.createComponent(model, "GUIAm2901");
- ModellingTool tool = ModellingTool.createFor(model);
-
- comp.moveTo(240, 0);
-
- GUIManualSwitch enable = new GUIManualSwitch(model, 1);
- WireCrossPoint wcp0 = new WireCrossPoint(model, 1);
- GUINotGate not1 = new GUINotGate(model, 1);
- GUINotGate not2 = new GUINotGate(model, 1);
- GUINotGate not3 = new GUINotGate(model, 1);
- GUIAndGate and = new GUIAndGate(model, 1);
- tool.connect(wcp0, enable, "");
- tool.connect(wcp0, and, "A");
- tool.connect(wcp0, not1, "A");
- tool.connect(not1, not2, "Y", "A");
- tool.connect(not2, not3, "Y", "A");
- tool.connect(not3, and, "Y", "B");
- enable.moveTo(20, -32.5);
- wcp0.moveTo(35, -26);
- not1.moveTo(50, -20);
- not2.moveTo(80, -20);
- not3.moveTo(110, -20);
- and.moveTo(135, -30);
- Pin last = and.getPin("Y");
-
- // guess which pins are outputs and which are inputs
- // TODO this code exists four times... but it seems too "hacky" to put it in a helper class
- List<String> inputPinNames = new ArrayList<>();
- List<String> outputPinNames = new ArrayList<>();
- for (Pin p : comp.getPins().values())
- if (p.getRelX() == 0)
- inputPinNames.add(p.name);
- else
- outputPinNames.add(p.name);
-
- inputPinNames.sort(Comparator.comparing(comp::getPin, Comparator.comparing(Pin::getRelY)));
- outputPinNames.sort(Comparator.comparing(comp::getPin, Comparator.comparing(Pin::getRelY)));
-
- for (int i = 0; i < inputPinNames.size(); i++)
- {
- double x = 55 + 70 * (i % 2);
- double y = 10 * i;
-
- WireCrossPoint wcp = new WireCrossPoint(model, 1);
- GUIComponent d_ff = IndirectGUIComponentCreator.createComponent(model, "GUIdff");
- GUIManualSwitch sw = new GUIManualSwitch(model, 1);
-
- tool.connect(last, wcp);
- tool.connect(wcp, d_ff, "C");
- tool.connect(sw, d_ff, "", "D");
- tool.connect(d_ff, comp, "Q", inputPinNames.get(i));
- last = wcp.getPin();
-
- TextComponent label = new TextComponent(model, inputPinNames.get(i));
-
- sw.moveTo(x, y + 7.5);
- wcp.moveTo(160, y);
- d_ff.moveTo(170, y);
- label.moveTo(x - 48, y + 8);
- }
-
- for (int i = 0; i < outputPinNames.size(); i++)
- {
- double x = 300 + 75 * (i % 2);
- double y = 10 * i - 2.5;
- GUIBitDisplay bd = new GUIBitDisplay(model, 1);
- bd.moveTo(x, y);
- tool.connect(bd.getInputPin(), comp, outputPinNames.get(i));
-
- TextComponent label = new TextComponent(model, outputPinNames.get(i));
- label.moveTo(x + 25, y);
- }
- }
-}
\ No newline at end of file
--- /dev/null
+package net.mograsim.logic.model.am2900;\r
+\r
+import static org.junit.jupiter.api.Assertions.fail;\r
+\r
+import java.lang.reflect.Field;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.LinkedList;\r
+import java.util.Objects;\r
+import java.util.Queue;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import net.mograsim.logic.core.components.BitDisplay;\r
+import net.mograsim.logic.core.components.ManualSwitch;\r
+import net.mograsim.logic.core.timeline.Timeline;\r
+import net.mograsim.logic.model.am2900.TestableCircuit.Result;\r
+import net.mograsim.logic.model.model.ViewModel;\r
+import net.mograsim.logic.model.model.ViewModelModifiable;\r
+import net.mograsim.logic.model.model.components.GUIComponent;\r
+import net.mograsim.logic.model.model.components.atomic.GUIBitDisplay;\r
+import net.mograsim.logic.model.model.components.atomic.GUIManualSwitch;\r
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;\r
+import net.mograsim.logic.model.model.wires.GUIWire;\r
+import net.mograsim.logic.model.model.wires.Pin;\r
+import net.mograsim.logic.model.modeladapter.LogicModelParameters;\r
+import net.mograsim.logic.model.modeladapter.ViewLogicModelAdapter;\r
+import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;\r
+import net.mograsim.logic.model.util.ModellingTool;\r
+\r
+public class TestEnvironmentHelper\r
+{\r
+ private final TestableCircuit testEnvInstance;\r
+ private final Class<?> testEnvClass;\r
+ private final String modelId;\r
+ private Field componentField;\r
+ private Field timelineField;\r
+\r
+ private GUIComponent component;\r
+ private Timeline timeline;\r
+ private ViewModelModifiable viewModel;\r
+ private ModellingTool modellingTool;\r
+ private HashMap<String, GUIManualSwitch> idSwitchMap = new HashMap<>();\r
+ private HashMap<String, GUIBitDisplay> idDisplayMap = new HashMap<>();\r
+\r
+ private DebugState debug = DebugState.NO_DEBUG;\r
+ private Set<String> wireDebugChangeSet;\r
+ private boolean debugWires = false;\r
+ public int debugEventThreshold = 10_000;\r
+ public int debugEventCount = 500;\r
+ private int eventCounter;\r
+\r
+ public TestEnvironmentHelper(TestableCircuit testEnv, String modelId)\r
+ {\r
+ this.testEnvInstance = testEnv;\r
+ this.modelId = modelId;\r
+ this.testEnvClass = testEnvInstance.getClass();\r
+ for (Field f : testEnvClass.getDeclaredFields())\r
+ {\r
+ if (GUIComponent.class.isAssignableFrom(f.getType()))\r
+ {\r
+ componentField = f;\r
+ componentField.setAccessible(true);\r
+ } else if (Timeline.class.isAssignableFrom(f.getType()))\r
+ {\r
+ timelineField = f;\r
+ timelineField.setAccessible(true);\r
+ }\r
+ }\r
+ if (componentField == null || timelineField == null)\r
+ throw new IllegalStateException("No component or timeline field found!");\r
+ }\r
+\r
+ public void setup(DebugState debug)\r
+ {\r
+ this.debug = debug;\r
+ // Create view model\r
+ viewModel = new ViewModelModifiable();\r
+ modellingTool = ModellingTool.createFor(viewModel);\r
+ component = IndirectGUIComponentCreator.createComponent(viewModel, modelId);\r
+ setField(componentField, component);\r
+\r
+ component.getPins().values().forEach(this::extendModelPin);\r
+\r
+ // Create logic model\r
+ LogicModelParameters params = new LogicModelParameters();\r
+ params.gateProcessTime = 50;\r
+ params.wireTravelTime = 10;\r
+ timeline = ViewLogicModelAdapter.convert(viewModel, params);\r
+ setField(timelineField, timeline);\r
+\r
+ // Bind switches/displays to this test class\r
+ component.getPins().values().forEach(this::bindModelPin);\r
+\r
+ if (debug == DebugState.DEBUG_AT_PERFORMANCE_COST)\r
+ {\r
+ setupDebugging();\r
+ }\r
+ timeline.addEventAddedListener(te -> eventCounter++);\r
+ }\r
+\r
+ private void extendModelPin(Pin p)\r
+ {\r
+ String javaIdentId = idToJavaIdentifier(p.name);\r
+ try\r
+ {\r
+ Field f = testEnvClass.getDeclaredField(javaIdentId);\r
+ Class<?> type = f.getType();\r
+ if (ManualSwitch.class.isAssignableFrom(type))\r
+ {\r
+ GUIManualSwitch gms = new GUIManualSwitch(viewModel, p.logicWidth);\r
+ modellingTool.connect(p, gms.getOutputPin());\r
+ idSwitchMap.put(p.name, gms);\r
+ } else if (BitDisplay.class.isAssignableFrom(type))\r
+ {\r
+ GUIBitDisplay gbd = new GUIBitDisplay(viewModel, p.logicWidth);\r
+ modellingTool.connect(p, gbd.getInputPin());\r
+ idDisplayMap.put(p.name, gbd);\r
+ } else\r
+ {\r
+ fail("unkown field type " + type);\r
+ }\r
+ }\r
+ catch (NoSuchFieldException | SecurityException e)\r
+ {\r
+ fail(e);\r
+ }\r
+ }\r
+\r
+ private void bindModelPin(Pin p)\r
+ {\r
+ String javaIdentId = idToJavaIdentifier(p.name);\r
+ if (idDisplayMap.containsKey(p.name))\r
+ setField(javaIdentId, idDisplayMap.get(p.name).getBitDisplay());\r
+ if (idSwitchMap.containsKey(p.name))\r
+ setField(javaIdentId, idSwitchMap.get(p.name).getManualSwitch());\r
+ }\r
+\r
+ private void setupDebugging()\r
+ {\r
+ // Debug code\r
+ HashSet<GUIWire> wiresIncludingSubmodels = new HashSet<>();\r
+ Queue<ViewModel> modelsToIterate = new LinkedList<>();\r
+ modelsToIterate.add(viewModel);\r
+ while (modelsToIterate.size() > 0)\r
+ {\r
+ ViewModel model = modelsToIterate.poll();\r
+ wiresIncludingSubmodels.addAll(model.getWiresByName().values());\r
+ for (GUIComponent comp : model.getComponentsByName().values())\r
+ if (comp instanceof SubmodelComponent)\r
+ modelsToIterate.offer(((SubmodelComponent) comp).submodel);\r
+ }\r
+ System.out.println(wiresIncludingSubmodels.size());\r
+ viewModel.setRedrawHandler(() -> wiresIncludingSubmodels.forEach(w ->\r
+ {\r
+ if (debugWires)\r
+ {\r
+ wireDebugChangeSet.add(w.toString());\r
+ }\r
+ }));\r
+ }\r
+\r
+ public Result run()\r
+ {\r
+ // Normal execution until completion or eventLimit\r
+ int eventLimit = debugEventThreshold;\r
+ eventCounter = 0;\r
+ debugWires = false;\r
+ while (eventCounter < eventLimit)\r
+ {\r
+ timeline.executeNext();\r
+ if (!timeline.hasNext())\r
+ return Result.SUCCESS;\r
+ }\r
+\r
+ // Start debugging if event limit is reached (if debug is active)\r
+ if (debug == DebugState.DEBUG_AT_PERFORMANCE_COST)\r
+ return debugThisRun();\r
+\r
+ return Result.OUT_OF_TIME;\r
+ }\r
+\r
+ private Result debugThisRun()\r
+ {\r
+ int eventLimit = debugEventThreshold;\r
+ debugWires = true;\r
+ wireDebugChangeSet = new TreeSet<>();\r
+ Set<String> oldChangeSet;\r
+ // observe wire changes to detect, if we are really stuck in an endless loop\r
+ do\r
+ {\r
+ eventLimit += debugEventCount;\r
+ oldChangeSet = wireDebugChangeSet;\r
+ wireDebugChangeSet = new TreeSet<>();\r
+ while (eventCounter < eventLimit)\r
+ {\r
+ timeline.executeNext();\r
+ if (!timeline.hasNext())\r
+ {\r
+ // no endless loop, but more events needed than expected\r
+ System.out.println("run() took longer than expected: " + eventCounter);\r
+ return Result.SUCCESS;\r
+ }\r
+ }\r
+ } while (!oldChangeSet.equals(wireDebugChangeSet));\r
+ // if stuck, abort execution and print wires\r
+ System.err.print("Problematic Wire updates:");\r
+ wireDebugChangeSet.forEach(System.out::println);\r
+ System.err.println("run() failed: " + eventCounter);\r
+ return Result.OUT_OF_TIME;\r
+ }\r
+\r
+ private static String idToJavaIdentifier(String s)\r
+ {\r
+ StringBuilder sb = new StringBuilder(s.length());\r
+ char c = s.charAt(0);\r
+ sb.append(Character.isJavaIdentifierStart(c) ? c : '_');\r
+ for (int i = 1; i < s.length(); i++)\r
+ sb.append(Character.isJavaIdentifierPart(c = s.charAt(i)) ? c : '_');\r
+ return sb.toString();\r
+ }\r
+\r
+ private <S> void setField(Field f, S value)\r
+ {\r
+ try\r
+ {\r
+ f.set(testEnvInstance, Objects.requireNonNull(value));\r
+ }\r
+ catch (Exception e)\r
+ {\r
+ fail(e);\r
+ }\r
+ }\r
+\r
+ private <S> void setField(String name, S value)\r
+ {\r
+ try\r
+ {\r
+ Field f = testEnvClass.getDeclaredField(name);\r
+ f.setAccessible(true);\r
+ f.set(testEnvInstance, Objects.requireNonNull(value));\r
+ }\r
+ catch (Exception e)\r
+ {\r
+ fail(e);\r
+ }\r
+ }\r
+\r
+ public enum DebugState\r
+ {\r
+ NO_DEBUG, DEBUG_AT_PERFORMANCE_COST;\r
+ }\r
+}\r
package net.mograsim.logic.model.am2900;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.lang.reflect.Field;
+import java.util.Objects;
+
+import net.mograsim.logic.core.types.Bit;
+import net.mograsim.logic.core.types.BitVector;
+import net.mograsim.logic.core.types.BitVector.BitVectorMutator;
+import net.mograsim.logic.model.am2900.am2901.TestableAm2901Impl;
+
public final class TestUtil
{
private TestUtil()
}
return sb.reverse().toString();
}
+
+ public static BitVector of(int value, int length)
+ {
+ BitVectorMutator mutator = BitVectorMutator.ofLength(length);
+ int val = value;
+ for (int i = length - 1; i >= 0; i--)
+ {
+ mutator.setMSBit(i, Bit.lastBitOf(val));
+ val >>>= 1;
+ }
+ return mutator.toBitVector();
+ }
}
+++ /dev/null
-package net.mograsim.logic.model.am2900;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.util.Arrays;
-import java.util.stream.Stream;
-
-public interface TestableAm2901
-{
- void setup();
-
- Result run();
-
- void setDest(Am2901_Dest dest);
-
- void setFunc(Am2901_Func func);
-
- void setSrc(Am2901_Src src);
-
- void setReg_A(String val_4_bit);
-
- void setReg_B(String val_4_bit);
-
- void setCarryIn(String val_1_bit);
-
- void setNotOutEnable(String val_1_bit);
-
- void setD(String val_4_bit);
-
- void setQ_0(String val_1_bit);
-
- void setQ_3(String val_1_bit);
-
- void setRAM_0(String val_1_bit);
-
- void setRAM_3(String val_1_bit);
-
- void clockOn(boolean isClockOn);
-
- void setDirectly(Register r, String val_4_bit);
-
- String getQ_0();
-
- String getQ_3();
-
- String getRAM_0();
-
- String getRAM_3();
-
- String getNotP();
-
- String getNotG();
-
- String getCarryOut();
-
- String getSign();
-
- String getZero();
-
- String getOverflow();
-
- String getY();
-
- String getDirectly(Register r);
-
- default void assertRunSuccess()
- {
- assertEquals(Result.SUCCESS, run());
- }
-
- default void assertFullCycleSuccess()
- {
- assertRunSuccess();
- clockOn(false);
- assertRunSuccess();
- clockOn(true);
- assertRunSuccess();
- }
-
- public enum Result
- {
- SUCCESS, OUT_OF_TIME, ERROR;
- }
-
- public enum Am2901_Dest
- {
- QREG, NOP, RAMA, RAMF, RAMQD, RAMD, RAMQU, RAMU;
-
- public boolean doesShift()
- {
- return ordinal() >= 4;
- }
-
- public int getShiftDir()
- {
- return doesShift() ? (ordinal() < 6 ? -1 : 1) : 0;
- }
-
- public int getI7()
- {
- return this.ordinal() >> 1 & 1;
- }
- }
-
- public enum Am2901_Func
- {
- ADD, SUBR, SUBS, OR, AND, NOTRS, EXOR, EXNOR;
- }
-
- public enum Am2901_Src
- {
- AQ, AB, ZQ, ZB, ZA, DA, DQ, DZ;
- }
-
- public enum Register
- {
- r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, rA, rB, rC, rD, rE, rF, Q;
-
- public String toBitString()
- {
- if (this.ordinal() > 0xF)
- throw new UnsupportedOperationException();
- return TestUtil.to4bitBin(this.ordinal());
- }
-
- public static Stream<Register> stream()
- {
- return Arrays.stream(values());
- }
- }
-}
+++ /dev/null
-package net.mograsim.logic.model.am2900;
-
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Queue;
-import java.util.Set;
-import java.util.TreeSet;
-
-import net.mograsim.logic.core.components.BitDisplay;
-import net.mograsim.logic.core.components.ManualSwitch;
-import net.mograsim.logic.core.timeline.Timeline;
-import net.mograsim.logic.core.types.Bit;
-import net.mograsim.logic.core.types.BitVector;
-import net.mograsim.logic.core.types.BitVector.BitVectorMutator;
-import net.mograsim.logic.model.model.ViewModel;
-import net.mograsim.logic.model.model.ViewModelModifiable;
-import net.mograsim.logic.model.model.components.GUIComponent;
-import net.mograsim.logic.model.model.components.atomic.GUIBitDisplay;
-import net.mograsim.logic.model.model.components.atomic.GUIManualSwitch;
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.model.wires.GUIWire;
-import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.modeladapter.LogicModelParameters;
-import net.mograsim.logic.model.modeladapter.ViewLogicModelAdapter;
-import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
-
-public class TestableAm2901Impl implements TestableAm2901
-{
- private GUIComponent am2901;
- private Timeline timeline;
- private ManualSwitch I8, I7, I6, I5, I4, I3, I2, I1, I0;
- private ManualSwitch C;
- private ManualSwitch Cn;
- private ManualSwitch D1, D2, D3, D4;
- private ManualSwitch A0, A1, A2, A3;
- private ManualSwitch B0, B1, B2, B3;
- private ManualSwitch IRAMn, IRAMn_3, IQn, IQn_3;
- private BitDisplay Y1, Y2, Y3, Y4;
- private BitDisplay F_0, Cn_4, OVR, F3;
- private BitDisplay ORAMn, ORAMn_3, OQn, OQn_3;
-
- private Set<String> wireDebugChangeSet;
- private boolean debugWires = false;
- public int debugEventThreshold = 10_000;
- public int debugEventCount = 500;
-
- private int eventCounter;
-
- @Override
- public Result run()
- {
- // Normal execution until completion or eventLimit
- int eventLimit = debugEventThreshold;
- eventCounter = 0;
- debugWires = false;
- while (eventCounter < eventLimit)
- {
- timeline.executeNext();
- if (!timeline.hasNext())
- {
-// System.out.println("run() took " + eventCounter + " events");
- return Result.SUCCESS;
- }
- }
- // Start debugging if event limit is reached
- debugWires = true;
- wireDebugChangeSet = new TreeSet<>();
- Set<String> oldChangeSet;
- // observe wire changes to detect, if we are really stuck in an endless loop
- do
- {
- eventLimit += debugEventCount;
- oldChangeSet = wireDebugChangeSet;
- wireDebugChangeSet = new TreeSet<>();
- while (eventCounter < eventLimit)
- {
- timeline.executeNext();
- if (!timeline.hasNext())
- {
- // no endless loop, but more events needed than expected
- System.out.println("run() took longer than expected: " + eventCounter);
- return Result.SUCCESS;
- }
- }
- } while (!oldChangeSet.equals(wireDebugChangeSet));
- // if stuck, abort execution and print wires
- System.err.print("Problematic Wire updates:");
- wireDebugChangeSet.forEach(System.out::println);
- System.err.println("run() failed: " + eventCounter);
- return Result.OUT_OF_TIME;
- }
-
- @SuppressWarnings("unused")
- @Override
- public void setup()
- {
- // Create view model
- ViewModelModifiable viewModel = new ViewModelModifiable();
- am2901 = IndirectGUIComponentCreator.createComponent(viewModel, "GUIAm2901");
- // guess which pins are outputs and which are inputs
- // TODO this code exists four times... but it seems too "hacky" to put it in a helper class
- List<String> inputPinNames = new ArrayList<>();
- List<String> outputPinNames = new ArrayList<>();
- for (Pin p : am2901.getPins().values())
- if (p.getRelX() == 0)
- inputPinNames.add(p.name);
- else
- outputPinNames.add(p.name);
- // Get switches
- HashMap<String, GUIManualSwitch> idSwitchMap = new HashMap<>();
- for (String id : inputPinNames)
- {
- GUIManualSwitch sw = new GUIManualSwitch(viewModel, 1);
- new GUIWire(viewModel, am2901.getPin(id), sw.getOutputPin());
- idSwitchMap.put(id, sw);
- }
- // Get displays
- HashMap<String, GUIBitDisplay> idDisplayMap = new HashMap<>();
- for (String id : outputPinNames)
- {
- GUIBitDisplay bd = new GUIBitDisplay(viewModel, 1);
-// bd.addRedrawListener(() -> System.out.println(id + " " + bd.getBitDisplay().getDisplayedValue()));
- new GUIWire(viewModel, am2901.getPin(id), bd.getInputPin());
- idDisplayMap.put(id, bd);
- }
- // Create logic model
- LogicModelParameters params = new LogicModelParameters();
- params.gateProcessTime = 50;
- params.wireTravelTime = 10;
- timeline = ViewLogicModelAdapter.convert(viewModel, params);
- // Bind switches/displays to this test class
- for (var entry : idSwitchMap.entrySet())
- setField(entry.getKey().replaceAll("\\+|=", "_"), entry.getValue().getManualSwitch());
- for (var entry : idDisplayMap.entrySet())
- setField(entry.getKey().replaceAll("\\+|=", "_"), entry.getValue().getBitDisplay());
-
- // Debug code
- HashSet<GUIWire> wiresIncludingSubmodels = new HashSet<>();
- Queue<ViewModel> modelsToIterate = new LinkedList<>();
- modelsToIterate.add(viewModel);
- while (modelsToIterate.size() > 0)
- {
- ViewModel model = modelsToIterate.poll();
- wiresIncludingSubmodels.addAll(model.getWiresByName().values());
- for (GUIComponent comp : model.getComponentsByName().values())
- if (comp instanceof SubmodelComponent)
- modelsToIterate.offer(((SubmodelComponent) comp).submodel);
- }
- // NOTE: This commented out code is only used for serious debugging (performance cost!)
-// System.out.println(wiresIncludingSubmodels.size());
-// viewModel.setRedrawHandler(() -> wiresIncludingSubmodels.forEach(w ->
-// {
-// if (debugWires)
-// {
-// wireDebugChangeSet.add(w.toString());
-// }
-// }));
- timeline.addEventAddedListener(te -> eventCounter++);
- }
-
- @Override
- public void setDest(Am2901_Dest dest)
- {
- var bits = of(dest.ordinal(), 3);
- I8.setState(bits.getLSBit(2));
- I7.setState(bits.getLSBit(1));
- I6.setState(bits.getLSBit(0));
- }
-
- @Override
- public void setFunc(Am2901_Func func)
- {
- var bits = of(func.ordinal(), 3);
- I5.setState(bits.getLSBit(2));
- I4.setState(bits.getLSBit(1));
- I3.setState(bits.getLSBit(0));
- }
-
- @Override
- public void setSrc(Am2901_Src src)
- {
- var bits = of(src.ordinal(), 3);
- I2.setState(bits.getLSBit(2));
- I1.setState(bits.getLSBit(1));
- I0.setState(bits.getLSBit(0));
- }
-
- @Override
- public void setReg_A(String val_4_bit)
- {
- var bits = BitVector.parse(val_4_bit);
- A3.setState(bits.getLSBit(3));
- A2.setState(bits.getLSBit(2));
- A1.setState(bits.getLSBit(1));
- A0.setState(bits.getLSBit(0));
- }
-
- @Override
- public void setReg_B(String val_4_bit)
- {
- var bits = BitVector.parse(val_4_bit);
- B3.setState(bits.getLSBit(3));
- B2.setState(bits.getLSBit(2));
- B1.setState(bits.getLSBit(1));
- B0.setState(bits.getLSBit(0));
- }
-
- @Override
- public void setCarryIn(String val_1_bit)
- {
- Cn.setState(Bit.parse(val_1_bit));
- }
-
- @Override
- public void setNotOutEnable(String val_1_bit)
- {
- throw new UnsupportedOperationException(); // TODO
- }
-
- @Override
- public void setD(String val_4_bit)
- {
- var bits = BitVector.parse(val_4_bit);
- D4.setState(bits.getLSBit(3));
- D3.setState(bits.getLSBit(2));
- D2.setState(bits.getLSBit(1));
- D1.setState(bits.getLSBit(0));
- }
-
- @Override
- public void setQ_0(String val_1_bit)
- {
- IQn.setState(Bit.parse(val_1_bit));
- }
-
- @Override
- public void setQ_3(String val_1_bit)
- {
- IQn_3.setState(Bit.parse(val_1_bit));
- }
-
- @Override
- public void setRAM_0(String val_1_bit)
- {
- IRAMn.setState(Bit.parse(val_1_bit));
- }
-
- @Override
- public void setRAM_3(String val_1_bit)
- {
- IRAMn_3.setState(Bit.parse(val_1_bit));
- }
-
- @Override
- public void clockOn(boolean isClockOn)
- {
- C.setState(isClockOn ? Bit.ONE : Bit.ZERO);
- }
-
- @Override
- public String getQ_0()
- {
- return OQn.getDisplayedValue().toString();
- }
-
- @Override
- public String getQ_3()
- {
- return OQn_3.getDisplayedValue().toString();
- }
-
- @Override
- public String getRAM_0()
- {
- return ORAMn.getDisplayedValue().toString();
- }
-
- @Override
- public String getRAM_3()
- {
- return ORAMn_3.getDisplayedValue().toString();
- }
-
- @Override
- public String getNotP()
- {
- throw new UnsupportedOperationException(); // TODO
- }
-
- @Override
- public String getNotG()
- {
- throw new UnsupportedOperationException(); // TODO
- }
-
- @Override
- public String getCarryOut()
- {
- return Cn_4.getDisplayedValue().toString();
- }
-
- @Override
- public String getSign()
- {
- return F3.getDisplayedValue().toString();
- }
-
- @Override
- public String getZero()
- {
- return F_0.getDisplayedValue().toString();
- }
-
- @Override
- public String getOverflow()
- {
- return OVR.getDisplayedValue().toString();
- }
-
- @Override
- public String getY()
- {
- var y3 = Y4.getDisplayedValue();
- var y2 = Y3.getDisplayedValue();
- var y1 = Y2.getDisplayedValue();
- var y0 = Y1.getDisplayedValue();
- return y3.concat(y2).concat(y1).concat(y0).toString();
- }
-
- private void setField(String name, Object value)
- {
- try
- {
- Field f = TestableAm2901Impl.class.getDeclaredField(name);
- f.setAccessible(true);
- f.set(this, Objects.requireNonNull(value));
- }
- catch (Exception e)
- {
- fail(e);
- }
- }
-
- private static BitVector of(int value, int length)
- {
- BitVectorMutator mutator = BitVectorMutator.ofLength(length);
- int val = value;
- for (int i = length - 1; i >= 0; i--)
- {
- mutator.setMSBit(i, Bit.lastBitOf(val));
- val >>>= 1;
- }
- return mutator.toBitVector();
- }
-
- @Override
- public void setDirectly(Register r, String val_4_bit)
- {
- am2901.setHighLevelState(regToStateID(r), BitVector.parse(val_4_bit));
- }
-
- @Override
- public String getDirectly(Register r)
- {
- return ((BitVector) am2901.getHighLevelState(regToStateID(r))).toString();
- }
-
- private static String regToStateID(Register r)
- {
- if (r == Register.Q)
- return "qreg.q";
- return "regs.c" + r.toBitString() + ".q";
- }
-}
--- /dev/null
+package net.mograsim.logic.model.am2900;\r
+\r
+import static org.junit.jupiter.api.Assertions.assertEquals;\r
+\r
+public interface TestableCircuit\r
+{\r
+ void setup();\r
+\r
+ Result run();\r
+\r
+ void clockOn(boolean isClockOn);\r
+\r
+ default void assertRunSuccess()\r
+ {\r
+ assertEquals(Result.SUCCESS, run());\r
+ }\r
+\r
+ default void assertFullCycleSuccess()\r
+ {\r
+ assertRunSuccess();\r
+ clockOn(false);\r
+ assertRunSuccess();\r
+ clockOn(true);\r
+ assertRunSuccess();\r
+ }\r
+\r
+ public enum Result\r
+ {\r
+ SUCCESS, OUT_OF_TIME, ERROR;\r
+ }\r
+}\r
--- /dev/null
+package net.mograsim.logic.model.am2900.am2901;
+
+import static net.mograsim.logic.model.am2900.TestUtil.*;
+import static net.mograsim.logic.model.am2900.am2901.TestableAm2901.Am2901_Dest.*;
+import static net.mograsim.logic.model.am2900.am2901.TestableAm2901.Am2901_Func.*;
+import static net.mograsim.logic.model.am2900.am2901.TestableAm2901.Am2901_Src.*;
+import static net.mograsim.logic.model.am2900.am2901.TestableAm2901.Register.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.awt.Point;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+import net.mograsim.logic.model.am2900.am2901.TestableAm2901.Register;
+
+@DisplayName("Am2901 Tests")
+@TestMethodOrder(OrderAnnotation.class)
+public class Am2901Test
+{
+ private TestableAm2901 am2901;
+
+ @BeforeEach
+ void initialize()
+ {
+ createAndSetup();
+ setInputsToZero();
+ }
+
+ void createAndSetup()
+ {
+ am2901 = new TestableAm2901Impl();
+ am2901.setup();
+ }
+
+ void setRegistersToZero()
+ {
+ setInputsToZero();
+ for (Register r : Register.values())
+ {
+ setRegisterToZero(r);
+ }
+ }
+
+ void setRegisterToZero(Register r)
+ {
+ am2901.setD("0000");
+ am2901.setSrc(DZ);
+ am2901.setFunc(AND);
+ setRegOutput(r);
+
+ am2901.assertFullCycleSuccess();
+ }
+
+ void setRegOutput(Register r)
+ {
+ if (r == Q)
+ {
+ am2901.setDest(QREG);
+ } else
+ {
+ am2901.setReg_B(r.toBitString());
+ am2901.setDest(RAMF);
+ }
+ }
+
+ void setInputsToZero()
+ {
+ am2901.setCarryIn("0");
+ am2901.setQ_0("0");
+ am2901.setQ_3("0");
+ am2901.setRAM_0("0");
+ am2901.setRAM_3("0");
+ am2901.setReg_A("0000");
+ am2901.setReg_B("0000");
+ am2901.setD("0000");
+ am2901.setSrc(AB);
+ am2901.setFunc(ADD);
+ am2901.setDest(QREG);
+// am2901.setNotOutEnable("0"); TODO
+ am2901.clockOn(true);
+ am2901.assertRunSuccess();
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @Order(1)
+ @DisplayName("Direct / high level access")
+ @EnumSource(Register.class)
+ void testDirectAccess(Register r)
+ {
+ assertEquals("UUUU", am2901.getDirectly(r));
+
+ am2901.setDirectly(r, "1011");
+
+ assertEquals("1011", am2901.getDirectly(r));
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @Order(2)
+ @DisplayName("Setting each register to 0")
+ @EnumSource(Register.class)
+ void testSetToZero(Register r)
+ {
+ assertEquals("UUUU", am2901.getDirectly(r));
+
+ setRegisterToZero(r);
+
+ assertEquals("0000", am2901.getDirectly(r));
+ assertEquals("0000", am2901.getY());
+ assertEquals("0", am2901.getCarryOut());
+ assertEquals("0", am2901.getOverflow());
+ assertEquals("0", am2901.getSign());
+ assertEquals("1", am2901.getZero());
+ }
+
+ @Test
+ @Order(3)
+ @DisplayName("Setting all registers to 0")
+ void testSetAllToZero()
+ {
+ setRegistersToZero();
+
+ assertEquals("0000", am2901.getY());
+ assertEquals("0", am2901.getCarryOut());
+ assertEquals("0", am2901.getOverflow());
+ assertEquals("0", am2901.getSign());
+ assertEquals("1", am2901.getZero());
+ assertEquals("0", am2901.getQ_0());
+ assertEquals("0", am2901.getQ_3());
+ assertEquals("0", am2901.getRAM_0());
+ assertEquals("0", am2901.getRAM_3());
+
+ assertAll("register values", Register.stream().map(r -> () ->
+ {
+ assertEquals("0000", am2901.getDirectly(r), r.name());
+ }));
+ }
+
+ @Test
+ @Order(4)
+ @DisplayName("ADD operation")
+ void testADD()
+ {
+ am2901.setSrc(DA);
+ am2901.setFunc(ADD);
+ am2901.setDest(NOP);
+ am2901.setReg_A(r0.toBitString());
+
+ assertAll(getAll4BitPairs().map(xy -> () ->
+ {
+ am2901.setDirectly(r0, to4bitBin(xy.x));
+ am2901.setD(to4bitBin(xy.y));
+
+ am2901.assertFullCycleSuccess();
+
+ int res32Bit = xy.x + xy.y;
+ int res4Bit = res32Bit & 0b1111;
+ int res32Bit_sgn = signed4ToSigned32(xy.x) + signed4ToSigned32(xy.y);
+ int res4Bit_sgn = signed4ToSigned32(res32Bit_sgn);
+
+ assertAll("Result of " + xy.x + " + " + xy.y + " = " + res32Bit,
+ () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
+ () -> assertEquals(to1bitBin(res4Bit == 0), am2901.getZero(), " F=0"),
+ () -> assertEquals(to1bitBin(res4Bit & 0b1000), am2901.getSign(), " F3"),
+ () -> assertEquals(to1bitBin(res32Bit > 15), am2901.getCarryOut(), " Cn+4"),
+ () -> assertEquals(to1bitBin(res4Bit_sgn != res32Bit_sgn), am2901.getOverflow(), " OVR"));
+ }));
+ }
+
+ @Test
+ @Order(4)
+ @DisplayName("AND operation")
+ void testAND()
+ {
+ am2901.setSrc(DA);
+ am2901.setFunc(AND);
+ am2901.setDest(NOP);
+ am2901.setReg_A(r0.toBitString());
+
+ assertAll(getAll4BitPairs().map(xy -> () ->
+ {
+ am2901.setDirectly(r0, to4bitBin(xy.x));
+ am2901.setD(to4bitBin(xy.y));
+
+ am2901.assertFullCycleSuccess();
+
+ int res32Bit = xy.x & xy.y;
+
+ assertAll("Result of " + xy.x + " & " + xy.y + " = " + res32Bit,
+ () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
+ () -> assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), " F=0"),
+ () -> assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), " F3")
+// () -> assertEquals(to1bitBin(res32Bit), am2901.getCarryOut(), " Cn+4"), // TODO
+// () -> assertEquals(to1bitBin(res32Bit), am2901.getOverflow(), " OVR") // TODO
+ );
+ }));
+ }
+
+ @Test
+ @Order(4)
+ @DisplayName("OR operation")
+ void testOR()
+ {
+ am2901.setSrc(DA);
+ am2901.setFunc(OR);
+ am2901.setDest(NOP);
+ am2901.setReg_A(r0.toBitString());
+
+ assertAll(getAll4BitPairs().map(xy -> () ->
+ {
+ am2901.setDirectly(r0, to4bitBin(xy.x));
+ am2901.setD(to4bitBin(xy.y));
+
+ am2901.assertFullCycleSuccess();
+
+ int res32Bit = xy.x | xy.y;
+
+ assertAll("Result of " + xy.x + " | " + xy.y + " = " + res32Bit,
+ () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
+ () -> assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), " F=0"),
+ () -> assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), " F3")
+// () -> assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getCarryOut(), " Cn+4"), // TODO
+// () -> assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getOverflow(), " OVR") // TODO
+ );
+ }));
+ }
+
+ @Test
+ @Order(4)
+ @DisplayName("XOR operation")
+ void testXOR()
+ {
+ am2901.setSrc(DA);
+ am2901.setFunc(EXOR);
+ am2901.setDest(NOP);
+ am2901.setReg_A(r0.toBitString());
+
+ assertAll(getAll4BitPairs().map(xy -> () ->
+ {
+ am2901.setDirectly(r0, to4bitBin(xy.x));
+ am2901.setD(to4bitBin(xy.y));
+
+ am2901.assertFullCycleSuccess();
+
+ int res32Bit = xy.x ^ xy.y;
+
+ assertAll("Result of " + xy.x + " ^ " + xy.y + " = " + res32Bit,
+ () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
+ () -> assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), " F=0"),
+ () -> assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), " F3"));
+ }));
+ }
+
+ @Test
+ @Order(4)
+ @DisplayName("SUB operation")
+ void testSUB()
+ {
+ am2901.setSrc(DA);
+ am2901.setCarryIn("1");
+ am2901.setFunc(SUBR);
+ am2901.setDest(NOP);
+ am2901.setReg_A(r0.toBitString());
+
+ assertAll(getAll4BitPairs().map(xy -> () ->
+ {
+ am2901.setDirectly(r0, to4bitBin(xy.x));
+ am2901.setD(to4bitBin(xy.y));
+
+ am2901.assertFullCycleSuccess();
+
+ int res32Bit = xy.x - xy.y;
+ int res4Bit = res32Bit & 0b1111;
+ int res32Bit_sgn = signed4ToSigned32(xy.x) - signed4ToSigned32(xy.y);
+ int res4Bit_sgn = signed4ToSigned32(res32Bit_sgn);
+
+ assertAll("Result of " + xy.x + " - " + xy.y + " = " + res32Bit,
+ () -> assertEquals(to4bitBin(res32Bit), am2901.getY(), " Y"),
+ () -> assertEquals(to1bitBin(res4Bit == 0), am2901.getZero(), " F=0"),
+ () -> assertEquals(to1bitBin(res4Bit & 0b1000), am2901.getSign(), " F3"),
+ () -> assertEquals(to1bitBin(xy.x >= xy.y), am2901.getCarryOut(), " Cn+4"),
+ () -> assertEquals(to1bitBin(res4Bit_sgn != res32Bit_sgn), am2901.getOverflow(), " OVR"));
+ }));
+ }
+
+ static Stream<Point> getAll4BitPairs()
+ {
+ return IntStream.range(0, 16).boxed().flatMap(x -> IntStream.range(0, 16).mapToObj(y -> new Point(x, y)));
+ }
+}
--- /dev/null
+package net.mograsim.logic.model.am2900.am2901;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import net.mograsim.logic.model.SimpleLogicUIStandalone;
+import net.mograsim.logic.model.model.ViewModelModifiable;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.atomic.GUIAndGate;
+import net.mograsim.logic.model.model.components.atomic.GUIBitDisplay;
+import net.mograsim.logic.model.model.components.atomic.GUIManualSwitch;
+import net.mograsim.logic.model.model.components.atomic.GUINotGate;
+import net.mograsim.logic.model.model.components.atomic.TextComponent;
+import net.mograsim.logic.model.model.wires.Pin;
+import net.mograsim.logic.model.model.wires.WireCrossPoint;
+import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
+import net.mograsim.logic.model.util.ModellingTool;
+
+public class Am2901Testbench
+{
+ public static void main(String[] args)
+ {
+ SimpleLogicUIStandalone.executeVisualisation(Am2901Testbench::createTestbench);
+ }
+
+ public static void createTestbench(ViewModelModifiable model)
+ {
+ GUIComponent comp = IndirectGUIComponentCreator.createComponent(model, "GUIAm2901");
+ ModellingTool tool = ModellingTool.createFor(model);
+
+ comp.moveTo(240, 0);
+
+ GUIManualSwitch enable = new GUIManualSwitch(model, 1);
+ WireCrossPoint wcp0 = new WireCrossPoint(model, 1);
+ GUINotGate not1 = new GUINotGate(model, 1);
+ GUINotGate not2 = new GUINotGate(model, 1);
+ GUINotGate not3 = new GUINotGate(model, 1);
+ GUIAndGate and = new GUIAndGate(model, 1);
+ tool.connect(wcp0, enable, "");
+ tool.connect(wcp0, and, "A");
+ tool.connect(wcp0, not1, "A");
+ tool.connect(not1, not2, "Y", "A");
+ tool.connect(not2, not3, "Y", "A");
+ tool.connect(not3, and, "Y", "B");
+ enable.moveTo(20, -32.5);
+ wcp0.moveTo(35, -26);
+ not1.moveTo(50, -20);
+ not2.moveTo(80, -20);
+ not3.moveTo(110, -20);
+ and.moveTo(135, -30);
+ Pin last = and.getPin("Y");
+
+ // guess which pins are outputs and which are inputs
+ // TODO this code exists four times... but it seems too "hacky" to put it in a helper class
+ List<String> inputPinNames = new ArrayList<>();
+ List<String> outputPinNames = new ArrayList<>();
+ for (Pin p : comp.getPins().values())
+ if (p.getRelX() == 0)
+ inputPinNames.add(p.name);
+ else
+ outputPinNames.add(p.name);
+
+ inputPinNames.sort(Comparator.comparing(comp::getPin, Comparator.comparing(Pin::getRelY)));
+ outputPinNames.sort(Comparator.comparing(comp::getPin, Comparator.comparing(Pin::getRelY)));
+
+ for (int i = 0; i < inputPinNames.size(); i++)
+ {
+ double x = 55 + 70 * (i % 2);
+ double y = 10 * i;
+
+ WireCrossPoint wcp = new WireCrossPoint(model, 1);
+ GUIComponent d_ff = IndirectGUIComponentCreator.createComponent(model, "GUIdff");
+ GUIManualSwitch sw = new GUIManualSwitch(model, 1);
+
+ tool.connect(last, wcp);
+ tool.connect(wcp, d_ff, "C");
+ tool.connect(sw, d_ff, "", "D");
+ tool.connect(d_ff, comp, "Q", inputPinNames.get(i));
+ last = wcp.getPin();
+
+ TextComponent label = new TextComponent(model, inputPinNames.get(i));
+
+ sw.moveTo(x, y + 7.5);
+ wcp.moveTo(160, y);
+ d_ff.moveTo(170, y);
+ label.moveTo(x - 48, y + 8);
+ }
+
+ for (int i = 0; i < outputPinNames.size(); i++)
+ {
+ double x = 300 + 75 * (i % 2);
+ double y = 10 * i - 2.5;
+ GUIBitDisplay bd = new GUIBitDisplay(model, 1);
+ bd.moveTo(x, y);
+ tool.connect(bd.getInputPin(), comp, outputPinNames.get(i));
+
+ TextComponent label = new TextComponent(model, outputPinNames.get(i));
+ label.moveTo(x + 25, y);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.logic.model.am2900.am2901;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import net.mograsim.logic.model.am2900.TestUtil;
+import net.mograsim.logic.model.am2900.TestableCircuit;
+
+public interface TestableAm2901 extends TestableCircuit
+{
+
+ void setDest(Am2901_Dest dest);
+
+ void setFunc(Am2901_Func func);
+
+ void setSrc(Am2901_Src src);
+
+ void setReg_A(String val_4_bit);
+
+ void setReg_B(String val_4_bit);
+
+ void setCarryIn(String val_1_bit);
+
+ void setNotOutEnable(String val_1_bit);
+
+ void setD(String val_4_bit);
+
+ void setQ_0(String val_1_bit);
+
+ void setQ_3(String val_1_bit);
+
+ void setRAM_0(String val_1_bit);
+
+ void setRAM_3(String val_1_bit);
+
+ void setDirectly(Register r, String val_4_bit);
+
+ String getQ_0();
+
+ String getQ_3();
+
+ String getRAM_0();
+
+ String getRAM_3();
+
+ String getNotP();
+
+ String getNotG();
+
+ String getCarryOut();
+
+ String getSign();
+
+ String getZero();
+
+ String getOverflow();
+
+ String getY();
+
+ String getDirectly(Register r);
+
+ public enum Am2901_Dest
+ {
+ QREG, NOP, RAMA, RAMF, RAMQD, RAMD, RAMQU, RAMU;
+
+ public boolean doesShift()
+ {
+ return ordinal() >= 4;
+ }
+
+ public int getShiftDir()
+ {
+ return doesShift() ? (ordinal() < 6 ? -1 : 1) : 0;
+ }
+
+ public int getI7()
+ {
+ return this.ordinal() >> 1 & 1;
+ }
+ }
+
+ public enum Am2901_Func
+ {
+ ADD, SUBR, SUBS, OR, AND, NOTRS, EXOR, EXNOR;
+ }
+
+ public enum Am2901_Src
+ {
+ AQ, AB, ZQ, ZB, ZA, DA, DQ, DZ;
+ }
+
+ public enum Register
+ {
+ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, rA, rB, rC, rD, rE, rF, Q;
+
+ public String toBitString()
+ {
+ if (this.ordinal() > 0xF)
+ throw new UnsupportedOperationException();
+ return TestUtil.to4bitBin(this.ordinal());
+ }
+
+ public static Stream<Register> stream()
+ {
+ return Arrays.stream(values());
+ }
+ }
+}
--- /dev/null
+package net.mograsim.logic.model.am2900.am2901;
+
+import net.mograsim.logic.core.components.BitDisplay;
+import net.mograsim.logic.core.components.ManualSwitch;
+import net.mograsim.logic.core.timeline.Timeline;
+import net.mograsim.logic.core.types.Bit;
+import net.mograsim.logic.core.types.BitVector;
+import net.mograsim.logic.model.am2900.TestEnvironmentHelper;
+import net.mograsim.logic.model.am2900.TestEnvironmentHelper.DebugState;
+import net.mograsim.logic.model.am2900.TestUtil;
+import net.mograsim.logic.model.model.components.GUIComponent;
+
+public class TestableAm2901Impl implements TestableAm2901
+{
+ private GUIComponent am2901;
+ private Timeline timeline;
+ private ManualSwitch I8, I7, I6, I5, I4, I3, I2, I1, I0;
+ private ManualSwitch C;
+ private ManualSwitch Cn;
+ private ManualSwitch D1, D2, D3, D4;
+ private ManualSwitch A0, A1, A2, A3;
+ private ManualSwitch B0, B1, B2, B3;
+ private ManualSwitch IRAMn, IRAMn_3, IQn, IQn_3;
+ private BitDisplay Y1, Y2, Y3, Y4;
+ private BitDisplay F_0, Cn_4, OVR, F3;
+ private BitDisplay ORAMn, ORAMn_3, OQn, OQn_3;
+
+ private final TestEnvironmentHelper testHelper = new TestEnvironmentHelper(this, "GUIAm2901");
+
+ @Override
+ public Result run()
+ {
+ return testHelper.run();
+ }
+
+ @Override
+ public void setup()
+ {
+ testHelper.setup(DebugState.NO_DEBUG);
+ }
+
+ @Override
+ public void setDest(Am2901_Dest dest)
+ {
+ var bits = TestUtil.of(dest.ordinal(), 3);
+ I8.setState(bits.getLSBit(2));
+ I7.setState(bits.getLSBit(1));
+ I6.setState(bits.getLSBit(0));
+ }
+
+ @Override
+ public void setFunc(Am2901_Func func)
+ {
+ var bits = TestUtil.of(func.ordinal(), 3);
+ I5.setState(bits.getLSBit(2));
+ I4.setState(bits.getLSBit(1));
+ I3.setState(bits.getLSBit(0));
+ }
+
+ @Override
+ public void setSrc(Am2901_Src src)
+ {
+ var bits = TestUtil.of(src.ordinal(), 3);
+ I2.setState(bits.getLSBit(2));
+ I1.setState(bits.getLSBit(1));
+ I0.setState(bits.getLSBit(0));
+ }
+
+ @Override
+ public void setReg_A(String val_4_bit)
+ {
+ var bits = BitVector.parse(val_4_bit);
+ A3.setState(bits.getLSBit(3));
+ A2.setState(bits.getLSBit(2));
+ A1.setState(bits.getLSBit(1));
+ A0.setState(bits.getLSBit(0));
+ }
+
+ @Override
+ public void setReg_B(String val_4_bit)
+ {
+ var bits = BitVector.parse(val_4_bit);
+ B3.setState(bits.getLSBit(3));
+ B2.setState(bits.getLSBit(2));
+ B1.setState(bits.getLSBit(1));
+ B0.setState(bits.getLSBit(0));
+ }
+
+ @Override
+ public void setCarryIn(String val_1_bit)
+ {
+ Cn.setState(Bit.parse(val_1_bit));
+ }
+
+ @Override
+ public void setNotOutEnable(String val_1_bit)
+ {
+ throw new UnsupportedOperationException(); // TODO
+ }
+
+ @Override
+ public void setD(String val_4_bit)
+ {
+ var bits = BitVector.parse(val_4_bit);
+ D4.setState(bits.getLSBit(3));
+ D3.setState(bits.getLSBit(2));
+ D2.setState(bits.getLSBit(1));
+ D1.setState(bits.getLSBit(0));
+ }
+
+ @Override
+ public void setQ_0(String val_1_bit)
+ {
+ IQn.setState(Bit.parse(val_1_bit));
+ }
+
+ @Override
+ public void setQ_3(String val_1_bit)
+ {
+ IQn_3.setState(Bit.parse(val_1_bit));
+ }
+
+ @Override
+ public void setRAM_0(String val_1_bit)
+ {
+ IRAMn.setState(Bit.parse(val_1_bit));
+ }
+
+ @Override
+ public void setRAM_3(String val_1_bit)
+ {
+ IRAMn_3.setState(Bit.parse(val_1_bit));
+ }
+
+ @Override
+ public void clockOn(boolean isClockOn)
+ {
+ C.setState(isClockOn ? Bit.ONE : Bit.ZERO);
+ }
+
+ @Override
+ public String getQ_0()
+ {
+ return OQn.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getQ_3()
+ {
+ return OQn_3.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getRAM_0()
+ {
+ return ORAMn.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getRAM_3()
+ {
+ return ORAMn_3.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getNotP()
+ {
+ throw new UnsupportedOperationException(); // TODO
+ }
+
+ @Override
+ public String getNotG()
+ {
+ throw new UnsupportedOperationException(); // TODO
+ }
+
+ @Override
+ public String getCarryOut()
+ {
+ return Cn_4.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getSign()
+ {
+ return F3.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getZero()
+ {
+ return F_0.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getOverflow()
+ {
+ return OVR.getDisplayedValue().toString();
+ }
+
+ @Override
+ public String getY()
+ {
+ var y3 = Y4.getDisplayedValue();
+ var y2 = Y3.getDisplayedValue();
+ var y1 = Y2.getDisplayedValue();
+ var y0 = Y1.getDisplayedValue();
+ return y3.concat(y2).concat(y1).concat(y0).toString();
+ }
+
+ @Override
+ public void setDirectly(Register r, String val_4_bit)
+ {
+ am2901.setHighLevelState(regToStateID(r), BitVector.parse(val_4_bit));
+ }
+
+ @Override
+ public String getDirectly(Register r)
+ {
+ return ((BitVector) am2901.getHighLevelState(regToStateID(r))).toString();
+ }
+
+ private static String regToStateID(Register r)
+ {
+ if (r == Register.Q)
+ return "qreg.q";
+ return "regs.c" + r.toBitString() + ".q";
+ }
+}