diff --git a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/Context8080Impl.java b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/Context8080Impl.java index 278b3dbfb..6bea59645 100644 --- a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/Context8080Impl.java +++ b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/Context8080Impl.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.cpu.intel8080; +import net.emustudio.emulib.plugins.cpu.AbstractCPUContext; import net.emustudio.plugins.cpu.intel8080.api.Context8080; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; @@ -27,7 +28,7 @@ import java.util.concurrent.ConcurrentMap; @ThreadSafe -public class Context8080Impl implements Context8080 { +public class Context8080Impl extends AbstractCPUContext implements Context8080 { public final static int DEFAULT_FREQUENCY_KHZ = 2000; private final static Logger LOGGER = LoggerFactory.getLogger(Context8080Impl.class); private final static byte NO_DATA = (byte) 0xFF; // ha! from survey.mac in cpm2.dsk: "inactive port could return 0xFF or echo port#" @@ -89,6 +90,11 @@ public boolean isInterruptSupported() { return true; } + @Override + public boolean passedCyclesSupported() { + return true; + } + /** * Signals raw interrupt to the CPU. *

diff --git a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/CpuImpl.java b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/CpuImpl.java index 4248cf132..d96d16a4e 100644 --- a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/CpuImpl.java +++ b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/CpuImpl.java @@ -23,12 +23,12 @@ import net.emustudio.emulib.plugins.annotations.PluginRoot; import net.emustudio.emulib.plugins.cpu.AbstractCPU; import net.emustudio.emulib.plugins.cpu.Disassembler; +import net.emustudio.emulib.plugins.cpu.FrequencyCalculator; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; import net.emustudio.emulib.runtime.InvalidContextException; import net.emustudio.emulib.runtime.settings.PluginSettings; import net.emustudio.plugins.cpu.intel8080.api.Context8080; -import net.emustudio.plugins.cpu.intel8080.api.FrequencyUpdater; import net.emustudio.plugins.cpu.intel8080.gui.StatusPanel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,11 +37,6 @@ import java.util.MissingResourceException; import java.util.Optional; import java.util.ResourceBundle; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; @PluginRoot( type = PLUGIN_TYPE.CPU, @@ -51,9 +46,6 @@ public class CpuImpl extends AbstractCPU { private final static Logger LOGGER = LoggerFactory.getLogger(CpuImpl.class); - private final ScheduledExecutorService frequencyScheduler = Executors.newSingleThreadScheduledExecutor(); - private final AtomicReference> frequencyUpdaterFuture = new AtomicReference<>(); - private final Context8080Impl context = new Context8080Impl(); private final InitializerFor8080 initializer; @@ -61,6 +53,8 @@ public class CpuImpl extends AbstractCPU { private StatusPanel statusPanel; private Disassembler disassembler; + private FrequencyCalculator frequencyCalculator; + public CpuImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { super(pluginID, applicationApi, settings); @@ -100,10 +94,13 @@ public void initialize() throws PluginInitializationException { context.setCpu(engine); disassembler = initializer.getDisassembler(); statusPanel = new StatusPanel(this, context, initializer.shouldDumpInstructions()); + frequencyCalculator = new FrequencyCalculator(engine::fireFrequencyChanged); } @Override protected void destroyInternal() { + frequencyCalculator.stop(); + frequencyCalculator.close(); context.clearDevices(); initializer.destroy(); } @@ -115,19 +112,19 @@ public EmulatorEngine getEngine() { @Override public void resetInternal(int startPos) { engine.reset(startPos); - stopFrequencyUpdater(); + frequencyCalculator.stop(); } @Override public void pause() { super.pause(); - stopFrequencyUpdater(); + frequencyCalculator.stop(); } @Override public void stop() { super.stop(); - stopFrequencyUpdater(); + frequencyCalculator.stop(); } @Override @@ -140,36 +137,13 @@ public JPanel getStatusPanel() { return statusPanel; } - private void stopFrequencyUpdater() { - Future tmpFuture; - - do { - tmpFuture = frequencyUpdaterFuture.get(); - if (tmpFuture != null) { - tmpFuture.cancel(false); - } - } while (!frequencyUpdaterFuture.compareAndSet(tmpFuture, null)); - } - - private void startFrequencyUpdater() { - Future tmpFuture; - Future newFuture = frequencyScheduler.scheduleAtFixedRate(new FrequencyUpdater(engine), 0, 1, TimeUnit.SECONDS); - - do { - tmpFuture = frequencyUpdaterFuture.get(); - if (tmpFuture != null) { - tmpFuture.cancel(false); - } - } while (!frequencyUpdaterFuture.compareAndSet(tmpFuture, newFuture)); - } - @Override public RunState call() { try { - startFrequencyUpdater(); + frequencyCalculator.start(); return engine.run(this); } finally { - stopFrequencyUpdater(); + frequencyCalculator.stop(); } } @@ -196,6 +170,7 @@ private Optional getResourceBundle() { try { return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.cpu.intel8080.version")); } catch (MissingResourceException e) { + e.printStackTrace(); return Optional.empty(); } } diff --git a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/EmulatorEngine.java b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/EmulatorEngine.java index a76130806..adb6c8ce2 100644 --- a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/EmulatorEngine.java +++ b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/EmulatorEngine.java @@ -70,7 +70,6 @@ public class EmulatorEngine implements CpuEngine { private short b2 = 0; private short b3 = 0; private int lastOpcode; - private long executedCycles = 0; private volatile DispatchListener dispatchListener; @@ -84,13 +83,6 @@ public void setDispatchListener(DispatchListener dispatchListener) { this.dispatchListener = dispatchListener; } - @Override - public long getAndResetGlobalExecutedCycles() { - long tmpExecutedCycles = executedCycles; - executedCycles = 0; - return tmpExecutedCycles; - } - public void addFrequencyChangedListener(FrequencyChangedListener listener) { frequencyChangedListeners.add(listener); } @@ -125,7 +117,7 @@ public CPU.RunState step() throws Exception { public CPU.RunState run(CPU cpu) { long startTime, endTime; - int cycles_executed; + int cyclesExecuted; int checkTimeSlice = 100; int cycles_to_execute = checkTimeSlice * context.getCPUFrequency(); int cycles; @@ -134,12 +126,12 @@ public CPU.RunState run(CPU cpu) { currentRunState = CPU.RunState.STATE_RUNNING; while (!Thread.currentThread().isInterrupted() && (currentRunState == CPU.RunState.STATE_RUNNING)) { startTime = System.nanoTime(); - cycles_executed = 0; - while ((cycles_executed < cycles_to_execute) && !Thread.currentThread().isInterrupted() && (currentRunState == CPU.RunState.STATE_RUNNING)) { + cyclesExecuted = 0; + while ((cyclesExecuted < cycles_to_execute) && !Thread.currentThread().isInterrupted() && (currentRunState == CPU.RunState.STATE_RUNNING)) { try { cycles = dispatch(); - cycles_executed += cycles; - executedCycles += cycles; + cyclesExecuted += cycles; + context.passedCycles(cycles); if (cpu.isBreakpointSet(PC)) { throw new Breakpoint(); } diff --git a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/CpuEngine.java b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/CpuEngine.java index d84ef6e80..81240e48b 100644 --- a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/CpuEngine.java +++ b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/CpuEngine.java @@ -20,10 +20,7 @@ public interface CpuEngine { - long getAndResetGlobalExecutedCycles(); - void fireFrequencyChanged(float newFrequency); void setDispatchListener(DispatchListener dispatchListener); - } diff --git a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/FrequencyUpdater.java b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/FrequencyUpdater.java deleted file mode 100644 index 58e0abc16..000000000 --- a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/FrequencyUpdater.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of emuStudio. - * - * Copyright (C) 2006-2023 Peter Jakubčo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.emustudio.plugins.cpu.intel8080.api; - -import net.jcip.annotations.ThreadSafe; - -import java.util.Objects; - -@ThreadSafe -public class FrequencyUpdater implements Runnable { - - private final CpuEngine cpu; - private long startTimeSaved = 0; - private float frequency; - - public FrequencyUpdater(CpuEngine cpu) { - this.cpu = Objects.requireNonNull(cpu); - } - - @Override - public void run() { - boolean frequencyChanged = false; - - synchronized (this) { - long endTime = System.nanoTime(); - long time = endTime - startTimeSaved; - long executedCycles = cpu.getAndResetGlobalExecutedCycles(); - - if (executedCycles > 0) { - frequency = (float) (executedCycles / (time / 1000000.0)); - startTimeSaved = endTime; - frequencyChanged = true; - } - } - - if (frequencyChanged) { - cpu.fireFrequencyChanged(frequency); - } - } -} diff --git a/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/CpuImplTest.java b/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/CpuImplTest.java index 9da5fe717..05e98bc5b 100644 --- a/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/CpuImplTest.java +++ b/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/CpuImplTest.java @@ -18,6 +18,8 @@ */ package net.emustudio.plugins.cpu.intel8080; +import net.emustudio.emulib.plugins.PluginInitializationException; +import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.ContextPool; import net.emustudio.emulib.runtime.settings.PluginSettings; @@ -31,15 +33,21 @@ public class CpuImplTest { private CpuImpl cpu; + @SuppressWarnings("unchecked") @Before - public void setup() { + public void setup() throws PluginInitializationException { ContextPool contextPool = createNiceMock(ContextPool.class); + MemoryContext memory = createMock(MemoryContext.class); + expect(memory.getCellTypeClass()).andReturn(Byte.class).anyTimes(); + replay(memory); + expect(contextPool.getMemoryContext(0, MemoryContext.class)).andReturn(memory).anyTimes(); replay(contextPool); ApplicationApi applicationApi = createNiceMock(ApplicationApi.class); expect(applicationApi.getContextPool()).andReturn(contextPool).anyTimes(); replay(applicationApi); this.cpu = new CpuImpl(0, applicationApi, PluginSettings.UNAVAILABLE); + this.cpu.initialize(); } @After diff --git a/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/api/FrequencyUpdaterTest.java b/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/api/FrequencyUpdaterTest.java deleted file mode 100644 index ecd0243b2..000000000 --- a/plugins/cpu/8080-cpu/src/test/java/net/emustudio/plugins/cpu/intel8080/api/FrequencyUpdaterTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of emuStudio. - * - * Copyright (C) 2006-2023 Peter Jakubčo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.emustudio.plugins.cpu.intel8080.api; - -import org.junit.Test; - -import static org.easymock.EasyMock.*; - -public class FrequencyUpdaterTest { - - @Test - public void testFrequencyNotChanged() throws Exception { - CpuEngine cpuEngine = createMock(CpuEngine.class); - expect(cpuEngine.getAndResetGlobalExecutedCycles()).andReturn(0L); - replay(cpuEngine); - - new FrequencyUpdater(cpuEngine).run(); - - verify(cpuEngine); - } - - @Test - public void testFrequencyChanged() throws Exception { - CpuEngine cpuEngine = createMock(CpuEngine.class); - expect(cpuEngine.getAndResetGlobalExecutedCycles()).andReturn(2000L); - cpuEngine.fireFrequencyChanged(anyFloat()); - expectLastCall().once(); - replay(cpuEngine); - - new FrequencyUpdater(cpuEngine).run(); - - verify(cpuEngine); - } -} diff --git a/plugins/cpu/brainduck-cpu/src/main/java/net/emustudio/plugins/cpu/brainduck/BrainCPUContextImpl.java b/plugins/cpu/brainduck-cpu/src/main/java/net/emustudio/plugins/cpu/brainduck/BrainCPUContextImpl.java index 20bc6aab2..b81cb2c1c 100644 --- a/plugins/cpu/brainduck-cpu/src/main/java/net/emustudio/plugins/cpu/brainduck/BrainCPUContextImpl.java +++ b/plugins/cpu/brainduck-cpu/src/main/java/net/emustudio/plugins/cpu/brainduck/BrainCPUContextImpl.java @@ -69,4 +69,19 @@ public byte readFromDevice() { Byte value = tmp.readData(); return (value == null) ? 0 : value; } + + @Override + public boolean passedCyclesSupported() { + return false; + } + + @Override + public void addPassedCyclesListener(PassedCyclesListener passedCyclesListener) { + + } + + @Override + public void removePassedCyclesListener(PassedCyclesListener passedCyclesListener) { + + } } diff --git a/plugins/cpu/ram-cpu/src/main/java/net/emustudio/plugins/cpu/ram/RamCpuContextImpl.java b/plugins/cpu/ram-cpu/src/main/java/net/emustudio/plugins/cpu/ram/RamCpuContextImpl.java index af9c64069..61b17c289 100644 --- a/plugins/cpu/ram-cpu/src/main/java/net/emustudio/plugins/cpu/ram/RamCpuContextImpl.java +++ b/plugins/cpu/ram-cpu/src/main/java/net/emustudio/plugins/cpu/ram/RamCpuContextImpl.java @@ -77,4 +77,19 @@ public void destroy() { Optional.ofNullable(storageTape).ifPresent(AbstractTapeContext::clear); Optional.ofNullable(outputTape).ifPresent(AbstractTapeContext::clear); } + + @Override + public boolean passedCyclesSupported() { + return false; + } + + @Override + public void addPassedCyclesListener(PassedCyclesListener passedCyclesListener) { + + } + + @Override + public void removePassedCyclesListener(PassedCyclesListener passedCyclesListener) { + + } } diff --git a/plugins/cpu/rasp-cpu/src/main/java/net/emustudio/plugins/cpu/rasp/RaspCpuContextImpl.java b/plugins/cpu/rasp-cpu/src/main/java/net/emustudio/plugins/cpu/rasp/RaspCpuContextImpl.java index 3c374e0a1..716fb993b 100644 --- a/plugins/cpu/rasp-cpu/src/main/java/net/emustudio/plugins/cpu/rasp/RaspCpuContextImpl.java +++ b/plugins/cpu/rasp-cpu/src/main/java/net/emustudio/plugins/cpu/rasp/RaspCpuContextImpl.java @@ -63,4 +63,19 @@ public void destroy() { Optional.ofNullable(inputTape).ifPresent(AbstractTapeContext::clear); Optional.ofNullable(outputTape).ifPresent(AbstractTapeContext::clear); } + + @Override + public boolean passedCyclesSupported() { + return false; + } + + @Override + public void addPassedCyclesListener(PassedCyclesListener passedCyclesListener) { + + } + + @Override + public void removePassedCyclesListener(PassedCyclesListener passedCyclesListener) { + + } } diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/ContextZ80Impl.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/ContextZ80Impl.java index 144a3ae9e..865bcdc8c 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/ContextZ80Impl.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/ContextZ80Impl.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.cpu.zilogZ80; +import net.emustudio.emulib.plugins.cpu.AbstractCPUContext; import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; import net.jcip.annotations.ThreadSafe; @@ -29,7 +30,7 @@ import java.util.concurrent.ConcurrentMap; @ThreadSafe -public final class ContextZ80Impl implements ContextZ80 { +public final class ContextZ80Impl extends AbstractCPUContext implements ContextZ80 { public final static int DEFAULT_FREQUENCY_KHZ = 4000; private final static byte NO_DATA = (byte) 0xFF; private final static Logger LOGGER = LoggerFactory.getLogger(ContextZ80Impl.class); @@ -115,7 +116,7 @@ public void signalNonMaskableInterrupt() { } @Override - public void addCycles(int tStates) { + public void addCycles(long tStates) { engine.addExecutedCyclesPerTimeSlice(tStates); } @@ -124,6 +125,11 @@ public Optional getTimedEventsProcessor() { return Optional.of(tep); } + @Override + public boolean passedCyclesSupported() { + return true; + } + public TimedEventsProcessor getTimedEventsProcessorNow() { // bypassing optional return tep; diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java index ec012e572..1dc6c8d94 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java @@ -23,12 +23,12 @@ import net.emustudio.emulib.plugins.annotations.PluginRoot; import net.emustudio.emulib.plugins.cpu.AbstractCPU; import net.emustudio.emulib.plugins.cpu.Disassembler; +import net.emustudio.emulib.plugins.cpu.FrequencyCalculator; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; import net.emustudio.emulib.runtime.InvalidContextException; import net.emustudio.emulib.runtime.settings.PluginSettings; import net.emustudio.plugins.cpu.intel8080.api.Context8080; -import net.emustudio.plugins.cpu.intel8080.api.FrequencyUpdater; import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; import net.emustudio.plugins.cpu.zilogZ80.gui.StatusPanel; import org.slf4j.Logger; @@ -38,11 +38,6 @@ import java.util.MissingResourceException; import java.util.Optional; import java.util.ResourceBundle; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; @PluginRoot( type = PLUGIN_TYPE.CPU, @@ -52,9 +47,6 @@ public class CpuImpl extends AbstractCPU { private static final Logger LOGGER = LoggerFactory.getLogger(CpuImpl.class); - private final ScheduledExecutorService frequencyScheduler = Executors.newSingleThreadScheduledExecutor(); - private final AtomicReference frequencyUpdaterFuture = new AtomicReference<>(); - private final ContextZ80Impl context = new ContextZ80Impl(); private final InitializerZ80 initializer; @@ -62,6 +54,8 @@ public class CpuImpl extends AbstractCPU { private Disassembler disassembler; private EmulatorEngine engine; + private FrequencyCalculator frequencyCalculator; + public CpuImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { super(pluginID, applicationApi, settings); try { @@ -102,6 +96,7 @@ public void initialize() throws PluginInitializationException { disassembler = initializer.getDisassembler(); engine = initializer.getEngine(); context.setEngine(engine); + frequencyCalculator = new FrequencyCalculator(engine::fireFrequencyChanged); statusPanel = new StatusPanel(this, context, initializer.shouldDumpInstructions()); } @@ -114,55 +109,32 @@ public JPanel getStatusPanel() { return statusPanel; } - private void stopFrequencyUpdater() { - Future tmpFuture; - - do { - tmpFuture = frequencyUpdaterFuture.get(); - if (tmpFuture != null) { - tmpFuture.cancel(false); - } - } while (!frequencyUpdaterFuture.compareAndSet(tmpFuture, null)); - } - - private void startFrequencyUpdater() { - Future tmpFuture; - Future newFuture = frequencyScheduler.scheduleAtFixedRate(new FrequencyUpdater(engine), 0, 1, TimeUnit.SECONDS); - - do { - tmpFuture = frequencyUpdaterFuture.get(); - if (tmpFuture != null) { - tmpFuture.cancel(false); - } - } while (!frequencyUpdaterFuture.compareAndSet(tmpFuture, newFuture)); - } - @Override public RunState call() { try { - startFrequencyUpdater(); + frequencyCalculator.start(); return engine.run(this); } finally { - stopFrequencyUpdater(); + frequencyCalculator.stop(); } } @Override protected void resetInternal(int startPos) { + frequencyCalculator.stop(); engine.reset(startPos); - stopFrequencyUpdater(); } @Override public void pause() { super.pause(); - stopFrequencyUpdater(); + frequencyCalculator.stop(); } @Override public void stop() { super.stop(); - stopFrequencyUpdater(); + frequencyCalculator.stop(); } @Override @@ -177,6 +149,8 @@ public Disassembler getDisassembler() { @Override protected void destroyInternal() { + frequencyCalculator.stop(); + frequencyCalculator.close(); context.clearDevices(); initializer.destroy(); } @@ -197,7 +171,6 @@ public String getDescription() { } - private Optional getResourceBundle() { try { return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.cpu.zilogZ80.version")); diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/EmulatorEngine.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/EmulatorEngine.java index 278229440..42b906250 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/EmulatorEngine.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/EmulatorEngine.java @@ -37,7 +37,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import static net.emustudio.plugins.cpu.zilogZ80.DispatchTables.*; @@ -68,8 +67,7 @@ public class EmulatorEngine implements CpuEngine { private final TimedEventsProcessor tep; private final MemoryContext memory; private final List frequencyChangedListeners = new CopyOnWriteArrayList<>(); - private final AtomicLong cyclesExecutedGlobal = new AtomicLong(0); - private final AtomicInteger cyclesExecutedPerTimeSlice = new AtomicInteger(0); + private final AtomicLong cyclesExecutedPerTimeSlice = new AtomicLong(0); public final int[] regs = new int[8]; public final int[] regs2 = new int[8]; @@ -139,12 +137,7 @@ public void setDispatchListener(DispatchListener dispatchListener) { this.dispatchListener = dispatchListener; } - @Override - public long getAndResetGlobalExecutedCycles() { - return cyclesExecutedGlobal.getAndSet(0); - } - - public void addExecutedCyclesPerTimeSlice(int tstates) { + public void addExecutedCyclesPerTimeSlice(long tstates) { cyclesExecutedPerTimeSlice.addAndGet(tstates); } @@ -240,8 +233,8 @@ public CPU.RunState run(CPU cpu) { private void advanceCycles(int cycles) { cyclesExecutedPerTimeSlice.addAndGet(cycles); - cyclesExecutedGlobal.addAndGet(cycles); tep.advanceClock(cycles); + context.passedCycles(cycles); } private void dispatch() throws Throwable { diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java index 9e409229b..634b9b59c 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java @@ -40,5 +40,5 @@ public interface ContextZ80 extends Context8080 { * * @param tStates number of t-states (machine cycles) to add */ - void addCycles(int tStates); + void addCycles(long tStates); } diff --git a/plugins/cpu/z80-cpu/src/test/java/net/emustudio/plugins/cpu/zilogZ80/CpuImplTest.java b/plugins/cpu/z80-cpu/src/test/java/net/emustudio/plugins/cpu/zilogZ80/CpuImplTest.java index 157d82d7c..cc73eab4d 100644 --- a/plugins/cpu/z80-cpu/src/test/java/net/emustudio/plugins/cpu/zilogZ80/CpuImplTest.java +++ b/plugins/cpu/z80-cpu/src/test/java/net/emustudio/plugins/cpu/zilogZ80/CpuImplTest.java @@ -18,8 +18,12 @@ */ package net.emustudio.plugins.cpu.zilogZ80; +import net.emustudio.emulib.plugins.PluginInitializationException; +import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; +import net.emustudio.emulib.runtime.ContextNotFoundException; import net.emustudio.emulib.runtime.ContextPool; +import net.emustudio.emulib.runtime.InvalidContextException; import net.emustudio.emulib.runtime.settings.PluginSettings; import org.junit.After; import org.junit.Before; @@ -31,15 +35,21 @@ public class CpuImplTest { private CpuImpl cpu; + @SuppressWarnings("unchecked") @Before - public void setup() { + public void setup() throws PluginInitializationException { ContextPool contextPool = createNiceMock(ContextPool.class); + MemoryContext memory = createMock(MemoryContext.class); + expect(memory.getCellTypeClass()).andReturn(Byte.class).anyTimes(); + replay(memory); + expect(contextPool.getMemoryContext(0, MemoryContext.class)).andReturn(memory).anyTimes(); replay(contextPool); ApplicationApi applicationApi = createNiceMock(ApplicationApi.class); expect(applicationApi.getContextPool()).andReturn(contextPool).anyTimes(); replay(applicationApi); this.cpu = new CpuImpl(0, applicationApi, PluginSettings.UNAVAILABLE); + this.cpu.initialize(); } @After