From e4a201cb63e74fb7780dae482e2fc953bee58fa5 Mon Sep 17 00:00:00 2001 From: Christian Femers Date: Sat, 29 Jun 2019 03:30:32 +0200 Subject: [PATCH] Fixed and added a lot of tests --- .../mograsim/logic/ui/am2900/Am2901Test.java | 259 +++++++++++++++--- .../logic/ui/am2900/Am2901Testbench.java | 86 ++++++ .../mograsim/logic/ui/am2900/TestUtil.java | 62 +++++ .../logic/ui/am2900/TestableAm2901.java | 57 +++- .../logic/ui/am2900/TestableAm2901Impl.java | 27 +- 5 files changed, 449 insertions(+), 42 deletions(-) create mode 100644 net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Testbench.java diff --git a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Test.java b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Test.java index 18d60c3b..55f2b85b 100644 --- a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Test.java +++ b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Test.java @@ -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 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 index 00000000..3b2515ed --- /dev/null +++ b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/Am2901Testbench.java @@ -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 diff --git a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestUtil.java b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestUtil.java index 08c7982e..937e566a 100644 --- a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestUtil.java +++ b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestUtil.java @@ -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(); + } } diff --git a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901.java b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901.java index cd57c997..fc4a80a5 100644 --- a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901.java +++ b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901.java @@ -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 stream() + { + return Arrays.stream(values()); + } + } + + public static class RegisterProvider implements ArgumentsProvider + { + + @Override + public Stream provideArguments(ExtensionContext context) throws Exception + { + return Register.stream().map(Arguments::of); + } + + } } diff --git a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java index a6eb7910..0f0e25f7 100644 --- a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java +++ b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java @@ -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 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"; + } } -- 2.17.1