Merge branch 'master' of github.com:badvision/lawless-legends

This commit is contained in:
Martin Haye 2018-03-27 11:21:17 -07:00
commit 433eaf3f47
7 changed files with 83 additions and 63 deletions

View File

@ -1340,7 +1340,16 @@ LEAVEX INY ;+INC_IP
STA IFPL STA IFPL
PLA PLA
STA IFPH STA IFPH
RETX STA ALTRDOFF STA ALTRDOFF
LDA PSR
PHA
PLP
RTS
RETX LDA IFPL
STA PPL
LDA IFPH
STA PPH
STA ALTRDOFF
LDA PSR LDA PSR
PHA PHA
PLP PLP

View File

@ -21,6 +21,7 @@ package jace.core;
import jace.apple2e.SoftSwitches; import jace.apple2e.SoftSwitches;
import jace.apple2e.Speaker; import jace.apple2e.Speaker;
import jace.config.ConfigurableField; import jace.config.ConfigurableField;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Optional; import java.util.Optional;
@ -40,7 +41,7 @@ import java.util.logging.Logger;
*/ */
public class Motherboard extends TimedDevice { public class Motherboard extends TimedDevice {
final public Set<Device> miscDevices = new LinkedHashSet<>(); final public Set<Device> miscDevices = Collections.synchronizedSet(new LinkedHashSet<>());
@ConfigurableField(name = "Enable Speaker", shortName = "speaker", defaultValue = "true") @ConfigurableField(name = "Enable Speaker", shortName = "speaker", defaultValue = "true")
public static boolean enableSpeaker = true; public static boolean enableSpeaker = true;
public Speaker speaker; public Speaker speaker;

View File

@ -21,6 +21,7 @@ package jace.core;
import jace.apple2e.SoftSwitches; import jace.apple2e.SoftSwitches;
import jace.config.Reconfigurable; import jace.config.Reconfigurable;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -160,7 +161,7 @@ public abstract class RAM implements Reconfigurable {
int index = address & 0x0FF; int index = address & 0x0FF;
Set<RAMListener> ioListeners = ioListenerMap[index]; Set<RAMListener> ioListeners = ioListenerMap[index];
if (ioListeners == null) { if (ioListeners == null) {
ioListeners = new HashSet<>(); ioListeners = Collections.synchronizedSet(new HashSet<>());
ioListenerMap[index] = ioListeners; ioListenerMap[index] = ioListeners;
} }
ioListeners.add(l); ioListeners.add(l);
@ -168,7 +169,7 @@ public abstract class RAM implements Reconfigurable {
int index = address >> 8; int index = address >> 8;
Set<RAMListener> otherListeners = listenerMap[index]; Set<RAMListener> otherListeners = listenerMap[index];
if (otherListeners == null) { if (otherListeners == null) {
otherListeners = new HashSet<>(); otherListeners = Collections.synchronizedSet(new HashSet<>());
listenerMap[index] = otherListeners; listenerMap[index] = otherListeners;
} }
otherListeners.add(l); otherListeners.add(l);

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;
@ -80,7 +79,7 @@ public class CardMockingboard extends Card implements Runnable {
Condition playbackFinished = timerSync.newCondition(); Condition playbackFinished = timerSync.newCondition();
@ConfigurableField(name = "Idle sample threshold", description = "Number of samples to wait before suspending sound") @ConfigurableField(name = "Idle sample threshold", description = "Number of samples to wait before suspending sound")
private int MAX_IDLE_SAMPLES = SAMPLE_RATE; private int MAX_IDLE_SAMPLES = SAMPLE_RATE;
@Override @Override
public String getDeviceName() { public String getDeviceName() {
return "Mockingboard"; return "Mockingboard";
@ -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();
}
}
}; };
} }
} }
@ -140,6 +146,18 @@ public class CardMockingboard extends Card implements Runnable {
suspend(); suspend();
} }
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) {
@ -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,21 @@ 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();
} }
}
private void doSoundTick() {
if (isRunning() && !pause) { if (isRunning() && !pause) {
// buildMixerTable(); // buildMixerTable();
timerSync.lock(); timerSync.lock();
@ -194,7 +220,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 +289,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 +317,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;
} }

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) {

View File

@ -1,7 +1,5 @@
package jace.lawless; package jace.lawless;
import jace.apple2e.MOS65C02;
import jace.apple2e.SoftSwitches;
import jace.cheat.Cheats; import jace.cheat.Cheats;
import jace.core.Computer; import jace.core.Computer;
import jace.core.RAMEvent; import jace.core.RAMEvent;
@ -12,11 +10,6 @@ import jace.lawless.LawlessVideo.RenderEngine;
*/ */
public class LawlessHacks extends Cheats { public class LawlessHacks extends Cheats {
// Location of font routines
int FONT_ROUTINES = 0x0EC00;
int FONT_ROUTINES_END = 0x0f800;
int FONT_SPEEDUP_CYCLES = 10000;
int FONT_ROUTINES_LEN = 0x0f00;
// Modes specified by the game engine // Modes specified by the game engine
int MODE_SOFTSWITCH = 0x0C020; int MODE_SOFTSWITCH = 0x0C020;
@ -28,21 +21,6 @@ public class LawlessHacks extends Cheats {
@Override @Override
public void registerListeners() { public void registerListeners() {
// Observe graphics changes // Observe graphics changes
addCheat(RAMEvent.TYPE.WRITE, (e) -> {
if (e.getAddress() >= 0x02000 && e.getAddress() <= 0x05FFF) {
((LawlessVideo) computer.getVideo()).setBWFlag(e.getAddress(),
!SoftSwitches.RAMWRT.getState() ||
computer.getCpu().getProgramCounter() < FONT_ROUTINES ||
computer.getCpu().getProgramCounter() > FONT_ROUTINES_END);
}
}, 0x02000, 0x05FFF);
// Watch for font routine usage for speedup
addCheat(RAMEvent.TYPE.EXECUTE, (e) -> {
if ((e.getAddress() & 0x0ff00) == FONT_ROUTINES) {
computer.motherboard.requestSpeed(this);
}
}, FONT_ROUTINES, FONT_ROUTINES | 0x0ff);
// Try to detect engines changing
addCheat(RAMEvent.TYPE.ANY, false, (e) -> { addCheat(RAMEvent.TYPE.ANY, false, (e) -> {
if ((e.getAddress() & 0x0FFF0) == MODE_SOFTSWITCH) { if ((e.getAddress() & 0x0FFF0) == MODE_SOFTSWITCH) {
System.out.println("Trapped " + e.getType().toString() + " to $"+Integer.toHexString(e.getAddress())); System.out.println("Trapped " + e.getType().toString() + " to $"+Integer.toHexString(e.getAddress()));

View File

@ -84,25 +84,6 @@ public class LawlessVideo extends VideoNTSC {
System.out.println("Detected engine same as before: " + e.name()); System.out.println("Detected engine same as before: " + e.name());
} }
} }
public void setBWFlag(int addr, boolean b) {
addr &= 0x01FFF;
int row = VideoNTSC.identifyHiresRow(addr);
if (row < 0 || row > 192) {
return;
}
int col = addr - VideoNTSC.calculateHiresOffset(row);
/*
if (row > 20 && row < 136 && col < 20) {
boolean prev = activeMask[row][col*2];
activeMask[row][col*2] = b;
activeMask[row][col*2+1] = b;
if (prev ^ b) {
redraw();
}
}
*/
}
static public int[] divBy56 = new int[560]; static public int[] divBy56 = new int[560];