Fixed and added a lot of tests
authorChristian Femers <femers@in.tum.de>
Sat, 29 Jun 2019 01:30:32 +0000 (03:30 +0200)
committerChristian Femers <femers@in.tum.de>
Sat, 29 Jun 2019 01:30:32 +0000 (03:30 +0200)
net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Test.java
net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Testbench.java [new file with mode: 0644]
net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestUtil.java
net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901.java
net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java

index 18d60c3..55f2b85 100644 (file)
@@ -1,15 +1,26 @@
 package net.mograsim.logic.ui.am2900;
 
+import static net.mograsim.logic.ui.am2900.TestUtil.*;
 import static net.mograsim.logic.ui.am2900.TestableAm2901.Am2901_Dest.*;
 import static net.mograsim.logic.ui.am2900.TestableAm2901.Am2901_Func.*;
 import static net.mograsim.logic.ui.am2900.TestableAm2901.Am2901_Src.*;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static net.mograsim.logic.ui.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.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.ArgumentsSource;
+import net.mograsim.logic.ui.am2900.TestableAm2901.Register;
 
-import net.mograsim.logic.ui.am2900.TestableAm2901.Result;
-
+@TestMethodOrder(OrderAnnotation.class)
 public class Am2901Test
 {
        private TestableAm2901 am2901;
@@ -18,21 +29,7 @@ public class Am2901Test
        void initialize()
        {
                createAndSetup();
-               setRegistersToZero();
-       }
-
-       @Test
-       void testInit()
-       {
-               assertEquals("0", am2901.getCarryOut());
-               assertEquals("0", am2901.getOverflow());
-               assertEquals("0", am2901.getSign());
-               assertEquals("1", am2901.getZero());
-               assertEquals("0000", am2901.getY());
-               assertEquals("0", am2901.getQ_0());
-               assertEquals("0", am2901.getQ_3());
-               assertEquals("0", am2901.getRAM_0());
-               assertEquals("0", am2901.getRAM_3());
+               setInputsToZero();
        }
 
        void createAndSetup()
@@ -44,19 +41,27 @@ public class Am2901Test
        void setRegistersToZero()
        {
                setInputsToZero();
-               for (Regsiter r : Regsiter.values())
+               for (Register r : Register.values())
                {
                        setRegisterToZero(r);
                }
        }
 
-       void setRegisterToZero(Regsiter r)
+       void setRegisterToZero(Register r)
        {
                System.out.println("Setting reg " + r + " to zero");
+
                am2901.setD("0000");
                am2901.setSrc(DZ);
                am2901.setFunc(AND);
-               if (r == Regsiter.Q)
+               setRegOutput(r);
+
+               am2901.assertFullCycleSuccess();
+       }
+
+       void setRegOutput(Register r)
+       {
+               if (r == Q)
                {
                        am2901.setDest(QREG);
                } else
@@ -64,11 +69,6 @@ public class Am2901Test
                        am2901.setReg_B(r.toBitString());
                        am2901.setDest(RAMF);
                }
-               assertRunSuccess();
-               am2901.toogleClock();
-               assertRunSuccess();
-               am2901.toogleClock();
-               assertRunSuccess();
        }
 
        void setInputsToZero()
@@ -85,23 +85,210 @@ public class Am2901Test
                am2901.setFunc(ADD);
                am2901.setDest(QREG);
 //             am2901.setNotOutEnable("0"); TODO
-               assertRunSuccess();
+               am2901.clockOn(true);
+               am2901.assertRunSuccess();
        }
 
-       void assertRunSuccess()
+       @Order(1)
+       @ParameterizedTest
+       @ArgumentsSource(TestableAm2901.RegisterProvider.class)
+       void testDirectAccess(Register r)
        {
-               assertEquals(Result.SUCCESS, am2901.run());
+               assertEquals("UUUU", am2901.getDirectly(r));
+
+               am2901.setDirectly(r, "1011");
+
+               assertEquals("1011", am2901.getDirectly(r));
        }
 
-       public enum Regsiter
+       @Order(2)
+       @ParameterizedTest
+       @ArgumentsSource(TestableAm2901.RegisterProvider.class)
+       void testSetToZero(Register r)
        {
-               r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, rA, rB, rC, rD, rE, rF, Q;
+               assertEquals("UUUU", am2901.getDirectly(r));
+
+               setRegisterToZero(r);
 
-               public String toBitString()
+               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());
+       }
+
+       @Order(3)
+       @Test
+       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 -> () ->
                {
-                       if (this.ordinal() > 0xF)
-                               throw new UnsupportedOperationException();
-                       return TestUtil.to4bitBin(this.ordinal());
-               }
+                       assertEquals("0000", am2901.getDirectly(r), r.name());
+               }));
+       }
+
+       @Order(4)
+       @Test
+       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);
+
+                       String desc = xy.x + " + " + xy.y + " = " + res4Bit + ": ";
+
+                       assertEquals(to4bitBin(res4Bit & 0b1111), am2901.getY(), desc + "Y");
+                       assertEquals(to1bitBin(res4Bit == 0), am2901.getZero(), desc + "F=0");
+                       assertEquals(to1bitBin(res4Bit & 0b1000), am2901.getSign(), desc + "F3");
+                       assertEquals(to1bitBin(res32Bit & 0b1_0000), am2901.getCarryOut(), desc + "Cn+4");
+                       assertEquals(to1bitBin(res4Bit_sgn != res32Bit_sgn), am2901.getOverflow(), desc + "OVR");
+               }));
+       }
+
+       @Order(4)
+       @Test
+       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;
+
+                       String desc = xy.x + " & " + xy.y + " = " + res32Bit + ": ";
+
+                       assertEquals(to4bitBin(res32Bit), am2901.getY(), desc + "Y");
+                       assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), desc + "F=0");
+                       assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), desc + "F3");
+//                     assertEquals(to1bitBin(res32Bit), am2901.getCarryOut(), desc + "Cn+4"); // TODO
+//                     assertEquals(to1bitBin(res32Bit), am2901.getOverflow(), desc + "OVR"); // TODO
+               }));
+       }
+
+       @Order(4)
+       @Test
+       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;
+
+                       String desc = xy.x + " | " + xy.y + " = " + res32Bit + ": ";
+
+                       assertEquals(to4bitBin(res32Bit), am2901.getY(), desc + "Y");
+                       assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), desc + "F=0");
+                       assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), desc + "F3");
+//                     assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getCarryOut(), desc + "Cn+4"); // TODO
+//                     assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getOverflow(), desc + "OVR"); // TODO
+               }));
+       }
+
+       @Order(4)
+       @Test
+       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;
+
+                       String desc = xy.x + " ^ " + xy.y + " = " + res32Bit + ": ";
+
+                       assertEquals(to4bitBin(res32Bit), am2901.getY(), desc + "Y");
+                       assertEquals(to1bitBin(res32Bit == 0), am2901.getZero(), desc + "F=0");
+                       assertEquals(to1bitBin(res32Bit & 0b1000), am2901.getSign(), desc + "F3");
+//                     assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getCarryOut(), desc + "Cn+4"); // TODO
+//                     assertEquals(to1bitBin(res32Bit != 0b1111), am2901.getOverflow(), desc + "OVR"); // TODO
+               }));
+       }
+
+       @Order(4)
+       @Test
+       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);
+
+                       String desc = xy.x + " - " + xy.y + " = " + res4Bit + ": ";
+
+                       assertEquals(to4bitBin(res4Bit & 0b1111), am2901.getY(), desc + "Y");
+                       assertEquals(to1bitBin(res4Bit == 0), am2901.getZero(), desc + "F=0");
+                       assertEquals(to1bitBin(res4Bit & 0b1000), am2901.getSign(), desc + "F3");
+                       assertEquals(to1bitBin(xy.x >= xy.y), am2901.getCarryOut(), desc + "Cn+4");
+                       assertEquals(to1bitBin(res4Bit_sgn != res32Bit_sgn), am2901.getOverflow(), desc + "OVR");
+               }));
+       }
+
+       static Stream<Point> getAll4BitPairs()
+       {
+               return IntStream.range(0, 16).boxed().flatMap(x -> IntStream.range(0, 16).mapToObj(y -> new Point(x, y)));
        }
 }
diff --git a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Testbench.java b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Testbench.java
new file mode 100644 (file)
index 0000000..3b2515e
--- /dev/null
@@ -0,0 +1,86 @@
+package net.mograsim.logic.ui.am2900;
+
+import net.mograsim.logic.ui.SimpleLogicUIStandalone;
+import net.mograsim.logic.ui.model.ViewModelModifiable;
+import net.mograsim.logic.ui.model.components.GUIAndGate;
+import net.mograsim.logic.ui.model.components.GUIBitDisplay;
+import net.mograsim.logic.ui.model.components.GUIManualSwitch;
+import net.mograsim.logic.ui.model.components.GUINotGate;
+import net.mograsim.logic.ui.model.components.SimpleRectangularSubmodelComponent;
+import net.mograsim.logic.ui.model.components.TextComponent;
+import net.mograsim.logic.ui.model.components.mi.nandbased.GUIdff;
+import net.mograsim.logic.ui.model.components.mi.nandbased.am2901.GUIAm2901;
+import net.mograsim.logic.ui.model.wires.ConnectionPoint;
+import net.mograsim.logic.ui.model.wires.WireCrossPoint;
+import net.mograsim.logic.ui.util.ModellingTool;
+
+public class Am2901Testbench
+{
+       public static void main(String[] args)
+       {
+               SimpleLogicUIStandalone.executeVisualisation(Am2901Testbench::createTestbench);
+       }
+
+       public static void createTestbench(ViewModelModifiable model)
+       {
+               SimpleRectangularSubmodelComponent comp = new GUIAm2901(model);
+               ModellingTool tool = ModellingTool.createFor(model);
+
+               comp.moveTo(240, 0);
+
+               GUIManualSwitch enable = new GUIManualSwitch(model);
+               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);
+               ConnectionPoint last = and.getPin("Y");
+
+               for (int i = 0; i < comp.getInputPinNames().size(); i++)
+               {
+                       double x = 55 + 70 * (i % 2);
+                       double y = 10 * i;
+
+                       WireCrossPoint wcp = new WireCrossPoint(model, 1);
+                       GUIdff d_ff = new GUIdff(model);
+                       GUIManualSwitch sw = new GUIManualSwitch(model);
+
+                       tool.connect(last, wcp);
+                       tool.connect(wcp, d_ff, "C");
+                       tool.connect(sw, d_ff, "", "D");
+                       tool.connect(d_ff, comp, "Q", comp.getInputPinNames().get(i));
+                       last = wcp.getPin();
+
+                       TextComponent label = new TextComponent(model, comp.getInputPinNames().get(i));
+
+                       sw.moveTo(x, y + 7.5);
+                       wcp.moveTo(160, y);
+                       d_ff.moveTo(170, y);
+                       label.moveTo(x - 25, y + 15);
+               }
+
+               for (int i = 0; i < comp.getOutputPinNames().size(); i++)
+               {
+                       double x = 300 + 75 * (i % 2);
+                       double y = 10 * i - 2.5;
+                       GUIBitDisplay bd = new GUIBitDisplay(model);
+                       bd.moveTo(x, y);
+                       tool.connect(bd.getInputPin(), comp, comp.getOutputPinNames().get(i));
+
+                       TextComponent label = new TextComponent(model, comp.getOutputPinNames().get(i));
+                       label.moveTo(x + 50, y + 8);
+               }
+       }
+}
\ No newline at end of file
index 08c7982..937e566 100644 (file)
@@ -9,6 +9,8 @@ public final class TestUtil
 
        /**
         * Transforms the last four bits of an int to a string that contains the binary ('1' and '0') representation of the 4 bits
+        * 
+        * @author Christian Femers
         */
        public static String to4bitBin(int x)
        {
@@ -19,4 +21,64 @@ public final class TestUtil
                sb.append((x & 0b0001) == 0 ? '0' : '1');
                return sb.toString();
        }
+
+       /**
+        * Transforms the given boolean to a string that contains the binary ('1' and '0') representation of the bit
+        * 
+        * @author Christian Femers
+        */
+       public static String to1bitBin(boolean bitIsSet)
+       {
+               return bitIsSet ? "1" : "0";
+       }
+
+       /**
+        * Transforms the given int to a string that contains the binary ('1' and '0') representation of the int. "0" is only returned when the
+        * int is equal to zero.
+        * 
+        * @author Christian Femers
+        */
+       public static String to1bitBin(int someInt)
+       {
+               return someInt != 0 ? "1" : "0";
+       }
+
+       /**
+        * Transforms a 4 bit signed integer (-8 to 7) to a int representing the same number. (Adding leading 1-bits if the 4 bit int is
+        * negative)
+        * 
+        * @author Christian Femers
+        */
+       public static int signed4ToSigned32(int signed4bit)
+       {
+               if ((signed4bit & 0b1000) > 0)
+                       return signed4bit | 0xFF_FF_FF_F0;
+               return signed4bit & 0x00_00_00_0F;
+       }
+
+       /**
+        * Transforms a 16 bit signed integer (-32768 to 32767 - a short) to a int representing the same number. (Adding leading 1-bits if the
+        * 16 bit int is negative)
+        * 
+        * @author Christian Femers
+        */
+       public static int signed16ToSigned32(int signed16bit)
+       {
+               return (short) signed16bit;
+       }
+
+       /**
+        * Transforms the last n bits of an int to a string that contains the binary ('1' and '0') representation of the n bits
+        * 
+        * @author Christian Femers
+        */
+       public static String toNbitString(int x, int n)
+       {
+               StringBuilder sb = new StringBuilder(n);
+               for (int i = 0; i < n; i++)
+               {
+                       sb.append((x >> i) & 1);
+               }
+               return sb.reverse().toString();
+       }
 }
index cd57c99..fc4a80a 100644 (file)
@@ -1,5 +1,14 @@
 package net.mograsim.logic.ui.am2900;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.ArgumentsProvider;
+
 public interface TestableAm2901
 {
        void setup();
@@ -30,7 +39,9 @@ public interface TestableAm2901
 
        void setRAM_3(String val_1_bit);
 
-       void toogleClock();
+       void clockOn(boolean isClockOn);
+
+       void setDirectly(Register r, String val_4_bit);
 
        String getQ_0();
 
@@ -54,6 +65,22 @@ public interface TestableAm2901
 
        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;
@@ -88,4 +115,32 @@ public interface TestableAm2901
        {
                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());
+               }
+       }
+
+       public static class RegisterProvider implements ArgumentsProvider
+       {
+
+               @Override
+               public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception
+               {
+                       return Register.stream().map(Arguments::of);
+               }
+
+       }
 }
index a6eb791..0f0e25f 100644 (file)
@@ -114,6 +114,7 @@ public class TestableAm2901Impl implements TestableAm2901
                for (String id : am2901.getOutputPinNames())
                {
                        GUIBitDisplay bd = new GUIBitDisplay(viewModel);
+//                     bd.addRedrawListener(() -> System.out.println(id + " " + bd.getBitDisplay().getDisplayedValue()));
                        new GUIWire(viewModel, am2901.getPin(id), bd.getInputPin());
                        idDisplayMap.put(id, bd);
                }
@@ -127,8 +128,6 @@ public class TestableAm2901Impl implements TestableAm2901
                        setField(entry.getKey().replaceAll("\\+|=", "_"), entry.getValue().getManualSwitch());
                for (var entry : idDisplayMap.entrySet())
                        setField(entry.getKey().replaceAll("\\+|=", "_"), entry.getValue().getBitDisplay());
-               // Switch Clock off first
-               C.switchOff();
 
                // Debug code
                HashSet<GUIWire> wiresIncludingSubmodels = new HashSet<>();
@@ -146,7 +145,6 @@ public class TestableAm2901Impl implements TestableAm2901
                {
                        if (debugWires)
                        {
-                               System.out.println(w);
                                wireDebugChangeSet.add(w.toString());
                        }
                }));
@@ -247,9 +245,9 @@ public class TestableAm2901Impl implements TestableAm2901
        }
 
        @Override
-       public void toogleClock()
+       public void clockOn(boolean isClockOn)
        {
-               C.toggle();
+               C.setState(isClockOn);
        }
 
        @Override
@@ -347,4 +345,23 @@ public class TestableAm2901Impl implements TestableAm2901
                }
                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 am2901.getHighLevelState(regToStateID(r)).toString();
+       }
+
+       private static String regToStateID(Register r)
+       {
+               if (r == Register.Q)
+                       return "qreg.q";
+               return "regs.c" + r.toBitString() + ".q";
+       }
 }