forked from Apple-2-Tools/jace
No-slot clock support added, thanks to Nick Westgate and the AppleWin team!
This commit is contained in:
parent
8e4a406f74
commit
913d2c654f
@ -34,6 +34,7 @@ import jace.hardware.CardDiskII;
|
||||
import jace.hardware.CardExt80Col;
|
||||
import jace.hardware.ConsoleProbe;
|
||||
import jace.hardware.Joystick;
|
||||
import jace.hardware.NoSlotClock;
|
||||
import jace.hardware.massStorage.CardMassStorage;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -59,7 +60,6 @@ public class Apple2e extends Computer {
|
||||
@ConfigurableField(name = "Slot 1", shortName = "s1card")
|
||||
public ClassSelection card1 = new ClassSelection(Card.class, null);
|
||||
@ConfigurableField(name = "Slot 2", shortName = "s2card")
|
||||
// public Class<? extends Card> card2 = CardSSC.class;
|
||||
public ClassSelection card2 = new ClassSelection(Card.class, null);
|
||||
@ConfigurableField(name = "Slot 3", shortName = "s3card")
|
||||
public ClassSelection card3 = new ClassSelection(Card.class, null);
|
||||
@ -86,12 +86,15 @@ public class Apple2e extends Computer {
|
||||
public boolean joy1enabled = false;
|
||||
@ConfigurableField(name = "Joystick 2 Enabled", shortName = "joy2", description = "If unchecked, then there is no joystick support.", enablesDevice = true)
|
||||
public boolean joy2enabled = false;
|
||||
@ConfigurableField(name = "No-Slot Clock Enabled", shortName = "clock", description = "If checked, no-slot clock will be enabled", enablesDevice = true)
|
||||
public boolean clockEnabled = true;
|
||||
|
||||
public Joystick joystick1;
|
||||
public Joystick joystick2;
|
||||
@ConfigurableField(name = "Activate Cheats", shortName = "cheat", defaultValue = "")
|
||||
public ClassSelection cheatEngine = new ClassSelection(Cheats.class, null);
|
||||
public Cheats activeCheatEngine = null;
|
||||
public NoSlotClock clock;
|
||||
|
||||
/**
|
||||
* Creates a new instance of Apple2e
|
||||
@ -218,27 +221,43 @@ public class Apple2e extends Computer {
|
||||
}
|
||||
}
|
||||
currentMemory.reconfigure();
|
||||
|
||||
if (joy1enabled) {
|
||||
if (joystick1 == null) {
|
||||
joystick1 = new Joystick(0, this);
|
||||
motherboard.miscDevices.add(joystick1);
|
||||
|
||||
if (motherboard != null) {
|
||||
if (joy1enabled) {
|
||||
if (joystick1 == null) {
|
||||
joystick1 = new Joystick(0, this);
|
||||
motherboard.miscDevices.add(joystick1);
|
||||
joystick1.attach();
|
||||
}
|
||||
} else if (joystick1 != null) {
|
||||
joystick1.detach();
|
||||
motherboard.miscDevices.remove(joystick1);
|
||||
joystick1 = null;
|
||||
}
|
||||
} else if (joystick1 != null) {
|
||||
joystick1.detach();
|
||||
motherboard.miscDevices.remove(joystick1);
|
||||
joystick1 = null;
|
||||
}
|
||||
|
||||
if (joy2enabled) {
|
||||
if (joystick2 == null) {
|
||||
joystick2 = new Joystick(1, this);
|
||||
motherboard.miscDevices.add(joystick2);
|
||||
|
||||
if (joy2enabled) {
|
||||
if (joystick2 == null) {
|
||||
joystick2 = new Joystick(1, this);
|
||||
motherboard.miscDevices.add(joystick2);
|
||||
joystick2.attach();
|
||||
}
|
||||
} else if (joystick2 != null) {
|
||||
joystick2.detach();
|
||||
motherboard.miscDevices.remove(joystick2);
|
||||
joystick2 = null;
|
||||
}
|
||||
|
||||
if (clockEnabled) {
|
||||
if (clock == null) {
|
||||
clock = new NoSlotClock(this);
|
||||
motherboard.miscDevices.add(clock);
|
||||
clock.attach();
|
||||
}
|
||||
} else if (clock != null) {
|
||||
motherboard.miscDevices.remove(clock);
|
||||
clock.detach();
|
||||
clock = null;
|
||||
}
|
||||
} else if (joystick2 != null) {
|
||||
joystick2.detach();
|
||||
motherboard.miscDevices.remove(joystick2);
|
||||
joystick2 = null;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -67,8 +67,6 @@ public class CardThunderclock extends Card {
|
||||
Logger.getLogger(CardDiskII.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
clockIcon = Utility.loadIconLabel("clock.png");
|
||||
clockFixIcon = Utility.loadIconLabel("clock_fix.png");
|
||||
clockFixIcon.setText("Fixed");
|
||||
}
|
||||
|
||||
// Raw format: 40 bits, in BCD form (it actually streams out in the reverse order of this, bit 0 first)
|
||||
@ -151,7 +149,7 @@ public class CardThunderclock extends Card {
|
||||
shiftMode = isShift;
|
||||
if (isRead) {
|
||||
if (attemptYearPatch) {
|
||||
performProdosPatch();
|
||||
performProdosPatch(computer);
|
||||
}
|
||||
getTime();
|
||||
clockIcon.setText("Slot " + getSlot());
|
||||
@ -288,14 +286,14 @@ public class CardThunderclock extends Card {
|
||||
(byte) 0x0f2
|
||||
};
|
||||
static int DRIVER_OFFSET = -26;
|
||||
int patchLoc = -1;
|
||||
static int patchLoc = -1;
|
||||
|
||||
/**
|
||||
* Scan active memory for the Prodos clock driver and patch the internal
|
||||
* code to use a fixed value for the present year. This means Prodos will
|
||||
* always tell time correctly.
|
||||
*/
|
||||
private void performProdosPatch() {
|
||||
public static void performProdosPatch(Computer computer) {
|
||||
PagedMemory ram = computer.getMemory().activeRead;
|
||||
if (patchLoc > 0) {
|
||||
// We've already patched, just validate
|
||||
@ -325,6 +323,8 @@ public class CardThunderclock extends Card {
|
||||
ram.writeByte(patchLoc + 1, (byte) year);
|
||||
ram.writeByte(patchLoc + 2, (byte) MOS65C02.OPCODE.NOP.getCode());
|
||||
ram.writeByte(patchLoc + 3, (byte) MOS65C02.OPCODE.NOP.getCode());
|
||||
EmulatorUILogic.addIndicator(this, clockFixIcon, 4000);
|
||||
Label clockFixIcon = Utility.loadIconLabel("clock_fix.png");
|
||||
clockFixIcon.setText("Fixed");
|
||||
EmulatorUILogic.addIndicator(CardThunderclock.class, clockFixIcon, 4000);
|
||||
}
|
||||
}
|
167
src/main/java/jace/hardware/NoSlotClock.java
Normal file
167
src/main/java/jace/hardware/NoSlotClock.java
Normal file
@ -0,0 +1,167 @@
|
||||
package jace.hardware;
|
||||
|
||||
import jace.EmulatorUILogic;
|
||||
import jace.apple2e.SoftSwitches;
|
||||
import jace.config.ConfigurableField;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Device;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import jace.core.Utility;
|
||||
import java.util.Calendar;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
/**
|
||||
* Provide No-slot-clock compatibility
|
||||
*
|
||||
* @author blurry
|
||||
*/
|
||||
public class NoSlotClock extends Device {
|
||||
|
||||
boolean clockActive;
|
||||
public long detectSequence = 0x5ca33ac55ca33ac5L;
|
||||
public long testSequence = 0;
|
||||
public long testMask = 0;
|
||||
public long dataRegister = 0;
|
||||
public long dataRegisterBit = 0;
|
||||
public int patternCount = 0;
|
||||
public boolean writeEnabled = false;
|
||||
@ConfigurableField(category = "Clock", name = "Patch Prodos", description = "If enabled, prodos clock routines will be patched directly", defaultValue = "false")
|
||||
public boolean patchProdosClock = false;
|
||||
Label clockIcon;
|
||||
|
||||
private final RAMListener listener = new RAMListener(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(0x0C100);
|
||||
setScopeEnd(0x0CFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(RAMEvent e) {
|
||||
// Ref: Sather UAIIe 5-28
|
||||
if (SoftSwitches.CXROM.isOn()) {
|
||||
return true;
|
||||
}
|
||||
if ((e.getAddress() & 0x0ff00) == 0x0c300 && SoftSwitches.SLOTC3ROM.isOff()) {
|
||||
return true;
|
||||
}
|
||||
return e.getAddress() >= 0x0c800 && SoftSwitches.INTC8ROM.isOn();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
boolean readMode = (e.getAddress() & 0x04) != 0;
|
||||
if (clockActive) {
|
||||
if (readMode) {
|
||||
int val = e.getOldValue() & 0b011111110;
|
||||
int bit = getNextDataBit();
|
||||
val |= bit;
|
||||
e.setNewValue(val);
|
||||
} else if (writeEnabled) {
|
||||
fakeWrite(e);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
dataRegisterBit++;
|
||||
if (dataRegisterBit >= 64) {
|
||||
deactivateClock();
|
||||
}
|
||||
} else if (readMode) {
|
||||
writeEnabled = true;
|
||||
testSequence = detectSequence;
|
||||
patternCount = 0;
|
||||
} else if (writeEnabled) {
|
||||
int bit = e.getAddress() & 0x01;
|
||||
if (bit == (testSequence & 0x01)) {
|
||||
testSequence >>= 1;
|
||||
patternCount++;
|
||||
if (patternCount == 64) {
|
||||
activateClock();
|
||||
}
|
||||
} else {
|
||||
writeEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public NoSlotClock(Computer computer) {
|
||||
super(computer);
|
||||
this.clockIcon = Utility.loadIconLabel("clock.png");
|
||||
this.clockIcon.setText("No Slot Clock");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
return "No Slot Clock";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "clock";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconfigure() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach() {
|
||||
computer.getMemory().addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
computer.getMemory().removeListener(listener);
|
||||
}
|
||||
|
||||
public void activateClock() {
|
||||
Calendar now = Calendar.getInstance();
|
||||
dataRegisterBit = 0;
|
||||
dataRegister = 0L;
|
||||
storeBCD(now.get(Calendar.MILLISECOND) / 10, 0);
|
||||
storeBCD(now.get(Calendar.SECOND), 1);
|
||||
storeBCD(now.get(Calendar.MINUTE), 2);
|
||||
storeBCD(now.get(Calendar.HOUR), 3);
|
||||
storeBCD(now.get(Calendar.DAY_OF_WEEK), 4);
|
||||
storeBCD(now.get(Calendar.DAY_OF_MONTH), 5);
|
||||
storeBCD(now.get(Calendar.MONTH) + 1, 6);
|
||||
storeBCD(now.get(Calendar.YEAR) % 100, 7);
|
||||
clockActive = true;
|
||||
EmulatorUILogic.addIndicator(this, clockIcon, 1000);
|
||||
if (patchProdosClock) {
|
||||
CardThunderclock.performProdosPatch(computer);
|
||||
}
|
||||
}
|
||||
|
||||
public void storeBCD(int val, int offset) {
|
||||
storeNibble(val % 10, offset * 8);
|
||||
storeNibble(val / 10, offset * 8 + 4);
|
||||
}
|
||||
|
||||
public void storeNibble(int val, int offset) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((val & 1) != 0) {
|
||||
dataRegister |= (1L << (offset + i));
|
||||
}
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivateClock() {
|
||||
clockActive = false;
|
||||
}
|
||||
|
||||
public int getNextDataBit() {
|
||||
return (int) ((dataRegister >> dataRegisterBit) & 0x01);
|
||||
}
|
||||
|
||||
public void fakeWrite(RAMEvent e) {
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user