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
PLA
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
PHA
PLP

View File

@ -21,6 +21,7 @@ package jace.core;
import jace.apple2e.SoftSwitches;
import jace.apple2e.Speaker;
import jace.config.ConfigurableField;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Optional;
@ -40,7 +41,7 @@ import java.util.logging.Logger;
*/
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")
public static boolean enableSpeaker = true;
public Speaker speaker;

View File

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

View File

@ -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;
}

View File

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

View File

@ -1,7 +1,5 @@
package jace.lawless;
import jace.apple2e.MOS65C02;
import jace.apple2e.SoftSwitches;
import jace.cheat.Cheats;
import jace.core.Computer;
import jace.core.RAMEvent;
@ -12,11 +10,6 @@ import jace.lawless.LawlessVideo.RenderEngine;
*/
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
int MODE_SOFTSWITCH = 0x0C020;
@ -28,21 +21,6 @@ public class LawlessHacks extends Cheats {
@Override
public void registerListeners() {
// 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) -> {
if ((e.getAddress() & 0x0FFF0) == MODE_SOFTSWITCH) {
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());
}
}
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];