mirror of
https://github.com/badvision/jace.git
synced 2025-01-06 08:31:25 +00:00
Committing upstream changes from Lawless Legends to address mockingboard init issues.
This commit is contained in:
parent
ad9da99cb8
commit
eb776d44af
@ -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() {
|
||||||
|
@ -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();
|
||||||
|
@ -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");
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user