forked from Apple-2-Tools/jace
Complete removal of the singleton pattern for the Computer object -- the Jace code can now run multiple "computers" if desired.
This commit is contained in:
parent
4b26a07c7f
commit
45add680d4
@ -71,10 +71,9 @@ public class ConvertDiskImage {
|
||||
// First read in the disk image, this decodes the disk as necessary
|
||||
FloppyDisk theDisk = null;
|
||||
try {
|
||||
theDisk = new FloppyDisk(in);
|
||||
theDisk = new FloppyDisk(in, null);
|
||||
} catch (IOException ex) {
|
||||
System.out.println("Couldn't read disk image");
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
if (!writeNibblized) {
|
||||
|
@ -20,7 +20,6 @@ package jace;
|
||||
|
||||
import jace.apple2e.Apple2e;
|
||||
import jace.config.Configuration;
|
||||
import jace.core.Computer;
|
||||
import jace.ui.AbstractEmulatorFrame;
|
||||
import jace.ui.EmulatorFrame;
|
||||
import java.awt.Component;
|
||||
@ -57,7 +56,7 @@ public class Emulator {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public Apple2e computer;
|
||||
public static Apple2e computer;
|
||||
public AbstractEmulatorFrame theApp;
|
||||
|
||||
/**
|
||||
@ -91,7 +90,7 @@ public class Emulator {
|
||||
Configuration.applySettings(settings);
|
||||
|
||||
// theApp = new MainFrame();
|
||||
theApp = new EmulatorFrame();
|
||||
theApp = new EmulatorFrame(computer);
|
||||
try {
|
||||
theApp.setIconImage(ImageIO.read(Emulator.class.getClassLoader().getResourceAsStream("jace/data/woz_figure.gif")));
|
||||
} catch (IOException ex) {
|
||||
@ -139,12 +138,12 @@ public class Emulator {
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) {
|
||||
Computer.getComputer().getVideo().suspend();
|
||||
computer.getVideo().suspend();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {
|
||||
Computer.getComputer().getVideo().resume();
|
||||
computer.getVideo().resume();
|
||||
resizeVideo();
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ import jace.apple2e.SoftSwitches;
|
||||
import jace.config.ConfigurationPanel;
|
||||
import jace.config.InvokableAction;
|
||||
import jace.core.CPU;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Debugger;
|
||||
import jace.core.RAM;
|
||||
import jace.core.RAMEvent;
|
||||
@ -69,7 +68,7 @@ public class EmulatorUILogic {
|
||||
@Override
|
||||
public void updateStatus() {
|
||||
enableDebug(true);
|
||||
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu();
|
||||
MOS65C02 cpu = (MOS65C02) Emulator.computer.getCpu();
|
||||
updateCPURegisters(cpu);
|
||||
}
|
||||
};
|
||||
@ -95,7 +94,7 @@ public class EmulatorUILogic {
|
||||
}
|
||||
|
||||
public static void enableTrace(boolean b) {
|
||||
Computer.getComputer().getCpu().setTraceEnabled(b);
|
||||
Emulator.computer.getCpu().setTraceEnabled(b);
|
||||
}
|
||||
|
||||
public static void stepForward() {
|
||||
@ -103,7 +102,7 @@ public class EmulatorUILogic {
|
||||
}
|
||||
|
||||
static void registerDebugger() {
|
||||
Computer.getComputer().getCpu().setDebug(debugger);
|
||||
Emulator.computer.getCpu().setDebug(debugger);
|
||||
}
|
||||
|
||||
public static Integer getValidAddress(String s) {
|
||||
@ -122,7 +121,7 @@ public class EmulatorUILogic {
|
||||
public static void updateWatchList(final DebuggerPanel panel) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
watches.stream().forEach((oldWatch) -> {
|
||||
Computer.getComputer().getMemory().removeListener(oldWatch);
|
||||
Emulator.computer.getMemory().removeListener(oldWatch);
|
||||
});
|
||||
if (panel == null) {
|
||||
return;
|
||||
@ -149,10 +148,10 @@ public class EmulatorUILogic {
|
||||
watchValue.setText(Integer.toHexString(e.getNewValue() & 0x0FF));
|
||||
}
|
||||
};
|
||||
Computer.getComputer().getMemory().addListener(newListener);
|
||||
Emulator.computer.getMemory().addListener(newListener);
|
||||
watches.add(newListener);
|
||||
// Print out the current value right away
|
||||
byte b = Computer.getComputer().getMemory().readRaw(address);
|
||||
byte b = Emulator.computer.getMemory().readRaw(address);
|
||||
watchValue.setText(Integer.toString(b & 0x0ff, 16));
|
||||
} else {
|
||||
watchValue.setText("00");
|
||||
@ -192,12 +191,12 @@ public class EmulatorUILogic {
|
||||
description = "Loads a binary file in memory and executes it. File should end with #06xxxx, where xxxx is the start address in hex",
|
||||
alternatives = "Execute program;Load binary;Load program;Load rom;Play single-load game")
|
||||
public static void runFile() {
|
||||
Computer.pause();
|
||||
Emulator.computer.pause();
|
||||
JFileChooser select = new JFileChooser();
|
||||
select.showDialog(Emulator.getFrame(), "Execute binary file");
|
||||
File binary = select.getSelectedFile();
|
||||
if (binary == null) {
|
||||
Computer.resume();
|
||||
Emulator.computer.resume();
|
||||
return;
|
||||
}
|
||||
runFile(binary);
|
||||
@ -215,7 +214,7 @@ public class EmulatorUILogic {
|
||||
}
|
||||
} catch (NumberFormatException | IOException ex) {
|
||||
}
|
||||
Computer.getComputer().getCpu().resume();
|
||||
Emulator.computer.getCpu().resume();
|
||||
}
|
||||
|
||||
public static void brun(File binary, int address) throws FileNotFoundException, IOException {
|
||||
@ -223,17 +222,17 @@ public class EmulatorUILogic {
|
||||
// If it was not yet halted, then it is the case that the CPU is processing another opcode
|
||||
// So if that is the case, the program counter will need to be decremented here to compensate
|
||||
// TODO: Find a better mousetrap for this one -- it's an ugly hack
|
||||
Computer.pause();
|
||||
Emulator.computer.pause();
|
||||
FileInputStream in = new FileInputStream(binary);
|
||||
byte[] data = new byte[in.available()];
|
||||
in.read(data);
|
||||
RAM ram = Computer.getComputer().getMemory();
|
||||
RAM ram = Emulator.computer.getMemory();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
ram.write(address + i, data[i], false, true);
|
||||
}
|
||||
CPU cpu = Computer.getComputer().getCpu();
|
||||
Computer.getComputer().getCpu().setProgramCounter(address);
|
||||
Computer.resume();
|
||||
CPU cpu = Emulator.computer.getCpu();
|
||||
Emulator.computer.getCpu().setProgramCounter(address);
|
||||
Emulator.computer.resume();
|
||||
}
|
||||
|
||||
@InvokableAction(
|
||||
@ -246,9 +245,9 @@ public class EmulatorUILogic {
|
||||
if (frame == null) {
|
||||
return;
|
||||
}
|
||||
Computer.pause();
|
||||
Emulator.computer.pause();
|
||||
frame.enforceIntegerRatio();
|
||||
Computer.resume();
|
||||
Emulator.computer.resume();
|
||||
}
|
||||
|
||||
@InvokableAction(
|
||||
@ -271,9 +270,9 @@ public class EmulatorUILogic {
|
||||
if (frame == null) {
|
||||
return;
|
||||
}
|
||||
Computer.pause();
|
||||
Emulator.computer.pause();
|
||||
frame.toggleFullscreen();
|
||||
Computer.resume();
|
||||
Emulator.computer.resume();
|
||||
}
|
||||
|
||||
@InvokableAction(
|
||||
@ -285,7 +284,7 @@ public class EmulatorUILogic {
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
|
||||
String timestamp = df.format(new Date());
|
||||
String type;
|
||||
int start = Computer.getComputer().getVideo().getCurrentWriter().actualWriter().getYOffset(0);
|
||||
int start = Emulator.computer.getVideo().getCurrentWriter().actualWriter().getYOffset(0);
|
||||
int len;
|
||||
if (start < 0x02000) {
|
||||
// Lo-res or double-lores
|
||||
@ -302,8 +301,8 @@ public class EmulatorUILogic {
|
||||
}
|
||||
File outFile = new File("screen_" + type + "_a" + Integer.toHexString(start) + "_" + timestamp);
|
||||
try (FileOutputStream out = new FileOutputStream(outFile)) {
|
||||
RAM128k ram = (RAM128k) Computer.getComputer().memory;
|
||||
Computer.pause();
|
||||
RAM128k ram = (RAM128k) Emulator.computer.memory;
|
||||
Emulator.computer.pause();
|
||||
if (dres) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
out.write(ram.getAuxVideoMemory().readByte(start + i));
|
||||
@ -323,8 +322,8 @@ public class EmulatorUILogic {
|
||||
alternatives = "Save image,save framebuffer,screenshot")
|
||||
public static void saveScreenshot() throws HeadlessException, IOException {
|
||||
JFileChooser select = new JFileChooser();
|
||||
Computer.pause();
|
||||
BufferedImage i = Computer.getComputer().getVideo().getFrameBuffer();
|
||||
Emulator.computer.pause();
|
||||
BufferedImage i = Emulator.computer.getVideo().getFrameBuffer();
|
||||
BufferedImage j = new BufferedImage(i.getWidth(), i.getHeight(), i.getType());
|
||||
j.getGraphics().drawImage(i, 0, 0, null);
|
||||
select.showSaveDialog(Emulator.getFrame());
|
||||
|
@ -37,6 +37,7 @@ import jace.hardware.Joystick;
|
||||
import jace.hardware.massStorage.CardMassStorage;
|
||||
import java.awt.Graphics;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@ -49,13 +50,12 @@ import java.util.logging.Logger;
|
||||
* overall configuration of the computer, but the actual operation of the
|
||||
* computer and its timing characteristics are managed in the Motherboard class.
|
||||
*
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
@Stateful
|
||||
public class Apple2e extends Computer {
|
||||
|
||||
static int IRQ_VECTOR = 0x003F2;
|
||||
public Motherboard motherboard;
|
||||
@ConfigurableField(name = "Slot 1", shortName = "s1card")
|
||||
public ClassSelection card1 = new ClassSelection(Card.class, null);
|
||||
@ConfigurableField(name = "Slot 2", shortName = "s2card")
|
||||
@ -96,9 +96,9 @@ public class Apple2e extends Computer {
|
||||
try {
|
||||
reconfigure();
|
||||
// Setup core resources
|
||||
joystick1 = new Joystick(0);
|
||||
joystick2 = new Joystick(1);
|
||||
setCpu(new MOS65C02());
|
||||
joystick1 = new Joystick(0, this);
|
||||
joystick2 = new Joystick(1, this);
|
||||
setCpu(new MOS65C02(this));
|
||||
reinitMotherboard();
|
||||
} catch (Throwable t) {
|
||||
System.err.println("Unable to initalize virtual machine");
|
||||
@ -115,7 +115,7 @@ public class Apple2e extends Computer {
|
||||
if (motherboard != null && motherboard.isRunning()) {
|
||||
motherboard.suspend();
|
||||
}
|
||||
motherboard = new Motherboard();
|
||||
motherboard = new Motherboard(this);
|
||||
motherboard.reconfigure();
|
||||
Motherboard.miscDevices.add(joystick1);
|
||||
Motherboard.miscDevices.add(joystick2);
|
||||
@ -123,7 +123,7 @@ public class Apple2e extends Computer {
|
||||
|
||||
@Override
|
||||
public void coldStart() {
|
||||
Computer.pause();
|
||||
pause();
|
||||
reinitMotherboard();
|
||||
reboot();
|
||||
//getMemory().dump();
|
||||
@ -139,7 +139,7 @@ public class Apple2e extends Computer {
|
||||
}
|
||||
}
|
||||
|
||||
Computer.resume();
|
||||
resume();
|
||||
/*
|
||||
getCpu().resume();
|
||||
getVideo().resume();
|
||||
@ -156,7 +156,7 @@ public class Apple2e extends Computer {
|
||||
|
||||
@Override
|
||||
public void warmStart() {
|
||||
boolean restart = Computer.pause();
|
||||
boolean restart = pause();
|
||||
for (SoftSwitches s : SoftSwitches.values()) {
|
||||
s.getSwitch().reset();
|
||||
}
|
||||
@ -169,10 +169,10 @@ public class Apple2e extends Computer {
|
||||
}
|
||||
}
|
||||
getCpu().resume();
|
||||
Computer.resume();
|
||||
resume();
|
||||
}
|
||||
|
||||
private void insertCard(Class<? extends Card> type, int slot) {
|
||||
private void insertCard(Class<? extends Card> type, int slot) throws NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
|
||||
if (getMemory().getCard(slot) != null) {
|
||||
if (getMemory().getCard(slot).getClass().equals(type)) {
|
||||
return;
|
||||
@ -181,7 +181,8 @@ public class Apple2e extends Computer {
|
||||
}
|
||||
if (type != null) {
|
||||
try {
|
||||
getMemory().addCard(type.newInstance(), slot);
|
||||
Card card = type.getConstructor(Computer.class).newInstance(this);
|
||||
getMemory().addCard(card, slot);
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
@ -190,10 +191,10 @@ public class Apple2e extends Computer {
|
||||
|
||||
@Override
|
||||
public final void reconfigure() {
|
||||
boolean restart = Computer.pause();
|
||||
boolean restart = pause();
|
||||
|
||||
super.reconfigure();
|
||||
|
||||
|
||||
RAM128k currentMemory = (RAM128k) getMemory();
|
||||
if (currentMemory != null && !(currentMemory.getClass().equals(ramCard.getValue()))) {
|
||||
try {
|
||||
@ -212,7 +213,7 @@ public class Apple2e extends Computer {
|
||||
try {
|
||||
setMemory(currentMemory);
|
||||
for (SoftSwitches s : SoftSwitches.values()) {
|
||||
s.getSwitch().register();
|
||||
s.getSwitch().register(this);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
@ -250,14 +251,18 @@ public class Apple2e extends Computer {
|
||||
}
|
||||
}
|
||||
|
||||
// Add all new cards
|
||||
insertCard(card1.getValue(), 1);
|
||||
insertCard(card2.getValue(), 2);
|
||||
insertCard(card3.getValue(), 3);
|
||||
insertCard(card4.getValue(), 4);
|
||||
insertCard(card5.getValue(), 5);
|
||||
insertCard(card6.getValue(), 6);
|
||||
insertCard(card7.getValue(), 7);
|
||||
try {
|
||||
// Add all new cards
|
||||
insertCard(card1.getValue(), 1);
|
||||
insertCard(card2.getValue(), 2);
|
||||
insertCard(card3.getValue(), 3);
|
||||
insertCard(card4.getValue(), 4);
|
||||
insertCard(card5.getValue(), 5);
|
||||
insertCard(card6.getValue(), 6);
|
||||
insertCard(card7.getValue(), 7);
|
||||
} catch (NoSuchMethodException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (enableHints) {
|
||||
enableHints();
|
||||
} else {
|
||||
@ -293,7 +298,7 @@ public class Apple2e extends Computer {
|
||||
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (restart) {
|
||||
Computer.resume();
|
||||
resume();
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,7 +347,7 @@ public class Apple2e extends Computer {
|
||||
if (getCpu().getProgramCounter() >> 8 != 0x0c6) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int row = 2;
|
||||
for (String s : new String[]{
|
||||
" Welcome to",
|
||||
|
@ -68,8 +68,12 @@ public class MOS65C02 extends CPU {
|
||||
@ConfigurableField(name = "Ext. opcode warnings", description = "If on, uses of 65c02 extended opcodes (or undocumented 6502 opcodes -- which will fail) will be logged to stdout for debugging purposes")
|
||||
public boolean warnAboutExtendedOpcodes = false;
|
||||
|
||||
private static RAM getMemory() {
|
||||
return Computer.getComputer().getMemory();
|
||||
private RAM getMemory() {
|
||||
return computer.getMemory();
|
||||
}
|
||||
|
||||
public MOS65C02(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -344,7 +348,7 @@ public class MOS65C02 extends CPU {
|
||||
|
||||
default int getValue(boolean isRead, MOS65C02 cpu) {
|
||||
int address = calculateAddress(cpu);
|
||||
return (address > -1) ? (0x0ff & getMemory().read(address, TYPE.READ_DATA, isRead, false)) : 0;
|
||||
return (address > -1) ? (0x0ff & cpu.getMemory().read(address, TYPE.READ_DATA, isRead, false)) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,42 +358,42 @@ public class MOS65C02 extends CPU {
|
||||
// RELATIVE(2, "#$~1 ($R)"),
|
||||
RELATIVE(2, "$R", (cpu) -> {
|
||||
int pc = cpu.getProgramCounter();
|
||||
int address = pc + 2 + getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
int address = pc + 2 + cpu.getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
// The wait cycles are not added unless the branch actually happens!
|
||||
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00));
|
||||
return address;
|
||||
}),
|
||||
IMMEDIATE(2, "#$~1", (cpu) -> cpu.getProgramCounter() + 1),
|
||||
ZEROPAGE(2, "$~1", (cpu) -> getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) & 0x00FF),
|
||||
ZEROPAGE_X(2, "$~1,X", (cpu) -> 0x0FF & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X)),
|
||||
ZEROPAGE_Y(2, "$~1,Y", (cpu) -> 0x0FF & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.Y)),
|
||||
ZEROPAGE(2, "$~1", (cpu) -> cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) & 0x00FF),
|
||||
ZEROPAGE_X(2, "$~1,X", (cpu) -> 0x0FF & (cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X)),
|
||||
ZEROPAGE_Y(2, "$~1,Y", (cpu) -> 0x0FF & (cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.Y)),
|
||||
INDIRECT(3, "$(~2~1)", (cpu) -> {
|
||||
int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
return getMemory().readWord(address, TYPE.READ_DATA, true, false);
|
||||
int address = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
return cpu.getMemory().readWord(address, TYPE.READ_DATA, true, false);
|
||||
}),
|
||||
INDIRECT_X(3, "$(~2~1,X)", (cpu) -> {
|
||||
int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
|
||||
return getMemory().readWord(address & 0x0FFFF, TYPE.READ_DATA, true, false);
|
||||
int address = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
|
||||
return cpu.getMemory().readWord(address & 0x0FFFF, TYPE.READ_DATA, true, false);
|
||||
}),
|
||||
INDIRECT_ZP(2, "$(~1)", (cpu) -> {
|
||||
int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
|
||||
int address = cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
return cpu.getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
|
||||
}),
|
||||
INDIRECT_ZP_X(2, "$(~1,X)", (cpu) -> {
|
||||
int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
|
||||
return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
|
||||
int address = cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
|
||||
return cpu.getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
|
||||
}),
|
||||
INDIRECT_ZP_Y(2, "$(~1),Y", (cpu) -> {
|
||||
int address = 0x00FF & getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
address = getMemory().readWord(address, TYPE.READ_DATA, true, false) + cpu.Y;
|
||||
int address = 0x00FF & cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
address = cpu.getMemory().readWord(address, TYPE.READ_DATA, true, false) + cpu.Y;
|
||||
if ((address & 0x00ff00) > 0) {
|
||||
cpu.addWaitCycles(1);
|
||||
}
|
||||
return address;
|
||||
}),
|
||||
ABSOLUTE(3, "$~2~1", (cpu) -> getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false)),
|
||||
ABSOLUTE(3, "$~2~1", (cpu) -> cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false)),
|
||||
ABSOLUTE_X(3, "$~2~1,X", (cpu) -> {
|
||||
int address2 = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
int address2 = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
int address = 0x0FFFF & (address2 + cpu.X);
|
||||
if ((address & 0x00FF00) != (address2 & 0x00FF00)) {
|
||||
cpu.addWaitCycles(1);
|
||||
@ -397,7 +401,7 @@ public class MOS65C02 extends CPU {
|
||||
return address;
|
||||
}),
|
||||
ABSOLUTE_Y(3, "$~2~1,Y", (cpu) -> {
|
||||
int address2 = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
int address2 = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
int address = 0x0FFFF & (address2 + cpu.Y);
|
||||
if ((address & 0x00FF00) != (address2 & 0x00FF00)) {
|
||||
cpu.addWaitCycles(1);
|
||||
@ -407,9 +411,9 @@ public class MOS65C02 extends CPU {
|
||||
ZP_REL(2, "$~1,$R", new AddressCalculator() {
|
||||
@Override
|
||||
public int calculateAddress(MOS65C02 cpu) {
|
||||
// Note: This is two's compliment addition and the getMemory().read() returns a signed 8-bit value
|
||||
// Note: This is two's compliment addition and the cpu.getMemory().read() returns a signed 8-bit value
|
||||
int pc = cpu.getProgramCounter();
|
||||
int address = pc + 2 + getMemory().read(pc + 2, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
int address = pc + 2 + cpu.getMemory().read(pc + 2, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
// The wait cycles are not added unless the branch actually happens!
|
||||
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00));
|
||||
return address;
|
||||
@ -418,8 +422,8 @@ public class MOS65C02 extends CPU {
|
||||
@Override
|
||||
public int getValue(boolean isRead, MOS65C02 cpu) {
|
||||
int pc = cpu.getProgramCounter();
|
||||
int address = getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
return getMemory().read(address, TYPE.READ_DATA, true, false);
|
||||
int address = cpu.getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||
return cpu.getMemory().read(address, TYPE.READ_DATA, true, false);
|
||||
}
|
||||
});
|
||||
private int size;
|
||||
@ -473,16 +477,16 @@ public class MOS65C02 extends CPU {
|
||||
return calculator;
|
||||
}
|
||||
|
||||
public String formatMode(int pc) {
|
||||
public String formatMode(int pc, MOS65C02 cpu) {
|
||||
if (implied) {
|
||||
return "";
|
||||
} else {
|
||||
int b1 = 0x00ff & getMemory().readRaw((pc + 1) & 0x0FFFF);
|
||||
int b1 = 0x00ff & cpu.getMemory().readRaw((pc + 1) & 0x0FFFF);
|
||||
if (relative) {
|
||||
String R = wordString(pc + 2 + (byte) b1);
|
||||
return f1 + R;
|
||||
} else if (twoByte) {
|
||||
int b2 = 0x00ff & getMemory().readRaw((pc + 2) & 0x0FFFF);
|
||||
int b2 = 0x00ff & cpu.getMemory().readRaw((pc + 2) & 0x0FFFF);
|
||||
return f1 + byte2(b2) + byte2(b1) + f2;
|
||||
} else {
|
||||
return f1 + byte2(b1) + f2;
|
||||
@ -548,7 +552,7 @@ public class MOS65C02 extends CPU {
|
||||
public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
|
||||
int mask = 0x0ff ^ (1 << bit);
|
||||
value &= mask;
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,7 +568,7 @@ public class MOS65C02 extends CPU {
|
||||
public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
|
||||
int mask = 1 << bit;
|
||||
value |= mask;
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,8 +624,8 @@ public class MOS65C02 extends CPU {
|
||||
cpu.setNZ(value);
|
||||
// Emulate correct behavior of fetch-store-modify
|
||||
// http://forum.6502.org/viewtopic.php?f=4&t=1617&view=previous
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}),
|
||||
ASL_A((address, value, addressMode, cpu) -> {
|
||||
cpu.C = cpu.A >> 7;
|
||||
@ -738,8 +742,8 @@ public class MOS65C02 extends CPU {
|
||||
}),
|
||||
DEC((address, value, addressMode, cpu) -> {
|
||||
value = 0x0FF & (value - 1);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.setNZ(value);
|
||||
}),
|
||||
DEA((address, value, addressMode, cpu) -> {
|
||||
@ -761,8 +765,8 @@ public class MOS65C02 extends CPU {
|
||||
INC((address, value, addressMode, cpu) -> {
|
||||
value = 0x0ff & (value + 1);
|
||||
// emulator correct fetch-modify-store behavior
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.setNZ(value);
|
||||
}),
|
||||
INA((address, value, addressMode, cpu) -> {
|
||||
@ -801,8 +805,8 @@ public class MOS65C02 extends CPU {
|
||||
value = (value >> 1) & 0x07F;
|
||||
cpu.setNZ(value);
|
||||
// emulator correct fetch-modify-store behavior
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}),
|
||||
LSR_A((address, value, addressMode, cpu) -> {
|
||||
cpu.C = cpu.A & 1;
|
||||
@ -856,8 +860,8 @@ public class MOS65C02 extends CPU {
|
||||
value = 0x0ff & ((value << 1) | oldC);
|
||||
cpu.setNZ(value);
|
||||
// emulator correct fetch-modify-store behavior
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}),
|
||||
ROL_A((address, value, addressMode, cpu) -> {
|
||||
int oldC = cpu.C;
|
||||
@ -871,8 +875,8 @@ public class MOS65C02 extends CPU {
|
||||
value = 0x0ff & ((value >> 1) | oldC);
|
||||
cpu.setNZ(value);
|
||||
// emulator correct fetch-modify-store behavior
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}),
|
||||
ROR_A((address, value, addressMode, cpu) -> {
|
||||
int oldC = cpu.C << 7;
|
||||
@ -947,19 +951,19 @@ public class MOS65C02 extends CPU {
|
||||
SMB6(new SMBCommand(6)),
|
||||
SMB7(new SMBCommand(7)),
|
||||
STA(true, (address, value, addressMode, cpu) -> {
|
||||
getMemory().write(address, (byte) cpu.A, true, false);
|
||||
cpu.getMemory().write(address, (byte) cpu.A, true, false);
|
||||
}),
|
||||
STP((address, value, addressMode, cpu) -> {
|
||||
cpu.suspend();
|
||||
}),
|
||||
STX(true, (address, value, addressMode, cpu) -> {
|
||||
getMemory().write(address, (byte) cpu.X, true, false);
|
||||
cpu.getMemory().write(address, (byte) cpu.X, true, false);
|
||||
}),
|
||||
STY(true, (address, value, addressMode, cpu) -> {
|
||||
getMemory().write(address, (byte) cpu.Y, true, false);
|
||||
cpu.getMemory().write(address, (byte) cpu.Y, true, false);
|
||||
}),
|
||||
STZ(true, (address, value, addressMode, cpu) -> {
|
||||
getMemory().write(address, (byte) 0, true, false);
|
||||
cpu.getMemory().write(address, (byte) 0, true, false);
|
||||
}),
|
||||
TAX((address, value, addressMode, cpu) -> {
|
||||
cpu.X = cpu.A;
|
||||
@ -972,12 +976,12 @@ public class MOS65C02 extends CPU {
|
||||
TRB((address, value, addressMode, cpu) -> {
|
||||
cpu.C = (value & cpu.A) != 0 ? 1 : 0;
|
||||
value &= ~cpu.A;
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}),
|
||||
TSB((address, value, addressMode, cpu) -> {
|
||||
cpu.C = (value & cpu.A) != 0 ? 1 : 0;
|
||||
value |= cpu.A;
|
||||
getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
}),
|
||||
TSX((address, value, addressMode, cpu) -> {
|
||||
cpu.X = cpu.STACK;
|
||||
@ -1033,8 +1037,8 @@ public class MOS65C02 extends CPU {
|
||||
}
|
||||
int pc = getProgramCounter();
|
||||
|
||||
// RAM ram = getMemory();
|
||||
// int op = 0x00ff & getMemory().read(pc, false);
|
||||
// RAM ram = cpu.getMemory();
|
||||
// int op = 0x00ff & cpu.getMemory().read(pc, false);
|
||||
// This makes it possible to trap the memory read of an opcode, when PC == Address, you know it is executing that opcode.
|
||||
int op = 0x00ff & getMemory().read(pc, TYPE.EXECUTE, true, false);
|
||||
OPCODE opcode = opcodes[op];
|
||||
@ -1203,7 +1207,7 @@ public class MOS65C02 extends CPU {
|
||||
// Cold/Warm boot procedure
|
||||
@Override
|
||||
public void reset() {
|
||||
boolean restart = Computer.pause();
|
||||
boolean restart = computer.pause();
|
||||
pushWord(getProgramCounter());
|
||||
push(getStatus());
|
||||
// STACK = 0x0ff;
|
||||
@ -1219,7 +1223,7 @@ public class MOS65C02 extends CPU {
|
||||
System.out.println("Reset called, setting PC to (" + Integer.toString(RESET_VECTOR, 16) + ") = " + Integer.toString(newPC, 16));
|
||||
setProgramCounter(newPC);
|
||||
if (restart) {
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1276,13 +1280,13 @@ public class MOS65C02 extends CPU {
|
||||
|
||||
public String disassemble() {
|
||||
int pc = getProgramCounter();
|
||||
// RAM ram = getMemory();
|
||||
// RAM ram = cpu.getMemory();
|
||||
int op = getMemory().readRaw(pc);
|
||||
OPCODE o = opcodes[op & 0x0ff];
|
||||
if (o == null) {
|
||||
return "???";
|
||||
}
|
||||
String format = o.getMode().formatMode(pc);
|
||||
String format = o.getMode().formatMode(pc, this);
|
||||
// format = format.replaceAll("~1", byte2(b1));
|
||||
// format = format.replaceAll("~2", byte2(b2));
|
||||
// format = format.replaceAll("R", R);
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.apple2e;
|
||||
|
||||
import jace.core.CPU;
|
||||
import jace.core.Card;
|
||||
import jace.core.Computer;
|
||||
import jace.core.PagedMemory;
|
||||
@ -44,16 +45,16 @@ abstract public class RAM128k extends RAM {
|
||||
public PagedMemory rom;
|
||||
public PagedMemory blank;
|
||||
|
||||
public RAM128k() {
|
||||
super();
|
||||
mainMemory = new PagedMemory(0xc000, PagedMemory.Type.ram);
|
||||
rom = new PagedMemory(0x3000, PagedMemory.Type.firmwareMain);
|
||||
cPageRom = new PagedMemory(0x1000, PagedMemory.Type.slotRom);
|
||||
languageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard);
|
||||
languageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard);
|
||||
activeRead = new PagedMemory(0x10000, PagedMemory.Type.ram);
|
||||
activeWrite = new PagedMemory(0x10000, PagedMemory.Type.ram);
|
||||
blank = new PagedMemory(0x100, PagedMemory.Type.ram);
|
||||
public RAM128k(Computer computer) {
|
||||
super(computer);
|
||||
mainMemory = new PagedMemory(0xc000, PagedMemory.Type.ram, computer);
|
||||
rom = new PagedMemory(0x3000, PagedMemory.Type.firmwareMain, computer);
|
||||
cPageRom = new PagedMemory(0x1000, PagedMemory.Type.slotRom, computer);
|
||||
languageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard, computer);
|
||||
languageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard, computer);
|
||||
activeRead = new PagedMemory(0x10000, PagedMemory.Type.ram, computer);
|
||||
activeWrite = new PagedMemory(0x10000, PagedMemory.Type.ram, computer);
|
||||
blank = new PagedMemory(0x100, PagedMemory.Type.ram, computer);
|
||||
|
||||
// Format memory with FF FF 00 00 pattern
|
||||
for (int i = 0; i < 0x0100; i++) {
|
||||
@ -191,13 +192,14 @@ abstract public class RAM128k extends RAM {
|
||||
}
|
||||
|
||||
public void log(String message) {
|
||||
if (Computer.getComputer().cpu != null && Computer.getComputer().cpu.isLogEnabled()) {
|
||||
CPU cpu = computer.getCpu();
|
||||
if (cpu != null && cpu.isLogEnabled()) {
|
||||
String stack = "";
|
||||
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
|
||||
stack += e.getClassName() + "." + e.getMethodName() + "(" + e.getLineNumber() + ");";
|
||||
}
|
||||
Computer.getComputer().cpu.log(stack);
|
||||
Computer.getComputer().cpu.log(message + ";" + SoftSwitches.RAMRD + ";" + SoftSwitches.RAMWRT + ";" + SoftSwitches.AUXZP + ";" + SoftSwitches._80STORE + ";" + SoftSwitches.HIRES + ";" + SoftSwitches.PAGE2 + ";" + SoftSwitches.LCBANK1 + ";" + SoftSwitches.LCRAM + ";" + SoftSwitches.LCWRITE);
|
||||
cpu.log(stack);
|
||||
cpu.log(message + ";" + SoftSwitches.RAMRD + ";" + SoftSwitches.RAMWRT + ";" + SoftSwitches.AUXZP + ";" + SoftSwitches._80STORE + ";" + SoftSwitches.HIRES + ";" + SoftSwitches.PAGE2 + ";" + SoftSwitches.LCBANK1 + ";" + SoftSwitches.LCRAM + ";" + SoftSwitches.LCWRITE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,21 +65,21 @@ public enum SoftSwitches {
|
||||
PAGE2(new VideoSoftSwitch("Page2", 0x0c054, 0x0c055, 0x0c01c, RAMEvent.TYPE.ANY, false) {
|
||||
@Override
|
||||
public void stateChanged() {
|
||||
// if (Computer.getComputer() == null) {
|
||||
// if (computer == null) {
|
||||
// return;
|
||||
// }
|
||||
// if (Computer.getComputer() == null && Computer.getComputer().getMemory() == null) {
|
||||
// if (computer == null && computer.getMemory() == null) {
|
||||
// return;
|
||||
// }
|
||||
// if (Computer.getComputer() == null && Computer.getComputer().getVideo() == null) {
|
||||
// if (computer == null && computer.getVideo() == null) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// PAGE2 is a hybrid switch; 80STORE ? memory : video
|
||||
if (_80STORE.isOn()) {
|
||||
Computer.getComputer().getMemory().configureActiveMemory();
|
||||
computer.getMemory().configureActiveMemory();
|
||||
} else {
|
||||
Computer.getComputer().getVideo().configureVideoMode();
|
||||
computer.getVideo().configureVideoMode();
|
||||
}
|
||||
}
|
||||
}),
|
||||
@ -127,10 +127,10 @@ public enum SoftSwitches {
|
||||
FLOATING_BUS(new SoftSwitch("FloatingBus", null, null, new int[]{0x0C050, 0x0C051, 0x0C052, 0x0C053, 0x0C054}, RAMEvent.TYPE.READ, null) {
|
||||
@Override
|
||||
protected byte readSwitch() {
|
||||
if (Computer.getComputer().getVideo() == null) {
|
||||
if (computer.getVideo() == null) {
|
||||
return 0;
|
||||
}
|
||||
return Computer.getComputer().getVideo().getFloatingBus();
|
||||
return computer.getVideo().getFloatingBus();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -163,7 +163,8 @@ public class Speaker extends Device {
|
||||
/**
|
||||
* Creates a new instance of Speaker
|
||||
*/
|
||||
public Speaker() {
|
||||
public Speaker(Computer computer) {
|
||||
super(computer);
|
||||
configureListener();
|
||||
reconfigure();
|
||||
}
|
||||
@ -189,7 +190,7 @@ public class Speaker extends Device {
|
||||
public void resume() {
|
||||
sdl = null;
|
||||
try {
|
||||
sdl = Motherboard.mixer.getLine(this);
|
||||
sdl = computer.getMotherboard().mixer.getLine(this);
|
||||
} catch (LineUnavailableException ex) {
|
||||
System.out.println("ERROR: Could not output sound: " + ex.getMessage());
|
||||
}
|
||||
@ -233,8 +234,9 @@ public class Speaker extends Device {
|
||||
}
|
||||
}
|
||||
}
|
||||
Motherboard.cancelSpeedRequest(this);
|
||||
Motherboard.mixer.returnLine(this);
|
||||
|
||||
computer.getMotherboard().cancelSpeedRequest(this);
|
||||
computer.getMotherboard().mixer.returnLine(this);
|
||||
|
||||
}
|
||||
});
|
||||
@ -280,9 +282,9 @@ public class Speaker extends Device {
|
||||
int wait = 0;
|
||||
while (bufferPos >= BUFFER_SIZE) {
|
||||
if (wait++ > 1000) {
|
||||
Computer.pause();
|
||||
computer.pause();
|
||||
detach();
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
Motherboard.enableSpeaker = false;
|
||||
gripe("Sound playback is not working properly. Check your configuration and sound system to ensure they are set up properly.");
|
||||
return;
|
||||
@ -322,11 +324,11 @@ public class Speaker extends Device {
|
||||
* Add a memory event listener for C03x for capturing speaker events
|
||||
*/
|
||||
private void configureListener() {
|
||||
Computer.getComputer().getMemory().addListener(listener);
|
||||
computer.getMemory().addListener(listener);
|
||||
}
|
||||
|
||||
private void removeListener() {
|
||||
Computer.getComputer().getMemory().removeListener(listener);
|
||||
computer.getMemory().removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,7 +70,8 @@ public class VideoDHGR extends Video {
|
||||
/**
|
||||
* Creates a new instance of VideoDHGR
|
||||
*/
|
||||
public VideoDHGR() {
|
||||
public VideoDHGR(Computer computer) {
|
||||
super(computer);
|
||||
hiresPage1 = new VideoWriter() {
|
||||
@Override
|
||||
public int getYOffset(int y) {
|
||||
@ -292,10 +293,10 @@ public class VideoDHGR extends Video {
|
||||
if ((xOffset & 0x01) == 1) {
|
||||
return;
|
||||
}
|
||||
int b1 = ((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset);
|
||||
int b2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset);
|
||||
int b3 = ((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1);
|
||||
int b4 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
|
||||
int b1 = ((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset);
|
||||
int b2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset);
|
||||
int b3 = ((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1);
|
||||
int b4 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
|
||||
int useColOffset = xOffset << 1;
|
||||
// This shouldn't be necessary but prevents an index bounds exception when graphics modes are flipped (Race condition?)
|
||||
if (useColOffset >= 77) {
|
||||
@ -318,8 +319,8 @@ public class VideoDHGR extends Video {
|
||||
if ((xOffset & 0x01) == 1) {
|
||||
return;
|
||||
}
|
||||
int b1 = 0x0ff & ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset);
|
||||
int b2 = 0x0ff & ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
|
||||
int b1 = 0x0ff & ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset);
|
||||
int b2 = 0x0ff & ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
|
||||
int dhgrWord = hgrToDhgr[(extraHalfBit && xOffset > 0) ? b1 | 0x0100 : b1][b2];
|
||||
extraHalfBit = (dhgrWord & 0x10000000) != 0;
|
||||
showDhgr(screen, times14[xOffset], y, dhgrWord & 0xfffffff);
|
||||
@ -375,7 +376,7 @@ public class VideoDHGR extends Video {
|
||||
}
|
||||
|
||||
protected void displayLores(BufferedImage screen, int xOffset, int y, int rowAddress) {
|
||||
int c1 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
int c1 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
if ((y & 7) < 4) {
|
||||
c1 &= 15;
|
||||
} else {
|
||||
@ -402,8 +403,8 @@ public class VideoDHGR extends Video {
|
||||
}
|
||||
|
||||
private void displayDoubleLores(BufferedImage screen, int xOffset, int y, int rowAddress) {
|
||||
int c1 = ((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
int c2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
int c1 = ((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
int c2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
if ((y & 7) < 4) {
|
||||
c1 &= 15;
|
||||
c2 &= 15;
|
||||
@ -549,8 +550,8 @@ public class VideoDHGR extends Video {
|
||||
return;
|
||||
}
|
||||
int yOffset = y & 7;
|
||||
byte byte2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
|
||||
int c1 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset));
|
||||
byte byte2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
|
||||
int c1 = getFontChar(((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset));
|
||||
int c2 = getFontChar(byte2);
|
||||
int b1 = Font.getByte(c1, yOffset);
|
||||
int b2 = Font.getByte(c2, yOffset);
|
||||
@ -566,10 +567,10 @@ public class VideoDHGR extends Video {
|
||||
return;
|
||||
}
|
||||
int yOffset = y & 7;
|
||||
int c1 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset));
|
||||
int c2 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset));
|
||||
int c3 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1));
|
||||
int c4 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1));
|
||||
int c1 = getFontChar(((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset));
|
||||
int c2 = getFontChar(((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset));
|
||||
int c3 = getFontChar(((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1));
|
||||
int c4 = getFontChar(((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1));
|
||||
int bits = Font.getByte(c1, yOffset) | (Font.getByte(c2, yOffset) << 7)
|
||||
| (Font.getByte(c3, yOffset) << 14) | (Font.getByte(c4, yOffset) << 21);
|
||||
showBW(screen, times14[xOffset], y, bits);
|
||||
@ -683,7 +684,7 @@ public class VideoDHGR extends Video {
|
||||
}
|
||||
|
||||
private void registerDirtyFlagChecks() {
|
||||
((RAM128k) Computer.getComputer().getMemory()).addListener(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
((RAM128k) computer.getMemory()).addListener(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(0x0400);
|
||||
@ -705,7 +706,7 @@ public class VideoDHGR extends Video {
|
||||
}
|
||||
}
|
||||
});
|
||||
((RAM128k) Computer.getComputer().getMemory()).addListener(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
((RAM128k) computer.getMemory()).addListener(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(0x2000);
|
||||
|
@ -63,6 +63,11 @@ public class VideoNTSC extends VideoDHGR {
|
||||
boolean colorActive = false;
|
||||
int rowStart = 0;
|
||||
|
||||
public VideoNTSC(Computer computer) {
|
||||
super(computer);
|
||||
createStateListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showBW(BufferedImage screen, int xOffset, int y, int dhgrWord) {
|
||||
if (lastKnownY != y) {
|
||||
@ -97,13 +102,13 @@ public class VideoNTSC extends VideoDHGR {
|
||||
pos = rowStart = divBy28[xOffset];
|
||||
colorActive = true;
|
||||
}
|
||||
int c1 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
int c1 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
|
||||
if ((y & 7) < 4) {
|
||||
c1 &= 15;
|
||||
} else {
|
||||
c1 >>= 4;
|
||||
}
|
||||
int c2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1) & 0x0FF;
|
||||
int c2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1) & 0x0FF;
|
||||
if ((y & 7) < 4) {
|
||||
c2 &= 15;
|
||||
} else {
|
||||
@ -346,9 +351,9 @@ public class VideoNTSC extends VideoDHGR {
|
||||
// System.out.println(state + ": "+ graphicsMode);
|
||||
}
|
||||
// These catch changes to the RGB mode to toggle between color, BW and mixed
|
||||
static final Set<RAMListener> rgbStateListeners = new HashSet<>();
|
||||
Set<RAMListener> rgbStateListeners = new HashSet<>();
|
||||
|
||||
static {
|
||||
private void createStateListeners() {
|
||||
rgbStateListeners.add(new RAMListener(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
@ -357,7 +362,7 @@ public class VideoNTSC extends VideoDHGR {
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
Video v = Computer.getComputer().getVideo();
|
||||
Video v = computer.getVideo();
|
||||
if (v instanceof VideoNTSC) {
|
||||
((VideoNTSC) v).rgbStateChange(ModeStateChanges.CLEAR_AN3);
|
||||
}
|
||||
@ -371,7 +376,7 @@ public class VideoNTSC extends VideoDHGR {
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
Video v = Computer.getComputer().getVideo();
|
||||
Video v = computer.getVideo();
|
||||
if (v instanceof VideoNTSC) {
|
||||
((VideoNTSC) v).rgbStateChange(ModeStateChanges.SET_AN3);
|
||||
}
|
||||
@ -385,7 +390,7 @@ public class VideoNTSC extends VideoDHGR {
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
Video v = Computer.getComputer().getVideo();
|
||||
Video v = computer.getVideo();
|
||||
if (v instanceof VideoNTSC) {
|
||||
// When reset hook is called, reset the graphics mode
|
||||
// This is useful in case a program is running that
|
||||
@ -405,21 +410,19 @@ public class VideoNTSC extends VideoDHGR {
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
Video v = Computer.getComputer().getVideo();
|
||||
Video v = computer.getVideo();
|
||||
if (v instanceof VideoNTSC) {
|
||||
((VideoNTSC) v).rgbStateChange(ModeStateChanges.SET_80);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
super.detach();
|
||||
rgbStateListeners.stream().forEach((l) -> {
|
||||
Computer.getComputer().getMemory().removeListener(l);
|
||||
computer.getMemory().removeListener(l);
|
||||
});
|
||||
}
|
||||
|
||||
@ -427,7 +430,7 @@ public class VideoNTSC extends VideoDHGR {
|
||||
public void attach() {
|
||||
super.attach();
|
||||
rgbStateListeners.stream().forEach((l) -> {
|
||||
Computer.getComputer().getMemory().addListener(l);
|
||||
computer.getMemory().addListener(l);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ public class IntC8SoftSwitch extends SoftSwitch {
|
||||
|
||||
@Override
|
||||
public void stateChanged() {
|
||||
if (Computer.getComputer().getMemory() != null) {
|
||||
Computer.getComputer().getMemory().configureActiveMemory();
|
||||
if (computer.getMemory() != null) {
|
||||
computer.getMemory().configureActiveMemory();
|
||||
}
|
||||
}
|
||||
}
|
@ -40,8 +40,8 @@ public class MemorySoftSwitch extends SoftSwitch {
|
||||
|
||||
public void stateChanged() {
|
||||
// System.out.println(getName()+ " was switched to "+getState());
|
||||
if (Computer.getComputer().getMemory() != null) {
|
||||
Computer.getComputer().getMemory().configureActiveMemory();
|
||||
if (computer.getMemory() != null) {
|
||||
computer.getMemory().configureActiveMemory();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,8 @@ public class VideoSoftSwitch extends SoftSwitch {
|
||||
|
||||
public void stateChanged() {
|
||||
// System.out.println("Set "+getName()+" -> "+getState());
|
||||
if (Computer.getComputer().getVideo() != null) {
|
||||
Computer.getComputer().getVideo().configureVideoMode();
|
||||
if (computer.getVideo() != null) {
|
||||
computer.getVideo().configureVideoMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,18 +30,22 @@ import java.util.Set;
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public abstract class Cheats extends Device {
|
||||
Set<RAMListener> listeners = new HashSet<RAMListener>();
|
||||
Set<RAMListener> listeners = new HashSet<>();
|
||||
|
||||
public Cheats(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
public void addCheat(RAMListener l) {
|
||||
listeners.add(l);
|
||||
Computer.getComputer().getMemory().addListener(l);
|
||||
computer.getMemory().addListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
for (RAMListener l : listeners) {
|
||||
Computer.getComputer().getMemory().removeListener(l);
|
||||
}
|
||||
listeners.stream().forEach((l) -> {
|
||||
computer.getMemory().removeListener(l);
|
||||
});
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
@ -51,6 +55,7 @@ public abstract class Cheats extends Device {
|
||||
attach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "cheat";
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
*/
|
||||
package jace.cheat;
|
||||
|
||||
import jace.core.Computer;
|
||||
import jace.Emulator;
|
||||
import jace.core.RAM;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMEvent.TYPE;
|
||||
@ -56,17 +56,14 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
gradient = bwGradient;
|
||||
}
|
||||
// This is used primarily during scroll events to repaint the whole area
|
||||
ChangeListener viewportChangeListener = new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
repaint();
|
||||
}
|
||||
ChangeListener viewportChangeListener = (ChangeEvent e) -> {
|
||||
repaint();
|
||||
};
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
super.validate();
|
||||
if (Computer.getComputer() != null) {
|
||||
if (Emulator.computer != null) {
|
||||
adjustSize();
|
||||
}
|
||||
if (getParent() != null) {
|
||||
@ -92,7 +89,7 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RAM ram = Computer.getComputer().getMemory();
|
||||
RAM ram = Emulator.computer.getMemory();
|
||||
for (int a = startAddress; a <= endAddress; a++) {
|
||||
drawValue(a, ram.readRaw(a) & 0x0ff, (Graphics2D) g);
|
||||
}
|
||||
@ -198,35 +195,31 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
if (mousePresent) {
|
||||
final int addr = convertXYtoAddr(mouseX, mouseY);
|
||||
if (addr >= 0) {
|
||||
final int value = Computer.getComputer().getMemory().readRaw(addr) & 0x0ff;
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
Integer lastChange = setBy.get(addr);
|
||||
Integer lastRead = readBy.get(addr);
|
||||
char c1 = (char) Math.max(32, value & 0x07f);
|
||||
char c2 = (char) (64 + (value % 32));
|
||||
char c3 = (char) (32 + (value % 96));
|
||||
|
||||
status.setText("$"
|
||||
+ spaceFill(Integer.toHexString(addr), 4) + ": "
|
||||
+ spaceFill(String.valueOf(value), 3) + " ($"
|
||||
+ spaceFill(Integer.toHexString(value), 2) + ") " + c1 + " " + c2 + " " + c3
|
||||
+ (lastChange != null
|
||||
? " Written by $"
|
||||
+ spaceFill(Integer.toHexString(lastChange), 4)
|
||||
: "")
|
||||
+ (lastRead != null
|
||||
? " Read by $"
|
||||
+ spaceFill(Integer.toHexString(lastRead), 4)
|
||||
: ""));
|
||||
}
|
||||
final int value = Emulator.computer.getMemory().readRaw(addr) & 0x0ff;
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
Integer lastChange = setBy.get(addr);
|
||||
Integer lastRead = readBy.get(addr);
|
||||
char c1 = (char) Math.max(32, value & 0x07f);
|
||||
char c2 = (char) (64 + (value % 32));
|
||||
char c3 = (char) (32 + (value % 96));
|
||||
|
||||
status.setText("$"
|
||||
+ spaceFill(Integer.toHexString(addr), 4) + ": "
|
||||
+ spaceFill(String.valueOf(value), 3) + " ($"
|
||||
+ spaceFill(Integer.toHexString(value), 2) + ") " + c1 + " " + c2 + " " + c3
|
||||
+ (lastChange != null
|
||||
? " Written by $"
|
||||
+ spaceFill(Integer.toHexString(lastChange), 4)
|
||||
: "")
|
||||
+ (lastRead != null
|
||||
? " Read by $"
|
||||
+ spaceFill(Integer.toHexString(lastRead), 4)
|
||||
: ""));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
status.setText("Nothing selected");
|
||||
}
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
status.setText("Nothing selected");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -274,20 +267,17 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
public void recalibrate() {
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
stopDisplay();
|
||||
int size = endAddress - startAddress + 1;
|
||||
int width = getParent().getWidth();
|
||||
columns = ((width / zoomAmount) / 16) * 16;
|
||||
int height = ((size / columns) + 1) * zoomAmount;
|
||||
setSize(width, height);
|
||||
setPreferredSize(new Dimension(width, height));
|
||||
getParent().validate();
|
||||
repaint();
|
||||
startDisplay();
|
||||
}
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
stopDisplay();
|
||||
int size = endAddress - startAddress + 1;
|
||||
int width1 = getParent().getWidth();
|
||||
columns = ((width1 / zoomAmount) / 16) * 16;
|
||||
int height1 = ((size / columns) + 1) * zoomAmount;
|
||||
setSize(width1, height1);
|
||||
setPreferredSize(new Dimension(width1, height1));
|
||||
getParent().validate();
|
||||
repaint();
|
||||
startDisplay();
|
||||
});
|
||||
}
|
||||
|
||||
@ -322,17 +312,17 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
static int ACTIVITY_DECREMENT = 5;
|
||||
static int ACTIVITY_MAX = 255;
|
||||
RAMListener memoryListener = null;
|
||||
Map<Integer, Integer> readActivity = new ConcurrentHashMap<Integer, Integer>();
|
||||
Map<Integer, Integer> writeActivity = new ConcurrentHashMap<Integer, Integer>();
|
||||
Map<Integer, Integer> pcActivity = new ConcurrentHashMap<Integer, Integer>();
|
||||
Set<Integer> activeRam = new ConcurrentSkipListSet<Integer>();
|
||||
Map<Integer, Integer> valueActivity = new ConcurrentHashMap<Integer, Integer>();
|
||||
Map<Integer, Integer> setBy = new ConcurrentHashMap<Integer, Integer>();
|
||||
Map<Integer, Integer> readBy = new ConcurrentHashMap<Integer, Integer>();
|
||||
Map<Integer, Integer> readActivity = new ConcurrentHashMap<>();
|
||||
Map<Integer, Integer> writeActivity = new ConcurrentHashMap<>();
|
||||
Map<Integer, Integer> pcActivity = new ConcurrentHashMap<>();
|
||||
Set<Integer> activeRam = new ConcurrentSkipListSet<>();
|
||||
Map<Integer, Integer> valueActivity = new ConcurrentHashMap<>();
|
||||
Map<Integer, Integer> setBy = new ConcurrentHashMap<>();
|
||||
Map<Integer, Integer> readBy = new ConcurrentHashMap<>();
|
||||
|
||||
void startDisplay() {
|
||||
if (memoryListener != null) {
|
||||
Computer.getComputer().getMemory().removeListener(memoryListener);
|
||||
Emulator.computer.getMemory().removeListener(memoryListener);
|
||||
memoryListener = null;
|
||||
}
|
||||
isDisplayActive = true;
|
||||
@ -349,7 +339,7 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
if (addr < startAddress || addr > endAddress) {
|
||||
return;
|
||||
}
|
||||
int pc = Computer.getComputer().getCpu().programCounter;
|
||||
int pc = Emulator.computer.getCpu().programCounter;
|
||||
if (e.getType() == TYPE.EXECUTE || e.getType() == TYPE.READ_OPERAND) {
|
||||
if (pcActivity.containsKey(addr)) {
|
||||
pcActivity.put(addr, Math.min(ACTIVITY_MAX, getInt(pcActivity.get(addr)) + ACTIVITY_INCREMENT));
|
||||
@ -375,73 +365,70 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
activeRam.add(addr);
|
||||
}
|
||||
};
|
||||
Computer.getComputer().getMemory().addListener(memoryListener);
|
||||
redrawThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mode == Modes.ACTIVITY) {
|
||||
// Activity heatmap mode
|
||||
while (isDisplayActive) {
|
||||
updateDetails();
|
||||
Graphics2D g = (Graphics2D) getGraphics();
|
||||
for (Iterator<Integer> i = activeRam.iterator(); i.hasNext();) {
|
||||
boolean remove = true;
|
||||
int addr = i.next();
|
||||
int read = getInt(readActivity.get(addr));
|
||||
if (read <= 0) {
|
||||
read = 0;
|
||||
} else {
|
||||
remove = false;
|
||||
readActivity.put(addr, read - ACTIVITY_DECREMENT);
|
||||
}
|
||||
int write = getInt(writeActivity.get(addr));
|
||||
if (write <= 0) {
|
||||
write = 0;
|
||||
} else {
|
||||
remove = false;
|
||||
writeActivity.put(addr, write - ACTIVITY_DECREMENT);
|
||||
}
|
||||
int pc = getInt(pcActivity.get(addr));
|
||||
if (pc <= 0) {
|
||||
pc = 0;
|
||||
} else {
|
||||
remove = false;
|
||||
pcActivity.put(addr, pc - ACTIVITY_DECREMENT);
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
i.remove();
|
||||
pcActivity.remove(addr);
|
||||
writeActivity.remove(addr);
|
||||
readActivity.remove(addr);
|
||||
}
|
||||
|
||||
drawActivity(addr, write, read, pc, g);
|
||||
Emulator.computer.getMemory().addListener(memoryListener);
|
||||
redrawThread = new Thread(() -> {
|
||||
if (mode == Modes.ACTIVITY) {
|
||||
// Activity heatmap mode
|
||||
while (isDisplayActive) {
|
||||
updateDetails();
|
||||
Graphics2D g = (Graphics2D) getGraphics();
|
||||
for (Iterator<Integer> i = activeRam.iterator(); i.hasNext();) {
|
||||
boolean remove = true;
|
||||
int addr = i.next();
|
||||
int read = getInt(readActivity.get(addr));
|
||||
if (read <= 0) {
|
||||
read = 0;
|
||||
} else {
|
||||
remove = false;
|
||||
readActivity.put(addr, read - ACTIVITY_DECREMENT);
|
||||
}
|
||||
g.dispose();
|
||||
try {
|
||||
Thread.sleep(UPDATE_INTERVAL);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(MemorySpyGrid.class.getName()).log(Level.SEVERE, null, ex);
|
||||
int write = getInt(writeActivity.get(addr));
|
||||
if (write <= 0) {
|
||||
write = 0;
|
||||
} else {
|
||||
remove = false;
|
||||
writeActivity.put(addr, write - ACTIVITY_DECREMENT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Redraw value, no activity counts needed
|
||||
while (isDisplayActive) {
|
||||
updateDetails();
|
||||
Graphics2D g = (Graphics2D) getGraphics();
|
||||
for (Iterator<Integer> i = valueActivity.keySet().iterator(); i.hasNext();) {
|
||||
int addr = i.next();
|
||||
int value = getInt(valueActivity.get(addr));
|
||||
int pc = getInt(pcActivity.get(addr));
|
||||
if (pc <= 0) {
|
||||
pc = 0;
|
||||
} else {
|
||||
remove = false;
|
||||
pcActivity.put(addr, pc - ACTIVITY_DECREMENT);
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
i.remove();
|
||||
drawValue(addr, value, g);
|
||||
}
|
||||
g.dispose();
|
||||
try {
|
||||
Thread.sleep(UPDATE_INTERVAL);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(MemorySpyGrid.class.getName()).log(Level.SEVERE, null, ex);
|
||||
pcActivity.remove(addr);
|
||||
writeActivity.remove(addr);
|
||||
readActivity.remove(addr);
|
||||
}
|
||||
|
||||
drawActivity(addr, write, read, pc, g);
|
||||
}
|
||||
g.dispose();
|
||||
try {
|
||||
Thread.sleep(UPDATE_INTERVAL);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(MemorySpyGrid.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Redraw value, no activity counts needed
|
||||
while (isDisplayActive) {
|
||||
updateDetails();
|
||||
Graphics2D g = (Graphics2D) getGraphics();
|
||||
for (Iterator<Integer> i = valueActivity.keySet().iterator(); i.hasNext();) {
|
||||
int addr = i.next();
|
||||
int value = getInt(valueActivity.get(addr));
|
||||
i.remove();
|
||||
drawValue(addr, value, g);
|
||||
}
|
||||
g.dispose();
|
||||
try {
|
||||
Thread.sleep(UPDATE_INTERVAL);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(MemorySpyGrid.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -453,7 +440,7 @@ public class MemorySpyGrid extends javax.swing.JPanel {
|
||||
void stopDisplay() {
|
||||
isDisplayActive = false;
|
||||
if (memoryListener != null) {
|
||||
Computer.getComputer().getMemory().removeListener(memoryListener);
|
||||
Emulator.computer.getMemory().removeListener(memoryListener);
|
||||
memoryListener = null;
|
||||
}
|
||||
if (redrawThread != null && redrawThread.isAlive()) {
|
||||
|
@ -44,16 +44,16 @@ public class MetaCheats extends Cheats {
|
||||
// This is used to help the handler exit faster when there is nothing to do
|
||||
boolean noCheats = true;
|
||||
|
||||
public MetaCheats() {
|
||||
super();
|
||||
public MetaCheats(Computer computer) {
|
||||
super(computer);
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
|
||||
Map<Integer, Integer> holdBytes = new TreeMap<Integer,Integer>();
|
||||
Map<Integer, Integer> holdWords = new TreeMap<Integer,Integer>();
|
||||
Set<Integer> disabled = new HashSet<Integer>();
|
||||
Map<Integer, Integer> results = new TreeMap<Integer,Integer>();
|
||||
Map<Integer, Integer> holdBytes = new TreeMap<>();
|
||||
Map<Integer, Integer> holdWords = new TreeMap<>();
|
||||
Set<Integer> disabled = new HashSet<>();
|
||||
Map<Integer, Integer> results = new TreeMap<>();
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
return "Meta-cheat engine";
|
||||
@ -80,7 +80,7 @@ public class MetaCheats extends Cheats {
|
||||
Logger.getLogger(MetaCheats.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
RAM128k ram = (RAM128k) Computer.getComputer().getMemory();
|
||||
RAM128k ram = (RAM128k) computer.getMemory();
|
||||
DefaultTableModel model = (DefaultTableModel) form.resultsTable.getModel();
|
||||
if (results.size() > MAX_RESULTS_SHOWN) {
|
||||
model.setRowCount(0);
|
||||
@ -90,8 +90,8 @@ public class MetaCheats extends Cheats {
|
||||
boolean useWord = form.searchForWord.isSelected();
|
||||
if (model.getRowCount() != results.size()) {
|
||||
model.setRowCount(0);
|
||||
List<Integer> iter = new ArrayList<Integer>(results.keySet());
|
||||
for (Integer i : iter) {
|
||||
List<Integer> iter = new ArrayList<>(results.keySet());
|
||||
iter.stream().forEach((i) -> {
|
||||
int val = results.get(i);
|
||||
if (useWord) {
|
||||
int current = ram.readWordRaw(i) & 0x0ffff;
|
||||
@ -100,9 +100,9 @@ public class MetaCheats extends Cheats {
|
||||
int current = ram.readRaw(i) & 0x0ff;
|
||||
model.addRow(new Object[]{hex(i, 4), val + " ("+hex(val,2)+")", current + " ("+hex(current,2)+")"});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
List<Integer> iter = new ArrayList<Integer>(results.keySet());
|
||||
List<Integer> iter = new ArrayList<>(results.keySet());
|
||||
for (int i=0; i < iter.size(); i++) {
|
||||
int val = results.get(iter.get(i));
|
||||
if (useWord) {
|
||||
@ -131,18 +131,18 @@ public class MetaCheats extends Cheats {
|
||||
noCheats = holdBytes.isEmpty() && holdWords.isEmpty() && disabled.isEmpty();
|
||||
DefaultTableModel model = (DefaultTableModel) form.activeCheatsTable.getModel();
|
||||
model.setRowCount(0);
|
||||
for (Integer i : holdBytes.keySet()) {
|
||||
holdBytes.keySet().stream().forEach((i) -> {
|
||||
String loc = hex(i, 4);
|
||||
if (disabled.contains(i)) loc += " (off)";
|
||||
int val = holdBytes.get(i);
|
||||
model.addRow(new Object[]{loc, val + " ("+hex(val,2)+")"});
|
||||
}
|
||||
for (Integer i : holdWords.keySet()) {
|
||||
});
|
||||
holdWords.keySet().stream().forEach((i) -> {
|
||||
String loc = hex(i, 4);
|
||||
if (disabled.contains(i)) loc += " (off)";
|
||||
int val = holdWords.get(i);
|
||||
model.addRow(new Object[]{loc, val + " ("+hex(val,4)+")"});
|
||||
}
|
||||
});
|
||||
}
|
||||
public void showCheatForm() {
|
||||
if (form == null) {
|
||||
@ -191,11 +191,8 @@ public class MetaCheats extends Cheats {
|
||||
if (results.isEmpty()) return;
|
||||
if (results.size() > MAX_RESULTS_SHOWN || isDrawing) return;
|
||||
if (results.containsKey(e.getAddress()) || results.containsKey(e.getAddress()-1)) {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
redrawResults();
|
||||
}
|
||||
Thread t = new Thread(() -> {
|
||||
redrawResults();
|
||||
});
|
||||
t.setName("Metacheat results updater");
|
||||
t.start();
|
||||
@ -258,7 +255,7 @@ public class MetaCheats extends Cheats {
|
||||
}
|
||||
|
||||
void performSearch(boolean useDeltaSearch, boolean searchForByteValues, int val) {
|
||||
RAM128k ram = (RAM128k) Computer.getComputer().getMemory();
|
||||
RAM128k ram = (RAM128k) computer.getMemory();
|
||||
if (results.isEmpty()) {
|
||||
int max = 0x010000;
|
||||
if (!searchForByteValues) max--;
|
||||
@ -272,8 +269,8 @@ public class MetaCheats extends Cheats {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Set<Integer> remove = new HashSet<Integer>();
|
||||
for (Integer i : results.keySet()) {
|
||||
Set<Integer> remove = new HashSet<>();
|
||||
results.keySet().stream().forEach((i) -> {
|
||||
int v = searchForByteValues ? ram.readRaw(i) & 0x0ff : ram.readWordRaw(i) & 0x0ffff;
|
||||
if (useDeltaSearch) {
|
||||
if (v - results.get(i) != val) {
|
||||
@ -288,10 +285,10 @@ public class MetaCheats extends Cheats {
|
||||
results.put(i,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Integer i : remove) {
|
||||
});
|
||||
remove.stream().forEach((i) -> {
|
||||
results.remove(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
form.resultsStatusLabel.setText("Search found "+results.size()+" result(s).");
|
||||
redrawResults();
|
||||
@ -308,7 +305,7 @@ public class MetaCheats extends Cheats {
|
||||
}
|
||||
|
||||
void addWatches(int addrStart, int addrEnd) {
|
||||
RAM128k ram = (RAM128k) Computer.getComputer().getMemory();
|
||||
RAM128k ram = (RAM128k) computer.getMemory();
|
||||
if (form == null) return;
|
||||
boolean searchForByteValues = form.searchForByte.isSelected();
|
||||
for (int i = addrStart; i <= addrEnd; i = i + (searchForByteValues ? 1 : 2)) {
|
||||
|
@ -109,11 +109,11 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
|
||||
public static int LinkMap = 0x0bda0;
|
||||
public static int Map = 0x0bea0;
|
||||
public static int MapInfo = 0x0bf00;
|
||||
public static int RedBufs = 0x05e00;
|
||||
public static int RedBuf = RedBufs + 90;
|
||||
public static final int RedBufs = 0x05e00;
|
||||
public static final int RedBuf = RedBufs + 90;
|
||||
// Source: https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/EQ.S
|
||||
public static int WipeBuf = RedBuf + 90;
|
||||
public static int MoveBuf = WipeBuf + 30;
|
||||
public static final int WipeBuf = RedBuf + 90;
|
||||
public static final int MoveBuf = WipeBuf + 30;
|
||||
// Object types
|
||||
// Source: https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/MOVEDATA.S
|
||||
public static int space = 0;
|
||||
@ -149,6 +149,10 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
|
||||
// This is the correct value for an open exit door.
|
||||
public static int ExitOpen = 172;
|
||||
|
||||
public PrinceOfPersiaCheats(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
return ("Prince of Persia");
|
||||
@ -317,7 +321,7 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
|
||||
// and 198-255 offscreen to the right.
|
||||
|
||||
// System.out.println("Clicked on " + col + "," + row + " -- screen " + (x * 280) + "," + (y * 192));
|
||||
RAM128k mem = (RAM128k) Computer.getComputer().getMemory();
|
||||
RAM128k mem = (RAM128k) computer.getMemory();
|
||||
PagedMemory auxMem = mem.getAuxMemory();
|
||||
|
||||
if (me.getButton() == MouseEvent.BUTTON1) {
|
||||
@ -363,7 +367,7 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
|
||||
* @param direction
|
||||
*/
|
||||
public void performAction(int row, int col, int direction) {
|
||||
RAM128k mem = (RAM128k) Computer.getComputer().getMemory();
|
||||
RAM128k mem = (RAM128k) computer.getMemory();
|
||||
PagedMemory auxMem = mem.getAuxMemory();
|
||||
byte currentScrn = auxMem.readByte(KidScrn);
|
||||
if (col < 0) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.config;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Utility;
|
||||
import java.io.File;
|
||||
@ -181,7 +182,7 @@ public class Configuration implements Reconfigurable {
|
||||
}
|
||||
}
|
||||
public final static ConfigNode BASE;
|
||||
public static Computer emulator = Computer.getComputer();
|
||||
public static Computer emulator = Emulator.computer;
|
||||
@ConfigurableField(name = "Autosave Changes", description = "If unchecked, changes are only saved when the Save button is pressed.")
|
||||
public static boolean saveAutomatically = false;
|
||||
|
||||
@ -341,7 +342,7 @@ public class Configuration implements Reconfigurable {
|
||||
public static boolean applySettings(ConfigNode node) {
|
||||
boolean resume = false;
|
||||
if (node == BASE) {
|
||||
resume = Computer.pause();
|
||||
resume = Emulator.computer.pause();
|
||||
}
|
||||
boolean hasChanged = false;
|
||||
if (node.changed) {
|
||||
@ -360,7 +361,7 @@ public class Configuration implements Reconfigurable {
|
||||
}
|
||||
|
||||
if (resume) {
|
||||
Computer.resume();
|
||||
Emulator.computer.resume();
|
||||
}
|
||||
|
||||
return hasChanged;
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.config;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.apple2e.Apple2e;
|
||||
import jace.config.Configuration.ConfigNode;
|
||||
import java.awt.Component;
|
||||
@ -42,8 +43,7 @@ import javax.swing.JTree;
|
||||
public class ConfigurationPanel extends javax.swing.JPanel {
|
||||
|
||||
public static void main(String... args) {
|
||||
new Apple2e();
|
||||
Apple2e.getComputer().reconfigure();
|
||||
Emulator.computer.reconfigure();
|
||||
Configuration.loadSettings();
|
||||
JFrame f = new JFrame();
|
||||
f.setContentPane(new ConfigurationPanel());
|
||||
|
@ -34,12 +34,10 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public abstract class CPU extends Device {
|
||||
|
||||
/**
|
||||
* Creates a new instance of CPU
|
||||
*/
|
||||
public CPU() {
|
||||
public CPU(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "cpu";
|
||||
@ -74,11 +72,11 @@ public abstract class CPU extends Device {
|
||||
}
|
||||
|
||||
public void dumpTrace() {
|
||||
Computer.pause();
|
||||
computer.pause();
|
||||
ArrayList<String> newLog = new ArrayList<>();
|
||||
ArrayList<String> log = traceLog;
|
||||
traceLog = newLog;
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
System.out.println("Most recent " + traceLength + " instructions:");
|
||||
log.stream().forEach((s) -> {
|
||||
System.out.println(s);
|
||||
|
@ -45,9 +45,10 @@ public abstract class Card extends Device {
|
||||
/**
|
||||
* Creates a new instance of Card
|
||||
*/
|
||||
public Card() {
|
||||
cxRom = new PagedMemory(0x0100, PagedMemory.Type.cardFirmware);
|
||||
c8Rom = new PagedMemory(0x0800, PagedMemory.Type.cardFirmware);
|
||||
public Card(Computer computer) {
|
||||
super(computer);
|
||||
cxRom = new PagedMemory(0x0100, PagedMemory.Type.cardFirmware, computer);
|
||||
c8Rom = new PagedMemory(0x0800, PagedMemory.Type.cardFirmware, computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,11 +69,13 @@ public abstract class Card extends Device {
|
||||
RAMEvent.TYPE.ANY,
|
||||
RAMEvent.SCOPE.RANGE,
|
||||
RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(slot * 16 + 0x00c080);
|
||||
setScopeEnd(slot * 16 + 0x00c08F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
int address = e.getAddress() & 0x0f;
|
||||
handleIOAccess(address, e.getType(), e.getNewValue(), e);
|
||||
@ -83,13 +86,15 @@ public abstract class Card extends Device {
|
||||
RAMEvent.TYPE.ANY,
|
||||
RAMEvent.SCOPE.RANGE,
|
||||
RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(slot * 256 + 0x00c000);
|
||||
setScopeEnd(slot * 256 + 0x00c0ff);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
Computer.getComputer().getMemory().setActiveCard(slot);
|
||||
computer.getMemory().setActiveCard(slot);
|
||||
if (SoftSwitches.CXROM.getState()) {
|
||||
return;
|
||||
}
|
||||
@ -108,7 +113,7 @@ public abstract class Card extends Device {
|
||||
|
||||
protected void doEvent(RAMEvent e) {
|
||||
if (SoftSwitches.CXROM.getState()
|
||||
|| Computer.getComputer().getMemory().getActiveSlot() != getSlot()
|
||||
|| computer.getMemory().getActiveSlot() != getSlot()
|
||||
|| SoftSwitches.INTC8ROM.getState()) {
|
||||
return;
|
||||
}
|
||||
@ -116,17 +121,17 @@ public abstract class Card extends Device {
|
||||
}
|
||||
};
|
||||
|
||||
Computer.getComputer().getMemory().addListener(ioListener);
|
||||
Computer.getComputer().getMemory().addListener(firmwareListener);
|
||||
Computer.getComputer().getMemory().addListener(c8firmwareListener);
|
||||
computer.getMemory().addListener(ioListener);
|
||||
computer.getMemory().addListener(firmwareListener);
|
||||
computer.getMemory().addListener(c8firmwareListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
suspend();
|
||||
Computer.getComputer().getMemory().removeListener(ioListener);
|
||||
Computer.getComputer().getMemory().removeListener(firmwareListener);
|
||||
Computer.getComputer().getMemory().removeListener(c8firmwareListener);
|
||||
computer.getMemory().removeListener(ioListener);
|
||||
computer.getMemory().removeListener(firmwareListener);
|
||||
computer.getMemory().removeListener(c8firmwareListener);
|
||||
}
|
||||
|
||||
abstract protected void handleIOAccess(int register, RAMEvent.TYPE type, int value, RAMEvent e);
|
||||
|
@ -35,12 +35,12 @@ import java.io.IOException;
|
||||
*/
|
||||
public abstract class Computer implements Reconfigurable {
|
||||
|
||||
static private Computer theComputer;
|
||||
public RAM memory;
|
||||
public CPU cpu;
|
||||
public Video video;
|
||||
public Keyboard keyboard;
|
||||
public StateManager stateManager;
|
||||
public Motherboard motherboard;
|
||||
public MediaLibrary mediaLibrary = MediaLibrary.getInstance();
|
||||
@ConfigurableField(category = "advanced", name = "State management", shortName = "rewind", description = "This enables rewind support, but consumes a lot of memory when active.")
|
||||
public boolean enableStateManager;
|
||||
@ -49,7 +49,6 @@ public abstract class Computer implements Reconfigurable {
|
||||
* Creates a new instance of Computer
|
||||
*/
|
||||
public Computer() {
|
||||
theComputer = this;
|
||||
keyboard = new Keyboard();
|
||||
}
|
||||
|
||||
@ -57,6 +56,10 @@ public abstract class Computer implements Reconfigurable {
|
||||
return memory;
|
||||
}
|
||||
|
||||
public Motherboard getMotherboard() {
|
||||
return motherboard;
|
||||
}
|
||||
|
||||
public void notifyVBLStateChanged(boolean state) {
|
||||
for (Card c : getMemory().cards) {
|
||||
if (c == null) {
|
||||
@ -105,22 +108,18 @@ public abstract class Computer implements Reconfigurable {
|
||||
|
||||
@InvokableAction(
|
||||
name = "Cold boot",
|
||||
description = "Process startup sequence from power-up",
|
||||
category = "general",
|
||||
alternatives = "Full reset;reset emulator")
|
||||
description = "Process startup sequence from power-up",
|
||||
category = "general",
|
||||
alternatives = "Full reset;reset emulator")
|
||||
public abstract void coldStart();
|
||||
|
||||
@InvokableAction(
|
||||
name = "Warm boot",
|
||||
description = "Process user-initatiated reboot (ctrl+apple+reset)",
|
||||
category = "general",
|
||||
alternatives = "reboot;reset;three-finger-salute")
|
||||
description = "Process user-initatiated reboot (ctrl+apple+reset)",
|
||||
category = "general",
|
||||
alternatives = "reboot;reset;three-finger-salute")
|
||||
public abstract void warmStart();
|
||||
|
||||
static public Computer getComputer() {
|
||||
return theComputer;
|
||||
}
|
||||
|
||||
public Keyboard getKeyboard() {
|
||||
return this.keyboard;
|
||||
}
|
||||
@ -132,28 +131,24 @@ public abstract class Computer implements Reconfigurable {
|
||||
protected abstract void doResume();
|
||||
|
||||
@InvokableAction(name = "Pause", description = "Stops the computer, allowing reconfiguration of core elements", alternatives = "freeze;halt")
|
||||
public static boolean pause() {
|
||||
boolean result = false;
|
||||
if (theComputer != null) {
|
||||
result = theComputer.isRunning();
|
||||
theComputer.doPause();
|
||||
}
|
||||
public boolean pause() {
|
||||
boolean result = isRunning();
|
||||
doPause();
|
||||
return result;
|
||||
}
|
||||
|
||||
@InvokableAction(name = "Resume", description = "Resumes the computer if it was previously paused", alternatives = "unpause;unfreeze;resume")
|
||||
public static void resume() {
|
||||
if (theComputer != null) {
|
||||
theComputer.doResume();
|
||||
}
|
||||
public void resume() {
|
||||
doResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconfigure() {
|
||||
if (enableStateManager) {
|
||||
stateManager = StateManager.getInstance();
|
||||
stateManager = StateManager.getInstance(this);
|
||||
} else {
|
||||
stateManager = null;
|
||||
StateManager.getInstance().invalidate();
|
||||
StateManager.getInstance(this).invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,12 @@ import jace.config.Reconfigurable;
|
||||
*/
|
||||
@Stateful
|
||||
public abstract class Device implements Reconfigurable {
|
||||
protected Computer computer;
|
||||
public Device(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
// Number of cycles to do nothing (for cpu/video cycle accuracy)
|
||||
|
||||
@Stateful
|
||||
private int waitCycles = 0;
|
||||
@Stateful
|
||||
|
@ -47,7 +47,10 @@ import java.util.logging.Logger;
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public class Keyboard implements Reconfigurable {
|
||||
|
||||
private Computer computer;
|
||||
public Keyboard(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "kbd";
|
||||
@ -79,16 +82,16 @@ public class Keyboard implements Reconfigurable {
|
||||
*/
|
||||
public Keyboard() {
|
||||
}
|
||||
private static Map<Integer, Set<KeyHandler>> keyHandlersByKey = new HashMap<Integer, Set<KeyHandler>>();
|
||||
private static Map<Object, Set<KeyHandler>> keyHandlersByOwner = new HashMap<Object, Set<KeyHandler>>();
|
||||
private static Map<Integer, Set<KeyHandler>> keyHandlersByKey = new HashMap<>();
|
||||
private static Map<Object, Set<KeyHandler>> keyHandlersByOwner = new HashMap<>();
|
||||
|
||||
public static void registerKeyHandler(KeyHandler l, Object owner) {
|
||||
if (!keyHandlersByKey.containsKey(l.key)) {
|
||||
keyHandlersByKey.put(l.key, new HashSet<KeyHandler>());
|
||||
keyHandlersByKey.put(l.key, new HashSet<>());
|
||||
}
|
||||
keyHandlersByKey.get(l.key).add(l);
|
||||
if (!keyHandlersByOwner.containsKey(owner)) {
|
||||
keyHandlersByOwner.put(owner, new HashSet<KeyHandler>());
|
||||
keyHandlersByOwner.put(owner, new HashSet<>());
|
||||
}
|
||||
keyHandlersByOwner.get(owner).add(l);
|
||||
}
|
||||
@ -97,12 +100,9 @@ public class Keyboard implements Reconfigurable {
|
||||
if (!keyHandlersByOwner.containsKey(owner)) {
|
||||
return;
|
||||
}
|
||||
for (KeyHandler handler : keyHandlersByOwner.get(owner)) {
|
||||
if (!keyHandlersByKey.containsKey(handler.key)) {
|
||||
continue;
|
||||
}
|
||||
keyHandlersByOwner.get(owner).stream().filter((handler) -> !(!keyHandlersByKey.containsKey(handler.key))).forEach((handler) -> {
|
||||
keyHandlersByKey.get(handler.key).remove(handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void processKeyDownEvents(KeyEvent e) {
|
||||
@ -216,7 +216,7 @@ public class Keyboard implements Reconfigurable {
|
||||
EmulatorUILogic.toggleDebugPanel();
|
||||
}
|
||||
if ((code == KeyEvent.VK_F12 || code == KeyEvent.VK_PAGE_UP || code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_PAUSE) && ((e.getModifiers() & KeyEvent.CTRL_MASK) > 0)) {
|
||||
Computer.getComputer().warmStart();
|
||||
computer.warmStart();
|
||||
}
|
||||
if (code == KeyEvent.VK_F1) {
|
||||
EmulatorUILogic.showMediaManager();
|
||||
@ -243,7 +243,7 @@ public class Keyboard implements Reconfigurable {
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(Keyboard.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
if ((e.getModifiers() & (KeyEvent.ALT_MASK|KeyEvent.META_MASK|KeyEvent.META_DOWN_MASK)) > 0) {
|
||||
// explicit left and right here because other locations
|
||||
@ -261,27 +261,27 @@ public class Keyboard implements Reconfigurable {
|
||||
}
|
||||
|
||||
private void pressOpenApple() {
|
||||
Computer.pause();
|
||||
computer.pause();
|
||||
SoftSwitches.PB0.getSwitch().setState(true);
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
|
||||
private void pressSolidApple() {
|
||||
Computer.pause();
|
||||
computer.pause();
|
||||
SoftSwitches.PB1.getSwitch().setState(true);
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
|
||||
private void releaseOpenApple() {
|
||||
Computer.pause();
|
||||
computer.pause();
|
||||
SoftSwitches.PB0.getSwitch().setState(false);
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
|
||||
private void releaseSolidApple() {
|
||||
Computer.pause();
|
||||
computer.pause();
|
||||
SoftSwitches.PB1.getSwitch().setState(false);
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -298,10 +298,7 @@ public class Keyboard implements Reconfigurable {
|
||||
contents = contents.replaceAll("\\n(\\r)?", (char) 0x0d + "");
|
||||
pasteBuffer = new StringReader(contents);
|
||||
}
|
||||
} catch (UnsupportedFlavorException ex) {
|
||||
Logger.getLogger(Keyboard.class
|
||||
.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
} catch (UnsupportedFlavorException | IOException ex) {
|
||||
Logger.getLogger(Keyboard.class
|
||||
.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
@ -38,21 +38,18 @@ import java.util.Set;
|
||||
*/
|
||||
public class Motherboard extends TimedDevice {
|
||||
|
||||
static final Computer computer = Computer.getComputer();
|
||||
static final CPU cpu = computer.getCpu();
|
||||
static Motherboard instance;
|
||||
static final public Set<Device> miscDevices = new HashSet<Device>();
|
||||
static final public Set<Device> miscDevices = new HashSet<>();
|
||||
@ConfigurableField(name = "Enable Speaker", shortName = "speaker", defaultValue = "true")
|
||||
public static boolean enableSpeaker = true;
|
||||
public static Speaker speaker;
|
||||
public static SoundMixer mixer = new SoundMixer();
|
||||
public Speaker speaker;
|
||||
public SoundMixer mixer;
|
||||
|
||||
static void vblankEnd() {
|
||||
void vblankEnd() {
|
||||
SoftSwitches.VBL.getSwitch().setState(true);
|
||||
computer.notifyVBLStateChanged(true);
|
||||
}
|
||||
|
||||
static void vblankStart() {
|
||||
void vblankStart() {
|
||||
SoftSwitches.VBL.getSwitch().setState(false);
|
||||
computer.notifyVBLStateChanged(false);
|
||||
}
|
||||
@ -60,10 +57,12 @@ public class Motherboard extends TimedDevice {
|
||||
/**
|
||||
* Creates a new instance of Motherboard
|
||||
*/
|
||||
public Motherboard() {
|
||||
instance = this;
|
||||
public Motherboard(Computer computer) {
|
||||
super(computer);
|
||||
mixer = new SoundMixer(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
return "Motherboard";
|
||||
}
|
||||
@ -77,15 +76,16 @@ public class Motherboard extends TimedDevice {
|
||||
public int clockCounter = 1;
|
||||
public Card[] cards;
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
try {
|
||||
clockCounter--;
|
||||
cpu.doTick();
|
||||
computer.getCpu().doTick();
|
||||
if (clockCounter > 0) {
|
||||
return;
|
||||
}
|
||||
clockCounter = cpuPerClock;
|
||||
Computer.getComputer().getVideo().doTick();
|
||||
computer.getVideo().doTick();
|
||||
// Unrolled loop since this happens so often
|
||||
if (cards[0] != null) {
|
||||
cards[0].doTick();
|
||||
@ -108,9 +108,9 @@ public class Motherboard extends TimedDevice {
|
||||
if (cards[6] != null) {
|
||||
cards[6].doTick();
|
||||
}
|
||||
for (Device m : miscDevices) {
|
||||
miscDevices.stream().forEach((m) -> {
|
||||
m.doTick();
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
@ -120,10 +120,12 @@ public class Motherboard extends TimedDevice {
|
||||
public static long SPEED = 1020484L; // (NTSC)
|
||||
//public static long SPEED = 1015625L; // (PAL)
|
||||
|
||||
@Override
|
||||
public long defaultCyclesPerSecond() {
|
||||
return SPEED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reconfigure() {
|
||||
boolean startAgain = pause();
|
||||
accelorationRequestors.clear();
|
||||
@ -136,7 +138,7 @@ public class Motherboard extends TimedDevice {
|
||||
if (enableSpeaker) {
|
||||
try {
|
||||
if (speaker == null) {
|
||||
speaker = new Speaker();
|
||||
speaker = new Speaker(computer);
|
||||
} else {
|
||||
speaker.attach();
|
||||
}
|
||||
@ -154,30 +156,28 @@ public class Motherboard extends TimedDevice {
|
||||
Motherboard.miscDevices.remove(speaker);
|
||||
}
|
||||
}
|
||||
if (startAgain && Computer.getComputer().getMemory() != null) {
|
||||
if (startAgain && computer.getMemory() != null) {
|
||||
resume();
|
||||
}
|
||||
}
|
||||
static HashSet<Object> accelorationRequestors = new HashSet<Object>();
|
||||
static HashSet<Object> accelorationRequestors = new HashSet<>();
|
||||
|
||||
static public void requestSpeed(Object requester) {
|
||||
public void requestSpeed(Object requester) {
|
||||
accelorationRequestors.add(requester);
|
||||
if (instance != null) {
|
||||
instance.enableTempMaxSpeed();
|
||||
}
|
||||
enableTempMaxSpeed();
|
||||
}
|
||||
|
||||
static public void cancelSpeedRequest(Object requester) {
|
||||
public void cancelSpeedRequest(Object requester) {
|
||||
accelorationRequestors.remove(requester);
|
||||
if (instance != null && accelorationRequestors.isEmpty()) {
|
||||
instance.disableTempMaxSpeed();
|
||||
if (accelorationRequestors.isEmpty()) {
|
||||
disableTempMaxSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach() {
|
||||
}
|
||||
Map<Card, Boolean> resume = new HashMap<Card, Boolean>();
|
||||
Map<Card, Boolean> resume = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean suspend() {
|
||||
|
@ -60,7 +60,9 @@ public class PagedMemory {
|
||||
/**
|
||||
* Creates a new instance of PagedMemory
|
||||
*/
|
||||
public PagedMemory(int size, Type memType) {
|
||||
Computer computer;
|
||||
public PagedMemory(int size, Type memType, Computer computer) {
|
||||
this.computer = computer;
|
||||
type = memType;
|
||||
internalMemory = new byte[size >> 8][256];
|
||||
for (int i = 0; i < size; i += 256) {
|
||||
@ -127,7 +129,7 @@ public class PagedMemory {
|
||||
|
||||
public void writeByte(int address, byte value) {
|
||||
byte[] page = getMemoryPage(address);
|
||||
StateManager.markDirtyValue(page);
|
||||
StateManager.markDirtyValue(page, computer);
|
||||
getMemoryPage(address)[address & 0x0ff] = value;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ import jace.config.Reconfigurable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* RAM is a 64K address space of paged memory. It also manages sets of memory
|
||||
@ -42,12 +41,14 @@ public abstract class RAM implements Reconfigurable {
|
||||
protected Card[] cards;
|
||||
// card 0 = 80 column card firmware / system rom
|
||||
public int activeSlot = 0;
|
||||
protected final Computer computer;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RAM
|
||||
*/
|
||||
public RAM() {
|
||||
listeners = new Vector<RAMListener>();
|
||||
public RAM(Computer computer) {
|
||||
this.computer = computer;
|
||||
listeners = new ArrayList<>();
|
||||
cards = new Card[8];
|
||||
refreshListenerMap();
|
||||
}
|
||||
@ -196,60 +197,60 @@ public abstract class RAM implements Reconfigurable {
|
||||
private void refreshListenerMap() {
|
||||
listenerMap = new ArrayList[256];
|
||||
ioListenerMap = new ArrayList[256];
|
||||
for (RAMListener l : listeners) {
|
||||
listeners.stream().forEach((l) -> {
|
||||
addListenerRange(l);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addListener(final RAMListener l) {
|
||||
boolean restart = Computer.pause();
|
||||
boolean restart = computer.pause();
|
||||
if (listeners.contains(l)) {
|
||||
return;
|
||||
}
|
||||
listeners.add(l);
|
||||
addListenerRange(l);
|
||||
if (restart) {
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(final RAMListener l) {
|
||||
boolean restart = Computer.pause();
|
||||
boolean restart = computer.pause();
|
||||
listeners.remove(l);
|
||||
refreshListenerMap();
|
||||
if (restart) {
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
}
|
||||
|
||||
public byte callListener(RAMEvent.TYPE t, int address, int oldValue, int newValue, boolean requireSyncronization) {
|
||||
List<RAMListener> activeListeners = null;
|
||||
List<RAMListener> activeListeners;
|
||||
if (requireSyncronization) {
|
||||
Computer.getComputer().getCpu().suspend();
|
||||
computer.getCpu().suspend();
|
||||
}
|
||||
if ((address & 0x0FF00) == 0x0C000) {
|
||||
activeListeners = ioListenerMap[address & 0x0FF];
|
||||
if (activeListeners == null && t.isRead()) {
|
||||
if (requireSyncronization) {
|
||||
Computer.getComputer().getCpu().resume();
|
||||
computer.getCpu().resume();
|
||||
}
|
||||
return Computer.getComputer().getVideo().getFloatingBus();
|
||||
return computer.getVideo().getFloatingBus();
|
||||
}
|
||||
} else {
|
||||
activeListeners = listenerMap[(address >> 8) & 0x0ff];
|
||||
}
|
||||
if (activeListeners != null) {
|
||||
RAMEvent e = new RAMEvent(t, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY, address, oldValue, newValue);
|
||||
for (RAMListener l : activeListeners) {
|
||||
activeListeners.stream().forEach((l) -> {
|
||||
l.handleEvent(e);
|
||||
}
|
||||
});
|
||||
if (requireSyncronization) {
|
||||
Computer.getComputer().getCpu().resume();
|
||||
computer.getCpu().resume();
|
||||
}
|
||||
return (byte) e.getNewValue();
|
||||
}
|
||||
if (requireSyncronization) {
|
||||
Computer.getComputer().getCpu().resume();
|
||||
computer.getCpu().resume();
|
||||
}
|
||||
return (byte) newValue;
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public abstract class SoftSwitch {
|
||||
private final List<Integer> exclusionQuery = new ArrayList<>();
|
||||
private String name;
|
||||
private boolean toggleType = false;
|
||||
protected Computer computer;
|
||||
|
||||
/**
|
||||
* Creates a new instance of SoftSwitch
|
||||
@ -235,18 +236,20 @@ public abstract class SoftSwitch {
|
||||
}
|
||||
}
|
||||
|
||||
public void register() {
|
||||
RAM m = Computer.getComputer().getMemory();
|
||||
public void register(Computer computer) {
|
||||
this.computer = computer;
|
||||
RAM m = computer.getMemory();
|
||||
listeners.stream().forEach((l) -> {
|
||||
m.addListener(l);
|
||||
});
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
RAM m = Computer.getComputer().getMemory();
|
||||
RAM m = computer.getMemory();
|
||||
listeners.stream().forEach((l) -> {
|
||||
m.removeListener(l);
|
||||
});
|
||||
this.computer = null;
|
||||
}
|
||||
|
||||
public void setState(boolean newState) {
|
||||
@ -259,7 +262,7 @@ public abstract class SoftSwitch {
|
||||
state = newState;
|
||||
/*
|
||||
if (queryAddresses != null) {
|
||||
RAM m = Computer.getComputer().getMemory();
|
||||
RAM m = computer.getMemory();
|
||||
for (int i:queryAddresses) {
|
||||
byte old = m.read(i, false);
|
||||
m.write(i, (byte) (old & 0x7f | (state ? 0x080:0x000)), false);
|
||||
|
@ -87,6 +87,10 @@ public class SoundMixer extends Device {
|
||||
};
|
||||
private Mixer theMixer;
|
||||
|
||||
public SoundMixer(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceName() {
|
||||
return "Sound Output";
|
||||
@ -132,7 +136,7 @@ public class SoundMixer extends Device {
|
||||
if (activeLines.containsKey(requester)) {
|
||||
return activeLines.get(requester);
|
||||
}
|
||||
SourceDataLine sdl = null;
|
||||
SourceDataLine sdl;
|
||||
if (availableLines.isEmpty()) {
|
||||
sdl = getNewLine();
|
||||
} else {
|
||||
|
@ -31,7 +31,8 @@ public abstract class TimedDevice extends Device {
|
||||
/**
|
||||
* Creates a new instance of TimedDevice
|
||||
*/
|
||||
public TimedDevice() {
|
||||
public TimedDevice(Computer computer) {
|
||||
super(computer);
|
||||
setSpeed(cyclesPerSecond);
|
||||
}
|
||||
@ConfigurableField(name = "Speed", description = "(in hertz)")
|
||||
|
@ -91,7 +91,8 @@ public abstract class Video extends Device {
|
||||
/**
|
||||
* Creates a new instance of Video
|
||||
*/
|
||||
public Video() {
|
||||
public Video(Computer computer) {
|
||||
super(computer);
|
||||
suspend();
|
||||
video = new BufferedImage(560, 192, BufferedImage.TYPE_INT_RGB);
|
||||
vPeriod = 0;
|
||||
@ -164,7 +165,7 @@ public abstract class Video extends Device {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
setFloatingBus(Computer.getComputer().getMemory().readRaw(scannerAddress + x));
|
||||
setFloatingBus(computer.getMemory().readRaw(scannerAddress + x));
|
||||
if (hPeriod > 0) {
|
||||
hPeriod--;
|
||||
if (hPeriod == 0) {
|
||||
@ -201,12 +202,12 @@ public abstract class Video extends Device {
|
||||
y = APPLE_SCREEN_LINES - (TOTAL_LINES - APPLE_SCREEN_LINES);
|
||||
isVblank = true;
|
||||
vblankStart();
|
||||
Motherboard.vblankStart();
|
||||
computer.getMotherboard().vblankStart();
|
||||
} else {
|
||||
y = 0;
|
||||
isVblank = false;
|
||||
vblankEnd();
|
||||
Motherboard.vblankEnd();
|
||||
computer.getMotherboard().vblankEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,10 @@ public class CardAppleMouse extends Card implements MouseListener {
|
||||
public boolean fullscreenFix = true;
|
||||
ImageIcon mouseActive = Utility.loadIcon("input-mouse.png");
|
||||
|
||||
public CardAppleMouse(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceName() {
|
||||
return "Apple Mouse";
|
||||
@ -232,7 +236,7 @@ public class CardAppleMouse extends Card implements MouseListener {
|
||||
}
|
||||
|
||||
private MOS65C02 getCPU() {
|
||||
return (MOS65C02) Computer.getComputer().getCpu();
|
||||
return (MOS65C02) computer.getCpu();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -321,7 +325,7 @@ public class CardAppleMouse extends Card implements MouseListener {
|
||||
* //gs homes mouse to low address, but //c and //e do not
|
||||
*/
|
||||
private void clampMouse() {
|
||||
RAM128k memory = (RAM128k) Computer.getComputer().memory;
|
||||
RAM128k memory = (RAM128k) computer.memory;
|
||||
byte clampMinLo = memory.getMainMemory().readByte(0x0478);
|
||||
byte clampMaxLo = memory.getMainMemory().readByte(0x04F8);
|
||||
byte clampMinHi = memory.getMainMemory().readByte(0x0578);
|
||||
@ -459,7 +463,7 @@ public class CardAppleMouse extends Card implements MouseListener {
|
||||
if (drawingArea == null) {
|
||||
return;
|
||||
}
|
||||
Graphics2D screen = (Graphics2D) Computer.getComputer().getVideo().getScreen();
|
||||
Graphics2D screen = (Graphics2D) computer.getVideo().getScreen();
|
||||
// Point currentMouseLocation = MouseInfo.getPointerInfo().getLocation();
|
||||
// Point topLeft = drawingArea.getLocationOnScreen();
|
||||
Point currentMouseLocation = Emulator.getFrame().getContentPane().getMousePosition();
|
||||
@ -506,7 +510,7 @@ public class CardAppleMouse extends Card implements MouseListener {
|
||||
y = clampMax.y;
|
||||
}
|
||||
|
||||
PagedMemory m = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory();
|
||||
PagedMemory m = ((RAM128k) computer.getMemory()).getMainMemory();
|
||||
int s = getSlot();
|
||||
/*
|
||||
* $0478 + slot Low byte of absolute X position
|
||||
|
@ -23,7 +23,7 @@ import jace.config.ConfigurableField;
|
||||
import jace.config.Name;
|
||||
import jace.config.Reconfigurable;
|
||||
import jace.core.Card;
|
||||
import jace.core.Motherboard;
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMEvent.TYPE;
|
||||
import jace.core.Utility;
|
||||
@ -48,14 +48,15 @@ import java.util.logging.Logger;
|
||||
public class CardDiskII extends Card implements Reconfigurable, MediaConsumerParent {
|
||||
|
||||
DiskIIDrive currentDrive;
|
||||
DiskIIDrive drive1 = new DiskIIDrive();
|
||||
DiskIIDrive drive2 = new DiskIIDrive();
|
||||
DiskIIDrive drive1 = new DiskIIDrive(computer);
|
||||
DiskIIDrive drive2 = new DiskIIDrive(computer);
|
||||
@ConfigurableField(category = "Disk", defaultValue = "254", name = "Default volume", description = "Value to use for disk volume number")
|
||||
static public int DEFAULT_VOLUME_NUMBER = 0x0FE;
|
||||
@ConfigurableField(category = "Disk", defaultValue = "true", name = "Speed boost", description = "If enabled, emulator will run at max speed during disk access")
|
||||
static public boolean USE_MAX_SPEED = true;
|
||||
|
||||
public CardDiskII() {
|
||||
public CardDiskII(Computer computer) {
|
||||
super(computer);
|
||||
try {
|
||||
loadRom("jace/data/DiskII.rom");
|
||||
} catch (IOException ex) {
|
||||
@ -195,10 +196,10 @@ public class CardDiskII extends Card implements Reconfigurable, MediaConsumerPar
|
||||
private void tweakTiming() {
|
||||
if (drive1.isOn() || drive2.isOn()) {
|
||||
if (USE_MAX_SPEED) {
|
||||
Motherboard.requestSpeed(this);
|
||||
computer.getMotherboard().requestSpeed(this);
|
||||
}
|
||||
} else {
|
||||
Motherboard.cancelSpeedRequest(this);
|
||||
computer.getMotherboard().cancelSpeedRequest(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
package jace.hardware;
|
||||
|
||||
import jace.apple2e.RAM128k;
|
||||
import jace.core.Computer;
|
||||
import jace.core.PagedMemory;
|
||||
import jace.state.Stateful;
|
||||
|
||||
@ -45,11 +46,11 @@ public class CardExt80Col extends RAM128k {
|
||||
return "128kb";
|
||||
}
|
||||
|
||||
public CardExt80Col() {
|
||||
super();
|
||||
auxMemory = new PagedMemory(0xc000, PagedMemory.Type.ram);
|
||||
auxLanguageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard);
|
||||
auxLanguageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard);
|
||||
public CardExt80Col(Computer computer) {
|
||||
super(computer);
|
||||
auxMemory = new PagedMemory(0xc000, PagedMemory.Type.ram, computer);
|
||||
auxLanguageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard, computer);
|
||||
auxLanguageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard, computer);
|
||||
initMemoryPattern(auxMemory);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
package jace.hardware;
|
||||
|
||||
import jace.config.Name;
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMEvent.TYPE;
|
||||
import java.io.IOException;
|
||||
@ -42,7 +43,8 @@ public class CardHayesMicromodem extends CardSSC {
|
||||
public int RING_INDICATOR_REG = 5;
|
||||
private boolean ringIndicator = false;
|
||||
|
||||
public CardHayesMicromodem() {
|
||||
public CardHayesMicromodem(Computer computer) {
|
||||
super(computer);
|
||||
ACIA_Data = 7;
|
||||
ACIA_Status = 6;
|
||||
ACIA_Control = 5;
|
||||
|
@ -86,12 +86,13 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
return "Mockingboard";
|
||||
}
|
||||
|
||||
public CardMockingboard() {
|
||||
public CardMockingboard(Computer computer) {
|
||||
super(computer);
|
||||
controllers = new R6522[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
//don't ask...
|
||||
final int j = i;
|
||||
controllers[i] = new R6522() {
|
||||
controllers[i] = new R6522(computer) {
|
||||
@Override
|
||||
public void sendOutputA(int value) {
|
||||
if (activeChip != null) {
|
||||
@ -156,7 +157,7 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
}
|
||||
if (activeChip == null) {
|
||||
System.err.println("Could not determine which PSG to communicate to");
|
||||
e.setNewValue(Computer.getComputer().getVideo().getFloatingBus());
|
||||
e.setNewValue(computer.getVideo().getFloatingBus());
|
||||
return;
|
||||
}
|
||||
R6522 controller = controllers[chip & 1];
|
||||
@ -172,7 +173,7 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
@Override
|
||||
protected void handleIOAccess(int register, TYPE type, int value, RAMEvent e) {
|
||||
// Oddly, all IO is done at the firmware address bank. It's a strange card.
|
||||
e.setNewValue(Computer.getComputer().getVideo().getFloatingBus());
|
||||
e.setNewValue(computer.getVideo().getFloatingBus());
|
||||
}
|
||||
long ticksSinceLastPlayback = 0;
|
||||
|
||||
@ -305,7 +306,7 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
SourceDataLine out = Motherboard.mixer.getLine(this);
|
||||
SourceDataLine out = computer.getMotherboard().mixer.getLine(this);
|
||||
int[] leftBuffer = new int[BUFFER_LENGTH];
|
||||
int[] rightBuffer = new int[BUFFER_LENGTH];
|
||||
int frameSize = out.getFormat().getFrameSize();
|
||||
@ -317,7 +318,7 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
ticksSinceLastPlayback = 0;
|
||||
int zeroSamples = 0;
|
||||
while (isRunning()) {
|
||||
Motherboard.requestSpeed(this);
|
||||
computer.getMotherboard().requestSpeed(this);
|
||||
playSound(leftBuffer, rightBuffer);
|
||||
int p = 0;
|
||||
for (int idx = 0; idx < BUFFER_LENGTH; idx++) {
|
||||
@ -345,7 +346,7 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
if (zeroSamples >= MAX_IDLE_SAMPLES) {
|
||||
zeroSamples = 0;
|
||||
pause = true;
|
||||
Motherboard.cancelSpeedRequest(this);
|
||||
computer.getMotherboard().cancelSpeedRequest(this);
|
||||
while (pause && isRunning()) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
@ -380,9 +381,9 @@ public class CardMockingboard extends Card implements Runnable {
|
||||
Logger.getLogger(CardMockingboard.class
|
||||
.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
Motherboard.cancelSpeedRequest(this);
|
||||
computer.getMotherboard().cancelSpeedRequest(this);
|
||||
System.out.println("Mockingboard playback stopped");
|
||||
Motherboard.mixer.returnLine(this);
|
||||
computer.getMotherboard().mixer.returnLine(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import jace.Emulator;
|
||||
import jace.config.ConfigurableField;
|
||||
import jace.config.Name;
|
||||
import jace.core.Card;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Motherboard;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMEvent.TYPE;
|
||||
@ -64,7 +65,8 @@ public class CardRamFactor extends Card {
|
||||
return "RamFactor";
|
||||
}
|
||||
ImageIcon indicator;
|
||||
public CardRamFactor() {
|
||||
public CardRamFactor(Computer computer) {
|
||||
super(computer);
|
||||
indicator=Utility.loadIcon("ram.png");
|
||||
try {
|
||||
loadRom("jace/data/RAMFactor14.rom");
|
||||
@ -162,7 +164,7 @@ public class CardRamFactor extends Card {
|
||||
@Override
|
||||
protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
|
||||
if (speedBoost) {
|
||||
Motherboard.requestSpeed(this);
|
||||
computer.getMotherboard().requestSpeed(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +176,7 @@ public class CardRamFactor extends Card {
|
||||
@Override
|
||||
protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
|
||||
if (speedBoost) {
|
||||
Motherboard.requestSpeed(this);
|
||||
computer.getMotherboard().requestSpeed(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,10 +53,10 @@ public class CardRamworks extends RAM128k {
|
||||
public int memorySize = 3072;
|
||||
public int maxBank = memorySize / 64;
|
||||
private Map<BankType, PagedMemory> generateBank() {
|
||||
Map<BankType, PagedMemory> memoryBank = new EnumMap<BankType, PagedMemory>(BankType.class);
|
||||
memoryBank.put(BankType.MAIN_MEMORY, new PagedMemory(0xc000, PagedMemory.Type.ram));
|
||||
memoryBank.put(BankType.LANGUAGE_CARD_1, new PagedMemory(0x3000, PagedMemory.Type.languageCard));
|
||||
memoryBank.put(BankType.LANGUAGE_CARD_2, new PagedMemory(0x1000, PagedMemory.Type.languageCard));
|
||||
Map<BankType, PagedMemory> memoryBank = new EnumMap<>(BankType.class);
|
||||
memoryBank.put(BankType.MAIN_MEMORY, new PagedMemory(0xc000, PagedMemory.Type.ram, computer));
|
||||
memoryBank.put(BankType.LANGUAGE_CARD_1, new PagedMemory(0x3000, PagedMemory.Type.languageCard, computer));
|
||||
memoryBank.put(BankType.LANGUAGE_CARD_2, new PagedMemory(0x1000, PagedMemory.Type.languageCard, computer));
|
||||
return memoryBank;
|
||||
}
|
||||
|
||||
@ -64,9 +64,9 @@ public class CardRamworks extends RAM128k {
|
||||
MAIN_MEMORY, LANGUAGE_CARD_1, LANGUAGE_CARD_2
|
||||
};
|
||||
|
||||
public CardRamworks() {
|
||||
super();
|
||||
memory = new ArrayList<Map<BankType, PagedMemory>>(maxBank);
|
||||
public CardRamworks(Computer computer) {
|
||||
super(computer);
|
||||
memory = new ArrayList<>(maxBank);
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ public class CardRamworks extends RAM128k {
|
||||
|
||||
@Override
|
||||
public void reconfigure() {
|
||||
boolean resume = Computer.pause();
|
||||
boolean resume = computer.pause();
|
||||
maxBank = memorySize / 64;
|
||||
if (maxBank < 1) maxBank = 1;
|
||||
if (maxBank > 128) maxBank = 128;
|
||||
@ -124,7 +124,7 @@ public class CardRamworks extends RAM128k {
|
||||
}
|
||||
configureActiveMemory();
|
||||
if (resume) {
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
}
|
||||
RAMListener bankSelectListener = new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
|
@ -94,6 +94,10 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
||||
// Bitmask for stop bits (FF = 8, 7F = 7, etc)
|
||||
private int DATA_BITS = 0x07F;
|
||||
|
||||
public CardSSC(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return "Super Serial Card";
|
||||
}
|
||||
@ -390,7 +394,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
||||
|
||||
private void triggerIRQ() {
|
||||
IRQ_TRIGGERED = true;
|
||||
Computer.getComputer().getCpu().generateInterrupt();
|
||||
computer.getCpu().generateInterrupt();
|
||||
}
|
||||
|
||||
public void hangUp() {
|
||||
|
@ -59,7 +59,8 @@ public class CardThunderclock extends Card {
|
||||
@ConfigurableField(category = "OS", name = "Patch Prodos Year", description = "If enabled, the Prodos clock driver will be patched to use the current year.")
|
||||
public boolean attemptYearPatch = true;
|
||||
|
||||
public CardThunderclock() {
|
||||
public CardThunderclock(Computer computer) {
|
||||
super(computer);
|
||||
try {
|
||||
loadRom("jace/data/thunderclock_plus.rom");
|
||||
} catch (IOException ex) {
|
||||
@ -213,7 +214,7 @@ public class CardThunderclock extends Card {
|
||||
ticks = 0;
|
||||
irqAsserted = true;
|
||||
if (irqEnabled) {
|
||||
Computer.getComputer().getCpu().generateInterrupt();
|
||||
computer.getCpu().generateInterrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -295,7 +296,7 @@ public class CardThunderclock extends Card {
|
||||
* always tell time correctly.
|
||||
*/
|
||||
private void performProdosPatch() {
|
||||
PagedMemory ram = Computer.getComputer().getMemory().activeRead;
|
||||
PagedMemory ram = computer.getMemory().activeRead;
|
||||
if (patchLoc > 0) {
|
||||
// We've already patched, just validate
|
||||
if (ram.readByte(patchLoc) == (byte) MOS65C02.OPCODE.LDA_IMM.getCode()) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.hardware;
|
||||
|
||||
import jace.core.Computer;
|
||||
import jace.library.MediaConsumer;
|
||||
import jace.library.MediaEntry;
|
||||
import jace.library.MediaEntry.MediaFile;
|
||||
@ -41,7 +42,12 @@ import javax.swing.ImageIcon;
|
||||
*/
|
||||
@Stateful
|
||||
public class DiskIIDrive implements MediaConsumer {
|
||||
Computer computer;
|
||||
|
||||
public DiskIIDrive(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
FloppyDisk disk;
|
||||
// Number of milliseconds to wait between last write and update to disk image
|
||||
public static long WRITE_UPDATE_DELAY = 1000;
|
||||
@ -77,7 +83,7 @@ public class DiskIIDrive implements MediaConsumer {
|
||||
public void reset() {
|
||||
driveOn = false;
|
||||
magnets = 0;
|
||||
dirtyTracks = new HashSet<Integer>();
|
||||
dirtyTracks = new HashSet<>();
|
||||
diskUpdatePending = false;
|
||||
}
|
||||
|
||||
@ -154,7 +160,7 @@ public class DiskIIDrive implements MediaConsumer {
|
||||
dirtyTracks.add(trackStartOffset / FloppyDisk.TRACK_NIBBLE_LENGTH);
|
||||
disk.nibbles[trackStartOffset + nibbleOffset++] = latch;
|
||||
triggerDiskUpdate();
|
||||
StateManager.markDirtyValue(disk.nibbles);
|
||||
StateManager.markDirtyValue(disk.nibbles, computer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,9 +192,9 @@ public class DiskIIDrive implements MediaConsumer {
|
||||
diskUpdatePending = true;
|
||||
// Update all tracks as necessary
|
||||
if (disk != null) {
|
||||
for (Integer track : dirtyTracks) {
|
||||
dirtyTracks.stream().forEach((track) -> {
|
||||
disk.updateTrack(track);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Empty out dirty list
|
||||
dirtyTracks.clear();
|
||||
@ -199,53 +205,54 @@ public class DiskIIDrive implements MediaConsumer {
|
||||
private void triggerDiskUpdate() {
|
||||
lastWriteTime = System.currentTimeMillis();
|
||||
if (writerThread == null || !writerThread.isAlive()) {
|
||||
writerThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long diff = 0;
|
||||
// Wait until there have been no virtual writes for specified delay time
|
||||
while ((diff = System.currentTimeMillis() - lastWriteTime) < WRITE_UPDATE_DELAY) {
|
||||
// Sleep for difference of time
|
||||
LockSupport.parkNanos(diff * 1000);
|
||||
// Note: In the meantime, there could have been another disk write,
|
||||
// in which case this loop will repeat again as needed.
|
||||
}
|
||||
updateDisk();
|
||||
writerThread = new Thread(() -> {
|
||||
long diff = 0;
|
||||
// Wait until there have been no virtual writes for specified delay time
|
||||
while ((diff = System.currentTimeMillis() - lastWriteTime) < WRITE_UPDATE_DELAY) {
|
||||
// Sleep for difference of time
|
||||
LockSupport.parkNanos(diff * 1000);
|
||||
// Note: In the meantime, there could have been another disk write,
|
||||
// in which case this loop will repeat again as needed.
|
||||
}
|
||||
updateDisk();
|
||||
});
|
||||
writerThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
void insertDisk(File diskPath) throws IOException {
|
||||
disk = new FloppyDisk(diskPath);
|
||||
dirtyTracks = new HashSet<Integer>();
|
||||
disk = new FloppyDisk(diskPath, computer);
|
||||
dirtyTracks = new HashSet<>();
|
||||
// Emulator state has changed significantly, reset state manager
|
||||
StateManager.getInstance().invalidate();
|
||||
StateManager.getInstance(computer).invalidate();
|
||||
}
|
||||
private ImageIcon icon;
|
||||
|
||||
@Override
|
||||
public ImageIcon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(ImageIcon i) {
|
||||
icon = i;
|
||||
}
|
||||
private MediaEntry currentMediaEntry;
|
||||
private MediaFile currentMediaFile;
|
||||
|
||||
@Override
|
||||
public void eject() {
|
||||
if (disk == null) {
|
||||
return;
|
||||
}
|
||||
waitForPendingWrites();
|
||||
disk = null;
|
||||
dirtyTracks = new HashSet<Integer>();
|
||||
dirtyTracks = new HashSet<>();
|
||||
// Emulator state has changed significantly, reset state manager
|
||||
StateManager.getInstance().invalidate();
|
||||
StateManager.getInstance(computer).invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertMedia(MediaEntry e, MediaFile f) throws IOException {
|
||||
if (!isAccepted(e, f)) {
|
||||
return;
|
||||
@ -256,14 +263,17 @@ public class DiskIIDrive implements MediaConsumer {
|
||||
currentMediaFile = f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaEntry getMediaEntry() {
|
||||
return currentMediaEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaFile getMediaFile() {
|
||||
return currentMediaFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccepted(MediaEntry e, MediaFile f) {
|
||||
if (f == null) return false;
|
||||
System.out.println("Type is accepted: "+f.path+"; "+e.type.toString()+": "+e.type.is140kb);
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.hardware;
|
||||
|
||||
import jace.core.Computer;
|
||||
import jace.state.StateManager;
|
||||
import jace.state.Stateful;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@ -109,16 +110,16 @@ public class FloppyDisk {
|
||||
* @param diskFile
|
||||
* @throws IOException
|
||||
*/
|
||||
public FloppyDisk(File diskFile) throws IOException {
|
||||
public FloppyDisk(File diskFile, Computer computer) throws IOException {
|
||||
FileInputStream input = new FileInputStream(diskFile);
|
||||
String name = diskFile.getName().toUpperCase();
|
||||
readDisk(input, name.endsWith(".PO"));
|
||||
readDisk(input, name.endsWith(".PO"), computer);
|
||||
writeProtected = !diskFile.canWrite();
|
||||
diskPath = diskFile;
|
||||
}
|
||||
|
||||
// brendanr: refactored to use input stream
|
||||
public void readDisk(InputStream diskFile, boolean prodosOrder) throws IOException {
|
||||
public void readDisk(InputStream diskFile, boolean prodosOrder, Computer computer) throws IOException {
|
||||
isNibblizedImage = true;
|
||||
volumeNumber = CardDiskII.DEFAULT_VOLUME_NUMBER;
|
||||
headerLength = 0;
|
||||
@ -154,8 +155,8 @@ public class FloppyDisk {
|
||||
} catch (IOException ex) {
|
||||
throw ex;
|
||||
}
|
||||
StateManager.markDirtyValue(nibbles);
|
||||
StateManager.markDirtyValue(currentSectorOrder);
|
||||
StateManager.markDirtyValue(nibbles, computer);
|
||||
StateManager.markDirtyValue(currentSectorOrder, computer);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -70,7 +70,8 @@ public class Joystick extends Device {
|
||||
Robot robot;
|
||||
Point centerPoint;
|
||||
|
||||
public Joystick(int port) {
|
||||
public Joystick(int port, Computer computer) {
|
||||
super(computer);
|
||||
centerPoint = new Point(screenSize.width / 2, screenSize.height / 2);
|
||||
this.port = port;
|
||||
if (port == 0) {
|
||||
@ -214,7 +215,7 @@ public class Joystick extends Device {
|
||||
};
|
||||
|
||||
private void registerListeners() {
|
||||
Computer.getComputer().getMemory().addListener(listener);
|
||||
computer.getMemory().addListener(listener);
|
||||
if (useKeyboard) {
|
||||
System.out.println("Registering key handlers");
|
||||
Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_LEFT, -1) {
|
||||
@ -273,7 +274,7 @@ public class Joystick extends Device {
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
Computer.getComputer().getMemory().removeListener(listener);
|
||||
computer.getMemory().removeListener(listener);
|
||||
Keyboard.unregisterAllHandlers(this);
|
||||
}
|
||||
}
|
@ -43,6 +43,10 @@ import javax.sound.midi.Synthesizer;
|
||||
@Name(value = "Passport Midi Interface", description = "MIDI sound card")
|
||||
public class PassportMidiInterface extends Card {
|
||||
|
||||
public PassportMidiInterface(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
|
||||
// There is no rom on this card, so nothing to do here
|
||||
@ -318,7 +322,7 @@ public class PassportMidiInterface extends Card {
|
||||
if (t.irqEnabled) {
|
||||
// System.out.println("Timer generating interrupt!");
|
||||
t.irqRequested = true;
|
||||
Computer.getComputer().getCpu().generateInterrupt();
|
||||
computer.getCpu().generateInterrupt();
|
||||
ptmStatusReadSinceIRQ = false;
|
||||
}
|
||||
if (t.mode == TIMER_MODE.continuous || t.mode == TIMER_MODE.freqComparison) {
|
||||
|
@ -29,6 +29,12 @@ import java.io.IOException;
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public abstract class ProdosDriver {
|
||||
Computer computer;
|
||||
|
||||
public ProdosDriver(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
public static int MLI_COMMAND = 0x042;
|
||||
public static int MLI_UNITNUMBER = 0x043;
|
||||
public static int MLI_BUFFER_ADDRESS = 0x044;
|
||||
@ -71,7 +77,7 @@ public abstract class ProdosDriver {
|
||||
|
||||
public void handleMLI() {
|
||||
int returnCode = prodosMLI().intValue;
|
||||
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu();
|
||||
MOS65C02 cpu = (MOS65C02) computer.getCpu();
|
||||
cpu.A = returnCode;
|
||||
// Clear carry flag if no error, otherwise set carry flag
|
||||
cpu.C = (returnCode == 0x00) ? 00 : 01;
|
||||
@ -79,7 +85,7 @@ public abstract class ProdosDriver {
|
||||
|
||||
private MLI_RETURN prodosMLI() {
|
||||
try {
|
||||
RAM memory = Computer.getComputer().getMemory();
|
||||
RAM memory = computer.getMemory();
|
||||
int cmd = memory.readRaw(MLI_COMMAND);
|
||||
MLI_COMMAND_TYPE command = MLI_COMMAND_TYPE.fromInt(cmd);
|
||||
int unit = (memory.readWordRaw(MLI_UNITNUMBER) & 0x080) > 0 ? 1 : 0;
|
||||
@ -96,7 +102,7 @@ public abstract class ProdosDriver {
|
||||
switch (command) {
|
||||
case STATUS:
|
||||
int blocks = getSize();
|
||||
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu();
|
||||
MOS65C02 cpu = (MOS65C02) computer.getCpu();
|
||||
cpu.X = blocks & 0x0ff;
|
||||
cpu.Y = (blocks >> 8) & 0x0ff;
|
||||
if (isWriteProtected()) {
|
||||
|
@ -31,7 +31,12 @@ import java.util.logging.Logger;
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public abstract class SmartportDriver {
|
||||
Computer computer;
|
||||
|
||||
public SmartportDriver(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
public static enum ERROR_CODE {
|
||||
NO_ERROR(0), INVALID_COMMAND(0x01), BAD_PARAM_COUNT(0x04), INVALID_UNIT(0x011), INVALID_CODE(0x021), BAD_BLOCK_NUMBER(0x02d);
|
||||
int intValue;
|
||||
@ -42,15 +47,15 @@ public abstract class SmartportDriver {
|
||||
|
||||
public void handleSmartport() {
|
||||
int returnCode = callSmartport().intValue;
|
||||
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu();
|
||||
MOS65C02 cpu = (MOS65C02) computer.getCpu();
|
||||
cpu.A = returnCode;
|
||||
// Clear carry flag if no error, otherwise set carry flag
|
||||
cpu.C = (returnCode == 0x00) ? 00 : 01;
|
||||
}
|
||||
|
||||
private ERROR_CODE callSmartport() {
|
||||
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu();
|
||||
RAM ram = Computer.getComputer().getMemory();
|
||||
MOS65C02 cpu = (MOS65C02) computer.getCpu();
|
||||
RAM ram = computer.getMemory();
|
||||
int callAddress = cpu.popWord() + 1;
|
||||
int command = ram.readRaw(callAddress);
|
||||
boolean extendedCall = command >= 0x040;
|
||||
|
@ -23,7 +23,6 @@ import jace.apple2e.MOS65C02;
|
||||
import jace.config.Name;
|
||||
import jace.core.Card;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Motherboard;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMEvent.TYPE;
|
||||
import jace.core.Utility;
|
||||
@ -47,7 +46,8 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
MassStorageDrive drive1;
|
||||
MassStorageDrive drive2;
|
||||
|
||||
public CardMassStorage() {
|
||||
public CardMassStorage(Computer computer) {
|
||||
super(computer);
|
||||
drive1 = new MassStorageDrive();
|
||||
drive2 = new MassStorageDrive();
|
||||
drive1.setIcon(Utility.loadIcon("drive-harddisk.png"));
|
||||
@ -86,7 +86,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ProdosDriver driver = new ProdosDriver() {
|
||||
ProdosDriver driver = new ProdosDriver(computer) {
|
||||
@Override
|
||||
public boolean changeUnit(int unit) {
|
||||
currentDrive = unit == 0 ? drive1 : drive2;
|
||||
@ -110,12 +110,12 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
|
||||
@Override
|
||||
public void mliRead(int block, int bufferAddress) throws IOException {
|
||||
getCurrentDisk().mliRead(block, bufferAddress);
|
||||
getCurrentDisk().mliRead(block, bufferAddress, computer.getMemory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mliWrite(int block, int bufferAddress) throws IOException {
|
||||
getCurrentDisk().mliWrite(block, bufferAddress);
|
||||
getCurrentDisk().mliWrite(block, bufferAddress, computer.getMemory());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -129,14 +129,14 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
try {
|
||||
detach();
|
||||
|
||||
int pc = Computer.getComputer().getCpu().getProgramCounter();
|
||||
int pc = computer.getCpu().getProgramCounter();
|
||||
if (drive1.getCurrentDisk() != null && getSlot() == 7 && (pc == 0x0c65e || pc == 0x0c661)) {
|
||||
// If the computer is in a loop trying to boot from cards 6, fast-boot from here instead
|
||||
// This is a convenience to boot a hard-drive if the emulator has started waiting for a currentDisk
|
||||
currentDrive = drive1;
|
||||
getCurrentDisk().boot0(getSlot());
|
||||
Card[] cards = Computer.getComputer().getMemory().getAllCards();
|
||||
Motherboard.cancelSpeedRequest(cards[6]);
|
||||
getCurrentDisk().boot0(getSlot(), computer);
|
||||
Card[] cards = computer.getMemory().getAllCards();
|
||||
computer.getMotherboard().cancelSpeedRequest(cards[6]);
|
||||
}
|
||||
attach();
|
||||
} catch (IOException ex) {
|
||||
@ -155,7 +155,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
|
||||
@Override
|
||||
protected void handleFirmwareAccess(int offset, TYPE type, int value, RAMEvent e) {
|
||||
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu();
|
||||
MOS65C02 cpu = (MOS65C02) computer.getCpu();
|
||||
// System.out.println(e.getType()+" "+Integer.toHexString(e.getAddress())+" from instruction at "+Integer.toHexString(cpu.getProgramCounter()));
|
||||
if (type.isRead()) {
|
||||
Emulator.getFrame().addIndicator(this, currentDrive.getIcon());
|
||||
@ -172,7 +172,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
try {
|
||||
if (drive1.getCurrentDisk() != null) {
|
||||
currentDrive = drive1;
|
||||
getCurrentDisk().boot0(getSlot());
|
||||
getCurrentDisk().boot0(getSlot(), computer);
|
||||
} else {
|
||||
// Patch for crash on start when no image is mounted
|
||||
e.setNewValue(0x060);
|
||||
@ -185,7 +185,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
cpu.setProgramCounter(0x0dfff);
|
||||
int address = 0x0480;
|
||||
for (char c : error.toCharArray()) {
|
||||
Computer.getComputer().getMemory().write(address++, (byte) (c + 0x080), false, false);
|
||||
computer.getMemory().write(address++, (byte) (c + 0x080), false, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -231,7 +231,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
public void tick() {
|
||||
// Nothing is done per CPU cycle
|
||||
}
|
||||
SmartportDriver smartport = new SmartportDriver() {
|
||||
SmartportDriver smartport = new SmartportDriver(computer) {
|
||||
@Override
|
||||
public boolean changeUnit(int unitNumber) {
|
||||
currentDrive = unitNumber == 1 ? drive1 : drive2;
|
||||
@ -240,12 +240,12 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
|
||||
|
||||
@Override
|
||||
public void read(int blockNum, int buffer) throws IOException {
|
||||
getCurrentDisk().mliRead(blockNum, buffer);
|
||||
getCurrentDisk().mliRead(blockNum, buffer, computer.getMemory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int blockNum, int buffer) throws IOException {
|
||||
getCurrentDisk().mliWrite(blockNum, buffer);
|
||||
getCurrentDisk().mliWrite(blockNum, buffer, computer.getMemory());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package jace.hardware.massStorage;
|
||||
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAM;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -29,9 +31,9 @@ public interface IDisk {
|
||||
public static int MAX_BLOCK = 65535;
|
||||
|
||||
public void mliFormat() throws IOException;
|
||||
public void mliRead(int block, int bufferAddress) throws IOException;
|
||||
public void mliWrite(int block, int bufferAddress) throws IOException;
|
||||
public void boot0(int slot) throws IOException;
|
||||
public void mliRead(int block, int bufferAddress, RAM memory) throws IOException;
|
||||
public void mliWrite(int block, int bufferAddress, RAM memory) throws IOException;
|
||||
public void boot0(int slot, Computer computer) throws IOException;
|
||||
|
||||
// Return size in 512k blocks
|
||||
public int getSize();
|
||||
|
@ -51,12 +51,13 @@ public class LargeDisk implements IDisk {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mliFormat() throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public void mliRead(int block, int bufferAddress) throws IOException {
|
||||
RAM memory = Computer.getComputer().getMemory();
|
||||
@Override
|
||||
public void mliRead(int block, int bufferAddress, RAM memory) throws IOException {
|
||||
if (block < physicalBlocks) {
|
||||
diskImage.seek((block * BLOCK_SIZE) + dataOffset);
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
@ -69,9 +70,9 @@ public class LargeDisk implements IDisk {
|
||||
}
|
||||
}
|
||||
|
||||
public void mliWrite(int block, int bufferAddress) throws IOException {
|
||||
@Override
|
||||
public void mliWrite(int block, int bufferAddress, RAM memory) throws IOException {
|
||||
if (block < physicalBlocks) {
|
||||
RAM memory = Computer.getComputer().getMemory();
|
||||
diskImage.seek((block * BLOCK_SIZE) + dataOffset);
|
||||
byte[] buf = new byte[BLOCK_SIZE];
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
@ -81,19 +82,20 @@ public class LargeDisk implements IDisk {
|
||||
}
|
||||
}
|
||||
|
||||
public void boot0(int slot) throws IOException {
|
||||
Computer.getComputer().getCpu().suspend();
|
||||
mliRead(0, 0x0800);
|
||||
@Override
|
||||
public void boot0(int slot, Computer computer) throws IOException {
|
||||
computer.getCpu().suspend();
|
||||
mliRead(0, 0x0800, computer.getMemory());
|
||||
byte slot16 = (byte) (slot << 4);
|
||||
((MOS65C02) Computer.getComputer().getCpu()).X = slot16;
|
||||
RAM memory = Computer.getComputer().getMemory();
|
||||
((MOS65C02) computer.getCpu()).X = slot16;
|
||||
RAM memory = computer.getMemory();
|
||||
memory.write(CardMassStorage.SLT16, slot16, false, false);
|
||||
memory.write(MLI_COMMAND, (byte) MLI_COMMAND_TYPE.READ.intValue, false, false);
|
||||
memory.write(MLI_UNITNUMBER, slot16, false, false);
|
||||
// Write location to block read routine to zero page
|
||||
memory.writeWord(0x048, 0x0c000 + CardMassStorage.DEVICE_DRIVER_OFFSET + (slot * 0x0100), false, false);
|
||||
((MOS65C02) Computer.getComputer().getCpu()).setProgramCounter(0x0800);
|
||||
Computer.getComputer().getCpu().resume();
|
||||
((MOS65C02) computer.getCpu()).setProgramCounter(0x0800);
|
||||
computer.getCpu().resume();
|
||||
}
|
||||
|
||||
public File getPhysicalPath() {
|
||||
@ -123,7 +125,9 @@ public class LargeDisk implements IDisk {
|
||||
Logger.getLogger(LargeDisk.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
try {
|
||||
fis.close();
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(LargeDisk.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
@ -55,10 +55,10 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
setPhysicalPath(rootPath);
|
||||
}
|
||||
|
||||
public void mliRead(int block, int bufferAddress) throws IOException {
|
||||
@Override
|
||||
public void mliRead(int block, int bufferAddress, RAM memory) throws IOException {
|
||||
// System.out.println("Read block " + block + " to " + Integer.toHexString(bufferAddress));
|
||||
DiskNode node = physicalMap.get(block);
|
||||
RAM memory = Computer.getComputer().getMemory();
|
||||
Arrays.fill(ioBuffer, (byte) (block & 0x0ff));
|
||||
if (node == null) {
|
||||
System.out.println("Reading unknown block?!");
|
||||
@ -83,11 +83,12 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
// System.out.println();
|
||||
}
|
||||
|
||||
public void mliWrite(int block, int bufferAddress) throws IOException {
|
||||
@Override
|
||||
public void mliWrite(int block, int bufferAddress, RAM memory) throws IOException {
|
||||
System.out.println("Write block " + block + " to " + Integer.toHexString(bufferAddress));
|
||||
throw new IOException("Write not implemented yet!");
|
||||
// DiskNode node = physicalMap.get(block);
|
||||
// RAM memory = Computer.getComputer().getMemory();
|
||||
// RAM memory = computer.getMemory();
|
||||
// if (node == null) {
|
||||
// // CAPTURE WRITES TO UNUSED BLOCKS
|
||||
// } else {
|
||||
@ -98,6 +99,7 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mliFormat() {
|
||||
throw new UnsupportedOperationException("Formatting for this type of media is not supported!");
|
||||
}
|
||||
@ -132,9 +134,9 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
// Mark space occupied by node
|
||||
public void allocateEntry(DiskNode node) {
|
||||
physicalMap.put(node.baseBlock, node);
|
||||
for (DiskNode sub : node.additionalNodes) {
|
||||
node.additionalNodes.stream().forEach((sub) -> {
|
||||
physicalMap.put(sub.getBaseBlock(), sub);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mark space occupied by nodes as free (remove allocation mapping)
|
||||
@ -143,11 +145,11 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
if (physicalMap.get(node.baseBlock) != null && physicalMap.get(node.baseBlock).equals(node)) {
|
||||
physicalMap.remove(node.baseBlock);
|
||||
}
|
||||
for (DiskNode sub : node.additionalNodes) {
|
||||
if (physicalMap.get(sub.getBaseBlock()) != null && physicalMap.get(sub.baseBlock).equals(sub)) {
|
||||
physicalMap.remove(sub.getBaseBlock());
|
||||
}
|
||||
}
|
||||
node.additionalNodes.stream().filter((sub) ->
|
||||
(physicalMap.get(sub.getBaseBlock()) != null && physicalMap.get(sub.baseBlock).equals(sub))).
|
||||
forEach((sub) -> {
|
||||
physicalMap.remove(sub.getBaseBlock());
|
||||
});
|
||||
}
|
||||
|
||||
// Is the specified block in use?
|
||||
@ -156,22 +158,22 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void boot0(int slot) throws IOException {
|
||||
public void boot0(int slot, Computer computer) throws IOException {
|
||||
File prodos = locateFile(physicalRoot, "PRODOS.SYS");
|
||||
if (prodos == null || !prodos.exists()) {
|
||||
throw new IOException("Unable to locate PRODOS.SYS");
|
||||
}
|
||||
Computer.getComputer().getCpu().suspend();
|
||||
computer.getCpu().suspend();
|
||||
byte slot16 = (byte) (slot << 4);
|
||||
((MOS65C02) Computer.getComputer().getCpu()).X = slot16;
|
||||
RAM memory = Computer.getComputer().getMemory();
|
||||
((MOS65C02) computer.getCpu()).X = slot16;
|
||||
RAM memory = computer.getMemory();
|
||||
memory.write(CardMassStorage.SLT16, slot16, false, false);
|
||||
memory.write(MLI_COMMAND, (byte) MLI_COMMAND_TYPE.READ.intValue, false, false);
|
||||
memory.write(MLI_UNITNUMBER, slot16, false, false);
|
||||
// Write location to block read routine to zero page
|
||||
memory.writeWord(0x048, 0x0c000 + CardMassStorage.DEVICE_DRIVER_OFFSET + (slot * 0x0100), false, false);
|
||||
EmulatorUILogic.brun(prodos, 0x02000);
|
||||
Computer.getComputer().getCpu().resume();
|
||||
computer.getCpu().resume();
|
||||
}
|
||||
|
||||
public File getPhysicalPath() {
|
||||
@ -183,7 +185,7 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
return;
|
||||
}
|
||||
physicalRoot = f;
|
||||
physicalMap = new HashMap<Integer, DiskNode>();
|
||||
physicalMap = new HashMap<>();
|
||||
if (!physicalRoot.exists() || !physicalRoot.isDirectory()) {
|
||||
try {
|
||||
throw new IOException("Root path must be a directory that exists!");
|
||||
@ -201,6 +203,7 @@ public class ProdosVirtualDisk implements IDisk {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eject() {
|
||||
// Nothing to do here...
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ import jace.core.Device;
|
||||
*/
|
||||
public abstract class R6522 extends Device {
|
||||
|
||||
public R6522() {
|
||||
public R6522(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
// 6522 VIA
|
||||
@ -140,7 +141,7 @@ public abstract class R6522 extends Device {
|
||||
if (timer1interruptEnabled) {
|
||||
// System.out.println("Timer 1 generated interrupt");
|
||||
timer1IRQ = true;
|
||||
Computer.getComputer().getCpu().generateInterrupt();
|
||||
computer.getCpu().generateInterrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,7 +152,7 @@ public abstract class R6522 extends Device {
|
||||
timer2counter = timer2latch;
|
||||
if (timer2interruptEnabled) {
|
||||
timer2IRQ = true;
|
||||
Computer.getComputer().getCpu().generateInterrupt();
|
||||
computer.getCpu().generateInterrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,10 @@
|
||||
*/
|
||||
package jace.library;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.config.ConfigurableField;
|
||||
import jace.config.Reconfigurable;
|
||||
import jace.core.Card;
|
||||
import jace.core.Computer;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
@ -50,14 +50,17 @@ public class MediaLibrary implements Reconfigurable {
|
||||
@ConfigurableField(category = "Library", defaultValue = "true", name = "Keep local copy", description = "Automatically download and save local copies of disks when written.")
|
||||
public static boolean CREATE_LOCAL_ON_SAVE = true;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Media Library";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "media";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconfigure() {
|
||||
rebuildDriveList();
|
||||
}
|
||||
@ -76,7 +79,7 @@ public class MediaLibrary implements Reconfigurable {
|
||||
return;
|
||||
}
|
||||
userInterface.Drives.removeAll();
|
||||
for (Card card : Computer.getComputer().memory.getAllCards()) {
|
||||
for (Card card : Emulator.computer.memory.getAllCards()) {
|
||||
if (card == null || !(card instanceof MediaConsumerParent)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ public class StateManager implements Reconfigurable {
|
||||
|
||||
private static StateManager instance;
|
||||
|
||||
public static StateManager getInstance() {
|
||||
public static StateManager getInstance(Computer computer) {
|
||||
if (instance == null) {
|
||||
instance = new StateManager();
|
||||
instance = new StateManager(computer);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
@ -63,9 +63,14 @@ public class StateManager implements Reconfigurable {
|
||||
public int captureFrequency = 3;
|
||||
private ObjectGraphNode<BufferedImage> imageGraphNode;
|
||||
|
||||
Computer computer;
|
||||
private StateManager(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
private void buildStateMap() {
|
||||
allStateVariables = new HashSet<ObjectGraphNode>();
|
||||
objectLookup = new WeakHashMap<Object, ObjectGraphNode>();
|
||||
allStateVariables = new HashSet<>();
|
||||
objectLookup = new WeakHashMap<>();
|
||||
ObjectGraphNode emulator = new ObjectGraphNode(Emulator.instance);
|
||||
emulator.name = "Emulator";
|
||||
Set visited = new HashSet();
|
||||
@ -235,8 +240,8 @@ public class StateManager implements Reconfigurable {
|
||||
}
|
||||
}
|
||||
|
||||
public static void markDirtyValue(Object o) {
|
||||
StateManager manager = getInstance();
|
||||
public static void markDirtyValue(Object o, Computer computer) {
|
||||
StateManager manager = getInstance(computer);
|
||||
if (manager.objectLookup == null) {
|
||||
return;
|
||||
}
|
||||
@ -259,8 +264,9 @@ public class StateManager implements Reconfigurable {
|
||||
* If reconfigure is called, it means the emulator state has changed too
|
||||
* greatly and we need to abandon captured states and start from scratch.
|
||||
*/
|
||||
@Override
|
||||
public void reconfigure() {
|
||||
boolean resume = Computer.pause();
|
||||
boolean resume = computer.pause();
|
||||
isValid = false;
|
||||
|
||||
// Now figure out how much memory we're allowed to eat
|
||||
@ -269,7 +275,7 @@ public class StateManager implements Reconfigurable {
|
||||
freeRequired = maxMemory / 50L;
|
||||
frameCounter = captureFrequency;
|
||||
if (resume) {
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
}
|
||||
boolean isValid = false;
|
||||
@ -329,7 +335,7 @@ public class StateManager implements Reconfigurable {
|
||||
}
|
||||
|
||||
private BufferedImage getScreenshot() {
|
||||
BufferedImage screen = Computer.getComputer().getVideo().getFrameBuffer();
|
||||
BufferedImage screen = computer.getVideo().getFrameBuffer();
|
||||
ColorModel cm = screen.getColorModel();
|
||||
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
|
||||
WritableRaster raster = screen.copyData(null);
|
||||
@ -391,7 +397,7 @@ public class StateManager implements Reconfigurable {
|
||||
}
|
||||
|
||||
public void rewind(int numStates) {
|
||||
boolean resume = Computer.pause();
|
||||
boolean resume = computer.pause();
|
||||
State state = alphaState.tail;
|
||||
while (numStates > 0 && state.previousState != null) {
|
||||
state = state.previousState;
|
||||
@ -400,10 +406,10 @@ public class StateManager implements Reconfigurable {
|
||||
state.apply();
|
||||
alphaState.tail = state;
|
||||
state.nextState = null;
|
||||
Computer.getComputer().getVideo().forceRefresh();
|
||||
computer.getVideo().forceRefresh();
|
||||
System.gc();
|
||||
if (resume) {
|
||||
Computer.resume();
|
||||
computer.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,49 @@ import jace.hardware.CardMockingboard;
|
||||
*/
|
||||
public class PlaybackEngine extends Computer {
|
||||
|
||||
Motherboard motherboard = new Motherboard();
|
||||
CardMockingboard mockingboard = new CardMockingboard();
|
||||
Computer dummyComputer = new Computer() {
|
||||
|
||||
@Override
|
||||
public void coldStart() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warmStart() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunning() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPause() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doResume() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
};
|
||||
Motherboard motherboard = new Motherboard(dummyComputer);
|
||||
CardMockingboard mockingboard = new CardMockingboard(dummyComputer);
|
||||
|
||||
public PlaybackEngine() {
|
||||
setMemory(new CardExt80Col());
|
||||
setCpu(new MOS65C02());
|
||||
setMemory(new CardExt80Col(dummyComputer));
|
||||
setCpu(new MOS65C02(dummyComputer));
|
||||
getMemory().addCard(mockingboard, 5);
|
||||
}
|
||||
|
||||
|
@ -50,12 +50,17 @@ import javax.swing.JPanel;
|
||||
*/
|
||||
public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implements Reconfigurable {
|
||||
|
||||
Computer computer;
|
||||
/**
|
||||
* Creates new form AbstractEmulatorFrame
|
||||
*/
|
||||
public AbstractEmulatorFrame() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public void setComputer(Computer computer) {
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addKeyListener(KeyListener l) {
|
||||
@ -252,39 +257,32 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
|
||||
private Map<Object, Set<ImageIcon>> indicators = new HashMap<Object, Set<ImageIcon>>();
|
||||
|
||||
public void resizeVideo() {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Computer.pause();
|
||||
Computer.getComputer().getVideo().suspend();
|
||||
JPanel debugger = getDebuggerPanel();
|
||||
Component screen = getScreen();
|
||||
Rectangle bounds = screen.getParent().getBounds();
|
||||
int width = (int) bounds.getWidth();
|
||||
int height = (int) bounds.getHeight();
|
||||
if (debugger.isVisible()) {
|
||||
debugger.setBounds(width - debugger.getWidth(), 0, debugger.getWidth(), height);
|
||||
width = (int) bounds.getWidth() - debugger.getWidth() + 1;
|
||||
screen.setSize(
|
||||
width,
|
||||
height);
|
||||
debugger.revalidate();
|
||||
} else {
|
||||
screen.setSize(
|
||||
width,
|
||||
height);
|
||||
}
|
||||
Computer.getComputer().getVideo().setWidth(width);
|
||||
Computer.getComputer().getVideo().setHeight(height);
|
||||
if (!isFullscreen || !fullscreenEnforceRatio) {
|
||||
Computer.getComputer().getVideo().setScreen(getScreenGraphics());
|
||||
}
|
||||
Computer.getComputer().getVideo().forceRefresh();
|
||||
screen.validate();
|
||||
screen.requestFocusInWindow();
|
||||
Computer.resume();
|
||||
Computer.getComputer().getVideo().resume();
|
||||
EventQueue.invokeLater(() -> {
|
||||
computer.pause();
|
||||
computer.getVideo().suspend();
|
||||
JPanel debugger = getDebuggerPanel();
|
||||
Component screen = getScreen();
|
||||
Rectangle bounds = screen.getParent().getBounds();
|
||||
int width1 = (int) bounds.getWidth();
|
||||
int height1 = (int) bounds.getHeight();
|
||||
if (debugger.isVisible()) {
|
||||
debugger.setBounds(width1 - debugger.getWidth(), 0, debugger.getWidth(), height1);
|
||||
width1 = (int) bounds.getWidth() - debugger.getWidth() + 1;
|
||||
screen.setSize(width1, height1);
|
||||
debugger.revalidate();
|
||||
} else {
|
||||
screen.setSize(width1, height1);
|
||||
}
|
||||
computer.getVideo().setWidth(width1);
|
||||
computer.getVideo().setHeight(height1);
|
||||
if (!isFullscreen || !fullscreenEnforceRatio) {
|
||||
computer.getVideo().setScreen(getScreenGraphics());
|
||||
}
|
||||
computer.getVideo().forceRefresh();
|
||||
screen.validate();
|
||||
screen.requestFocusInWindow();
|
||||
computer.resume();
|
||||
computer.getVideo().resume();
|
||||
});
|
||||
}
|
||||
|
||||
@ -324,8 +322,8 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
|
||||
b.setSize(560 * scale, 384 * scale);
|
||||
b.x = (w / 2) - (b.width / 2);
|
||||
b.y = (h / 2) - (b.height / 2);
|
||||
Computer.pause();
|
||||
Computer.getComputer().getVideo().suspend();
|
||||
computer.pause();
|
||||
computer.getVideo().suspend();
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
@ -335,9 +333,9 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
|
||||
g.fill(getBounds());
|
||||
Graphics2D gg = (Graphics2D) g.create(b.x, b.y, b.width, b.height);
|
||||
gg.scale((double) b.width / (double) sw, (double) b.height / (double) sh);
|
||||
Computer.getComputer().getVideo().setScreen(gg);
|
||||
Computer.getComputer().getVideo().resume();
|
||||
Computer.resume();
|
||||
computer.getVideo().setScreen(gg);
|
||||
computer.getVideo().resume();
|
||||
computer.resume();
|
||||
} else {
|
||||
b = getBounds();
|
||||
getScreen().setBounds(getBounds());
|
||||
@ -364,8 +362,8 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Computer.pause();
|
||||
Computer.getComputer().getVideo().suspend();
|
||||
computer.pause();
|
||||
computer.getVideo().suspend();
|
||||
isFullscreen = !isFullscreen;
|
||||
GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
|
||||
if (isFullscreen) {
|
||||
@ -382,8 +380,8 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
|
||||
device.setFullScreenWindow(null);
|
||||
}
|
||||
resizeVideo();
|
||||
Computer.getComputer().getVideo().resume();
|
||||
Computer.resume();
|
||||
computer.getVideo().resume();
|
||||
computer.resume();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.8" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="3"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
@ -47,12 +47,14 @@
|
||||
<Property name="opaque" type="boolean" value="true"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout"/>
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
|
||||
<Property name="useNullLayout" type="boolean" value="true"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="jace.ui.ScreenPanel" name="screen">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout$JLayeredPaneConstraintsDescription">
|
||||
<JLayeredPaneConstraints x="0" y="0" width="560" height="520" layer="0" position="-1"/>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
|
||||
<AbsoluteConstraints x="0" y="0" width="560" height="520"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
@ -70,9 +72,12 @@
|
||||
</Layout>
|
||||
</Container>
|
||||
<Component class="jace.ui.DebuggerPanel" name="debuggerPanel">
|
||||
<AuxValues>
|
||||
<AuxValue name="JLayeredPane.layer" type="java.lang.Integer" value="200"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout$JLayeredPaneConstraintsDescription">
|
||||
<JLayeredPaneConstraints x="460" y="0" width="-1" height="-1" layer="200" position="-1"/>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
|
||||
<AbsoluteConstraints x="460" y="0" width="-1" height="-1"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
|
@ -77,7 +77,8 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
/**
|
||||
* Creates new form EmulatorFrame
|
||||
*/
|
||||
public EmulatorFrame() {
|
||||
public EmulatorFrame(Computer computer) {
|
||||
setComputer(computer);
|
||||
initComponents();
|
||||
layers.setDoubleBuffered(true);
|
||||
screen.setDoubleBuffered(true);
|
||||
@ -94,6 +95,7 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
screen.setFocusTraversalKeysEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addKeyListener(KeyListener l) {
|
||||
super.addKeyListener(l);
|
||||
layers.addKeyListener(l);
|
||||
@ -154,10 +156,8 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new EmulatorFrame().setVisible(true);
|
||||
}
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
new EmulatorFrame(null).setVisible(true);
|
||||
});
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
@ -165,15 +165,17 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
public javax.swing.JLayeredPane layers;
|
||||
public jace.ui.ScreenPanel screen;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
Set<JLabel> previousIndicators = new HashSet<JLabel>();
|
||||
Set<JLabel> previousIndicators = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void doRedrawIndicators(Set<ImageIcon> ind) {
|
||||
synchronized (previousIndicators) {
|
||||
for (JLabel l : previousIndicators) {
|
||||
previousIndicators.stream().map((l) -> {
|
||||
l.setVisible(false);
|
||||
return l;
|
||||
}).forEach((l) -> {
|
||||
layers.remove(l);
|
||||
}
|
||||
});
|
||||
previousIndicators.clear();
|
||||
}
|
||||
if (ind != null && !ind.isEmpty()) {
|
||||
@ -195,8 +197,8 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
label.setVisible(true);
|
||||
}
|
||||
} else {
|
||||
if (Computer.getComputer() != null && Computer.getComputer().video != null) {
|
||||
Computer.getComputer().video.forceRefresh();
|
||||
if (computer != null && computer.video != null) {
|
||||
computer.video.forceRefresh();
|
||||
}
|
||||
// This was causing a whole screen flicker -- bad.
|
||||
// screen.repaint();
|
||||
@ -208,16 +210,16 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
public void repaintIndicators() {
|
||||
synchronized (previousIndicators) {
|
||||
if (previousIndicators != null) {
|
||||
for (JLabel l : previousIndicators) {
|
||||
previousIndicators.stream().forEach((l) -> {
|
||||
Graphics g = l.getGraphics();
|
||||
if (g != null) {
|
||||
l.paint(g);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<ImageIcon, JLabel> indicatorCache = new HashMap<ImageIcon, JLabel>();
|
||||
Map<ImageIcon, JLabel> indicatorCache = new HashMap<>();
|
||||
|
||||
private JLabel createIndicatorIcon(ImageIcon i) {
|
||||
if (indicatorCache.containsKey(i)) {
|
||||
@ -240,7 +242,7 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
|
||||
indicatorCache.put(i, renderedLabel);
|
||||
return renderedLabel;
|
||||
}
|
||||
Map<String, JFrame> modals = new HashMap<String, JFrame>();
|
||||
Map<String, JFrame> modals = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected void displayModalDialog(final String name, JPanel ui, List<String> ancestors) {
|
||||
|
@ -91,10 +91,8 @@ public class MainFrame extends AbstractEmulatorFrame {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new MainFrame().setVisible(true);
|
||||
}
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
new MainFrame().setVisible(true);
|
||||
});
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.ui;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.core.Computer;
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Color;
|
||||
@ -31,15 +32,21 @@ import java.awt.Graphics;
|
||||
*/
|
||||
public class ScreenCanvas extends Canvas {
|
||||
|
||||
Computer computer;
|
||||
public ScreenCanvas() {
|
||||
setBackground(new Color(0, 0, 64));
|
||||
setIgnoreRepaint(true);
|
||||
}
|
||||
|
||||
public Computer getComputer() {
|
||||
return Emulator.computer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
if (Computer.getComputer() != null) {
|
||||
Computer.getComputer().getVideo().forceRefresh();
|
||||
if (getComputer() != null) {
|
||||
getComputer().getVideo().forceRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.ui;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.core.Computer;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
@ -35,11 +36,15 @@ public class ScreenPanel extends JPanel {
|
||||
setBackground(new Color(0, 0, 64));
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
public Computer getComputer() {
|
||||
return Emulator.computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
if (Computer.getComputer() != null) {
|
||||
Computer.getComputer().getVideo().forceRefresh();
|
||||
if (getComputer() != null) {
|
||||
getComputer().getVideo().forceRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#Generated by Maven
|
||||
#Sun Sep 07 16:06:31 CDT 2014
|
||||
#Wed Sep 17 00:59:53 CDT 2014
|
||||
version=2.0-SNAPSHOT
|
||||
groupId=org.badvision
|
||||
artifactId=jace
|
||||
|
@ -63,7 +63,6 @@ jace/apple2e/Speaker$2.class
|
||||
jace/cheat/MetaCheatForm.class
|
||||
jace/library/MediaEditUI$1.class
|
||||
jace/cheat/PrinceOfPersiaCheats$5.class
|
||||
.netbeans_automatic_build
|
||||
jace/apple2e/SoftSwitches$3.class
|
||||
jace/library/MediaLibraryUI$tocOptions$1.class
|
||||
jace/core/TimedDevice.class
|
||||
|
Loading…
Reference in New Issue
Block a user