1 package net.mograsim.logic.model.am2900;
3 import static org.junit.jupiter.api.Assertions.assertEquals;
5 import java.io.IOException;
6 import java.util.concurrent.ThreadLocalRandom;
7 import java.util.concurrent.atomic.AtomicInteger;
8 import java.util.concurrent.atomic.AtomicReference;
9 import java.util.stream.IntStream;
11 import org.junit.jupiter.api.AfterAll;
12 import org.junit.jupiter.api.BeforeAll;
13 import org.junit.jupiter.api.Test;
14 import org.junit.jupiter.api.TestInstance;
15 import org.junit.jupiter.api.TestInstance.Lifecycle;
16 import org.junit.jupiter.params.ParameterizedTest;
17 import org.junit.jupiter.params.provider.MethodSource;
19 import net.mograsim.logic.core.types.BitVector;
20 import net.mograsim.logic.model.LogicUIStandaloneGUI;
21 import net.mograsim.logic.model.am2900.machine.Am2900Machine;
22 import net.mograsim.logic.model.am2900.machine.Am2900MainMemoryDefinition;
23 import net.mograsim.logic.model.am2900.machine.Am2900MicroInstructionDefinition;
24 import net.mograsim.logic.model.am2900.machine.Am2900MicroInstructionMemoryDefinition;
25 import net.mograsim.logic.model.am2900.machine.StrictAm2900MachineDefinition;
26 import net.mograsim.logic.model.am2900.machine.registers.am2901.NumberedRegister;
27 import net.mograsim.logic.model.preferences.DefaultRenderPreferences;
28 import net.mograsim.machine.MainMemory;
29 import net.mograsim.machine.mi.MicroInstruction;
30 import net.mograsim.machine.mi.MicroInstructionDefinition;
31 import net.mograsim.machine.mi.MicroInstructionMemory;
32 import net.mograsim.machine.mi.MicroInstructionMemoryParser;
33 import net.mograsim.machine.mi.StandardMicroInstructionMemory;
34 import net.mograsim.machine.mi.parameters.MicroInstructionParameter;
35 import net.mograsim.machine.mi.parameters.ParameterClassification;
36 import net.mograsim.machine.standard.memory.WordAddressableMemory;
38 @TestInstance(Lifecycle.PER_CLASS)
41 private static final boolean startGUI = false;
43 private Am2900Machine mach;
44 private MicroInstructionMemory mpm;
45 private MainMemory ram;
46 private AtomicInteger machState;
47 private AtomicInteger halfCycleCount;
48 private AtomicReference<MicroInstructionMemory> mpmToSetNextCycle;
51 public void setupMachine() throws IOException
54 mach = new StrictAm2900MachineDefinition().createNew();
55 mpm = MicroInstructionMemoryParser.parseMemory(Am2900MicroInstructionMemoryDefinition.instance,
56 TestGCD.class.getResourceAsStream("gcd.mpm"));
57 ram = new WordAddressableMemory(Am2900MainMemoryDefinition.instance);
58 mach.getMainMemory().bind(ram);
63 machState = new AtomicInteger(2);
64 halfCycleCount = new AtomicInteger();
65 // needed for avoiding hazard loops in the first muIR
66 mpmToSetNextCycle = new AtomicReference<>();
67 mach.getClock().registerObserver(c ->
69 halfCycleCount.addAndGet(1);
70 synchronized (machState)
72 long muPC = mach.getActiveMicroInstructionAddress();
77 } else if (muPC == 0x12)
82 if (!mach.getClock().isOn())
84 MicroInstructionMemory mpmToSet = mpmToSetNextCycle.getAndSet(null);
86 mach.getMicroInstructionMemory().bind(mpmToSet);
93 Thread execT = new Thread(mach.getTimeline()::executeAll, "Logic executer");
94 execT.setDaemon(true);
97 System.out.println("Machine initialized");
101 private void startGUI()
103 new Thread(() -> new LogicUIStandaloneGUI(mach.getModel(), new DefaultRenderPreferences()).run(), "GUI thread").start();
107 public void testGCDHardcodedCases() throws InterruptedException
114 checkGCD(48820, 8480);
115 checkGCD(21420, 11288);
116 checkGCD(15862, 21219);
120 @MethodSource("generateRandomInts")
121 public void testGCDRandomCases(int i) throws InterruptedException
128 public static IntStream generateRandomInts()
130 return ThreadLocalRandom.current().ints(10);
133 private void checkGCD(int euclidA, int euclidB) throws InterruptedException
135 int exp = gcd(euclidA, euclidB);
136 System.out.println("Checking gcd(" + euclidA + ", " + euclidB + ") + (expected " + exp + ")");
137 int act = executeGCD(euclidA, euclidB);
138 assertEquals(exp, act);
141 private static int gcd(int a, int b)
145 return gcd(b, a % b);
148 private int executeGCD(int euclidA, int euclidB) throws InterruptedException
150 ram.setCell(0, BitVector.from(euclidA, 16));
151 ram.setCell(1, BitVector.from(euclidB, 16));
155 synchronized (machState)
157 while (machState.get() != 1)
161 BitVector result = mach.getRegister(NumberedRegister.instancesCorrectOrder.get(1));
162 return result.isBinary() ? (int) result.getUnsignedValueLong() : -1;
165 private void resetMachine() throws InterruptedException
167 MicroInstructionDefinition muiDef = Am2900MicroInstructionDefinition.instance;
168 ParameterClassification[] paramClassifications = muiDef.getParameterClassifications();
169 MicroInstructionParameter[] defaultParams = muiDef.createDefaultInstruction().getParameters();
170 defaultParams[19] = paramClassifications[19].parse("JZ");
171 MicroInstruction jzMI = MicroInstruction.create(defaultParams);
173 MicroInstructionMemory jzMPM = new StandardMicroInstructionMemory(Am2900MicroInstructionMemoryDefinition.instance);
174 jzMPM.setCell(0x00, jzMI);
175 jzMPM.setCell(0x13, jzMI);
176 mpmToSetNextCycle.set(jzMPM);
178 synchronized (machState)
180 while (machState.get() != 0)
184 mpmToSetNextCycle.set(mpm);
188 public void printStats()
190 System.out.println("Machine executed " + halfCycleCount.get() + " cycles in total (including JZs)");