From e52d4016dde31094a7d12f35135f4bc191358d9c Mon Sep 17 00:00:00 2001 From: Brendan Robert Date: Wed, 21 Mar 2018 20:24:32 -0500 Subject: [PATCH] Self-clocking mockingboard is no longer tied to the main emulator speed --- .../java/jace/hardware/CardMockingboard.java | 65 ++++++++++++++----- .../jace/hardware/mockingboard/R6522.java | 21 +++++- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/Platform/Apple/tools/jace/src/main/java/jace/hardware/CardMockingboard.java b/Platform/Apple/tools/jace/src/main/java/jace/hardware/CardMockingboard.java index 2ecc5053..de102a5f 100644 --- a/Platform/Apple/tools/jace/src/main/java/jace/hardware/CardMockingboard.java +++ b/Platform/Apple/tools/jace/src/main/java/jace/hardware/CardMockingboard.java @@ -27,7 +27,6 @@ import jace.core.RAMEvent; import jace.core.RAMEvent.TYPE; import jace.core.RAMListener; import jace.core.SoundMixer; -import static jace.core.Utility.*; import jace.hardware.mockingboard.PSG; import jace.hardware.mockingboard.R6522; import java.util.concurrent.TimeUnit; @@ -80,7 +79,7 @@ public class CardMockingboard extends Card implements Runnable { Condition playbackFinished = timerSync.newCondition(); @ConfigurableField(name = "Idle sample threshold", description = "Number of samples to wait before suspending sound") private int MAX_IDLE_SAMPLES = SAMPLE_RATE; - + @Override public String getDeviceName() { return "Mockingboard"; @@ -90,7 +89,7 @@ public class CardMockingboard extends Card implements Runnable { super(computer); controllers = new R6522[2]; for (int i = 0; i < 2; i++) { - //don't ask... + // has to be final to be used inside of anonymous class below final int j = i; controllers[i] = new R6522(computer) { int controller = j; @@ -131,6 +130,13 @@ public class CardMockingboard extends Card implements Runnable { public String getShortName() { return "timer" + j; } + + public void doTick() { + super.doTick(); + if (controller == 0) { + doSoundTick(); + } + } }; } } @@ -140,6 +146,18 @@ public class CardMockingboard extends Card implements Runnable { suspend(); } RAMListener mainListener = null; + + boolean heatbeatUnclocked = false; + long heartbeatReclockTime = 0L; + long unclockTime = 5000L; + + private void setUnclocked(boolean unclocked) { + heatbeatUnclocked = unclocked; + for (R6522 controller : controllers) { + controller.setUnclocked(unclocked); + } + heartbeatReclockTime = System.currentTimeMillis() + unclockTime; + } @Override protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) { @@ -152,7 +170,7 @@ public class CardMockingboard extends Card implements Runnable { chip++; } if (chip >= 2) { - System.err.println("Could not determine which PSG to communicate to"); + System.err.println("Could not determine which PSG to communicate to for access to regsiter + " + Integer.toHexString(register)); e.setNewValue(computer.getVideo().getFloatingBus()); return; } @@ -177,13 +195,21 @@ public class CardMockingboard extends Card implements Runnable { @Override public void tick() { - for (R6522 c : controllers) { - if (c == null || !c.isRunning()) { - continue; + if (heatbeatUnclocked) { + if (System.currentTimeMillis() - heartbeatReclockTime >= unclockTime) { + setUnclocked(false); + } else { + for (R6522 c : controllers) { + if (c == null || !c.isRunning()) { + continue; + } + c.doTick(); + } } - c.tick(); } - + } + + private void doSoundTick() { if (isRunning() && !pause) { // buildMixerTable(); timerSync.lock(); @@ -194,7 +220,7 @@ public class CardMockingboard extends Card implements Runnable { while (isRunning() && ticksSinceLastPlayback >= ticksBetweenPlayback) { if (!playbackFinished.await(1, TimeUnit.SECONDS)) { // gripe("The mockingboard playback thread has stalled. Disabling mockingboard."); - suspend(); + suspendSound(); } } } @@ -263,14 +289,15 @@ public class CardMockingboard extends Card implements Runnable { @Override public void resume() { pause = false; - if (!isRunning()) { - if (chips == null) { - initPSG(); - for (PSG psg : chips) { - psg.setRate(phasorMode ? CLOCK_SPEED * 2 : CLOCK_SPEED, SAMPLE_RATE); - psg.reset(); - } + if (chips == null) { + initPSG(); + for (PSG psg : chips) { + psg.setRate(phasorMode ? CLOCK_SPEED * 2 : CLOCK_SPEED, SAMPLE_RATE); + psg.reset(); } + } + if (!isRunning()) { + setUnclocked(true); for (R6522 controller : controllers) { controller.attach(); controller.resume(); @@ -290,6 +317,10 @@ public class CardMockingboard extends Card implements Runnable { controller.suspend(); controller.detach(); } + return suspendSound(); + } + + public boolean suspendSound() { if (playbackThread == null || !playbackThread.isAlive()) { return false; } diff --git a/Platform/Apple/tools/jace/src/main/java/jace/hardware/mockingboard/R6522.java b/Platform/Apple/tools/jace/src/main/java/jace/hardware/mockingboard/R6522.java index 72e9dea3..f23c3c34 100644 --- a/Platform/Apple/tools/jace/src/main/java/jace/hardware/mockingboard/R6522.java +++ b/Platform/Apple/tools/jace/src/main/java/jace/hardware/mockingboard/R6522.java @@ -20,13 +20,15 @@ package jace.hardware.mockingboard; import jace.core.Computer; import jace.core.Device; +import jace.core.TimedDevice; /** * Implementation of 6522 VIA chip * * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ -public abstract class R6522 extends Device { +public abstract class R6522 extends TimedDevice { + public static long SPEED = 1020484L; // (NTSC) public R6522(Computer computer) { super(computer); @@ -34,9 +36,15 @@ public abstract class R6522 extends Device { timer1running = true; timer1latch = 0x1fff; timer1interruptEnabled = false; + setSpeedInHz(SPEED); setRun(true); } + @Override + public long defaultCyclesPerSecond() { + return SPEED; + } + // 6522 VIA // http://www.applevault.com/twiki/Main/Mockingboard/6522.pdf // I/O registers @@ -133,6 +141,7 @@ public abstract class R6522 extends Device { public int timer2latch = 0; public int timer2counter = 0; public boolean timer2running = false; + public boolean unclocked = false; @Override protected String getDeviceName() { @@ -141,6 +150,16 @@ public abstract class R6522 extends Device { @Override public void tick() { + if (!unclocked) { + doTick(); + } + } + + public void setUnclocked(boolean unclocked) { + this.unclocked = unclocked; + } + + public void doTick() { if (timer1running) { timer1counter--; if (timer1counter < 0) {