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