Committing upstream changes from Lawless Legends to address mockingboard init issues.

This commit is contained in:
Brendan Robert 2018-05-22 22:28:13 -05:00
parent ad9da99cb8
commit eb776d44af
4 changed files with 909 additions and 825 deletions

View File

@ -305,7 +305,7 @@ public class MetaCheat extends Cheats {
} }
int fadeCounter = 0; int fadeCounter = 0;
int FADE_TIMER_VALUE = (int) (Emulator.computer.getMotherboard().cyclesPerSecond / 60); int FADE_TIMER_VALUE = (int) (Emulator.computer.getMotherboard().getSpeedInHz() / 60);
@Override @Override
public void tick() { public void tick() {

View File

@ -21,8 +21,8 @@ package jace.core;
import jace.config.ConfigurableField; import jace.config.ConfigurableField;
/** /**
* A timed device is a device which executes so many ticks in a given time * A timed device is a device which executes so many ticks in a given time interval. This is the core of the emulator
* interval. This is the core of the emulator timing mechanics. * timing mechanics.
* *
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/ */
@ -30,15 +30,16 @@ public abstract class TimedDevice extends Device {
/** /**
* Creates a new instance of TimedDevice * Creates a new instance of TimedDevice
*
* @param computer * @param computer
*/ */
public TimedDevice(Computer computer) { public TimedDevice(Computer computer) {
super(computer); super(computer);
setSpeed(cyclesPerSecond); setSpeedInHz(cyclesPerSecond);
} }
@ConfigurableField(name = "Speed", description = "(Percentage)") @ConfigurableField(name = "Speed", description = "(Percentage)")
public int speedRatio = 100; public int speedRatio = 100;
public long cyclesPerSecond = defaultCyclesPerSecond(); private long cyclesPerSecond = defaultCyclesPerSecond();
@ConfigurableField(name = "Max speed") @ConfigurableField(name = "Max speed")
public boolean maxspeed = false; public boolean maxspeed = false;
@ -57,10 +58,11 @@ public abstract class TimedDevice extends Device {
public boolean suspend() { public boolean suspend() {
disableTempMaxSpeed(); disableTempMaxSpeed();
boolean result = super.suspend(); boolean result = super.suspend();
if (worker != null && worker.isAlive()) { Thread w = worker;
if (w != null && w.isAlive()) {
try { try {
worker.interrupt(); w.interrupt();
worker.join(1000); w.join(1000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
@ -114,13 +116,44 @@ public abstract class TimedDevice extends Device {
long cyclesPerInterval; // How many cycles to wait until a pause interval long cyclesPerInterval; // How many cycles to wait until a pause interval
long nextSync; // When was the last pause? long nextSync; // When was the last pause?
public final void setSpeed(long cyclesPerSecond) { public final int getSpeedRatio() {
return speedRatio;
}
public final void setMaxSpeed(boolean enabled) {
maxspeed = enabled;
if (!enabled) {
disableTempMaxSpeed();
}
}
public final boolean isMaxSpeed() {
return maxspeed;
}
public final long getSpeedInHz() {
return cyclesPerInterval * 100L;
}
public final void setSpeedInHz(long cyclesPerSecond) {
// System.out.println("Raw set speed for " + getName() + " to " + cyclesPerSecond + "hz");
speedRatio = (int) Math.round(cyclesPerSecond * 100.0 / defaultCyclesPerSecond());
cyclesPerInterval = cyclesPerSecond / 100L; cyclesPerInterval = cyclesPerSecond / 100L;
nanosPerInterval = (long) (cyclesPerInterval * NANOS_PER_SECOND / cyclesPerSecond); nanosPerInterval = (long) (cyclesPerInterval * NANOS_PER_SECOND / cyclesPerSecond);
// System.out.println("Will pause " + nanosPerInterval + " nanos every " + cyclesPerInterval + " cycles"); // System.out.println("Will pause " + nanosPerInterval + " nanos every " + cyclesPerInterval + " cycles");
cycleTimer = 0; cycleTimer = 0;
resetSyncTimer(); resetSyncTimer();
} }
public final void setSpeedInPercentage(int ratio) {
// System.out.println("Setting " + getName() + " speed ratio to " + speedRatio);
cyclesPerSecond = defaultCyclesPerSecond() * ratio / 100;
if (cyclesPerSecond == 0) {
cyclesPerSecond = defaultCyclesPerSecond();
}
setSpeedInHz(cyclesPerSecond);
}
long skip = 0; long skip = 0;
long wait = 0; long wait = 0;
@ -171,11 +204,6 @@ public abstract class TimedDevice extends Device {
@Override @Override
public void reconfigure() { public void reconfigure() {
cyclesPerSecond = defaultCyclesPerSecond() * speedRatio / 100;
if (cyclesPerSecond == 0) {
cyclesPerSecond = defaultCyclesPerSecond();
}
setSpeed(cyclesPerSecond);
} }
public abstract long defaultCyclesPerSecond(); public abstract long defaultCyclesPerSecond();

View File

@ -27,7 +27,6 @@ import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
import jace.core.RAMListener; import jace.core.RAMListener;
import jace.core.SoundMixer; import jace.core.SoundMixer;
import static jace.core.Utility.*;
import jace.hardware.mockingboard.PSG; import jace.hardware.mockingboard.PSG;
import jace.hardware.mockingboard.R6522; import jace.hardware.mockingboard.R6522;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -90,7 +89,7 @@ public class CardMockingboard extends Card implements Runnable {
super(computer); super(computer);
controllers = new R6522[2]; controllers = new R6522[2];
for (int i = 0; i < 2; i++) { 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; final int j = i;
controllers[i] = new R6522(computer) { controllers[i] = new R6522(computer) {
int controller = j; int controller = j;
@ -131,6 +130,13 @@ public class CardMockingboard extends Card implements Runnable {
public String getShortName() { public String getShortName() {
return "timer" + j; return "timer" + j;
} }
public void doTick() {
super.doTick();
if (controller == 0) {
doSoundTick();
}
}
}; };
} }
} }
@ -141,6 +147,18 @@ public class CardMockingboard extends Card implements Runnable {
} }
RAMListener mainListener = null; 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 @Override
protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) { protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
resume(); resume();
@ -152,7 +170,7 @@ public class CardMockingboard extends Card implements Runnable {
chip++; chip++;
} }
if (chip >= 2) { 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()); e.setNewValue(computer.getVideo().getFloatingBus());
return; return;
} }
@ -177,13 +195,25 @@ public class CardMockingboard extends Card implements Runnable {
@Override @Override
public void tick() { public void tick() {
for (R6522 c : controllers) { if (heatbeatUnclocked) {
if (c == null || !c.isRunning()) { if (System.currentTimeMillis() - heartbeatReclockTime >= unclockTime) {
continue; setUnclocked(false);
} else {
for (R6522 c : controllers) {
if (c == null || !c.isRunning()) {
continue;
}
c.doTick();
}
} }
c.tick();
} }
}
public boolean isRunning() {
return super.isRunning() && playbackThread != null && playbackThread.isAlive();
}
private void doSoundTick() {
if (isRunning() && !pause) { if (isRunning() && !pause) {
// buildMixerTable(); // buildMixerTable();
timerSync.lock(); timerSync.lock();
@ -194,7 +224,7 @@ public class CardMockingboard extends Card implements Runnable {
while (isRunning() && ticksSinceLastPlayback >= ticksBetweenPlayback) { while (isRunning() && ticksSinceLastPlayback >= ticksBetweenPlayback) {
if (!playbackFinished.await(1, TimeUnit.SECONDS)) { if (!playbackFinished.await(1, TimeUnit.SECONDS)) {
// gripe("The mockingboard playback thread has stalled. Disabling mockingboard."); // gripe("The mockingboard playback thread has stalled. Disabling mockingboard.");
suspend(); suspendSound();
} }
} }
} }
@ -263,14 +293,15 @@ public class CardMockingboard extends Card implements Runnable {
@Override @Override
public void resume() { public void resume() {
pause = false; pause = false;
if (!isRunning()) { if (chips == null) {
if (chips == null) { initPSG();
initPSG(); for (PSG psg : chips) {
for (PSG psg : chips) { psg.setRate(phasorMode ? CLOCK_SPEED * 2 : CLOCK_SPEED, SAMPLE_RATE);
psg.setRate(phasorMode ? CLOCK_SPEED * 2 : CLOCK_SPEED, SAMPLE_RATE); psg.reset();
psg.reset();
}
} }
}
if (!isRunning()) {
setUnclocked(true);
for (R6522 controller : controllers) { for (R6522 controller : controllers) {
controller.attach(); controller.attach();
controller.resume(); controller.resume();
@ -290,6 +321,10 @@ public class CardMockingboard extends Card implements Runnable {
controller.suspend(); controller.suspend();
controller.detach(); controller.detach();
} }
return suspendSound();
}
public boolean suspendSound() {
if (playbackThread == null || !playbackThread.isAlive()) { if (playbackThread == null || !playbackThread.isAlive()) {
return false; return false;
} }
@ -325,11 +360,11 @@ public class CardMockingboard extends Card implements Runnable {
int zeroSamples = 0; int zeroSamples = 0;
setRun(true); setRun(true);
LockSupport.parkNanos(5000); LockSupport.parkNanos(5000);
while (isRunning()) { while (isRunning() && !Thread.interrupted()) {
while (isRunning() && !computer.isRunning()) { while (isRunning() && !computer.isRunning()) {
Thread.currentThread().yield(); Thread.sleep(1000);
} }
if (isRunning()) { if (isRunning() && !Thread.interrupted()) {
playSound(leftBuffer, rightBuffer); playSound(leftBuffer, rightBuffer);
int p = 0; int p = 0;
for (int idx = 0; idx < BUFFER_LENGTH; idx++) { for (int idx = 0; idx < BUFFER_LENGTH; idx++) {
@ -394,6 +429,8 @@ public class CardMockingboard extends Card implements Runnable {
} catch (LineUnavailableException ex) { } catch (LineUnavailableException ex) {
Logger.getLogger(CardMockingboard.class Logger.getLogger(CardMockingboard.class
.getName()).log(Level.SEVERE, null, ex); .getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(CardMockingboard.class.getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
computer.getMotherboard().cancelSpeedRequest(this); computer.getMotherboard().cancelSpeedRequest(this);
System.out.println("Mockingboard playback stopped"); System.out.println("Mockingboard playback stopped");

View File

@ -20,13 +20,15 @@ package jace.hardware.mockingboard;
import jace.core.Computer; import jace.core.Computer;
import jace.core.Device; import jace.core.Device;
import jace.core.TimedDevice;
/** /**
* Implementation of 6522 VIA chip * Implementation of 6522 VIA chip
* *
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @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) { public R6522(Computer computer) {
super(computer); super(computer);
@ -34,9 +36,15 @@ public abstract class R6522 extends Device {
timer1running = true; timer1running = true;
timer1latch = 0x1fff; timer1latch = 0x1fff;
timer1interruptEnabled = false; timer1interruptEnabled = false;
setSpeedInHz(SPEED);
setRun(true); setRun(true);
} }
@Override
public long defaultCyclesPerSecond() {
return SPEED;
}
// 6522 VIA // 6522 VIA
// http://www.applevault.com/twiki/Main/Mockingboard/6522.pdf // http://www.applevault.com/twiki/Main/Mockingboard/6522.pdf
// I/O registers // I/O registers
@ -133,6 +141,7 @@ public abstract class R6522 extends Device {
public int timer2latch = 0; public int timer2latch = 0;
public int timer2counter = 0; public int timer2counter = 0;
public boolean timer2running = false; public boolean timer2running = false;
public boolean unclocked = false;
@Override @Override
protected String getDeviceName() { protected String getDeviceName() {
@ -141,6 +150,16 @@ public abstract class R6522 extends Device {
@Override @Override
public void tick() { public void tick() {
if (!unclocked) {
doTick();
}
}
public void setUnclocked(boolean unclocked) {
this.unclocked = unclocked;
}
public void doTick() {
if (timer1running) { if (timer1running) {
timer1counter--; timer1counter--;
if (timer1counter < 0) { if (timer1counter < 0) {