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.machine.MainMemory;
28 import net.mograsim.machine.mi.MicroInstruction;
29 import net.mograsim.machine.mi.MicroInstructionDefinition;
30 import net.mograsim.machine.mi.MicroInstructionMemory;
31 import net.mograsim.machine.mi.MicroInstructionMemoryParser;
32 import net.mograsim.machine.mi.StandardMicroInstructionMemory;
33 import net.mograsim.machine.mi.parameters.MicroInstructionParameter;
34 import net.mograsim.machine.mi.parameters.ParameterClassification;
35 import net.mograsim.machine.standard.memory.WordAddressableMemory;
37 @TestInstance(Lifecycle.PER_CLASS)
40 private static final boolean startGUI = false;
42 private Am2900Machine mach;
43 private MicroInstructionMemory mpm;
44 private MainMemory ram;
45 private AtomicInteger machState;
46 private AtomicInteger halfCycleCount;
47 private AtomicReference<MicroInstructionMemory> mpmToSetNextCycle;
50 public void setupMachine() throws IOException
53 mach = new StrictAm2900MachineDefinition().createNew();
54 mpm = MicroInstructionMemoryParser.parseMemory(Am2900MicroInstructionMemoryDefinition.instance,
55 TestGCD.class.getResourceAsStream("gcd.mpm"));
56 ram = new WordAddressableMemory(Am2900MainMemoryDefinition.instance);
57 mach.getMainMemory().bind(ram);
62 machState = new AtomicInteger(2);
63 halfCycleCount = new AtomicInteger();
64 // needed for avoiding hazard loops in the first muIR
65 mpmToSetNextCycle = new AtomicReference<>();
66 mach.getClock().registerObserver(c ->
68 halfCycleCount.addAndGet(1);
69 synchronized (machState)
71 long muPC = mach.getActiveMicroInstructionAddress();
76 } else if (muPC == 0x12)
81 if (!mach.getClock().isOn())
83 MicroInstructionMemory mpmToSet = mpmToSetNextCycle.getAndSet(null);
85 mach.getMicroInstructionMemory().bind(mpmToSet);
92 Thread execT = new Thread(mach.getTimeline()::executeAll, "Logic executer");
93 execT.setDaemon(true);
96 System.out.println("Machine initialized");
100 private void startGUI()
102 new Thread(() -> new LogicUIStandaloneGUI(mach.getModel()).run(), "GUI thread").start();
106 public void testGCDHardcodedCases() throws InterruptedException
113 checkGCD(48820, 8480);
114 checkGCD(21420, 11288);
115 checkGCD(15862, 21219);
119 @MethodSource("generateRandomInts")
120 public void testGCDRandomCases(int i) throws InterruptedException
127 public static IntStream generateRandomInts()
129 return ThreadLocalRandom.current().ints(10);
132 private void checkGCD(int euclidA, int euclidB) throws InterruptedException
134 int exp = gcd(euclidA, euclidB);
135 System.out.println("Checking gcd(" + euclidA + ", " + euclidB + ") + (expected " + exp + ")");
136 int act = executeGCD(euclidA, euclidB);
137 assertEquals(exp, act);
140 private static int gcd(int a, int b)
144 return gcd(b, a % b);
147 private int executeGCD(int euclidA, int euclidB) throws InterruptedException
149 ram.setCell(0, BitVector.from(euclidA, 16));
150 ram.setCell(1, BitVector.from(euclidB, 16));
154 synchronized (machState)
156 while (machState.get() != 1)
160 BitVector result = mach.getRegister(NumberedRegister.instancesCorrectOrder.get(1));
161 return result.isBinary() ? (int) result.getUnsignedValueLong() : -1;
164 private void resetMachine() throws InterruptedException
166 MicroInstructionDefinition muiDef = Am2900MicroInstructionDefinition.instance;
167 ParameterClassification[] paramClassifications = muiDef.getParameterClassifications();
168 MicroInstructionParameter[] defaultParams = muiDef.createDefaultInstruction().getParameters();
169 defaultParams[19] = paramClassifications[19].parse("JZ");
170 MicroInstruction jzMI = MicroInstruction.create(defaultParams);
172 MicroInstructionMemory jzMPM = new StandardMicroInstructionMemory(Am2900MicroInstructionMemoryDefinition.instance);
173 jzMPM.setCell(0x00, jzMI);
174 jzMPM.setCell(0x13, jzMI);
175 mpmToSetNextCycle.set(jzMPM);
177 synchronized (machState)
179 while (machState.get() != 0)
183 mpmToSetNextCycle.set(mpm);
187 public void printStats()
189 System.out.println("Machine executed " + halfCycleCount.get() + " cycles in total (including JZs)");