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.Am2900ExpertMachineDefinition;
22 import net.mograsim.logic.model.am2900.machine.Am2900Machine;
23 import net.mograsim.logic.model.am2900.machine.Am2900MainMemoryDefinition;
24 import net.mograsim.logic.model.am2900.machine.Am2900MicroInstructionDefinition;
25 import net.mograsim.logic.model.am2900.machine.Am2900MicroInstructionMemoryDefinition;
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.StandardMainMemory;
30 import net.mograsim.machine.mi.MicroInstruction;
31 import net.mograsim.machine.mi.MicroInstructionDefinition;
32 import net.mograsim.machine.mi.MicroInstructionMemory;
33 import net.mograsim.machine.mi.MicroInstructionMemoryParser;
34 import net.mograsim.machine.mi.StandardMicroInstructionMemory;
35 import net.mograsim.machine.mi.parameters.MicroInstructionParameter;
36 import net.mograsim.machine.mi.parameters.ParameterClassification;
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 Am2900ExpertMachineDefinition().createNew();
55 mpm = MicroInstructionMemoryParser.parseMemory(Am2900MicroInstructionMemoryDefinition.instance,
56 TestGCD.class.getResourceAsStream("gcd.mpm"));
57 ram = new StandardMainMemory(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);
117 checkGCD(15525, 57040);
121 @MethodSource("generateRandomInts")
122 public void testGCDRandomCases(int i) throws InterruptedException
129 public static IntStream generateRandomInts()
131 return ThreadLocalRandom.current().ints(10);
134 private void checkGCD(int euclidA, int euclidB) throws InterruptedException
136 int exp = gcd(euclidA, euclidB);
137 System.out.println("Checking gcd(" + euclidA + ", " + euclidB + "); expected " + exp);
138 int act = executeGCD(euclidA, euclidB);
139 assertEquals(exp, act);
142 private static int gcd(int a, int b)
146 return gcd(b, a % b);
149 private int executeGCD(int euclidA, int euclidB) throws InterruptedException
151 ram.setCell(0, BitVector.from(euclidA, 16));
152 ram.setCell(1, BitVector.from(euclidB, 16));
156 synchronized (machState)
158 while (machState.get() != 1)
162 BitVector result = mach.getRegister(NumberedRegister.instancesCorrectOrder.get(1));
163 return result.isBinary() ? (int) result.getUnsignedValueLong() : -1;
166 private void resetMachine() throws InterruptedException
168 MicroInstructionDefinition muiDef = Am2900MicroInstructionDefinition.instance;
169 ParameterClassification[] paramClassifications = muiDef.getParameterClassifications();
170 MicroInstructionParameter[] defaultParams = muiDef.createDefaultInstruction().getParameters();
171 defaultParams[19] = paramClassifications[19].parse("JZ");
172 MicroInstruction jzMI = MicroInstruction.create(defaultParams);
174 MicroInstructionMemory jzMPM = new StandardMicroInstructionMemory(Am2900MicroInstructionMemoryDefinition.instance);
175 jzMPM.setCell(0x00, jzMI);
176 jzMPM.setCell(0x13, jzMI);
177 mpmToSetNextCycle.set(jzMPM);
179 synchronized (machState)
181 while (machState.get() != 0)
185 mpmToSetNextCycle.set(mpm);
189 public void printStats()
191 System.out.println("Machine executed " + halfCycleCount.get() + " cycles in total (including JZs)");