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:
Brendan Robert 2014-09-17 23:09:57 -05:00
parent 4b26a07c7f
commit 45add680d4
62 changed files with 806 additions and 674 deletions

View File

@ -71,10 +71,9 @@ public class ConvertDiskImage {
// First read in the disk image, this decodes the disk as necessary // First read in the disk image, this decodes the disk as necessary
FloppyDisk theDisk = null; FloppyDisk theDisk = null;
try { try {
theDisk = new FloppyDisk(in); theDisk = new FloppyDisk(in, null);
} catch (IOException ex) { } catch (IOException ex) {
System.out.println("Couldn't read disk image"); System.out.println("Couldn't read disk image");
ex.printStackTrace();
return; return;
} }
if (!writeNibblized) { if (!writeNibblized) {

View File

@ -20,7 +20,6 @@ package jace;
import jace.apple2e.Apple2e; import jace.apple2e.Apple2e;
import jace.config.Configuration; import jace.config.Configuration;
import jace.core.Computer;
import jace.ui.AbstractEmulatorFrame; import jace.ui.AbstractEmulatorFrame;
import jace.ui.EmulatorFrame; import jace.ui.EmulatorFrame;
import java.awt.Component; import java.awt.Component;
@ -57,7 +56,7 @@ public class Emulator {
return null; return null;
} }
} }
public Apple2e computer; public static Apple2e computer;
public AbstractEmulatorFrame theApp; public AbstractEmulatorFrame theApp;
/** /**
@ -91,7 +90,7 @@ public class Emulator {
Configuration.applySettings(settings); Configuration.applySettings(settings);
// theApp = new MainFrame(); // theApp = new MainFrame();
theApp = new EmulatorFrame(); theApp = new EmulatorFrame(computer);
try { try {
theApp.setIconImage(ImageIO.read(Emulator.class.getClassLoader().getResourceAsStream("jace/data/woz_figure.gif"))); theApp.setIconImage(ImageIO.read(Emulator.class.getClassLoader().getResourceAsStream("jace/data/woz_figure.gif")));
} catch (IOException ex) { } catch (IOException ex) {
@ -139,12 +138,12 @@ public class Emulator {
@Override @Override
public void windowIconified(WindowEvent e) { public void windowIconified(WindowEvent e) {
Computer.getComputer().getVideo().suspend(); computer.getVideo().suspend();
} }
@Override @Override
public void windowDeiconified(WindowEvent e) { public void windowDeiconified(WindowEvent e) {
Computer.getComputer().getVideo().resume(); computer.getVideo().resume();
resizeVideo(); resizeVideo();
} }

View File

@ -24,7 +24,6 @@ import jace.apple2e.SoftSwitches;
import jace.config.ConfigurationPanel; import jace.config.ConfigurationPanel;
import jace.config.InvokableAction; import jace.config.InvokableAction;
import jace.core.CPU; import jace.core.CPU;
import jace.core.Computer;
import jace.core.Debugger; import jace.core.Debugger;
import jace.core.RAM; import jace.core.RAM;
import jace.core.RAMEvent; import jace.core.RAMEvent;
@ -69,7 +68,7 @@ public class EmulatorUILogic {
@Override @Override
public void updateStatus() { public void updateStatus() {
enableDebug(true); enableDebug(true);
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu(); MOS65C02 cpu = (MOS65C02) Emulator.computer.getCpu();
updateCPURegisters(cpu); updateCPURegisters(cpu);
} }
}; };
@ -95,7 +94,7 @@ public class EmulatorUILogic {
} }
public static void enableTrace(boolean b) { public static void enableTrace(boolean b) {
Computer.getComputer().getCpu().setTraceEnabled(b); Emulator.computer.getCpu().setTraceEnabled(b);
} }
public static void stepForward() { public static void stepForward() {
@ -103,7 +102,7 @@ public class EmulatorUILogic {
} }
static void registerDebugger() { static void registerDebugger() {
Computer.getComputer().getCpu().setDebug(debugger); Emulator.computer.getCpu().setDebug(debugger);
} }
public static Integer getValidAddress(String s) { public static Integer getValidAddress(String s) {
@ -122,7 +121,7 @@ public class EmulatorUILogic {
public static void updateWatchList(final DebuggerPanel panel) { public static void updateWatchList(final DebuggerPanel panel) {
java.awt.EventQueue.invokeLater(() -> { java.awt.EventQueue.invokeLater(() -> {
watches.stream().forEach((oldWatch) -> { watches.stream().forEach((oldWatch) -> {
Computer.getComputer().getMemory().removeListener(oldWatch); Emulator.computer.getMemory().removeListener(oldWatch);
}); });
if (panel == null) { if (panel == null) {
return; return;
@ -149,10 +148,10 @@ public class EmulatorUILogic {
watchValue.setText(Integer.toHexString(e.getNewValue() & 0x0FF)); watchValue.setText(Integer.toHexString(e.getNewValue() & 0x0FF));
} }
}; };
Computer.getComputer().getMemory().addListener(newListener); Emulator.computer.getMemory().addListener(newListener);
watches.add(newListener); watches.add(newListener);
// Print out the current value right away // 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)); watchValue.setText(Integer.toString(b & 0x0ff, 16));
} else { } else {
watchValue.setText("00"); 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", 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") alternatives = "Execute program;Load binary;Load program;Load rom;Play single-load game")
public static void runFile() { public static void runFile() {
Computer.pause(); Emulator.computer.pause();
JFileChooser select = new JFileChooser(); JFileChooser select = new JFileChooser();
select.showDialog(Emulator.getFrame(), "Execute binary file"); select.showDialog(Emulator.getFrame(), "Execute binary file");
File binary = select.getSelectedFile(); File binary = select.getSelectedFile();
if (binary == null) { if (binary == null) {
Computer.resume(); Emulator.computer.resume();
return; return;
} }
runFile(binary); runFile(binary);
@ -215,7 +214,7 @@ public class EmulatorUILogic {
} }
} catch (NumberFormatException | IOException ex) { } catch (NumberFormatException | IOException ex) {
} }
Computer.getComputer().getCpu().resume(); Emulator.computer.getCpu().resume();
} }
public static void brun(File binary, int address) throws FileNotFoundException, IOException { 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 // 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 // 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 // TODO: Find a better mousetrap for this one -- it's an ugly hack
Computer.pause(); Emulator.computer.pause();
FileInputStream in = new FileInputStream(binary); FileInputStream in = new FileInputStream(binary);
byte[] data = new byte[in.available()]; byte[] data = new byte[in.available()];
in.read(data); in.read(data);
RAM ram = Computer.getComputer().getMemory(); RAM ram = Emulator.computer.getMemory();
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
ram.write(address + i, data[i], false, true); ram.write(address + i, data[i], false, true);
} }
CPU cpu = Computer.getComputer().getCpu(); CPU cpu = Emulator.computer.getCpu();
Computer.getComputer().getCpu().setProgramCounter(address); Emulator.computer.getCpu().setProgramCounter(address);
Computer.resume(); Emulator.computer.resume();
} }
@InvokableAction( @InvokableAction(
@ -246,9 +245,9 @@ public class EmulatorUILogic {
if (frame == null) { if (frame == null) {
return; return;
} }
Computer.pause(); Emulator.computer.pause();
frame.enforceIntegerRatio(); frame.enforceIntegerRatio();
Computer.resume(); Emulator.computer.resume();
} }
@InvokableAction( @InvokableAction(
@ -271,9 +270,9 @@ public class EmulatorUILogic {
if (frame == null) { if (frame == null) {
return; return;
} }
Computer.pause(); Emulator.computer.pause();
frame.toggleFullscreen(); frame.toggleFullscreen();
Computer.resume(); Emulator.computer.resume();
} }
@InvokableAction( @InvokableAction(
@ -285,7 +284,7 @@ public class EmulatorUILogic {
SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss"); SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
String timestamp = df.format(new Date()); String timestamp = df.format(new Date());
String type; String type;
int start = Computer.getComputer().getVideo().getCurrentWriter().actualWriter().getYOffset(0); int start = Emulator.computer.getVideo().getCurrentWriter().actualWriter().getYOffset(0);
int len; int len;
if (start < 0x02000) { if (start < 0x02000) {
// Lo-res or double-lores // Lo-res or double-lores
@ -302,8 +301,8 @@ public class EmulatorUILogic {
} }
File outFile = new File("screen_" + type + "_a" + Integer.toHexString(start) + "_" + timestamp); File outFile = new File("screen_" + type + "_a" + Integer.toHexString(start) + "_" + timestamp);
try (FileOutputStream out = new FileOutputStream(outFile)) { try (FileOutputStream out = new FileOutputStream(outFile)) {
RAM128k ram = (RAM128k) Computer.getComputer().memory; RAM128k ram = (RAM128k) Emulator.computer.memory;
Computer.pause(); Emulator.computer.pause();
if (dres) { if (dres) {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
out.write(ram.getAuxVideoMemory().readByte(start + i)); out.write(ram.getAuxVideoMemory().readByte(start + i));
@ -323,8 +322,8 @@ public class EmulatorUILogic {
alternatives = "Save image,save framebuffer,screenshot") alternatives = "Save image,save framebuffer,screenshot")
public static void saveScreenshot() throws HeadlessException, IOException { public static void saveScreenshot() throws HeadlessException, IOException {
JFileChooser select = new JFileChooser(); JFileChooser select = new JFileChooser();
Computer.pause(); Emulator.computer.pause();
BufferedImage i = Computer.getComputer().getVideo().getFrameBuffer(); BufferedImage i = Emulator.computer.getVideo().getFrameBuffer();
BufferedImage j = new BufferedImage(i.getWidth(), i.getHeight(), i.getType()); BufferedImage j = new BufferedImage(i.getWidth(), i.getHeight(), i.getType());
j.getGraphics().drawImage(i, 0, 0, null); j.getGraphics().drawImage(i, 0, 0, null);
select.showSaveDialog(Emulator.getFrame()); select.showSaveDialog(Emulator.getFrame());

View File

@ -37,6 +37,7 @@ import jace.hardware.Joystick;
import jace.hardware.massStorage.CardMassStorage; import jace.hardware.massStorage.CardMassStorage;
import java.awt.Graphics; import java.awt.Graphics;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; 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 * overall configuration of the computer, but the actual operation of the
* computer and its timing characteristics are managed in the Motherboard class. * 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 @Stateful
public class Apple2e extends Computer { public class Apple2e extends Computer {
static int IRQ_VECTOR = 0x003F2; static int IRQ_VECTOR = 0x003F2;
public Motherboard motherboard;
@ConfigurableField(name = "Slot 1", shortName = "s1card") @ConfigurableField(name = "Slot 1", shortName = "s1card")
public ClassSelection card1 = new ClassSelection(Card.class, null); public ClassSelection card1 = new ClassSelection(Card.class, null);
@ConfigurableField(name = "Slot 2", shortName = "s2card") @ConfigurableField(name = "Slot 2", shortName = "s2card")
@ -96,9 +96,9 @@ public class Apple2e extends Computer {
try { try {
reconfigure(); reconfigure();
// Setup core resources // Setup core resources
joystick1 = new Joystick(0); joystick1 = new Joystick(0, this);
joystick2 = new Joystick(1); joystick2 = new Joystick(1, this);
setCpu(new MOS65C02()); setCpu(new MOS65C02(this));
reinitMotherboard(); reinitMotherboard();
} catch (Throwable t) { } catch (Throwable t) {
System.err.println("Unable to initalize virtual machine"); System.err.println("Unable to initalize virtual machine");
@ -115,7 +115,7 @@ public class Apple2e extends Computer {
if (motherboard != null && motherboard.isRunning()) { if (motherboard != null && motherboard.isRunning()) {
motherboard.suspend(); motherboard.suspend();
} }
motherboard = new Motherboard(); motherboard = new Motherboard(this);
motherboard.reconfigure(); motherboard.reconfigure();
Motherboard.miscDevices.add(joystick1); Motherboard.miscDevices.add(joystick1);
Motherboard.miscDevices.add(joystick2); Motherboard.miscDevices.add(joystick2);
@ -123,7 +123,7 @@ public class Apple2e extends Computer {
@Override @Override
public void coldStart() { public void coldStart() {
Computer.pause(); pause();
reinitMotherboard(); reinitMotherboard();
reboot(); reboot();
//getMemory().dump(); //getMemory().dump();
@ -139,7 +139,7 @@ public class Apple2e extends Computer {
} }
} }
Computer.resume(); resume();
/* /*
getCpu().resume(); getCpu().resume();
getVideo().resume(); getVideo().resume();
@ -156,7 +156,7 @@ public class Apple2e extends Computer {
@Override @Override
public void warmStart() { public void warmStart() {
boolean restart = Computer.pause(); boolean restart = pause();
for (SoftSwitches s : SoftSwitches.values()) { for (SoftSwitches s : SoftSwitches.values()) {
s.getSwitch().reset(); s.getSwitch().reset();
} }
@ -169,10 +169,10 @@ public class Apple2e extends Computer {
} }
} }
getCpu().resume(); 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) != null) {
if (getMemory().getCard(slot).getClass().equals(type)) { if (getMemory().getCard(slot).getClass().equals(type)) {
return; return;
@ -181,7 +181,8 @@ public class Apple2e extends Computer {
} }
if (type != null) { if (type != null) {
try { try {
getMemory().addCard(type.newInstance(), slot); Card card = type.getConstructor(Computer.class).newInstance(this);
getMemory().addCard(card, slot);
} catch (InstantiationException | IllegalAccessException ex) { } catch (InstantiationException | IllegalAccessException ex) {
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
} }
@ -190,10 +191,10 @@ public class Apple2e extends Computer {
@Override @Override
public final void reconfigure() { public final void reconfigure() {
boolean restart = Computer.pause(); boolean restart = pause();
super.reconfigure(); super.reconfigure();
RAM128k currentMemory = (RAM128k) getMemory(); RAM128k currentMemory = (RAM128k) getMemory();
if (currentMemory != null && !(currentMemory.getClass().equals(ramCard.getValue()))) { if (currentMemory != null && !(currentMemory.getClass().equals(ramCard.getValue()))) {
try { try {
@ -212,7 +213,7 @@ public class Apple2e extends Computer {
try { try {
setMemory(currentMemory); setMemory(currentMemory);
for (SoftSwitches s : SoftSwitches.values()) { for (SoftSwitches s : SoftSwitches.values()) {
s.getSwitch().register(); s.getSwitch().register(this);
} }
} catch (Throwable ex) { } catch (Throwable ex) {
} }
@ -250,14 +251,18 @@ public class Apple2e extends Computer {
} }
} }
// Add all new cards try {
insertCard(card1.getValue(), 1); // Add all new cards
insertCard(card2.getValue(), 2); insertCard(card1.getValue(), 1);
insertCard(card3.getValue(), 3); insertCard(card2.getValue(), 2);
insertCard(card4.getValue(), 4); insertCard(card3.getValue(), 3);
insertCard(card5.getValue(), 5); insertCard(card4.getValue(), 4);
insertCard(card6.getValue(), 6); insertCard(card5.getValue(), 5);
insertCard(card7.getValue(), 7); 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) { if (enableHints) {
enableHints(); enableHints();
} else { } else {
@ -293,7 +298,7 @@ public class Apple2e extends Computer {
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
} }
if (restart) { if (restart) {
Computer.resume(); resume();
} }
} }
@ -342,7 +347,7 @@ public class Apple2e extends Computer {
if (getCpu().getProgramCounter() >> 8 != 0x0c6) { if (getCpu().getProgramCounter() >> 8 != 0x0c6) {
return; return;
} }
int row = 2; int row = 2;
for (String s : new String[]{ for (String s : new String[]{
" Welcome to", " Welcome to",

View File

@ -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") @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; public boolean warnAboutExtendedOpcodes = false;
private static RAM getMemory() { private RAM getMemory() {
return Computer.getComputer().getMemory(); return computer.getMemory();
}
public MOS65C02(Computer computer) {
super(computer);
} }
@Override @Override
@ -344,7 +348,7 @@ public class MOS65C02 extends CPU {
default int getValue(boolean isRead, MOS65C02 cpu) { default int getValue(boolean isRead, MOS65C02 cpu) {
int address = calculateAddress(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, "#$~1 ($R)"),
RELATIVE(2, "$R", (cpu) -> { RELATIVE(2, "$R", (cpu) -> {
int pc = cpu.getProgramCounter(); 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! // The wait cycles are not added unless the branch actually happens!
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00)); cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00));
return address; return address;
}), }),
IMMEDIATE(2, "#$~1", (cpu) -> cpu.getProgramCounter() + 1), IMMEDIATE(2, "#$~1", (cpu) -> cpu.getProgramCounter() + 1),
ZEROPAGE(2, "$~1", (cpu) -> getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) & 0x00FF), ZEROPAGE(2, "$~1", (cpu) -> 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_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 & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.Y)), 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) -> { INDIRECT(3, "$(~2~1)", (cpu) -> {
int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false); int address = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
return getMemory().readWord(address, TYPE.READ_DATA, true, false); return cpu.getMemory().readWord(address, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_X(3, "$(~2~1,X)", (cpu) -> { INDIRECT_X(3, "$(~2~1,X)", (cpu) -> {
int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X; int address = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
return getMemory().readWord(address & 0x0FFFF, TYPE.READ_DATA, true, false); return cpu.getMemory().readWord(address & 0x0FFFF, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_ZP(2, "$(~1)", (cpu) -> { INDIRECT_ZP(2, "$(~1)", (cpu) -> {
int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false); int address = cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false); return cpu.getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_ZP_X(2, "$(~1,X)", (cpu) -> { INDIRECT_ZP_X(2, "$(~1,X)", (cpu) -> {
int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X; int address = cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false); return cpu.getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_ZP_Y(2, "$(~1),Y", (cpu) -> { INDIRECT_ZP_Y(2, "$(~1),Y", (cpu) -> {
int address = 0x00FF & getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false); int address = 0x00FF & cpu.getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
address = getMemory().readWord(address, TYPE.READ_DATA, true, false) + cpu.Y; address = cpu.getMemory().readWord(address, TYPE.READ_DATA, true, false) + cpu.Y;
if ((address & 0x00ff00) > 0) { if ((address & 0x00ff00) > 0) {
cpu.addWaitCycles(1); cpu.addWaitCycles(1);
} }
return address; 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) -> { 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); int address = 0x0FFFF & (address2 + cpu.X);
if ((address & 0x00FF00) != (address2 & 0x00FF00)) { if ((address & 0x00FF00) != (address2 & 0x00FF00)) {
cpu.addWaitCycles(1); cpu.addWaitCycles(1);
@ -397,7 +401,7 @@ public class MOS65C02 extends CPU {
return address; return address;
}), }),
ABSOLUTE_Y(3, "$~2~1,Y", (cpu) -> { 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); int address = 0x0FFFF & (address2 + cpu.Y);
if ((address & 0x00FF00) != (address2 & 0x00FF00)) { if ((address & 0x00FF00) != (address2 & 0x00FF00)) {
cpu.addWaitCycles(1); cpu.addWaitCycles(1);
@ -407,9 +411,9 @@ public class MOS65C02 extends CPU {
ZP_REL(2, "$~1,$R", new AddressCalculator() { ZP_REL(2, "$~1,$R", new AddressCalculator() {
@Override @Override
public int calculateAddress(MOS65C02 cpu) { 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 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! // The wait cycles are not added unless the branch actually happens!
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00)); cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00));
return address; return address;
@ -418,8 +422,8 @@ public class MOS65C02 extends CPU {
@Override @Override
public int getValue(boolean isRead, MOS65C02 cpu) { public int getValue(boolean isRead, MOS65C02 cpu) {
int pc = cpu.getProgramCounter(); int pc = cpu.getProgramCounter();
int address = getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false); int address = cpu.getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
return getMemory().read(address, TYPE.READ_DATA, true, false); return cpu.getMemory().read(address, TYPE.READ_DATA, true, false);
} }
}); });
private int size; private int size;
@ -473,16 +477,16 @@ public class MOS65C02 extends CPU {
return calculator; return calculator;
} }
public String formatMode(int pc) { public String formatMode(int pc, MOS65C02 cpu) {
if (implied) { if (implied) {
return ""; return "";
} else { } else {
int b1 = 0x00ff & getMemory().readRaw((pc + 1) & 0x0FFFF); int b1 = 0x00ff & cpu.getMemory().readRaw((pc + 1) & 0x0FFFF);
if (relative) { if (relative) {
String R = wordString(pc + 2 + (byte) b1); String R = wordString(pc + 2 + (byte) b1);
return f1 + R; return f1 + R;
} else if (twoByte) { } 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; return f1 + byte2(b2) + byte2(b1) + f2;
} else { } else {
return f1 + byte2(b1) + f2; 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) { public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
int mask = 0x0ff ^ (1 << bit); int mask = 0x0ff ^ (1 << bit);
value &= mask; 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) { public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
int mask = 1 << bit; int mask = 1 << bit;
value |= mask; 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); cpu.setNZ(value);
// Emulate correct behavior of fetch-store-modify // Emulate correct behavior of fetch-store-modify
// http://forum.6502.org/viewtopic.php?f=4&t=1617&view=previous // http://forum.6502.org/viewtopic.php?f=4&t=1617&view=previous
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
}), }),
ASL_A((address, value, addressMode, cpu) -> { ASL_A((address, value, addressMode, cpu) -> {
cpu.C = cpu.A >> 7; cpu.C = cpu.A >> 7;
@ -738,8 +742,8 @@ public class MOS65C02 extends CPU {
}), }),
DEC((address, value, addressMode, cpu) -> { DEC((address, value, addressMode, cpu) -> {
value = 0x0FF & (value - 1); value = 0x0FF & (value - 1);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
cpu.setNZ(value); cpu.setNZ(value);
}), }),
DEA((address, value, addressMode, cpu) -> { DEA((address, value, addressMode, cpu) -> {
@ -761,8 +765,8 @@ public class MOS65C02 extends CPU {
INC((address, value, addressMode, cpu) -> { INC((address, value, addressMode, cpu) -> {
value = 0x0ff & (value + 1); value = 0x0ff & (value + 1);
// emulator correct fetch-modify-store behavior // emulator correct fetch-modify-store behavior
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
cpu.setNZ(value); cpu.setNZ(value);
}), }),
INA((address, value, addressMode, cpu) -> { INA((address, value, addressMode, cpu) -> {
@ -801,8 +805,8 @@ public class MOS65C02 extends CPU {
value = (value >> 1) & 0x07F; value = (value >> 1) & 0x07F;
cpu.setNZ(value); cpu.setNZ(value);
// emulator correct fetch-modify-store behavior // emulator correct fetch-modify-store behavior
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
}), }),
LSR_A((address, value, addressMode, cpu) -> { LSR_A((address, value, addressMode, cpu) -> {
cpu.C = cpu.A & 1; cpu.C = cpu.A & 1;
@ -856,8 +860,8 @@ public class MOS65C02 extends CPU {
value = 0x0ff & ((value << 1) | oldC); value = 0x0ff & ((value << 1) | oldC);
cpu.setNZ(value); cpu.setNZ(value);
// emulator correct fetch-modify-store behavior // emulator correct fetch-modify-store behavior
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
}), }),
ROL_A((address, value, addressMode, cpu) -> { ROL_A((address, value, addressMode, cpu) -> {
int oldC = cpu.C; int oldC = cpu.C;
@ -871,8 +875,8 @@ public class MOS65C02 extends CPU {
value = 0x0ff & ((value >> 1) | oldC); value = 0x0ff & ((value >> 1) | oldC);
cpu.setNZ(value); cpu.setNZ(value);
// emulator correct fetch-modify-store behavior // emulator correct fetch-modify-store behavior
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
}), }),
ROR_A((address, value, addressMode, cpu) -> { ROR_A((address, value, addressMode, cpu) -> {
int oldC = cpu.C << 7; int oldC = cpu.C << 7;
@ -947,19 +951,19 @@ public class MOS65C02 extends CPU {
SMB6(new SMBCommand(6)), SMB6(new SMBCommand(6)),
SMB7(new SMBCommand(7)), SMB7(new SMBCommand(7)),
STA(true, (address, value, addressMode, cpu) -> { 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) -> { STP((address, value, addressMode, cpu) -> {
cpu.suspend(); cpu.suspend();
}), }),
STX(true, (address, value, addressMode, cpu) -> { 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) -> { 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) -> { 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) -> { TAX((address, value, addressMode, cpu) -> {
cpu.X = cpu.A; cpu.X = cpu.A;
@ -972,12 +976,12 @@ public class MOS65C02 extends CPU {
TRB((address, value, addressMode, cpu) -> { TRB((address, value, addressMode, cpu) -> {
cpu.C = (value & cpu.A) != 0 ? 1 : 0; cpu.C = (value & cpu.A) != 0 ? 1 : 0;
value &= ~cpu.A; value &= ~cpu.A;
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
}), }),
TSB((address, value, addressMode, cpu) -> { TSB((address, value, addressMode, cpu) -> {
cpu.C = (value & cpu.A) != 0 ? 1 : 0; cpu.C = (value & cpu.A) != 0 ? 1 : 0;
value |= cpu.A; value |= cpu.A;
getMemory().write(address, (byte) value, true, false); cpu.getMemory().write(address, (byte) value, true, false);
}), }),
TSX((address, value, addressMode, cpu) -> { TSX((address, value, addressMode, cpu) -> {
cpu.X = cpu.STACK; cpu.X = cpu.STACK;
@ -1033,8 +1037,8 @@ public class MOS65C02 extends CPU {
} }
int pc = getProgramCounter(); int pc = getProgramCounter();
// RAM ram = getMemory(); // RAM ram = cpu.getMemory();
// int op = 0x00ff & getMemory().read(pc, false); // 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. // 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); int op = 0x00ff & getMemory().read(pc, TYPE.EXECUTE, true, false);
OPCODE opcode = opcodes[op]; OPCODE opcode = opcodes[op];
@ -1203,7 +1207,7 @@ public class MOS65C02 extends CPU {
// Cold/Warm boot procedure // Cold/Warm boot procedure
@Override @Override
public void reset() { public void reset() {
boolean restart = Computer.pause(); boolean restart = computer.pause();
pushWord(getProgramCounter()); pushWord(getProgramCounter());
push(getStatus()); push(getStatus());
// STACK = 0x0ff; // 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)); System.out.println("Reset called, setting PC to (" + Integer.toString(RESET_VECTOR, 16) + ") = " + Integer.toString(newPC, 16));
setProgramCounter(newPC); setProgramCounter(newPC);
if (restart) { if (restart) {
Computer.resume(); computer.resume();
} }
} }
@ -1276,13 +1280,13 @@ public class MOS65C02 extends CPU {
public String disassemble() { public String disassemble() {
int pc = getProgramCounter(); int pc = getProgramCounter();
// RAM ram = getMemory(); // RAM ram = cpu.getMemory();
int op = getMemory().readRaw(pc); int op = getMemory().readRaw(pc);
OPCODE o = opcodes[op & 0x0ff]; OPCODE o = opcodes[op & 0x0ff];
if (o == null) { if (o == null) {
return "???"; return "???";
} }
String format = o.getMode().formatMode(pc); String format = o.getMode().formatMode(pc, this);
// format = format.replaceAll("~1", byte2(b1)); // format = format.replaceAll("~1", byte2(b1));
// format = format.replaceAll("~2", byte2(b2)); // format = format.replaceAll("~2", byte2(b2));
// format = format.replaceAll("R", R); // format = format.replaceAll("R", R);

View File

@ -18,6 +18,7 @@
*/ */
package jace.apple2e; package jace.apple2e;
import jace.core.CPU;
import jace.core.Card; import jace.core.Card;
import jace.core.Computer; import jace.core.Computer;
import jace.core.PagedMemory; import jace.core.PagedMemory;
@ -44,16 +45,16 @@ abstract public class RAM128k extends RAM {
public PagedMemory rom; public PagedMemory rom;
public PagedMemory blank; public PagedMemory blank;
public RAM128k() { public RAM128k(Computer computer) {
super(); super(computer);
mainMemory = new PagedMemory(0xc000, PagedMemory.Type.ram); mainMemory = new PagedMemory(0xc000, PagedMemory.Type.ram, computer);
rom = new PagedMemory(0x3000, PagedMemory.Type.firmwareMain); rom = new PagedMemory(0x3000, PagedMemory.Type.firmwareMain, computer);
cPageRom = new PagedMemory(0x1000, PagedMemory.Type.slotRom); cPageRom = new PagedMemory(0x1000, PagedMemory.Type.slotRom, computer);
languageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard); languageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard, computer);
languageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard); languageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard, computer);
activeRead = new PagedMemory(0x10000, PagedMemory.Type.ram); activeRead = new PagedMemory(0x10000, PagedMemory.Type.ram, computer);
activeWrite = new PagedMemory(0x10000, PagedMemory.Type.ram); activeWrite = new PagedMemory(0x10000, PagedMemory.Type.ram, computer);
blank = new PagedMemory(0x100, PagedMemory.Type.ram); blank = new PagedMemory(0x100, PagedMemory.Type.ram, computer);
// Format memory with FF FF 00 00 pattern // Format memory with FF FF 00 00 pattern
for (int i = 0; i < 0x0100; i++) { for (int i = 0; i < 0x0100; i++) {
@ -191,13 +192,14 @@ abstract public class RAM128k extends RAM {
} }
public void log(String message) { 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 = ""; String stack = "";
for (StackTraceElement e : Thread.currentThread().getStackTrace()) { for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
stack += e.getClassName() + "." + e.getMethodName() + "(" + e.getLineNumber() + ");"; stack += e.getClassName() + "." + e.getMethodName() + "(" + e.getLineNumber() + ");";
} }
Computer.getComputer().cpu.log(stack); 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(message + ";" + SoftSwitches.RAMRD + ";" + SoftSwitches.RAMWRT + ";" + SoftSwitches.AUXZP + ";" + SoftSwitches._80STORE + ";" + SoftSwitches.HIRES + ";" + SoftSwitches.PAGE2 + ";" + SoftSwitches.LCBANK1 + ";" + SoftSwitches.LCRAM + ";" + SoftSwitches.LCWRITE);
} }
} }

View File

@ -65,21 +65,21 @@ public enum SoftSwitches {
PAGE2(new VideoSoftSwitch("Page2", 0x0c054, 0x0c055, 0x0c01c, RAMEvent.TYPE.ANY, false) { PAGE2(new VideoSoftSwitch("Page2", 0x0c054, 0x0c055, 0x0c01c, RAMEvent.TYPE.ANY, false) {
@Override @Override
public void stateChanged() { public void stateChanged() {
// if (Computer.getComputer() == null) { // if (computer == null) {
// return; // return;
// } // }
// if (Computer.getComputer() == null && Computer.getComputer().getMemory() == null) { // if (computer == null && computer.getMemory() == null) {
// return; // return;
// } // }
// if (Computer.getComputer() == null && Computer.getComputer().getVideo() == null) { // if (computer == null && computer.getVideo() == null) {
// return; // return;
// } // }
// PAGE2 is a hybrid switch; 80STORE ? memory : video // PAGE2 is a hybrid switch; 80STORE ? memory : video
if (_80STORE.isOn()) { if (_80STORE.isOn()) {
Computer.getComputer().getMemory().configureActiveMemory(); computer.getMemory().configureActiveMemory();
} else { } 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) { FLOATING_BUS(new SoftSwitch("FloatingBus", null, null, new int[]{0x0C050, 0x0C051, 0x0C052, 0x0C053, 0x0C054}, RAMEvent.TYPE.READ, null) {
@Override @Override
protected byte readSwitch() { protected byte readSwitch() {
if (Computer.getComputer().getVideo() == null) { if (computer.getVideo() == null) {
return 0; return 0;
} }
return Computer.getComputer().getVideo().getFloatingBus(); return computer.getVideo().getFloatingBus();
} }
@Override @Override

View File

@ -163,7 +163,8 @@ public class Speaker extends Device {
/** /**
* Creates a new instance of Speaker * Creates a new instance of Speaker
*/ */
public Speaker() { public Speaker(Computer computer) {
super(computer);
configureListener(); configureListener();
reconfigure(); reconfigure();
} }
@ -189,7 +190,7 @@ public class Speaker extends Device {
public void resume() { public void resume() {
sdl = null; sdl = null;
try { try {
sdl = Motherboard.mixer.getLine(this); sdl = computer.getMotherboard().mixer.getLine(this);
} catch (LineUnavailableException ex) { } catch (LineUnavailableException ex) {
System.out.println("ERROR: Could not output sound: " + ex.getMessage()); 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; int wait = 0;
while (bufferPos >= BUFFER_SIZE) { while (bufferPos >= BUFFER_SIZE) {
if (wait++ > 1000) { if (wait++ > 1000) {
Computer.pause(); computer.pause();
detach(); detach();
Computer.resume(); computer.resume();
Motherboard.enableSpeaker = false; Motherboard.enableSpeaker = false;
gripe("Sound playback is not working properly. Check your configuration and sound system to ensure they are set up properly."); gripe("Sound playback is not working properly. Check your configuration and sound system to ensure they are set up properly.");
return; return;
@ -322,11 +324,11 @@ public class Speaker extends Device {
* Add a memory event listener for C03x for capturing speaker events * Add a memory event listener for C03x for capturing speaker events
*/ */
private void configureListener() { private void configureListener() {
Computer.getComputer().getMemory().addListener(listener); computer.getMemory().addListener(listener);
} }
private void removeListener() { private void removeListener() {
Computer.getComputer().getMemory().removeListener(listener); computer.getMemory().removeListener(listener);
} }
/** /**

View File

@ -70,7 +70,8 @@ public class VideoDHGR extends Video {
/** /**
* Creates a new instance of VideoDHGR * Creates a new instance of VideoDHGR
*/ */
public VideoDHGR() { public VideoDHGR(Computer computer) {
super(computer);
hiresPage1 = new VideoWriter() { hiresPage1 = new VideoWriter() {
@Override @Override
public int getYOffset(int y) { public int getYOffset(int y) {
@ -292,10 +293,10 @@ public class VideoDHGR extends Video {
if ((xOffset & 0x01) == 1) { if ((xOffset & 0x01) == 1) {
return; return;
} }
int b1 = ((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset); int b1 = ((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset);
int b2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset); int b2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset);
int b3 = ((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1); int b3 = ((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1);
int b4 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1); int b4 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
int useColOffset = xOffset << 1; int useColOffset = xOffset << 1;
// This shouldn't be necessary but prevents an index bounds exception when graphics modes are flipped (Race condition?) // This shouldn't be necessary but prevents an index bounds exception when graphics modes are flipped (Race condition?)
if (useColOffset >= 77) { if (useColOffset >= 77) {
@ -318,8 +319,8 @@ public class VideoDHGR extends Video {
if ((xOffset & 0x01) == 1) { if ((xOffset & 0x01) == 1) {
return; return;
} }
int b1 = 0x0ff & ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset); int b1 = 0x0ff & ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset);
int b2 = 0x0ff & ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1); int b2 = 0x0ff & ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
int dhgrWord = hgrToDhgr[(extraHalfBit && xOffset > 0) ? b1 | 0x0100 : b1][b2]; int dhgrWord = hgrToDhgr[(extraHalfBit && xOffset > 0) ? b1 | 0x0100 : b1][b2];
extraHalfBit = (dhgrWord & 0x10000000) != 0; extraHalfBit = (dhgrWord & 0x10000000) != 0;
showDhgr(screen, times14[xOffset], y, dhgrWord & 0xfffffff); 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) { 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) { if ((y & 7) < 4) {
c1 &= 15; c1 &= 15;
} else { } else {
@ -402,8 +403,8 @@ public class VideoDHGR extends Video {
} }
private void displayDoubleLores(BufferedImage screen, int xOffset, int y, int rowAddress) { private void displayDoubleLores(BufferedImage screen, int xOffset, int y, int rowAddress) {
int c1 = ((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset) & 0x0FF; int c1 = ((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset) & 0x0FF;
int c2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF; int c2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset) & 0x0FF;
if ((y & 7) < 4) { if ((y & 7) < 4) {
c1 &= 15; c1 &= 15;
c2 &= 15; c2 &= 15;
@ -549,8 +550,8 @@ public class VideoDHGR extends Video {
return; return;
} }
int yOffset = y & 7; int yOffset = y & 7;
byte byte2 = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1); byte byte2 = ((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset + 1);
int c1 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset)); int c1 = getFontChar(((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset));
int c2 = getFontChar(byte2); int c2 = getFontChar(byte2);
int b1 = Font.getByte(c1, yOffset); int b1 = Font.getByte(c1, yOffset);
int b2 = Font.getByte(c2, yOffset); int b2 = Font.getByte(c2, yOffset);
@ -566,10 +567,10 @@ public class VideoDHGR extends Video {
return; return;
} }
int yOffset = y & 7; int yOffset = y & 7;
int c1 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset)); int c1 = getFontChar(((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset));
int c2 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getMainMemory().readByte(rowAddress + xOffset)); int c2 = getFontChar(((RAM128k) computer.getMemory()).getMainMemory().readByte(rowAddress + xOffset));
int c3 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1)); int c3 = getFontChar(((RAM128k) computer.getMemory()).getAuxVideoMemory().readByte(rowAddress + xOffset + 1));
int c4 = getFontChar(((RAM128k) Computer.getComputer().getMemory()).getMainMemory().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) int bits = Font.getByte(c1, yOffset) | (Font.getByte(c2, yOffset) << 7)
| (Font.getByte(c3, yOffset) << 14) | (Font.getByte(c4, yOffset) << 21); | (Font.getByte(c3, yOffset) << 14) | (Font.getByte(c4, yOffset) << 21);
showBW(screen, times14[xOffset], y, bits); showBW(screen, times14[xOffset], y, bits);
@ -683,7 +684,7 @@ public class VideoDHGR extends Video {
} }
private void registerDirtyFlagChecks() { 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 @Override
protected void doConfig() { protected void doConfig() {
setScopeStart(0x0400); 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 @Override
protected void doConfig() { protected void doConfig() {
setScopeStart(0x2000); setScopeStart(0x2000);

View File

@ -63,6 +63,11 @@ public class VideoNTSC extends VideoDHGR {
boolean colorActive = false; boolean colorActive = false;
int rowStart = 0; int rowStart = 0;
public VideoNTSC(Computer computer) {
super(computer);
createStateListeners();
}
@Override @Override
protected void showBW(BufferedImage screen, int xOffset, int y, int dhgrWord) { protected void showBW(BufferedImage screen, int xOffset, int y, int dhgrWord) {
if (lastKnownY != y) { if (lastKnownY != y) {
@ -97,13 +102,13 @@ public class VideoNTSC extends VideoDHGR {
pos = rowStart = divBy28[xOffset]; pos = rowStart = divBy28[xOffset];
colorActive = true; 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) { if ((y & 7) < 4) {
c1 &= 15; c1 &= 15;
} else { } else {
c1 >>= 4; 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) { if ((y & 7) < 4) {
c2 &= 15; c2 &= 15;
} else { } else {
@ -346,9 +351,9 @@ public class VideoNTSC extends VideoDHGR {
// System.out.println(state + ": "+ graphicsMode); // System.out.println(state + ": "+ graphicsMode);
} }
// These catch changes to the RGB mode to toggle between color, BW and mixed // 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) { rgbStateListeners.add(new RAMListener(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
@Override @Override
protected void doConfig() { protected void doConfig() {
@ -357,7 +362,7 @@ public class VideoNTSC extends VideoDHGR {
@Override @Override
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
Video v = Computer.getComputer().getVideo(); Video v = computer.getVideo();
if (v instanceof VideoNTSC) { if (v instanceof VideoNTSC) {
((VideoNTSC) v).rgbStateChange(ModeStateChanges.CLEAR_AN3); ((VideoNTSC) v).rgbStateChange(ModeStateChanges.CLEAR_AN3);
} }
@ -371,7 +376,7 @@ public class VideoNTSC extends VideoDHGR {
@Override @Override
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
Video v = Computer.getComputer().getVideo(); Video v = computer.getVideo();
if (v instanceof VideoNTSC) { if (v instanceof VideoNTSC) {
((VideoNTSC) v).rgbStateChange(ModeStateChanges.SET_AN3); ((VideoNTSC) v).rgbStateChange(ModeStateChanges.SET_AN3);
} }
@ -385,7 +390,7 @@ public class VideoNTSC extends VideoDHGR {
@Override @Override
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
Video v = Computer.getComputer().getVideo(); Video v = computer.getVideo();
if (v instanceof VideoNTSC) { if (v instanceof VideoNTSC) {
// When reset hook is called, reset the graphics mode // When reset hook is called, reset the graphics mode
// This is useful in case a program is running that // This is useful in case a program is running that
@ -405,21 +410,19 @@ public class VideoNTSC extends VideoDHGR {
@Override @Override
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
Video v = Computer.getComputer().getVideo(); Video v = computer.getVideo();
if (v instanceof VideoNTSC) { if (v instanceof VideoNTSC) {
((VideoNTSC) v).rgbStateChange(ModeStateChanges.SET_80); ((VideoNTSC) v).rgbStateChange(ModeStateChanges.SET_80);
} }
} }
}); });
} }
@Override @Override
public void detach() { public void detach() {
super.detach(); super.detach();
rgbStateListeners.stream().forEach((l) -> { 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() { public void attach() {
super.attach(); super.attach();
rgbStateListeners.stream().forEach((l) -> { rgbStateListeners.stream().forEach((l) -> {
Computer.getComputer().getMemory().addListener(l); computer.getMemory().addListener(l);
}); });
} }
} }

View File

@ -76,8 +76,8 @@ public class IntC8SoftSwitch extends SoftSwitch {
@Override @Override
public void stateChanged() { public void stateChanged() {
if (Computer.getComputer().getMemory() != null) { if (computer.getMemory() != null) {
Computer.getComputer().getMemory().configureActiveMemory(); computer.getMemory().configureActiveMemory();
} }
} }
} }

View File

@ -40,8 +40,8 @@ public class MemorySoftSwitch extends SoftSwitch {
public void stateChanged() { public void stateChanged() {
// System.out.println(getName()+ " was switched to "+getState()); // System.out.println(getName()+ " was switched to "+getState());
if (Computer.getComputer().getMemory() != null) { if (computer.getMemory() != null) {
Computer.getComputer().getMemory().configureActiveMemory(); computer.getMemory().configureActiveMemory();
} }
} }

View File

@ -40,8 +40,8 @@ public class VideoSoftSwitch extends SoftSwitch {
public void stateChanged() { public void stateChanged() {
// System.out.println("Set "+getName()+" -> "+getState()); // System.out.println("Set "+getName()+" -> "+getState());
if (Computer.getComputer().getVideo() != null) { if (computer.getVideo() != null) {
Computer.getComputer().getVideo().configureVideoMode(); computer.getVideo().configureVideoMode();
} }
} }

View File

@ -30,18 +30,22 @@ import java.util.Set;
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/ */
public abstract class Cheats extends Device { 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) { public void addCheat(RAMListener l) {
listeners.add(l); listeners.add(l);
Computer.getComputer().getMemory().addListener(l); computer.getMemory().addListener(l);
} }
@Override @Override
public void detach() { public void detach() {
for (RAMListener l : listeners) { listeners.stream().forEach((l) -> {
Computer.getComputer().getMemory().removeListener(l); computer.getMemory().removeListener(l);
} });
listeners.clear(); listeners.clear();
} }
@ -51,6 +55,7 @@ public abstract class Cheats extends Device {
attach(); attach();
} }
@Override
public String getShortName() { public String getShortName() {
return "cheat"; return "cheat";
} }

View File

@ -18,7 +18,7 @@
*/ */
package jace.cheat; package jace.cheat;
import jace.core.Computer; import jace.Emulator;
import jace.core.RAM; import jace.core.RAM;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
@ -56,17 +56,14 @@ public class MemorySpyGrid extends javax.swing.JPanel {
gradient = bwGradient; gradient = bwGradient;
} }
// This is used primarily during scroll events to repaint the whole area // This is used primarily during scroll events to repaint the whole area
ChangeListener viewportChangeListener = new ChangeListener() { ChangeListener viewportChangeListener = (ChangeEvent e) -> {
@Override repaint();
public void stateChanged(ChangeEvent e) {
repaint();
}
}; };
@Override @Override
public void validate() { public void validate() {
super.validate(); super.validate();
if (Computer.getComputer() != null) { if (Emulator.computer != null) {
adjustSize(); adjustSize();
} }
if (getParent() != null) { if (getParent() != null) {
@ -92,7 +89,7 @@ public class MemorySpyGrid extends javax.swing.JPanel {
} }
} }
} else { } else {
RAM ram = Computer.getComputer().getMemory(); RAM ram = Emulator.computer.getMemory();
for (int a = startAddress; a <= endAddress; a++) { for (int a = startAddress; a <= endAddress; a++) {
drawValue(a, ram.readRaw(a) & 0x0ff, (Graphics2D) g); drawValue(a, ram.readRaw(a) & 0x0ff, (Graphics2D) g);
} }
@ -198,35 +195,31 @@ public class MemorySpyGrid extends javax.swing.JPanel {
if (mousePresent) { if (mousePresent) {
final int addr = convertXYtoAddr(mouseX, mouseY); final int addr = convertXYtoAddr(mouseX, mouseY);
if (addr >= 0) { if (addr >= 0) {
final int value = Computer.getComputer().getMemory().readRaw(addr) & 0x0ff; final int value = Emulator.computer.getMemory().readRaw(addr) & 0x0ff;
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(() -> {
public void run() { Integer lastChange = setBy.get(addr);
Integer lastChange = setBy.get(addr); Integer lastRead = readBy.get(addr);
Integer lastRead = readBy.get(addr); char c1 = (char) Math.max(32, value & 0x07f);
char c1 = (char) Math.max(32, value & 0x07f); char c2 = (char) (64 + (value % 32));
char c2 = (char) (64 + (value % 32)); char c3 = (char) (32 + (value % 96));
char c3 = (char) (32 + (value % 96));
status.setText("$"
status.setText("$" + spaceFill(Integer.toHexString(addr), 4) + ": "
+ spaceFill(Integer.toHexString(addr), 4) + ": " + spaceFill(String.valueOf(value), 3) + " ($"
+ spaceFill(String.valueOf(value), 3) + " ($" + spaceFill(Integer.toHexString(value), 2) + ") " + c1 + " " + c2 + " " + c3
+ spaceFill(Integer.toHexString(value), 2) + ") " + c1 + " " + c2 + " " + c3 + (lastChange != null
+ (lastChange != null ? " Written by $"
? " Written by $" + spaceFill(Integer.toHexString(lastChange), 4)
+ spaceFill(Integer.toHexString(lastChange), 4) : "")
: "") + (lastRead != null
+ (lastRead != null ? " Read by $"
? " Read by $" + spaceFill(Integer.toHexString(lastRead), 4)
+ spaceFill(Integer.toHexString(lastRead), 4) : ""));
: ""));
}
}); });
} }
} else { } else {
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(() -> {
public void run() { status.setText("Nothing selected");
status.setText("Nothing selected");
}
}); });
} }
} }
@ -274,20 +267,17 @@ public class MemorySpyGrid extends javax.swing.JPanel {
} }
public void recalibrate() { public void recalibrate() {
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(() -> {
@Override stopDisplay();
public void run() { int size = endAddress - startAddress + 1;
stopDisplay(); int width1 = getParent().getWidth();
int size = endAddress - startAddress + 1; columns = ((width1 / zoomAmount) / 16) * 16;
int width = getParent().getWidth(); int height1 = ((size / columns) + 1) * zoomAmount;
columns = ((width / zoomAmount) / 16) * 16; setSize(width1, height1);
int height = ((size / columns) + 1) * zoomAmount; setPreferredSize(new Dimension(width1, height1));
setSize(width, height); getParent().validate();
setPreferredSize(new Dimension(width, height)); repaint();
getParent().validate(); startDisplay();
repaint();
startDisplay();
}
}); });
} }
@ -322,17 +312,17 @@ public class MemorySpyGrid extends javax.swing.JPanel {
static int ACTIVITY_DECREMENT = 5; static int ACTIVITY_DECREMENT = 5;
static int ACTIVITY_MAX = 255; static int ACTIVITY_MAX = 255;
RAMListener memoryListener = null; RAMListener memoryListener = null;
Map<Integer, Integer> readActivity = new ConcurrentHashMap<Integer, Integer>(); Map<Integer, Integer> readActivity = new ConcurrentHashMap<>();
Map<Integer, Integer> writeActivity = new ConcurrentHashMap<Integer, Integer>(); Map<Integer, Integer> writeActivity = new ConcurrentHashMap<>();
Map<Integer, Integer> pcActivity = new ConcurrentHashMap<Integer, Integer>(); Map<Integer, Integer> pcActivity = new ConcurrentHashMap<>();
Set<Integer> activeRam = new ConcurrentSkipListSet<Integer>(); Set<Integer> activeRam = new ConcurrentSkipListSet<>();
Map<Integer, Integer> valueActivity = new ConcurrentHashMap<Integer, Integer>(); Map<Integer, Integer> valueActivity = new ConcurrentHashMap<>();
Map<Integer, Integer> setBy = new ConcurrentHashMap<Integer, Integer>(); Map<Integer, Integer> setBy = new ConcurrentHashMap<>();
Map<Integer, Integer> readBy = new ConcurrentHashMap<Integer, Integer>(); Map<Integer, Integer> readBy = new ConcurrentHashMap<>();
void startDisplay() { void startDisplay() {
if (memoryListener != null) { if (memoryListener != null) {
Computer.getComputer().getMemory().removeListener(memoryListener); Emulator.computer.getMemory().removeListener(memoryListener);
memoryListener = null; memoryListener = null;
} }
isDisplayActive = true; isDisplayActive = true;
@ -349,7 +339,7 @@ public class MemorySpyGrid extends javax.swing.JPanel {
if (addr < startAddress || addr > endAddress) { if (addr < startAddress || addr > endAddress) {
return; return;
} }
int pc = Computer.getComputer().getCpu().programCounter; int pc = Emulator.computer.getCpu().programCounter;
if (e.getType() == TYPE.EXECUTE || e.getType() == TYPE.READ_OPERAND) { if (e.getType() == TYPE.EXECUTE || e.getType() == TYPE.READ_OPERAND) {
if (pcActivity.containsKey(addr)) { if (pcActivity.containsKey(addr)) {
pcActivity.put(addr, Math.min(ACTIVITY_MAX, getInt(pcActivity.get(addr)) + ACTIVITY_INCREMENT)); 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); activeRam.add(addr);
} }
}; };
Computer.getComputer().getMemory().addListener(memoryListener); Emulator.computer.getMemory().addListener(memoryListener);
redrawThread = new Thread(new Runnable() { redrawThread = new Thread(() -> {
@Override if (mode == Modes.ACTIVITY) {
public void run() { // Activity heatmap mode
if (mode == Modes.ACTIVITY) { while (isDisplayActive) {
// Activity heatmap mode updateDetails();
while (isDisplayActive) { Graphics2D g = (Graphics2D) getGraphics();
updateDetails(); for (Iterator<Integer> i = activeRam.iterator(); i.hasNext();) {
Graphics2D g = (Graphics2D) getGraphics(); boolean remove = true;
for (Iterator<Integer> i = activeRam.iterator(); i.hasNext();) { int addr = i.next();
boolean remove = true; int read = getInt(readActivity.get(addr));
int addr = i.next(); if (read <= 0) {
int read = getInt(readActivity.get(addr)); read = 0;
if (read <= 0) { } else {
read = 0; remove = false;
} else { readActivity.put(addr, read - ACTIVITY_DECREMENT);
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);
} }
g.dispose(); int write = getInt(writeActivity.get(addr));
try { if (write <= 0) {
Thread.sleep(UPDATE_INTERVAL); write = 0;
} catch (InterruptedException ex) { } else {
Logger.getLogger(MemorySpyGrid.class.getName()).log(Level.SEVERE, null, ex); remove = false;
writeActivity.put(addr, write - ACTIVITY_DECREMENT);
} }
} int pc = getInt(pcActivity.get(addr));
} else { if (pc <= 0) {
// Redraw value, no activity counts needed pc = 0;
while (isDisplayActive) { } else {
updateDetails(); remove = false;
Graphics2D g = (Graphics2D) getGraphics(); pcActivity.put(addr, pc - ACTIVITY_DECREMENT);
for (Iterator<Integer> i = valueActivity.keySet().iterator(); i.hasNext();) { }
int addr = i.next();
int value = getInt(valueActivity.get(addr)); if (remove) {
i.remove(); i.remove();
drawValue(addr, value, g); pcActivity.remove(addr);
} writeActivity.remove(addr);
g.dispose(); readActivity.remove(addr);
try {
Thread.sleep(UPDATE_INTERVAL);
} catch (InterruptedException ex) {
Logger.getLogger(MemorySpyGrid.class.getName()).log(Level.SEVERE, null, ex);
} }
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() { void stopDisplay() {
isDisplayActive = false; isDisplayActive = false;
if (memoryListener != null) { if (memoryListener != null) {
Computer.getComputer().getMemory().removeListener(memoryListener); Emulator.computer.getMemory().removeListener(memoryListener);
memoryListener = null; memoryListener = null;
} }
if (redrawThread != null && redrawThread.isAlive()) { if (redrawThread != null && redrawThread.isAlive()) {

View File

@ -44,16 +44,16 @@ public class MetaCheats extends Cheats {
// This is used to help the handler exit faster when there is nothing to do // This is used to help the handler exit faster when there is nothing to do
boolean noCheats = true; boolean noCheats = true;
public MetaCheats() { public MetaCheats(Computer computer) {
super(); super(computer);
singleton = this; singleton = this;
} }
Map<Integer, Integer> holdBytes = new TreeMap<Integer,Integer>(); Map<Integer, Integer> holdBytes = new TreeMap<>();
Map<Integer, Integer> holdWords = new TreeMap<Integer,Integer>(); Map<Integer, Integer> holdWords = new TreeMap<>();
Set<Integer> disabled = new HashSet<Integer>(); Set<Integer> disabled = new HashSet<>();
Map<Integer, Integer> results = new TreeMap<Integer,Integer>(); Map<Integer, Integer> results = new TreeMap<>();
@Override @Override
protected String getDeviceName() { protected String getDeviceName() {
return "Meta-cheat engine"; return "Meta-cheat engine";
@ -80,7 +80,7 @@ public class MetaCheats extends Cheats {
Logger.getLogger(MetaCheats.class.getName()).log(Level.SEVERE, null, ex); 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(); DefaultTableModel model = (DefaultTableModel) form.resultsTable.getModel();
if (results.size() > MAX_RESULTS_SHOWN) { if (results.size() > MAX_RESULTS_SHOWN) {
model.setRowCount(0); model.setRowCount(0);
@ -90,8 +90,8 @@ public class MetaCheats extends Cheats {
boolean useWord = form.searchForWord.isSelected(); boolean useWord = form.searchForWord.isSelected();
if (model.getRowCount() != results.size()) { if (model.getRowCount() != results.size()) {
model.setRowCount(0); model.setRowCount(0);
List<Integer> iter = new ArrayList<Integer>(results.keySet()); List<Integer> iter = new ArrayList<>(results.keySet());
for (Integer i : iter) { iter.stream().forEach((i) -> {
int val = results.get(i); int val = results.get(i);
if (useWord) { if (useWord) {
int current = ram.readWordRaw(i) & 0x0ffff; int current = ram.readWordRaw(i) & 0x0ffff;
@ -100,9 +100,9 @@ public class MetaCheats extends Cheats {
int current = ram.readRaw(i) & 0x0ff; int current = ram.readRaw(i) & 0x0ff;
model.addRow(new Object[]{hex(i, 4), val + " ("+hex(val,2)+")", current + " ("+hex(current,2)+")"}); model.addRow(new Object[]{hex(i, 4), val + " ("+hex(val,2)+")", current + " ("+hex(current,2)+")"});
} }
} });
} else { } else {
List<Integer> iter = new ArrayList<Integer>(results.keySet()); List<Integer> iter = new ArrayList<>(results.keySet());
for (int i=0; i < iter.size(); i++) { for (int i=0; i < iter.size(); i++) {
int val = results.get(iter.get(i)); int val = results.get(iter.get(i));
if (useWord) { if (useWord) {
@ -131,18 +131,18 @@ public class MetaCheats extends Cheats {
noCheats = holdBytes.isEmpty() && holdWords.isEmpty() && disabled.isEmpty(); noCheats = holdBytes.isEmpty() && holdWords.isEmpty() && disabled.isEmpty();
DefaultTableModel model = (DefaultTableModel) form.activeCheatsTable.getModel(); DefaultTableModel model = (DefaultTableModel) form.activeCheatsTable.getModel();
model.setRowCount(0); model.setRowCount(0);
for (Integer i : holdBytes.keySet()) { holdBytes.keySet().stream().forEach((i) -> {
String loc = hex(i, 4); String loc = hex(i, 4);
if (disabled.contains(i)) loc += " (off)"; if (disabled.contains(i)) loc += " (off)";
int val = holdBytes.get(i); int val = holdBytes.get(i);
model.addRow(new Object[]{loc, val + " ("+hex(val,2)+")"}); model.addRow(new Object[]{loc, val + " ("+hex(val,2)+")"});
} });
for (Integer i : holdWords.keySet()) { holdWords.keySet().stream().forEach((i) -> {
String loc = hex(i, 4); String loc = hex(i, 4);
if (disabled.contains(i)) loc += " (off)"; if (disabled.contains(i)) loc += " (off)";
int val = holdWords.get(i); int val = holdWords.get(i);
model.addRow(new Object[]{loc, val + " ("+hex(val,4)+")"}); model.addRow(new Object[]{loc, val + " ("+hex(val,4)+")"});
} });
} }
public void showCheatForm() { public void showCheatForm() {
if (form == null) { if (form == null) {
@ -191,11 +191,8 @@ public class MetaCheats extends Cheats {
if (results.isEmpty()) return; if (results.isEmpty()) return;
if (results.size() > MAX_RESULTS_SHOWN || isDrawing) return; if (results.size() > MAX_RESULTS_SHOWN || isDrawing) return;
if (results.containsKey(e.getAddress()) || results.containsKey(e.getAddress()-1)) { if (results.containsKey(e.getAddress()) || results.containsKey(e.getAddress()-1)) {
Thread t = new Thread(new Runnable() { Thread t = new Thread(() -> {
@Override redrawResults();
public void run() {
redrawResults();
}
}); });
t.setName("Metacheat results updater"); t.setName("Metacheat results updater");
t.start(); t.start();
@ -258,7 +255,7 @@ public class MetaCheats extends Cheats {
} }
void performSearch(boolean useDeltaSearch, boolean searchForByteValues, int val) { void performSearch(boolean useDeltaSearch, boolean searchForByteValues, int val) {
RAM128k ram = (RAM128k) Computer.getComputer().getMemory(); RAM128k ram = (RAM128k) computer.getMemory();
if (results.isEmpty()) { if (results.isEmpty()) {
int max = 0x010000; int max = 0x010000;
if (!searchForByteValues) max--; if (!searchForByteValues) max--;
@ -272,8 +269,8 @@ public class MetaCheats extends Cheats {
} }
} }
} else { } else {
Set<Integer> remove = new HashSet<Integer>(); Set<Integer> remove = new HashSet<>();
for (Integer i : results.keySet()) { results.keySet().stream().forEach((i) -> {
int v = searchForByteValues ? ram.readRaw(i) & 0x0ff : ram.readWordRaw(i) & 0x0ffff; int v = searchForByteValues ? ram.readRaw(i) & 0x0ff : ram.readWordRaw(i) & 0x0ffff;
if (useDeltaSearch) { if (useDeltaSearch) {
if (v - results.get(i) != val) { if (v - results.get(i) != val) {
@ -288,10 +285,10 @@ public class MetaCheats extends Cheats {
results.put(i,v); results.put(i,v);
} }
} }
} });
for (Integer i : remove) { remove.stream().forEach((i) -> {
results.remove(i); results.remove(i);
} });
} }
form.resultsStatusLabel.setText("Search found "+results.size()+" result(s)."); form.resultsStatusLabel.setText("Search found "+results.size()+" result(s).");
redrawResults(); redrawResults();
@ -308,7 +305,7 @@ public class MetaCheats extends Cheats {
} }
void addWatches(int addrStart, int addrEnd) { void addWatches(int addrStart, int addrEnd) {
RAM128k ram = (RAM128k) Computer.getComputer().getMemory(); RAM128k ram = (RAM128k) computer.getMemory();
if (form == null) return; if (form == null) return;
boolean searchForByteValues = form.searchForByte.isSelected(); boolean searchForByteValues = form.searchForByte.isSelected();
for (int i = addrStart; i <= addrEnd; i = i + (searchForByteValues ? 1 : 2)) { for (int i = addrStart; i <= addrEnd; i = i + (searchForByteValues ? 1 : 2)) {

View File

@ -109,11 +109,11 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
public static int LinkMap = 0x0bda0; public static int LinkMap = 0x0bda0;
public static int Map = 0x0bea0; public static int Map = 0x0bea0;
public static int MapInfo = 0x0bf00; public static int MapInfo = 0x0bf00;
public static int RedBufs = 0x05e00; public static final int RedBufs = 0x05e00;
public static int RedBuf = RedBufs + 90; 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 // 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 final int WipeBuf = RedBuf + 90;
public static int MoveBuf = WipeBuf + 30; public static final int MoveBuf = WipeBuf + 30;
// Object types // Object types
// Source: https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/MOVEDATA.S // Source: https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/MOVEDATA.S
public static int space = 0; 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. // This is the correct value for an open exit door.
public static int ExitOpen = 172; public static int ExitOpen = 172;
public PrinceOfPersiaCheats(Computer computer) {
super(computer);
}
@Override @Override
protected String getDeviceName() { protected String getDeviceName() {
return ("Prince of Persia"); return ("Prince of Persia");
@ -317,7 +321,7 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
// and 198-255 offscreen to the right. // and 198-255 offscreen to the right.
// System.out.println("Clicked on " + col + "," + row + " -- screen " + (x * 280) + "," + (y * 192)); // 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(); PagedMemory auxMem = mem.getAuxMemory();
if (me.getButton() == MouseEvent.BUTTON1) { if (me.getButton() == MouseEvent.BUTTON1) {
@ -363,7 +367,7 @@ public class PrinceOfPersiaCheats extends Cheats implements MouseListener {
* @param direction * @param direction
*/ */
public void performAction(int row, int col, int 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(); PagedMemory auxMem = mem.getAuxMemory();
byte currentScrn = auxMem.readByte(KidScrn); byte currentScrn = auxMem.readByte(KidScrn);
if (col < 0) { if (col < 0) {

View File

@ -18,6 +18,7 @@
*/ */
package jace.config; package jace.config;
import jace.Emulator;
import jace.core.Computer; import jace.core.Computer;
import jace.core.Utility; import jace.core.Utility;
import java.io.File; import java.io.File;
@ -181,7 +182,7 @@ public class Configuration implements Reconfigurable {
} }
} }
public final static ConfigNode BASE; 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.") @ConfigurableField(name = "Autosave Changes", description = "If unchecked, changes are only saved when the Save button is pressed.")
public static boolean saveAutomatically = false; public static boolean saveAutomatically = false;
@ -341,7 +342,7 @@ public class Configuration implements Reconfigurable {
public static boolean applySettings(ConfigNode node) { public static boolean applySettings(ConfigNode node) {
boolean resume = false; boolean resume = false;
if (node == BASE) { if (node == BASE) {
resume = Computer.pause(); resume = Emulator.computer.pause();
} }
boolean hasChanged = false; boolean hasChanged = false;
if (node.changed) { if (node.changed) {
@ -360,7 +361,7 @@ public class Configuration implements Reconfigurable {
} }
if (resume) { if (resume) {
Computer.resume(); Emulator.computer.resume();
} }
return hasChanged; return hasChanged;

View File

@ -18,6 +18,7 @@
*/ */
package jace.config; package jace.config;
import jace.Emulator;
import jace.apple2e.Apple2e; import jace.apple2e.Apple2e;
import jace.config.Configuration.ConfigNode; import jace.config.Configuration.ConfigNode;
import java.awt.Component; import java.awt.Component;
@ -42,8 +43,7 @@ import javax.swing.JTree;
public class ConfigurationPanel extends javax.swing.JPanel { public class ConfigurationPanel extends javax.swing.JPanel {
public static void main(String... args) { public static void main(String... args) {
new Apple2e(); Emulator.computer.reconfigure();
Apple2e.getComputer().reconfigure();
Configuration.loadSettings(); Configuration.loadSettings();
JFrame f = new JFrame(); JFrame f = new JFrame();
f.setContentPane(new ConfigurationPanel()); f.setContentPane(new ConfigurationPanel());

View File

@ -34,12 +34,10 @@ import java.util.logging.Logger;
*/ */
public abstract class CPU extends Device { public abstract class CPU extends Device {
/** public CPU(Computer computer) {
* Creates a new instance of CPU super(computer);
*/
public CPU() {
} }
@Override @Override
public String getShortName() { public String getShortName() {
return "cpu"; return "cpu";
@ -74,11 +72,11 @@ public abstract class CPU extends Device {
} }
public void dumpTrace() { public void dumpTrace() {
Computer.pause(); computer.pause();
ArrayList<String> newLog = new ArrayList<>(); ArrayList<String> newLog = new ArrayList<>();
ArrayList<String> log = traceLog; ArrayList<String> log = traceLog;
traceLog = newLog; traceLog = newLog;
Computer.resume(); computer.resume();
System.out.println("Most recent " + traceLength + " instructions:"); System.out.println("Most recent " + traceLength + " instructions:");
log.stream().forEach((s) -> { log.stream().forEach((s) -> {
System.out.println(s); System.out.println(s);

View File

@ -45,9 +45,10 @@ public abstract class Card extends Device {
/** /**
* Creates a new instance of Card * Creates a new instance of Card
*/ */
public Card() { public Card(Computer computer) {
cxRom = new PagedMemory(0x0100, PagedMemory.Type.cardFirmware); super(computer);
c8Rom = new PagedMemory(0x0800, PagedMemory.Type.cardFirmware); cxRom = new PagedMemory(0x0100, PagedMemory.Type.cardFirmware, computer);
c8Rom = new PagedMemory(0x0800, PagedMemory.Type.cardFirmware, computer);
} }
@Override @Override
@ -68,11 +69,13 @@ public abstract class Card extends Device {
RAMEvent.TYPE.ANY, RAMEvent.TYPE.ANY,
RAMEvent.SCOPE.RANGE, RAMEvent.SCOPE.RANGE,
RAMEvent.VALUE.ANY) { RAMEvent.VALUE.ANY) {
@Override
protected void doConfig() { protected void doConfig() {
setScopeStart(slot * 16 + 0x00c080); setScopeStart(slot * 16 + 0x00c080);
setScopeEnd(slot * 16 + 0x00c08F); setScopeEnd(slot * 16 + 0x00c08F);
} }
@Override
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
int address = e.getAddress() & 0x0f; int address = e.getAddress() & 0x0f;
handleIOAccess(address, e.getType(), e.getNewValue(), e); handleIOAccess(address, e.getType(), e.getNewValue(), e);
@ -83,13 +86,15 @@ public abstract class Card extends Device {
RAMEvent.TYPE.ANY, RAMEvent.TYPE.ANY,
RAMEvent.SCOPE.RANGE, RAMEvent.SCOPE.RANGE,
RAMEvent.VALUE.ANY) { RAMEvent.VALUE.ANY) {
@Override
protected void doConfig() { protected void doConfig() {
setScopeStart(slot * 256 + 0x00c000); setScopeStart(slot * 256 + 0x00c000);
setScopeEnd(slot * 256 + 0x00c0ff); setScopeEnd(slot * 256 + 0x00c0ff);
} }
@Override
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
Computer.getComputer().getMemory().setActiveCard(slot); computer.getMemory().setActiveCard(slot);
if (SoftSwitches.CXROM.getState()) { if (SoftSwitches.CXROM.getState()) {
return; return;
} }
@ -108,7 +113,7 @@ public abstract class Card extends Device {
protected void doEvent(RAMEvent e) { protected void doEvent(RAMEvent e) {
if (SoftSwitches.CXROM.getState() if (SoftSwitches.CXROM.getState()
|| Computer.getComputer().getMemory().getActiveSlot() != getSlot() || computer.getMemory().getActiveSlot() != getSlot()
|| SoftSwitches.INTC8ROM.getState()) { || SoftSwitches.INTC8ROM.getState()) {
return; return;
} }
@ -116,17 +121,17 @@ public abstract class Card extends Device {
} }
}; };
Computer.getComputer().getMemory().addListener(ioListener); computer.getMemory().addListener(ioListener);
Computer.getComputer().getMemory().addListener(firmwareListener); computer.getMemory().addListener(firmwareListener);
Computer.getComputer().getMemory().addListener(c8firmwareListener); computer.getMemory().addListener(c8firmwareListener);
} }
@Override @Override
public void detach() { public void detach() {
suspend(); suspend();
Computer.getComputer().getMemory().removeListener(ioListener); computer.getMemory().removeListener(ioListener);
Computer.getComputer().getMemory().removeListener(firmwareListener); computer.getMemory().removeListener(firmwareListener);
Computer.getComputer().getMemory().removeListener(c8firmwareListener); computer.getMemory().removeListener(c8firmwareListener);
} }
abstract protected void handleIOAccess(int register, RAMEvent.TYPE type, int value, RAMEvent e); abstract protected void handleIOAccess(int register, RAMEvent.TYPE type, int value, RAMEvent e);

View File

@ -35,12 +35,12 @@ import java.io.IOException;
*/ */
public abstract class Computer implements Reconfigurable { public abstract class Computer implements Reconfigurable {
static private Computer theComputer;
public RAM memory; public RAM memory;
public CPU cpu; public CPU cpu;
public Video video; public Video video;
public Keyboard keyboard; public Keyboard keyboard;
public StateManager stateManager; public StateManager stateManager;
public Motherboard motherboard;
public MediaLibrary mediaLibrary = MediaLibrary.getInstance(); 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.") @ConfigurableField(category = "advanced", name = "State management", shortName = "rewind", description = "This enables rewind support, but consumes a lot of memory when active.")
public boolean enableStateManager; public boolean enableStateManager;
@ -49,7 +49,6 @@ public abstract class Computer implements Reconfigurable {
* Creates a new instance of Computer * Creates a new instance of Computer
*/ */
public Computer() { public Computer() {
theComputer = this;
keyboard = new Keyboard(); keyboard = new Keyboard();
} }
@ -57,6 +56,10 @@ public abstract class Computer implements Reconfigurable {
return memory; return memory;
} }
public Motherboard getMotherboard() {
return motherboard;
}
public void notifyVBLStateChanged(boolean state) { public void notifyVBLStateChanged(boolean state) {
for (Card c : getMemory().cards) { for (Card c : getMemory().cards) {
if (c == null) { if (c == null) {
@ -105,22 +108,18 @@ public abstract class Computer implements Reconfigurable {
@InvokableAction( @InvokableAction(
name = "Cold boot", name = "Cold boot",
description = "Process startup sequence from power-up", description = "Process startup sequence from power-up",
category = "general", category = "general",
alternatives = "Full reset;reset emulator") alternatives = "Full reset;reset emulator")
public abstract void coldStart(); public abstract void coldStart();
@InvokableAction( @InvokableAction(
name = "Warm boot", name = "Warm boot",
description = "Process user-initatiated reboot (ctrl+apple+reset)", description = "Process user-initatiated reboot (ctrl+apple+reset)",
category = "general", category = "general",
alternatives = "reboot;reset;three-finger-salute") alternatives = "reboot;reset;three-finger-salute")
public abstract void warmStart(); public abstract void warmStart();
static public Computer getComputer() {
return theComputer;
}
public Keyboard getKeyboard() { public Keyboard getKeyboard() {
return this.keyboard; return this.keyboard;
} }
@ -132,28 +131,24 @@ public abstract class Computer implements Reconfigurable {
protected abstract void doResume(); protected abstract void doResume();
@InvokableAction(name = "Pause", description = "Stops the computer, allowing reconfiguration of core elements", alternatives = "freeze;halt") @InvokableAction(name = "Pause", description = "Stops the computer, allowing reconfiguration of core elements", alternatives = "freeze;halt")
public static boolean pause() { public boolean pause() {
boolean result = false; boolean result = isRunning();
if (theComputer != null) { doPause();
result = theComputer.isRunning();
theComputer.doPause();
}
return result; return result;
} }
@InvokableAction(name = "Resume", description = "Resumes the computer if it was previously paused", alternatives = "unpause;unfreeze;resume") @InvokableAction(name = "Resume", description = "Resumes the computer if it was previously paused", alternatives = "unpause;unfreeze;resume")
public static void resume() { public void resume() {
if (theComputer != null) { doResume();
theComputer.doResume();
}
} }
@Override
public void reconfigure() { public void reconfigure() {
if (enableStateManager) { if (enableStateManager) {
stateManager = StateManager.getInstance(); stateManager = StateManager.getInstance(this);
} else { } else {
stateManager = null; stateManager = null;
StateManager.getInstance().invalidate(); StateManager.getInstance(this).invalidate();
} }
} }
} }

View File

@ -36,8 +36,12 @@ import jace.config.Reconfigurable;
*/ */
@Stateful @Stateful
public abstract class Device implements Reconfigurable { 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) // Number of cycles to do nothing (for cpu/video cycle accuracy)
@Stateful @Stateful
private int waitCycles = 0; private int waitCycles = 0;
@Stateful @Stateful

View File

@ -47,7 +47,10 @@ import java.util.logging.Logger;
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/ */
public class Keyboard implements Reconfigurable { public class Keyboard implements Reconfigurable {
private Computer computer;
public Keyboard(Computer computer) {
this.computer = computer;
}
@Override @Override
public String getShortName() { public String getShortName() {
return "kbd"; return "kbd";
@ -79,16 +82,16 @@ public class Keyboard implements Reconfigurable {
*/ */
public Keyboard() { public Keyboard() {
} }
private static Map<Integer, Set<KeyHandler>> keyHandlersByKey = new HashMap<Integer, Set<KeyHandler>>(); private static Map<Integer, Set<KeyHandler>> keyHandlersByKey = new HashMap<>();
private static Map<Object, Set<KeyHandler>> keyHandlersByOwner = new HashMap<Object, Set<KeyHandler>>(); private static Map<Object, Set<KeyHandler>> keyHandlersByOwner = new HashMap<>();
public static void registerKeyHandler(KeyHandler l, Object owner) { public static void registerKeyHandler(KeyHandler l, Object owner) {
if (!keyHandlersByKey.containsKey(l.key)) { if (!keyHandlersByKey.containsKey(l.key)) {
keyHandlersByKey.put(l.key, new HashSet<KeyHandler>()); keyHandlersByKey.put(l.key, new HashSet<>());
} }
keyHandlersByKey.get(l.key).add(l); keyHandlersByKey.get(l.key).add(l);
if (!keyHandlersByOwner.containsKey(owner)) { if (!keyHandlersByOwner.containsKey(owner)) {
keyHandlersByOwner.put(owner, new HashSet<KeyHandler>()); keyHandlersByOwner.put(owner, new HashSet<>());
} }
keyHandlersByOwner.get(owner).add(l); keyHandlersByOwner.get(owner).add(l);
} }
@ -97,12 +100,9 @@ public class Keyboard implements Reconfigurable {
if (!keyHandlersByOwner.containsKey(owner)) { if (!keyHandlersByOwner.containsKey(owner)) {
return; return;
} }
for (KeyHandler handler : keyHandlersByOwner.get(owner)) { keyHandlersByOwner.get(owner).stream().filter((handler) -> !(!keyHandlersByKey.containsKey(handler.key))).forEach((handler) -> {
if (!keyHandlersByKey.containsKey(handler.key)) {
continue;
}
keyHandlersByKey.get(handler.key).remove(handler); keyHandlersByKey.get(handler.key).remove(handler);
} });
} }
public static void processKeyDownEvents(KeyEvent e) { public static void processKeyDownEvents(KeyEvent e) {
@ -216,7 +216,7 @@ public class Keyboard implements Reconfigurable {
EmulatorUILogic.toggleDebugPanel(); 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)) { 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) { if (code == KeyEvent.VK_F1) {
EmulatorUILogic.showMediaManager(); EmulatorUILogic.showMediaManager();
@ -243,7 +243,7 @@ public class Keyboard implements Reconfigurable {
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(Keyboard.class.getName()).log(Level.SEVERE, null, 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) { if ((e.getModifiers() & (KeyEvent.ALT_MASK|KeyEvent.META_MASK|KeyEvent.META_DOWN_MASK)) > 0) {
// explicit left and right here because other locations // explicit left and right here because other locations
@ -261,27 +261,27 @@ public class Keyboard implements Reconfigurable {
} }
private void pressOpenApple() { private void pressOpenApple() {
Computer.pause(); computer.pause();
SoftSwitches.PB0.getSwitch().setState(true); SoftSwitches.PB0.getSwitch().setState(true);
Computer.resume(); computer.resume();
} }
private void pressSolidApple() { private void pressSolidApple() {
Computer.pause(); computer.pause();
SoftSwitches.PB1.getSwitch().setState(true); SoftSwitches.PB1.getSwitch().setState(true);
Computer.resume(); computer.resume();
} }
private void releaseOpenApple() { private void releaseOpenApple() {
Computer.pause(); computer.pause();
SoftSwitches.PB0.getSwitch().setState(false); SoftSwitches.PB0.getSwitch().setState(false);
Computer.resume(); computer.resume();
} }
private void releaseSolidApple() { private void releaseSolidApple() {
Computer.pause(); computer.pause();
SoftSwitches.PB1.getSwitch().setState(false); 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 + ""); contents = contents.replaceAll("\\n(\\r)?", (char) 0x0d + "");
pasteBuffer = new StringReader(contents); pasteBuffer = new StringReader(contents);
} }
} catch (UnsupportedFlavorException ex) { } catch (UnsupportedFlavorException | IOException ex) {
Logger.getLogger(Keyboard.class
.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Keyboard.class Logger.getLogger(Keyboard.class
.getName()).log(Level.SEVERE, null, ex); .getName()).log(Level.SEVERE, null, ex);
} }

View File

@ -38,21 +38,18 @@ import java.util.Set;
*/ */
public class Motherboard extends TimedDevice { public class Motherboard extends TimedDevice {
static final Computer computer = Computer.getComputer(); static final public Set<Device> miscDevices = new HashSet<>();
static final CPU cpu = computer.getCpu();
static Motherboard instance;
static final public Set<Device> miscDevices = new HashSet<Device>();
@ConfigurableField(name = "Enable Speaker", shortName = "speaker", defaultValue = "true") @ConfigurableField(name = "Enable Speaker", shortName = "speaker", defaultValue = "true")
public static boolean enableSpeaker = true; public static boolean enableSpeaker = true;
public static Speaker speaker; public Speaker speaker;
public static SoundMixer mixer = new SoundMixer(); public SoundMixer mixer;
static void vblankEnd() { void vblankEnd() {
SoftSwitches.VBL.getSwitch().setState(true); SoftSwitches.VBL.getSwitch().setState(true);
computer.notifyVBLStateChanged(true); computer.notifyVBLStateChanged(true);
} }
static void vblankStart() { void vblankStart() {
SoftSwitches.VBL.getSwitch().setState(false); SoftSwitches.VBL.getSwitch().setState(false);
computer.notifyVBLStateChanged(false); computer.notifyVBLStateChanged(false);
} }
@ -60,10 +57,12 @@ public class Motherboard extends TimedDevice {
/** /**
* Creates a new instance of Motherboard * Creates a new instance of Motherboard
*/ */
public Motherboard() { public Motherboard(Computer computer) {
instance = this; super(computer);
mixer = new SoundMixer(computer);
} }
@Override
protected String getDeviceName() { protected String getDeviceName() {
return "Motherboard"; return "Motherboard";
} }
@ -77,15 +76,16 @@ public class Motherboard extends TimedDevice {
public int clockCounter = 1; public int clockCounter = 1;
public Card[] cards; public Card[] cards;
@Override
public void tick() { public void tick() {
try { try {
clockCounter--; clockCounter--;
cpu.doTick(); computer.getCpu().doTick();
if (clockCounter > 0) { if (clockCounter > 0) {
return; return;
} }
clockCounter = cpuPerClock; clockCounter = cpuPerClock;
Computer.getComputer().getVideo().doTick(); computer.getVideo().doTick();
// Unrolled loop since this happens so often // Unrolled loop since this happens so often
if (cards[0] != null) { if (cards[0] != null) {
cards[0].doTick(); cards[0].doTick();
@ -108,9 +108,9 @@ public class Motherboard extends TimedDevice {
if (cards[6] != null) { if (cards[6] != null) {
cards[6].doTick(); cards[6].doTick();
} }
for (Device m : miscDevices) { miscDevices.stream().forEach((m) -> {
m.doTick(); m.doTick();
} });
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
} }
@ -120,10 +120,12 @@ public class Motherboard extends TimedDevice {
public static long SPEED = 1020484L; // (NTSC) public static long SPEED = 1020484L; // (NTSC)
//public static long SPEED = 1015625L; // (PAL) //public static long SPEED = 1015625L; // (PAL)
@Override
public long defaultCyclesPerSecond() { public long defaultCyclesPerSecond() {
return SPEED; return SPEED;
} }
@Override
public synchronized void reconfigure() { public synchronized void reconfigure() {
boolean startAgain = pause(); boolean startAgain = pause();
accelorationRequestors.clear(); accelorationRequestors.clear();
@ -136,7 +138,7 @@ public class Motherboard extends TimedDevice {
if (enableSpeaker) { if (enableSpeaker) {
try { try {
if (speaker == null) { if (speaker == null) {
speaker = new Speaker(); speaker = new Speaker(computer);
} else { } else {
speaker.attach(); speaker.attach();
} }
@ -154,30 +156,28 @@ public class Motherboard extends TimedDevice {
Motherboard.miscDevices.remove(speaker); Motherboard.miscDevices.remove(speaker);
} }
} }
if (startAgain && Computer.getComputer().getMemory() != null) { if (startAgain && computer.getMemory() != null) {
resume(); 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); accelorationRequestors.add(requester);
if (instance != null) { enableTempMaxSpeed();
instance.enableTempMaxSpeed();
}
} }
static public void cancelSpeedRequest(Object requester) { public void cancelSpeedRequest(Object requester) {
accelorationRequestors.remove(requester); accelorationRequestors.remove(requester);
if (instance != null && accelorationRequestors.isEmpty()) { if (accelorationRequestors.isEmpty()) {
instance.disableTempMaxSpeed(); disableTempMaxSpeed();
} }
} }
@Override @Override
public void attach() { public void attach() {
} }
Map<Card, Boolean> resume = new HashMap<Card, Boolean>(); Map<Card, Boolean> resume = new HashMap<>();
@Override @Override
public boolean suspend() { public boolean suspend() {

View File

@ -60,7 +60,9 @@ public class PagedMemory {
/** /**
* Creates a new instance of 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; type = memType;
internalMemory = new byte[size >> 8][256]; internalMemory = new byte[size >> 8][256];
for (int i = 0; i < size; i += 256) { for (int i = 0; i < size; i += 256) {
@ -127,7 +129,7 @@ public class PagedMemory {
public void writeByte(int address, byte value) { public void writeByte(int address, byte value) {
byte[] page = getMemoryPage(address); byte[] page = getMemoryPage(address);
StateManager.markDirtyValue(page); StateManager.markDirtyValue(page, computer);
getMemoryPage(address)[address & 0x0ff] = value; getMemoryPage(address)[address & 0x0ff] = value;
} }

View File

@ -23,7 +23,6 @@ import jace.config.Reconfigurable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Vector;
/** /**
* RAM is a 64K address space of paged memory. It also manages sets of memory * 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; protected Card[] cards;
// card 0 = 80 column card firmware / system rom // card 0 = 80 column card firmware / system rom
public int activeSlot = 0; public int activeSlot = 0;
protected final Computer computer;
/** /**
* Creates a new instance of RAM * Creates a new instance of RAM
*/ */
public RAM() { public RAM(Computer computer) {
listeners = new Vector<RAMListener>(); this.computer = computer;
listeners = new ArrayList<>();
cards = new Card[8]; cards = new Card[8];
refreshListenerMap(); refreshListenerMap();
} }
@ -196,60 +197,60 @@ public abstract class RAM implements Reconfigurable {
private void refreshListenerMap() { private void refreshListenerMap() {
listenerMap = new ArrayList[256]; listenerMap = new ArrayList[256];
ioListenerMap = new ArrayList[256]; ioListenerMap = new ArrayList[256];
for (RAMListener l : listeners) { listeners.stream().forEach((l) -> {
addListenerRange(l); addListenerRange(l);
} });
} }
public void addListener(final RAMListener l) { public void addListener(final RAMListener l) {
boolean restart = Computer.pause(); boolean restart = computer.pause();
if (listeners.contains(l)) { if (listeners.contains(l)) {
return; return;
} }
listeners.add(l); listeners.add(l);
addListenerRange(l); addListenerRange(l);
if (restart) { if (restart) {
Computer.resume(); computer.resume();
} }
} }
public void removeListener(final RAMListener l) { public void removeListener(final RAMListener l) {
boolean restart = Computer.pause(); boolean restart = computer.pause();
listeners.remove(l); listeners.remove(l);
refreshListenerMap(); refreshListenerMap();
if (restart) { if (restart) {
Computer.resume(); computer.resume();
} }
} }
public byte callListener(RAMEvent.TYPE t, int address, int oldValue, int newValue, boolean requireSyncronization) { public byte callListener(RAMEvent.TYPE t, int address, int oldValue, int newValue, boolean requireSyncronization) {
List<RAMListener> activeListeners = null; List<RAMListener> activeListeners;
if (requireSyncronization) { if (requireSyncronization) {
Computer.getComputer().getCpu().suspend(); computer.getCpu().suspend();
} }
if ((address & 0x0FF00) == 0x0C000) { if ((address & 0x0FF00) == 0x0C000) {
activeListeners = ioListenerMap[address & 0x0FF]; activeListeners = ioListenerMap[address & 0x0FF];
if (activeListeners == null && t.isRead()) { if (activeListeners == null && t.isRead()) {
if (requireSyncronization) { if (requireSyncronization) {
Computer.getComputer().getCpu().resume(); computer.getCpu().resume();
} }
return Computer.getComputer().getVideo().getFloatingBus(); return computer.getVideo().getFloatingBus();
} }
} else { } else {
activeListeners = listenerMap[(address >> 8) & 0x0ff]; activeListeners = listenerMap[(address >> 8) & 0x0ff];
} }
if (activeListeners != null) { if (activeListeners != null) {
RAMEvent e = new RAMEvent(t, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY, address, oldValue, newValue); 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); l.handleEvent(e);
} });
if (requireSyncronization) { if (requireSyncronization) {
Computer.getComputer().getCpu().resume(); computer.getCpu().resume();
} }
return (byte) e.getNewValue(); return (byte) e.getNewValue();
} }
if (requireSyncronization) { if (requireSyncronization) {
Computer.getComputer().getCpu().resume(); computer.getCpu().resume();
} }
return (byte) newValue; return (byte) newValue;
} }

View File

@ -47,6 +47,7 @@ public abstract class SoftSwitch {
private final List<Integer> exclusionQuery = new ArrayList<>(); private final List<Integer> exclusionQuery = new ArrayList<>();
private String name; private String name;
private boolean toggleType = false; private boolean toggleType = false;
protected Computer computer;
/** /**
* Creates a new instance of SoftSwitch * Creates a new instance of SoftSwitch
@ -235,18 +236,20 @@ public abstract class SoftSwitch {
} }
} }
public void register() { public void register(Computer computer) {
RAM m = Computer.getComputer().getMemory(); this.computer = computer;
RAM m = computer.getMemory();
listeners.stream().forEach((l) -> { listeners.stream().forEach((l) -> {
m.addListener(l); m.addListener(l);
}); });
} }
public void unregister() { public void unregister() {
RAM m = Computer.getComputer().getMemory(); RAM m = computer.getMemory();
listeners.stream().forEach((l) -> { listeners.stream().forEach((l) -> {
m.removeListener(l); m.removeListener(l);
}); });
this.computer = null;
} }
public void setState(boolean newState) { public void setState(boolean newState) {
@ -259,7 +262,7 @@ public abstract class SoftSwitch {
state = newState; state = newState;
/* /*
if (queryAddresses != null) { if (queryAddresses != null) {
RAM m = Computer.getComputer().getMemory(); RAM m = computer.getMemory();
for (int i:queryAddresses) { for (int i:queryAddresses) {
byte old = m.read(i, false); byte old = m.read(i, false);
m.write(i, (byte) (old & 0x7f | (state ? 0x080:0x000)), false); m.write(i, (byte) (old & 0x7f | (state ? 0x080:0x000)), false);

View File

@ -87,6 +87,10 @@ public class SoundMixer extends Device {
}; };
private Mixer theMixer; private Mixer theMixer;
public SoundMixer(Computer computer) {
super(computer);
}
@Override @Override
public String getDeviceName() { public String getDeviceName() {
return "Sound Output"; return "Sound Output";
@ -132,7 +136,7 @@ public class SoundMixer extends Device {
if (activeLines.containsKey(requester)) { if (activeLines.containsKey(requester)) {
return activeLines.get(requester); return activeLines.get(requester);
} }
SourceDataLine sdl = null; SourceDataLine sdl;
if (availableLines.isEmpty()) { if (availableLines.isEmpty()) {
sdl = getNewLine(); sdl = getNewLine();
} else { } else {

View File

@ -31,7 +31,8 @@ public abstract class TimedDevice extends Device {
/** /**
* Creates a new instance of TimedDevice * Creates a new instance of TimedDevice
*/ */
public TimedDevice() { public TimedDevice(Computer computer) {
super(computer);
setSpeed(cyclesPerSecond); setSpeed(cyclesPerSecond);
} }
@ConfigurableField(name = "Speed", description = "(in hertz)") @ConfigurableField(name = "Speed", description = "(in hertz)")

View File

@ -91,7 +91,8 @@ public abstract class Video extends Device {
/** /**
* Creates a new instance of Video * Creates a new instance of Video
*/ */
public Video() { public Video(Computer computer) {
super(computer);
suspend(); suspend();
video = new BufferedImage(560, 192, BufferedImage.TYPE_INT_RGB); video = new BufferedImage(560, 192, BufferedImage.TYPE_INT_RGB);
vPeriod = 0; vPeriod = 0;
@ -164,7 +165,7 @@ public abstract class Video extends Device {
@Override @Override
public void tick() { public void tick() {
setFloatingBus(Computer.getComputer().getMemory().readRaw(scannerAddress + x)); setFloatingBus(computer.getMemory().readRaw(scannerAddress + x));
if (hPeriod > 0) { if (hPeriod > 0) {
hPeriod--; hPeriod--;
if (hPeriod == 0) { if (hPeriod == 0) {
@ -201,12 +202,12 @@ public abstract class Video extends Device {
y = APPLE_SCREEN_LINES - (TOTAL_LINES - APPLE_SCREEN_LINES); y = APPLE_SCREEN_LINES - (TOTAL_LINES - APPLE_SCREEN_LINES);
isVblank = true; isVblank = true;
vblankStart(); vblankStart();
Motherboard.vblankStart(); computer.getMotherboard().vblankStart();
} else { } else {
y = 0; y = 0;
isVblank = false; isVblank = false;
vblankEnd(); vblankEnd();
Motherboard.vblankEnd(); computer.getMotherboard().vblankEnd();
} }
} }
} }

View File

@ -88,6 +88,10 @@ public class CardAppleMouse extends Card implements MouseListener {
public boolean fullscreenFix = true; public boolean fullscreenFix = true;
ImageIcon mouseActive = Utility.loadIcon("input-mouse.png"); ImageIcon mouseActive = Utility.loadIcon("input-mouse.png");
public CardAppleMouse(Computer computer) {
super(computer);
}
@Override @Override
public String getDeviceName() { public String getDeviceName() {
return "Apple Mouse"; return "Apple Mouse";
@ -232,7 +236,7 @@ public class CardAppleMouse extends Card implements MouseListener {
} }
private MOS65C02 getCPU() { 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 * //gs homes mouse to low address, but //c and //e do not
*/ */
private void clampMouse() { private void clampMouse() {
RAM128k memory = (RAM128k) Computer.getComputer().memory; RAM128k memory = (RAM128k) computer.memory;
byte clampMinLo = memory.getMainMemory().readByte(0x0478); byte clampMinLo = memory.getMainMemory().readByte(0x0478);
byte clampMaxLo = memory.getMainMemory().readByte(0x04F8); byte clampMaxLo = memory.getMainMemory().readByte(0x04F8);
byte clampMinHi = memory.getMainMemory().readByte(0x0578); byte clampMinHi = memory.getMainMemory().readByte(0x0578);
@ -459,7 +463,7 @@ public class CardAppleMouse extends Card implements MouseListener {
if (drawingArea == null) { if (drawingArea == null) {
return; return;
} }
Graphics2D screen = (Graphics2D) Computer.getComputer().getVideo().getScreen(); Graphics2D screen = (Graphics2D) computer.getVideo().getScreen();
// Point currentMouseLocation = MouseInfo.getPointerInfo().getLocation(); // Point currentMouseLocation = MouseInfo.getPointerInfo().getLocation();
// Point topLeft = drawingArea.getLocationOnScreen(); // Point topLeft = drawingArea.getLocationOnScreen();
Point currentMouseLocation = Emulator.getFrame().getContentPane().getMousePosition(); Point currentMouseLocation = Emulator.getFrame().getContentPane().getMousePosition();
@ -506,7 +510,7 @@ public class CardAppleMouse extends Card implements MouseListener {
y = clampMax.y; y = clampMax.y;
} }
PagedMemory m = ((RAM128k) Computer.getComputer().getMemory()).getMainMemory(); PagedMemory m = ((RAM128k) computer.getMemory()).getMainMemory();
int s = getSlot(); int s = getSlot();
/* /*
* $0478 + slot Low byte of absolute X position * $0478 + slot Low byte of absolute X position

View File

@ -23,7 +23,7 @@ import jace.config.ConfigurableField;
import jace.config.Name; import jace.config.Name;
import jace.config.Reconfigurable; import jace.config.Reconfigurable;
import jace.core.Card; import jace.core.Card;
import jace.core.Motherboard; import jace.core.Computer;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
import jace.core.Utility; import jace.core.Utility;
@ -48,14 +48,15 @@ import java.util.logging.Logger;
public class CardDiskII extends Card implements Reconfigurable, MediaConsumerParent { public class CardDiskII extends Card implements Reconfigurable, MediaConsumerParent {
DiskIIDrive currentDrive; DiskIIDrive currentDrive;
DiskIIDrive drive1 = new DiskIIDrive(); DiskIIDrive drive1 = new DiskIIDrive(computer);
DiskIIDrive drive2 = new DiskIIDrive(); DiskIIDrive drive2 = new DiskIIDrive(computer);
@ConfigurableField(category = "Disk", defaultValue = "254", name = "Default volume", description = "Value to use for disk volume number") @ConfigurableField(category = "Disk", defaultValue = "254", name = "Default volume", description = "Value to use for disk volume number")
static public int DEFAULT_VOLUME_NUMBER = 0x0FE; 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") @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; static public boolean USE_MAX_SPEED = true;
public CardDiskII() { public CardDiskII(Computer computer) {
super(computer);
try { try {
loadRom("jace/data/DiskII.rom"); loadRom("jace/data/DiskII.rom");
} catch (IOException ex) { } catch (IOException ex) {
@ -195,10 +196,10 @@ public class CardDiskII extends Card implements Reconfigurable, MediaConsumerPar
private void tweakTiming() { private void tweakTiming() {
if (drive1.isOn() || drive2.isOn()) { if (drive1.isOn() || drive2.isOn()) {
if (USE_MAX_SPEED) { if (USE_MAX_SPEED) {
Motherboard.requestSpeed(this); computer.getMotherboard().requestSpeed(this);
} }
} else { } else {
Motherboard.cancelSpeedRequest(this); computer.getMotherboard().cancelSpeedRequest(this);
} }
} }

View File

@ -19,6 +19,7 @@
package jace.hardware; package jace.hardware;
import jace.apple2e.RAM128k; import jace.apple2e.RAM128k;
import jace.core.Computer;
import jace.core.PagedMemory; import jace.core.PagedMemory;
import jace.state.Stateful; import jace.state.Stateful;
@ -45,11 +46,11 @@ public class CardExt80Col extends RAM128k {
return "128kb"; return "128kb";
} }
public CardExt80Col() { public CardExt80Col(Computer computer) {
super(); super(computer);
auxMemory = new PagedMemory(0xc000, PagedMemory.Type.ram); auxMemory = new PagedMemory(0xc000, PagedMemory.Type.ram, computer);
auxLanguageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard); auxLanguageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard, computer);
auxLanguageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard); auxLanguageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard, computer);
initMemoryPattern(auxMemory); initMemoryPattern(auxMemory);
} }

View File

@ -19,6 +19,7 @@
package jace.hardware; package jace.hardware;
import jace.config.Name; import jace.config.Name;
import jace.core.Computer;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
import java.io.IOException; import java.io.IOException;
@ -42,7 +43,8 @@ public class CardHayesMicromodem extends CardSSC {
public int RING_INDICATOR_REG = 5; public int RING_INDICATOR_REG = 5;
private boolean ringIndicator = false; private boolean ringIndicator = false;
public CardHayesMicromodem() { public CardHayesMicromodem(Computer computer) {
super(computer);
ACIA_Data = 7; ACIA_Data = 7;
ACIA_Status = 6; ACIA_Status = 6;
ACIA_Control = 5; ACIA_Control = 5;

View File

@ -86,12 +86,13 @@ public class CardMockingboard extends Card implements Runnable {
return "Mockingboard"; return "Mockingboard";
} }
public CardMockingboard() { public CardMockingboard(Computer computer) {
super(computer);
controllers = new R6522[2]; controllers = new R6522[2];
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
//don't ask... //don't ask...
final int j = i; final int j = i;
controllers[i] = new R6522() { controllers[i] = new R6522(computer) {
@Override @Override
public void sendOutputA(int value) { public void sendOutputA(int value) {
if (activeChip != null) { if (activeChip != null) {
@ -156,7 +157,7 @@ public class CardMockingboard extends Card implements Runnable {
} }
if (activeChip == null) { if (activeChip == null) {
System.err.println("Could not determine which PSG to communicate to"); System.err.println("Could not determine which PSG to communicate to");
e.setNewValue(Computer.getComputer().getVideo().getFloatingBus()); e.setNewValue(computer.getVideo().getFloatingBus());
return; return;
} }
R6522 controller = controllers[chip & 1]; R6522 controller = controllers[chip & 1];
@ -172,7 +173,7 @@ public class CardMockingboard extends Card implements Runnable {
@Override @Override
protected void handleIOAccess(int register, TYPE type, int value, RAMEvent e) { 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. // 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; long ticksSinceLastPlayback = 0;
@ -305,7 +306,7 @@ public class CardMockingboard extends Card implements Runnable {
*/ */
public void run() { public void run() {
try { try {
SourceDataLine out = Motherboard.mixer.getLine(this); SourceDataLine out = computer.getMotherboard().mixer.getLine(this);
int[] leftBuffer = new int[BUFFER_LENGTH]; int[] leftBuffer = new int[BUFFER_LENGTH];
int[] rightBuffer = new int[BUFFER_LENGTH]; int[] rightBuffer = new int[BUFFER_LENGTH];
int frameSize = out.getFormat().getFrameSize(); int frameSize = out.getFormat().getFrameSize();
@ -317,7 +318,7 @@ public class CardMockingboard extends Card implements Runnable {
ticksSinceLastPlayback = 0; ticksSinceLastPlayback = 0;
int zeroSamples = 0; int zeroSamples = 0;
while (isRunning()) { while (isRunning()) {
Motherboard.requestSpeed(this); computer.getMotherboard().requestSpeed(this);
playSound(leftBuffer, rightBuffer); playSound(leftBuffer, rightBuffer);
int p = 0; int p = 0;
for (int idx = 0; idx < BUFFER_LENGTH; idx++) { for (int idx = 0; idx < BUFFER_LENGTH; idx++) {
@ -345,7 +346,7 @@ public class CardMockingboard extends Card implements Runnable {
if (zeroSamples >= MAX_IDLE_SAMPLES) { if (zeroSamples >= MAX_IDLE_SAMPLES) {
zeroSamples = 0; zeroSamples = 0;
pause = true; pause = true;
Motherboard.cancelSpeedRequest(this); computer.getMotherboard().cancelSpeedRequest(this);
while (pause && isRunning()) { while (pause && isRunning()) {
try { try {
Thread.sleep(50); Thread.sleep(50);
@ -380,9 +381,9 @@ public class CardMockingboard extends Card implements Runnable {
Logger.getLogger(CardMockingboard.class Logger.getLogger(CardMockingboard.class
.getName()).log(Level.SEVERE, null, ex); .getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
Motherboard.cancelSpeedRequest(this); computer.getMotherboard().cancelSpeedRequest(this);
System.out.println("Mockingboard playback stopped"); System.out.println("Mockingboard playback stopped");
Motherboard.mixer.returnLine(this); computer.getMotherboard().mixer.returnLine(this);
} }
} }

View File

@ -22,6 +22,7 @@ import jace.Emulator;
import jace.config.ConfigurableField; import jace.config.ConfigurableField;
import jace.config.Name; import jace.config.Name;
import jace.core.Card; import jace.core.Card;
import jace.core.Computer;
import jace.core.Motherboard; import jace.core.Motherboard;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
@ -64,7 +65,8 @@ public class CardRamFactor extends Card {
return "RamFactor"; return "RamFactor";
} }
ImageIcon indicator; ImageIcon indicator;
public CardRamFactor() { public CardRamFactor(Computer computer) {
super(computer);
indicator=Utility.loadIcon("ram.png"); indicator=Utility.loadIcon("ram.png");
try { try {
loadRom("jace/data/RAMFactor14.rom"); loadRom("jace/data/RAMFactor14.rom");
@ -162,7 +164,7 @@ public class CardRamFactor extends Card {
@Override @Override
protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) { protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
if (speedBoost) { if (speedBoost) {
Motherboard.requestSpeed(this); computer.getMotherboard().requestSpeed(this);
} }
} }
@ -174,7 +176,7 @@ public class CardRamFactor extends Card {
@Override @Override
protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) { protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
if (speedBoost) { if (speedBoost) {
Motherboard.requestSpeed(this); computer.getMotherboard().requestSpeed(this);
} }
} }

View File

@ -53,10 +53,10 @@ public class CardRamworks extends RAM128k {
public int memorySize = 3072; public int memorySize = 3072;
public int maxBank = memorySize / 64; public int maxBank = memorySize / 64;
private Map<BankType, PagedMemory> generateBank() { private Map<BankType, PagedMemory> generateBank() {
Map<BankType, PagedMemory> memoryBank = new EnumMap<BankType, PagedMemory>(BankType.class); Map<BankType, PagedMemory> memoryBank = new EnumMap<>(BankType.class);
memoryBank.put(BankType.MAIN_MEMORY, new PagedMemory(0xc000, PagedMemory.Type.ram)); memoryBank.put(BankType.MAIN_MEMORY, new PagedMemory(0xc000, PagedMemory.Type.ram, computer));
memoryBank.put(BankType.LANGUAGE_CARD_1, new PagedMemory(0x3000, PagedMemory.Type.languageCard)); 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)); memoryBank.put(BankType.LANGUAGE_CARD_2, new PagedMemory(0x1000, PagedMemory.Type.languageCard, computer));
return memoryBank; return memoryBank;
} }
@ -64,9 +64,9 @@ public class CardRamworks extends RAM128k {
MAIN_MEMORY, LANGUAGE_CARD_1, LANGUAGE_CARD_2 MAIN_MEMORY, LANGUAGE_CARD_1, LANGUAGE_CARD_2
}; };
public CardRamworks() { public CardRamworks(Computer computer) {
super(); super(computer);
memory = new ArrayList<Map<BankType, PagedMemory>>(maxBank); memory = new ArrayList<>(maxBank);
reconfigure(); reconfigure();
} }
@ -115,7 +115,7 @@ public class CardRamworks extends RAM128k {
@Override @Override
public void reconfigure() { public void reconfigure() {
boolean resume = Computer.pause(); boolean resume = computer.pause();
maxBank = memorySize / 64; maxBank = memorySize / 64;
if (maxBank < 1) maxBank = 1; if (maxBank < 1) maxBank = 1;
if (maxBank > 128) maxBank = 128; if (maxBank > 128) maxBank = 128;
@ -124,7 +124,7 @@ public class CardRamworks extends RAM128k {
} }
configureActiveMemory(); configureActiveMemory();
if (resume) { if (resume) {
Computer.resume(); computer.resume();
} }
} }
RAMListener bankSelectListener = new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) { RAMListener bankSelectListener = new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {

View File

@ -94,6 +94,10 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
// Bitmask for stop bits (FF = 8, 7F = 7, etc) // Bitmask for stop bits (FF = 8, 7F = 7, etc)
private int DATA_BITS = 0x07F; private int DATA_BITS = 0x07F;
public CardSSC(Computer computer) {
super(computer);
}
public String getDeviceName() { public String getDeviceName() {
return "Super Serial Card"; return "Super Serial Card";
} }
@ -390,7 +394,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
private void triggerIRQ() { private void triggerIRQ() {
IRQ_TRIGGERED = true; IRQ_TRIGGERED = true;
Computer.getComputer().getCpu().generateInterrupt(); computer.getCpu().generateInterrupt();
} }
public void hangUp() { public void hangUp() {

View File

@ -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.") @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 boolean attemptYearPatch = true;
public CardThunderclock() { public CardThunderclock(Computer computer) {
super(computer);
try { try {
loadRom("jace/data/thunderclock_plus.rom"); loadRom("jace/data/thunderclock_plus.rom");
} catch (IOException ex) { } catch (IOException ex) {
@ -213,7 +214,7 @@ public class CardThunderclock extends Card {
ticks = 0; ticks = 0;
irqAsserted = true; irqAsserted = true;
if (irqEnabled) { if (irqEnabled) {
Computer.getComputer().getCpu().generateInterrupt(); computer.getCpu().generateInterrupt();
} }
} }
} }
@ -295,7 +296,7 @@ public class CardThunderclock extends Card {
* always tell time correctly. * always tell time correctly.
*/ */
private void performProdosPatch() { private void performProdosPatch() {
PagedMemory ram = Computer.getComputer().getMemory().activeRead; PagedMemory ram = computer.getMemory().activeRead;
if (patchLoc > 0) { if (patchLoc > 0) {
// We've already patched, just validate // We've already patched, just validate
if (ram.readByte(patchLoc) == (byte) MOS65C02.OPCODE.LDA_IMM.getCode()) { if (ram.readByte(patchLoc) == (byte) MOS65C02.OPCODE.LDA_IMM.getCode()) {

View File

@ -18,6 +18,7 @@
*/ */
package jace.hardware; package jace.hardware;
import jace.core.Computer;
import jace.library.MediaConsumer; import jace.library.MediaConsumer;
import jace.library.MediaEntry; import jace.library.MediaEntry;
import jace.library.MediaEntry.MediaFile; import jace.library.MediaEntry.MediaFile;
@ -41,7 +42,12 @@ import javax.swing.ImageIcon;
*/ */
@Stateful @Stateful
public class DiskIIDrive implements MediaConsumer { public class DiskIIDrive implements MediaConsumer {
Computer computer;
public DiskIIDrive(Computer computer) {
this.computer = computer;
}
FloppyDisk disk; FloppyDisk disk;
// Number of milliseconds to wait between last write and update to disk image // Number of milliseconds to wait between last write and update to disk image
public static long WRITE_UPDATE_DELAY = 1000; public static long WRITE_UPDATE_DELAY = 1000;
@ -77,7 +83,7 @@ public class DiskIIDrive implements MediaConsumer {
public void reset() { public void reset() {
driveOn = false; driveOn = false;
magnets = 0; magnets = 0;
dirtyTracks = new HashSet<Integer>(); dirtyTracks = new HashSet<>();
diskUpdatePending = false; diskUpdatePending = false;
} }
@ -154,7 +160,7 @@ public class DiskIIDrive implements MediaConsumer {
dirtyTracks.add(trackStartOffset / FloppyDisk.TRACK_NIBBLE_LENGTH); dirtyTracks.add(trackStartOffset / FloppyDisk.TRACK_NIBBLE_LENGTH);
disk.nibbles[trackStartOffset + nibbleOffset++] = latch; disk.nibbles[trackStartOffset + nibbleOffset++] = latch;
triggerDiskUpdate(); triggerDiskUpdate();
StateManager.markDirtyValue(disk.nibbles); StateManager.markDirtyValue(disk.nibbles, computer);
} }
} }
@ -186,9 +192,9 @@ public class DiskIIDrive implements MediaConsumer {
diskUpdatePending = true; diskUpdatePending = true;
// Update all tracks as necessary // Update all tracks as necessary
if (disk != null) { if (disk != null) {
for (Integer track : dirtyTracks) { dirtyTracks.stream().forEach((track) -> {
disk.updateTrack(track); disk.updateTrack(track);
} });
} }
// Empty out dirty list // Empty out dirty list
dirtyTracks.clear(); dirtyTracks.clear();
@ -199,53 +205,54 @@ public class DiskIIDrive implements MediaConsumer {
private void triggerDiskUpdate() { private void triggerDiskUpdate() {
lastWriteTime = System.currentTimeMillis(); lastWriteTime = System.currentTimeMillis();
if (writerThread == null || !writerThread.isAlive()) { if (writerThread == null || !writerThread.isAlive()) {
writerThread = new Thread(new Runnable() { writerThread = new Thread(() -> {
@Override long diff = 0;
public void run() { // Wait until there have been no virtual writes for specified delay time
long diff = 0; while ((diff = System.currentTimeMillis() - lastWriteTime) < WRITE_UPDATE_DELAY) {
// Wait until there have been no virtual writes for specified delay time // Sleep for difference of time
while ((diff = System.currentTimeMillis() - lastWriteTime) < WRITE_UPDATE_DELAY) { LockSupport.parkNanos(diff * 1000);
// Sleep for difference of time // Note: In the meantime, there could have been another disk write,
LockSupport.parkNanos(diff * 1000); // in which case this loop will repeat again as needed.
// Note: In the meantime, there could have been another disk write,
// in which case this loop will repeat again as needed.
}
updateDisk();
} }
updateDisk();
}); });
writerThread.start(); writerThread.start();
} }
} }
void insertDisk(File diskPath) throws IOException { void insertDisk(File diskPath) throws IOException {
disk = new FloppyDisk(diskPath); disk = new FloppyDisk(diskPath, computer);
dirtyTracks = new HashSet<Integer>(); dirtyTracks = new HashSet<>();
// Emulator state has changed significantly, reset state manager // Emulator state has changed significantly, reset state manager
StateManager.getInstance().invalidate(); StateManager.getInstance(computer).invalidate();
} }
private ImageIcon icon; private ImageIcon icon;
@Override
public ImageIcon getIcon() { public ImageIcon getIcon() {
return icon; return icon;
} }
@Override
public void setIcon(ImageIcon i) { public void setIcon(ImageIcon i) {
icon = i; icon = i;
} }
private MediaEntry currentMediaEntry; private MediaEntry currentMediaEntry;
private MediaFile currentMediaFile; private MediaFile currentMediaFile;
@Override
public void eject() { public void eject() {
if (disk == null) { if (disk == null) {
return; return;
} }
waitForPendingWrites(); waitForPendingWrites();
disk = null; disk = null;
dirtyTracks = new HashSet<Integer>(); dirtyTracks = new HashSet<>();
// Emulator state has changed significantly, reset state manager // 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 { public void insertMedia(MediaEntry e, MediaFile f) throws IOException {
if (!isAccepted(e, f)) { if (!isAccepted(e, f)) {
return; return;
@ -256,14 +263,17 @@ public class DiskIIDrive implements MediaConsumer {
currentMediaFile = f; currentMediaFile = f;
} }
@Override
public MediaEntry getMediaEntry() { public MediaEntry getMediaEntry() {
return currentMediaEntry; return currentMediaEntry;
} }
@Override
public MediaFile getMediaFile() { public MediaFile getMediaFile() {
return currentMediaFile; return currentMediaFile;
} }
@Override
public boolean isAccepted(MediaEntry e, MediaFile f) { public boolean isAccepted(MediaEntry e, MediaFile f) {
if (f == null) return false; if (f == null) return false;
System.out.println("Type is accepted: "+f.path+"; "+e.type.toString()+": "+e.type.is140kb); System.out.println("Type is accepted: "+f.path+"; "+e.type.toString()+": "+e.type.is140kb);

View File

@ -18,6 +18,7 @@
*/ */
package jace.hardware; package jace.hardware;
import jace.core.Computer;
import jace.state.StateManager; import jace.state.StateManager;
import jace.state.Stateful; import jace.state.Stateful;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -109,16 +110,16 @@ public class FloppyDisk {
* @param diskFile * @param diskFile
* @throws IOException * @throws IOException
*/ */
public FloppyDisk(File diskFile) throws IOException { public FloppyDisk(File diskFile, Computer computer) throws IOException {
FileInputStream input = new FileInputStream(diskFile); FileInputStream input = new FileInputStream(diskFile);
String name = diskFile.getName().toUpperCase(); String name = diskFile.getName().toUpperCase();
readDisk(input, name.endsWith(".PO")); readDisk(input, name.endsWith(".PO"), computer);
writeProtected = !diskFile.canWrite(); writeProtected = !diskFile.canWrite();
diskPath = diskFile; diskPath = diskFile;
} }
// brendanr: refactored to use input stream // 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; isNibblizedImage = true;
volumeNumber = CardDiskII.DEFAULT_VOLUME_NUMBER; volumeNumber = CardDiskII.DEFAULT_VOLUME_NUMBER;
headerLength = 0; headerLength = 0;
@ -154,8 +155,8 @@ public class FloppyDisk {
} catch (IOException ex) { } catch (IOException ex) {
throw ex; throw ex;
} }
StateManager.markDirtyValue(nibbles); StateManager.markDirtyValue(nibbles, computer);
StateManager.markDirtyValue(currentSectorOrder); StateManager.markDirtyValue(currentSectorOrder, computer);
} }
/* /*

View File

@ -70,7 +70,8 @@ public class Joystick extends Device {
Robot robot; Robot robot;
Point centerPoint; Point centerPoint;
public Joystick(int port) { public Joystick(int port, Computer computer) {
super(computer);
centerPoint = new Point(screenSize.width / 2, screenSize.height / 2); centerPoint = new Point(screenSize.width / 2, screenSize.height / 2);
this.port = port; this.port = port;
if (port == 0) { if (port == 0) {
@ -214,7 +215,7 @@ public class Joystick extends Device {
}; };
private void registerListeners() { private void registerListeners() {
Computer.getComputer().getMemory().addListener(listener); computer.getMemory().addListener(listener);
if (useKeyboard) { if (useKeyboard) {
System.out.println("Registering key handlers"); System.out.println("Registering key handlers");
Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_LEFT, -1) { Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_LEFT, -1) {
@ -273,7 +274,7 @@ public class Joystick extends Device {
} }
private void removeListeners() { private void removeListeners() {
Computer.getComputer().getMemory().removeListener(listener); computer.getMemory().removeListener(listener);
Keyboard.unregisterAllHandlers(this); Keyboard.unregisterAllHandlers(this);
} }
} }

View File

@ -43,6 +43,10 @@ import javax.sound.midi.Synthesizer;
@Name(value = "Passport Midi Interface", description = "MIDI sound card") @Name(value = "Passport Midi Interface", description = "MIDI sound card")
public class PassportMidiInterface extends Card { public class PassportMidiInterface extends Card {
public PassportMidiInterface(Computer computer) {
super(computer);
}
@Override @Override
protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) { protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
// There is no rom on this card, so nothing to do here // There is no rom on this card, so nothing to do here
@ -318,7 +322,7 @@ public class PassportMidiInterface extends Card {
if (t.irqEnabled) { if (t.irqEnabled) {
// System.out.println("Timer generating interrupt!"); // System.out.println("Timer generating interrupt!");
t.irqRequested = true; t.irqRequested = true;
Computer.getComputer().getCpu().generateInterrupt(); computer.getCpu().generateInterrupt();
ptmStatusReadSinceIRQ = false; ptmStatusReadSinceIRQ = false;
} }
if (t.mode == TIMER_MODE.continuous || t.mode == TIMER_MODE.freqComparison) { if (t.mode == TIMER_MODE.continuous || t.mode == TIMER_MODE.freqComparison) {

View File

@ -29,6 +29,12 @@ import java.io.IOException;
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/ */
public abstract class ProdosDriver { public abstract class ProdosDriver {
Computer computer;
public ProdosDriver(Computer computer) {
this.computer = computer;
}
public static int MLI_COMMAND = 0x042; public static int MLI_COMMAND = 0x042;
public static int MLI_UNITNUMBER = 0x043; public static int MLI_UNITNUMBER = 0x043;
public static int MLI_BUFFER_ADDRESS = 0x044; public static int MLI_BUFFER_ADDRESS = 0x044;
@ -71,7 +77,7 @@ public abstract class ProdosDriver {
public void handleMLI() { public void handleMLI() {
int returnCode = prodosMLI().intValue; int returnCode = prodosMLI().intValue;
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu(); MOS65C02 cpu = (MOS65C02) computer.getCpu();
cpu.A = returnCode; cpu.A = returnCode;
// Clear carry flag if no error, otherwise set carry flag // Clear carry flag if no error, otherwise set carry flag
cpu.C = (returnCode == 0x00) ? 00 : 01; cpu.C = (returnCode == 0x00) ? 00 : 01;
@ -79,7 +85,7 @@ public abstract class ProdosDriver {
private MLI_RETURN prodosMLI() { private MLI_RETURN prodosMLI() {
try { try {
RAM memory = Computer.getComputer().getMemory(); RAM memory = computer.getMemory();
int cmd = memory.readRaw(MLI_COMMAND); int cmd = memory.readRaw(MLI_COMMAND);
MLI_COMMAND_TYPE command = MLI_COMMAND_TYPE.fromInt(cmd); MLI_COMMAND_TYPE command = MLI_COMMAND_TYPE.fromInt(cmd);
int unit = (memory.readWordRaw(MLI_UNITNUMBER) & 0x080) > 0 ? 1 : 0; int unit = (memory.readWordRaw(MLI_UNITNUMBER) & 0x080) > 0 ? 1 : 0;
@ -96,7 +102,7 @@ public abstract class ProdosDriver {
switch (command) { switch (command) {
case STATUS: case STATUS:
int blocks = getSize(); int blocks = getSize();
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu(); MOS65C02 cpu = (MOS65C02) computer.getCpu();
cpu.X = blocks & 0x0ff; cpu.X = blocks & 0x0ff;
cpu.Y = (blocks >> 8) & 0x0ff; cpu.Y = (blocks >> 8) & 0x0ff;
if (isWriteProtected()) { if (isWriteProtected()) {

View File

@ -31,7 +31,12 @@ import java.util.logging.Logger;
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/ */
public abstract class SmartportDriver { public abstract class SmartportDriver {
Computer computer;
public SmartportDriver(Computer computer) {
this.computer = computer;
}
public static enum ERROR_CODE { 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); NO_ERROR(0), INVALID_COMMAND(0x01), BAD_PARAM_COUNT(0x04), INVALID_UNIT(0x011), INVALID_CODE(0x021), BAD_BLOCK_NUMBER(0x02d);
int intValue; int intValue;
@ -42,15 +47,15 @@ public abstract class SmartportDriver {
public void handleSmartport() { public void handleSmartport() {
int returnCode = callSmartport().intValue; int returnCode = callSmartport().intValue;
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu(); MOS65C02 cpu = (MOS65C02) computer.getCpu();
cpu.A = returnCode; cpu.A = returnCode;
// Clear carry flag if no error, otherwise set carry flag // Clear carry flag if no error, otherwise set carry flag
cpu.C = (returnCode == 0x00) ? 00 : 01; cpu.C = (returnCode == 0x00) ? 00 : 01;
} }
private ERROR_CODE callSmartport() { private ERROR_CODE callSmartport() {
MOS65C02 cpu = (MOS65C02) Computer.getComputer().getCpu(); MOS65C02 cpu = (MOS65C02) computer.getCpu();
RAM ram = Computer.getComputer().getMemory(); RAM ram = computer.getMemory();
int callAddress = cpu.popWord() + 1; int callAddress = cpu.popWord() + 1;
int command = ram.readRaw(callAddress); int command = ram.readRaw(callAddress);
boolean extendedCall = command >= 0x040; boolean extendedCall = command >= 0x040;

View File

@ -23,7 +23,6 @@ import jace.apple2e.MOS65C02;
import jace.config.Name; import jace.config.Name;
import jace.core.Card; import jace.core.Card;
import jace.core.Computer; import jace.core.Computer;
import jace.core.Motherboard;
import jace.core.RAMEvent; import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE; import jace.core.RAMEvent.TYPE;
import jace.core.Utility; import jace.core.Utility;
@ -47,7 +46,8 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
MassStorageDrive drive1; MassStorageDrive drive1;
MassStorageDrive drive2; MassStorageDrive drive2;
public CardMassStorage() { public CardMassStorage(Computer computer) {
super(computer);
drive1 = new MassStorageDrive(); drive1 = new MassStorageDrive();
drive2 = new MassStorageDrive(); drive2 = new MassStorageDrive();
drive1.setIcon(Utility.loadIcon("drive-harddisk.png")); drive1.setIcon(Utility.loadIcon("drive-harddisk.png"));
@ -86,7 +86,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
} }
return null; return null;
} }
ProdosDriver driver = new ProdosDriver() { ProdosDriver driver = new ProdosDriver(computer) {
@Override @Override
public boolean changeUnit(int unit) { public boolean changeUnit(int unit) {
currentDrive = unit == 0 ? drive1 : drive2; currentDrive = unit == 0 ? drive1 : drive2;
@ -110,12 +110,12 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
@Override @Override
public void mliRead(int block, int bufferAddress) throws IOException { public void mliRead(int block, int bufferAddress) throws IOException {
getCurrentDisk().mliRead(block, bufferAddress); getCurrentDisk().mliRead(block, bufferAddress, computer.getMemory());
} }
@Override @Override
public void mliWrite(int block, int bufferAddress) throws IOException { public void mliWrite(int block, int bufferAddress) throws IOException {
getCurrentDisk().mliWrite(block, bufferAddress); getCurrentDisk().mliWrite(block, bufferAddress, computer.getMemory());
} }
@Override @Override
@ -129,14 +129,14 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
try { try {
detach(); detach();
int pc = Computer.getComputer().getCpu().getProgramCounter(); int pc = computer.getCpu().getProgramCounter();
if (drive1.getCurrentDisk() != null && getSlot() == 7 && (pc == 0x0c65e || pc == 0x0c661)) { 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 // 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 // This is a convenience to boot a hard-drive if the emulator has started waiting for a currentDisk
currentDrive = drive1; currentDrive = drive1;
getCurrentDisk().boot0(getSlot()); getCurrentDisk().boot0(getSlot(), computer);
Card[] cards = Computer.getComputer().getMemory().getAllCards(); Card[] cards = computer.getMemory().getAllCards();
Motherboard.cancelSpeedRequest(cards[6]); computer.getMotherboard().cancelSpeedRequest(cards[6]);
} }
attach(); attach();
} catch (IOException ex) { } catch (IOException ex) {
@ -155,7 +155,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
@Override @Override
protected void handleFirmwareAccess(int offset, TYPE type, int value, RAMEvent e) { 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())); // System.out.println(e.getType()+" "+Integer.toHexString(e.getAddress())+" from instruction at "+Integer.toHexString(cpu.getProgramCounter()));
if (type.isRead()) { if (type.isRead()) {
Emulator.getFrame().addIndicator(this, currentDrive.getIcon()); Emulator.getFrame().addIndicator(this, currentDrive.getIcon());
@ -172,7 +172,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
try { try {
if (drive1.getCurrentDisk() != null) { if (drive1.getCurrentDisk() != null) {
currentDrive = drive1; currentDrive = drive1;
getCurrentDisk().boot0(getSlot()); getCurrentDisk().boot0(getSlot(), computer);
} else { } else {
// Patch for crash on start when no image is mounted // Patch for crash on start when no image is mounted
e.setNewValue(0x060); e.setNewValue(0x060);
@ -185,7 +185,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
cpu.setProgramCounter(0x0dfff); cpu.setProgramCounter(0x0dfff);
int address = 0x0480; int address = 0x0480;
for (char c : error.toCharArray()) { 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 { } else {
@ -231,7 +231,7 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
public void tick() { public void tick() {
// Nothing is done per CPU cycle // Nothing is done per CPU cycle
} }
SmartportDriver smartport = new SmartportDriver() { SmartportDriver smartport = new SmartportDriver(computer) {
@Override @Override
public boolean changeUnit(int unitNumber) { public boolean changeUnit(int unitNumber) {
currentDrive = unitNumber == 1 ? drive1 : drive2; currentDrive = unitNumber == 1 ? drive1 : drive2;
@ -240,12 +240,12 @@ public class CardMassStorage extends Card implements MediaConsumerParent {
@Override @Override
public void read(int blockNum, int buffer) throws IOException { public void read(int blockNum, int buffer) throws IOException {
getCurrentDisk().mliRead(blockNum, buffer); getCurrentDisk().mliRead(blockNum, buffer, computer.getMemory());
} }
@Override @Override
public void write(int blockNum, int buffer) throws IOException { public void write(int blockNum, int buffer) throws IOException {
getCurrentDisk().mliWrite(blockNum, buffer); getCurrentDisk().mliWrite(blockNum, buffer, computer.getMemory());
} }
@Override @Override

View File

@ -18,6 +18,8 @@
*/ */
package jace.hardware.massStorage; package jace.hardware.massStorage;
import jace.core.Computer;
import jace.core.RAM;
import java.io.IOException; import java.io.IOException;
/** /**
@ -29,9 +31,9 @@ public interface IDisk {
public static int MAX_BLOCK = 65535; public static int MAX_BLOCK = 65535;
public void mliFormat() throws IOException; public void mliFormat() throws IOException;
public void mliRead(int block, int bufferAddress) throws IOException; public void mliRead(int block, int bufferAddress, RAM memory) throws IOException;
public void mliWrite(int block, int bufferAddress) throws IOException; public void mliWrite(int block, int bufferAddress, RAM memory) throws IOException;
public void boot0(int slot) throws IOException; public void boot0(int slot, Computer computer) throws IOException;
// Return size in 512k blocks // Return size in 512k blocks
public int getSize(); public int getSize();

View File

@ -51,12 +51,13 @@ public class LargeDisk implements IDisk {
} }
} }
@Override
public void mliFormat() throws IOException { public void mliFormat() throws IOException {
throw new UnsupportedOperationException("Not supported yet."); throw new UnsupportedOperationException("Not supported yet.");
} }
public void mliRead(int block, int bufferAddress) throws IOException { @Override
RAM memory = Computer.getComputer().getMemory(); public void mliRead(int block, int bufferAddress, RAM memory) throws IOException {
if (block < physicalBlocks) { if (block < physicalBlocks) {
diskImage.seek((block * BLOCK_SIZE) + dataOffset); diskImage.seek((block * BLOCK_SIZE) + dataOffset);
for (int i = 0; i < BLOCK_SIZE; i++) { 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) { if (block < physicalBlocks) {
RAM memory = Computer.getComputer().getMemory();
diskImage.seek((block * BLOCK_SIZE) + dataOffset); diskImage.seek((block * BLOCK_SIZE) + dataOffset);
byte[] buf = new byte[BLOCK_SIZE]; byte[] buf = new byte[BLOCK_SIZE];
for (int i = 0; i < BLOCK_SIZE; i++) { for (int i = 0; i < BLOCK_SIZE; i++) {
@ -81,19 +82,20 @@ public class LargeDisk implements IDisk {
} }
} }
public void boot0(int slot) throws IOException { @Override
Computer.getComputer().getCpu().suspend(); public void boot0(int slot, Computer computer) throws IOException {
mliRead(0, 0x0800); computer.getCpu().suspend();
mliRead(0, 0x0800, computer.getMemory());
byte slot16 = (byte) (slot << 4); byte slot16 = (byte) (slot << 4);
((MOS65C02) Computer.getComputer().getCpu()).X = slot16; ((MOS65C02) computer.getCpu()).X = slot16;
RAM memory = Computer.getComputer().getMemory(); RAM memory = computer.getMemory();
memory.write(CardMassStorage.SLT16, slot16, false, false); memory.write(CardMassStorage.SLT16, slot16, false, false);
memory.write(MLI_COMMAND, (byte) MLI_COMMAND_TYPE.READ.intValue, false, false); memory.write(MLI_COMMAND, (byte) MLI_COMMAND_TYPE.READ.intValue, false, false);
memory.write(MLI_UNITNUMBER, slot16, false, false); memory.write(MLI_UNITNUMBER, slot16, false, false);
// Write location to block read routine to zero page // Write location to block read routine to zero page
memory.writeWord(0x048, 0x0c000 + CardMassStorage.DEVICE_DRIVER_OFFSET + (slot * 0x0100), false, false); memory.writeWord(0x048, 0x0c000 + CardMassStorage.DEVICE_DRIVER_OFFSET + (slot * 0x0100), false, false);
((MOS65C02) Computer.getComputer().getCpu()).setProgramCounter(0x0800); ((MOS65C02) computer.getCpu()).setProgramCounter(0x0800);
Computer.getComputer().getCpu().resume(); computer.getCpu().resume();
} }
public File getPhysicalPath() { public File getPhysicalPath() {
@ -123,7 +125,9 @@ public class LargeDisk implements IDisk {
Logger.getLogger(LargeDisk.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(LargeDisk.class.getName()).log(Level.SEVERE, null, ex);
} finally { } finally {
try { try {
fis.close(); if (fis != null) {
fis.close();
}
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(LargeDisk.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(LargeDisk.class.getName()).log(Level.SEVERE, null, ex);
} }

View File

@ -55,10 +55,10 @@ public class ProdosVirtualDisk implements IDisk {
setPhysicalPath(rootPath); 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)); // System.out.println("Read block " + block + " to " + Integer.toHexString(bufferAddress));
DiskNode node = physicalMap.get(block); DiskNode node = physicalMap.get(block);
RAM memory = Computer.getComputer().getMemory();
Arrays.fill(ioBuffer, (byte) (block & 0x0ff)); Arrays.fill(ioBuffer, (byte) (block & 0x0ff));
if (node == null) { if (node == null) {
System.out.println("Reading unknown block?!"); System.out.println("Reading unknown block?!");
@ -83,11 +83,12 @@ public class ProdosVirtualDisk implements IDisk {
// System.out.println(); // 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)); System.out.println("Write block " + block + " to " + Integer.toHexString(bufferAddress));
throw new IOException("Write not implemented yet!"); throw new IOException("Write not implemented yet!");
// DiskNode node = physicalMap.get(block); // DiskNode node = physicalMap.get(block);
// RAM memory = Computer.getComputer().getMemory(); // RAM memory = computer.getMemory();
// if (node == null) { // if (node == null) {
// // CAPTURE WRITES TO UNUSED BLOCKS // // CAPTURE WRITES TO UNUSED BLOCKS
// } else { // } else {
@ -98,6 +99,7 @@ public class ProdosVirtualDisk implements IDisk {
// } // }
} }
@Override
public void mliFormat() { public void mliFormat() {
throw new UnsupportedOperationException("Formatting for this type of media is not supported!"); 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 // Mark space occupied by node
public void allocateEntry(DiskNode node) { public void allocateEntry(DiskNode node) {
physicalMap.put(node.baseBlock, node); physicalMap.put(node.baseBlock, node);
for (DiskNode sub : node.additionalNodes) { node.additionalNodes.stream().forEach((sub) -> {
physicalMap.put(sub.getBaseBlock(), sub); physicalMap.put(sub.getBaseBlock(), sub);
} });
} }
// Mark space occupied by nodes as free (remove allocation mapping) // 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)) { if (physicalMap.get(node.baseBlock) != null && physicalMap.get(node.baseBlock).equals(node)) {
physicalMap.remove(node.baseBlock); physicalMap.remove(node.baseBlock);
} }
for (DiskNode sub : node.additionalNodes) { node.additionalNodes.stream().filter((sub) ->
if (physicalMap.get(sub.getBaseBlock()) != null && physicalMap.get(sub.baseBlock).equals(sub)) { (physicalMap.get(sub.getBaseBlock()) != null && physicalMap.get(sub.baseBlock).equals(sub))).
physicalMap.remove(sub.getBaseBlock()); forEach((sub) -> {
} physicalMap.remove(sub.getBaseBlock());
} });
} }
// Is the specified block in use? // Is the specified block in use?
@ -156,22 +158,22 @@ public class ProdosVirtualDisk implements IDisk {
} }
@Override @Override
public void boot0(int slot) throws IOException { public void boot0(int slot, Computer computer) throws IOException {
File prodos = locateFile(physicalRoot, "PRODOS.SYS"); File prodos = locateFile(physicalRoot, "PRODOS.SYS");
if (prodos == null || !prodos.exists()) { if (prodos == null || !prodos.exists()) {
throw new IOException("Unable to locate PRODOS.SYS"); throw new IOException("Unable to locate PRODOS.SYS");
} }
Computer.getComputer().getCpu().suspend(); computer.getCpu().suspend();
byte slot16 = (byte) (slot << 4); byte slot16 = (byte) (slot << 4);
((MOS65C02) Computer.getComputer().getCpu()).X = slot16; ((MOS65C02) computer.getCpu()).X = slot16;
RAM memory = Computer.getComputer().getMemory(); RAM memory = computer.getMemory();
memory.write(CardMassStorage.SLT16, slot16, false, false); memory.write(CardMassStorage.SLT16, slot16, false, false);
memory.write(MLI_COMMAND, (byte) MLI_COMMAND_TYPE.READ.intValue, false, false); memory.write(MLI_COMMAND, (byte) MLI_COMMAND_TYPE.READ.intValue, false, false);
memory.write(MLI_UNITNUMBER, slot16, false, false); memory.write(MLI_UNITNUMBER, slot16, false, false);
// Write location to block read routine to zero page // Write location to block read routine to zero page
memory.writeWord(0x048, 0x0c000 + CardMassStorage.DEVICE_DRIVER_OFFSET + (slot * 0x0100), false, false); memory.writeWord(0x048, 0x0c000 + CardMassStorage.DEVICE_DRIVER_OFFSET + (slot * 0x0100), false, false);
EmulatorUILogic.brun(prodos, 0x02000); EmulatorUILogic.brun(prodos, 0x02000);
Computer.getComputer().getCpu().resume(); computer.getCpu().resume();
} }
public File getPhysicalPath() { public File getPhysicalPath() {
@ -183,7 +185,7 @@ public class ProdosVirtualDisk implements IDisk {
return; return;
} }
physicalRoot = f; physicalRoot = f;
physicalMap = new HashMap<Integer, DiskNode>(); physicalMap = new HashMap<>();
if (!physicalRoot.exists() || !physicalRoot.isDirectory()) { if (!physicalRoot.exists() || !physicalRoot.isDirectory()) {
try { try {
throw new IOException("Root path must be a directory that exists!"); throw new IOException("Root path must be a directory that exists!");
@ -201,6 +203,7 @@ public class ProdosVirtualDisk implements IDisk {
} }
@Override
public void eject() { public void eject() {
// Nothing to do here... // Nothing to do here...
} }

View File

@ -27,7 +27,8 @@ import jace.core.Device;
*/ */
public abstract class R6522 extends Device { public abstract class R6522 extends Device {
public R6522() { public R6522(Computer computer) {
super(computer);
} }
// 6522 VIA // 6522 VIA
@ -140,7 +141,7 @@ public abstract class R6522 extends Device {
if (timer1interruptEnabled) { if (timer1interruptEnabled) {
// System.out.println("Timer 1 generated interrupt"); // System.out.println("Timer 1 generated interrupt");
timer1IRQ = true; timer1IRQ = true;
Computer.getComputer().getCpu().generateInterrupt(); computer.getCpu().generateInterrupt();
} }
} }
} }
@ -151,7 +152,7 @@ public abstract class R6522 extends Device {
timer2counter = timer2latch; timer2counter = timer2latch;
if (timer2interruptEnabled) { if (timer2interruptEnabled) {
timer2IRQ = true; timer2IRQ = true;
Computer.getComputer().getCpu().generateInterrupt(); computer.getCpu().generateInterrupt();
} }
} }
} }

View File

@ -18,10 +18,10 @@
*/ */
package jace.library; package jace.library;
import jace.Emulator;
import jace.config.ConfigurableField; import jace.config.ConfigurableField;
import jace.config.Reconfigurable; import jace.config.Reconfigurable;
import jace.core.Card; import jace.core.Card;
import jace.core.Computer;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; 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.") @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; public static boolean CREATE_LOCAL_ON_SAVE = true;
@Override
public String getName() { public String getName() {
return "Media Library"; return "Media Library";
} }
@Override
public String getShortName() { public String getShortName() {
return "media"; return "media";
} }
@Override
public void reconfigure() { public void reconfigure() {
rebuildDriveList(); rebuildDriveList();
} }
@ -76,7 +79,7 @@ public class MediaLibrary implements Reconfigurable {
return; return;
} }
userInterface.Drives.removeAll(); userInterface.Drives.removeAll();
for (Card card : Computer.getComputer().memory.getAllCards()) { for (Card card : Emulator.computer.memory.getAllCards()) {
if (card == null || !(card instanceof MediaConsumerParent)) { if (card == null || !(card instanceof MediaConsumerParent)) {
continue; continue;
} }

View File

@ -46,9 +46,9 @@ public class StateManager implements Reconfigurable {
private static StateManager instance; private static StateManager instance;
public static StateManager getInstance() { public static StateManager getInstance(Computer computer) {
if (instance == null) { if (instance == null) {
instance = new StateManager(); instance = new StateManager(computer);
} }
return instance; return instance;
} }
@ -63,9 +63,14 @@ public class StateManager implements Reconfigurable {
public int captureFrequency = 3; public int captureFrequency = 3;
private ObjectGraphNode<BufferedImage> imageGraphNode; private ObjectGraphNode<BufferedImage> imageGraphNode;
Computer computer;
private StateManager(Computer computer) {
this.computer = computer;
}
private void buildStateMap() { private void buildStateMap() {
allStateVariables = new HashSet<ObjectGraphNode>(); allStateVariables = new HashSet<>();
objectLookup = new WeakHashMap<Object, ObjectGraphNode>(); objectLookup = new WeakHashMap<>();
ObjectGraphNode emulator = new ObjectGraphNode(Emulator.instance); ObjectGraphNode emulator = new ObjectGraphNode(Emulator.instance);
emulator.name = "Emulator"; emulator.name = "Emulator";
Set visited = new HashSet(); Set visited = new HashSet();
@ -235,8 +240,8 @@ public class StateManager implements Reconfigurable {
} }
} }
public static void markDirtyValue(Object o) { public static void markDirtyValue(Object o, Computer computer) {
StateManager manager = getInstance(); StateManager manager = getInstance(computer);
if (manager.objectLookup == null) { if (manager.objectLookup == null) {
return; return;
} }
@ -259,8 +264,9 @@ public class StateManager implements Reconfigurable {
* If reconfigure is called, it means the emulator state has changed too * If reconfigure is called, it means the emulator state has changed too
* greatly and we need to abandon captured states and start from scratch. * greatly and we need to abandon captured states and start from scratch.
*/ */
@Override
public void reconfigure() { public void reconfigure() {
boolean resume = Computer.pause(); boolean resume = computer.pause();
isValid = false; isValid = false;
// Now figure out how much memory we're allowed to eat // Now figure out how much memory we're allowed to eat
@ -269,7 +275,7 @@ public class StateManager implements Reconfigurable {
freeRequired = maxMemory / 50L; freeRequired = maxMemory / 50L;
frameCounter = captureFrequency; frameCounter = captureFrequency;
if (resume) { if (resume) {
Computer.resume(); computer.resume();
} }
} }
boolean isValid = false; boolean isValid = false;
@ -329,7 +335,7 @@ public class StateManager implements Reconfigurable {
} }
private BufferedImage getScreenshot() { private BufferedImage getScreenshot() {
BufferedImage screen = Computer.getComputer().getVideo().getFrameBuffer(); BufferedImage screen = computer.getVideo().getFrameBuffer();
ColorModel cm = screen.getColorModel(); ColorModel cm = screen.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = screen.copyData(null); WritableRaster raster = screen.copyData(null);
@ -391,7 +397,7 @@ public class StateManager implements Reconfigurable {
} }
public void rewind(int numStates) { public void rewind(int numStates) {
boolean resume = Computer.pause(); boolean resume = computer.pause();
State state = alphaState.tail; State state = alphaState.tail;
while (numStates > 0 && state.previousState != null) { while (numStates > 0 && state.previousState != null) {
state = state.previousState; state = state.previousState;
@ -400,10 +406,10 @@ public class StateManager implements Reconfigurable {
state.apply(); state.apply();
alphaState.tail = state; alphaState.tail = state;
state.nextState = null; state.nextState = null;
Computer.getComputer().getVideo().forceRefresh(); computer.getVideo().forceRefresh();
System.gc(); System.gc();
if (resume) { if (resume) {
Computer.resume(); computer.resume();
} }
} }
} }

View File

@ -31,12 +31,49 @@ import jace.hardware.CardMockingboard;
*/ */
public class PlaybackEngine extends Computer { public class PlaybackEngine extends Computer {
Motherboard motherboard = new Motherboard(); Computer dummyComputer = new Computer() {
CardMockingboard mockingboard = new CardMockingboard();
@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() { public PlaybackEngine() {
setMemory(new CardExt80Col()); setMemory(new CardExt80Col(dummyComputer));
setCpu(new MOS65C02()); setCpu(new MOS65C02(dummyComputer));
getMemory().addCard(mockingboard, 5); getMemory().addCard(mockingboard, 5);
} }

View File

@ -50,12 +50,17 @@ import javax.swing.JPanel;
*/ */
public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implements Reconfigurable { public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implements Reconfigurable {
Computer computer;
/** /**
* Creates new form AbstractEmulatorFrame * Creates new form AbstractEmulatorFrame
*/ */
public AbstractEmulatorFrame() { public AbstractEmulatorFrame() {
initComponents(); initComponents();
} }
public void setComputer(Computer computer) {
this.computer = computer;
}
@Override @Override
public synchronized void addKeyListener(KeyListener l) { 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>>(); private Map<Object, Set<ImageIcon>> indicators = new HashMap<Object, Set<ImageIcon>>();
public void resizeVideo() { public void resizeVideo() {
EventQueue.invokeLater(new Runnable() { EventQueue.invokeLater(() -> {
@Override computer.pause();
public void run() { computer.getVideo().suspend();
Computer.pause(); JPanel debugger = getDebuggerPanel();
Computer.getComputer().getVideo().suspend(); Component screen = getScreen();
JPanel debugger = getDebuggerPanel(); Rectangle bounds = screen.getParent().getBounds();
Component screen = getScreen(); int width1 = (int) bounds.getWidth();
Rectangle bounds = screen.getParent().getBounds(); int height1 = (int) bounds.getHeight();
int width = (int) bounds.getWidth(); if (debugger.isVisible()) {
int height = (int) bounds.getHeight(); debugger.setBounds(width1 - debugger.getWidth(), 0, debugger.getWidth(), height1);
if (debugger.isVisible()) { width1 = (int) bounds.getWidth() - debugger.getWidth() + 1;
debugger.setBounds(width - debugger.getWidth(), 0, debugger.getWidth(), height); screen.setSize(width1, height1);
width = (int) bounds.getWidth() - debugger.getWidth() + 1; debugger.revalidate();
screen.setSize( } else {
width, screen.setSize(width1, height1);
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();
} }
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.setSize(560 * scale, 384 * scale);
b.x = (w / 2) - (b.width / 2); b.x = (w / 2) - (b.width / 2);
b.y = (h / 2) - (b.height / 2); b.y = (h / 2) - (b.height / 2);
Computer.pause(); computer.pause();
Computer.getComputer().getVideo().suspend(); computer.getVideo().suspend();
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
@ -335,9 +333,9 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
g.fill(getBounds()); g.fill(getBounds());
Graphics2D gg = (Graphics2D) g.create(b.x, b.y, b.width, b.height); 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); gg.scale((double) b.width / (double) sw, (double) b.height / (double) sh);
Computer.getComputer().getVideo().setScreen(gg); computer.getVideo().setScreen(gg);
Computer.getComputer().getVideo().resume(); computer.getVideo().resume();
Computer.resume(); computer.resume();
} else { } else {
b = getBounds(); b = getBounds();
getScreen().setBounds(getBounds()); getScreen().setBounds(getBounds());
@ -364,8 +362,8 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
EventQueue.invokeLater(new Runnable() { EventQueue.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
Computer.pause(); computer.pause();
Computer.getComputer().getVideo().suspend(); computer.getVideo().suspend();
isFullscreen = !isFullscreen; isFullscreen = !isFullscreen;
GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
if (isFullscreen) { if (isFullscreen) {
@ -382,8 +380,8 @@ public abstract class AbstractEmulatorFrame extends javax.swing.JFrame implement
device.setFullScreenWindow(null); device.setFullScreenWindow(null);
} }
resizeVideo(); resizeVideo();
Computer.getComputer().getVideo().resume(); computer.getVideo().resume();
Computer.resume(); computer.resume();
} }
}); });
} }

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?> <?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> <Properties>
<Property name="defaultCloseOperation" type="int" value="3"/> <Property name="defaultCloseOperation" type="int" value="3"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
@ -47,12 +47,14 @@
<Property name="opaque" type="boolean" value="true"/> <Property name="opaque" type="boolean" value="true"/>
</Properties> </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> <SubComponents>
<Container class="jace.ui.ScreenPanel" name="screen"> <Container class="jace.ui.ScreenPanel" name="screen">
<Constraints> <Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout$JLayeredPaneConstraintsDescription"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
<JLayeredPaneConstraints x="0" y="0" width="560" height="520" layer="0" position="-1"/> <AbsoluteConstraints x="0" y="0" width="560" height="520"/>
</Constraint> </Constraint>
</Constraints> </Constraints>
@ -70,9 +72,12 @@
</Layout> </Layout>
</Container> </Container>
<Component class="jace.ui.DebuggerPanel" name="debuggerPanel"> <Component class="jace.ui.DebuggerPanel" name="debuggerPanel">
<AuxValues>
<AuxValue name="JLayeredPane.layer" type="java.lang.Integer" value="200"/>
</AuxValues>
<Constraints> <Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JLayeredPaneSupportLayout$JLayeredPaneConstraintsDescription"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
<JLayeredPaneConstraints x="460" y="0" width="-1" height="-1" layer="200" position="-1"/> <AbsoluteConstraints x="460" y="0" width="-1" height="-1"/>
</Constraint> </Constraint>
</Constraints> </Constraints>
</Component> </Component>

View File

@ -77,7 +77,8 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
/** /**
* Creates new form EmulatorFrame * Creates new form EmulatorFrame
*/ */
public EmulatorFrame() { public EmulatorFrame(Computer computer) {
setComputer(computer);
initComponents(); initComponents();
layers.setDoubleBuffered(true); layers.setDoubleBuffered(true);
screen.setDoubleBuffered(true); screen.setDoubleBuffered(true);
@ -94,6 +95,7 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
screen.setFocusTraversalKeysEnabled(false); screen.setFocusTraversalKeysEnabled(false);
} }
@Override
public synchronized void addKeyListener(KeyListener l) { public synchronized void addKeyListener(KeyListener l) {
super.addKeyListener(l); super.addKeyListener(l);
layers.addKeyListener(l); layers.addKeyListener(l);
@ -154,10 +156,8 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
* @param args the command line arguments * @param args the command line arguments
*/ */
public static void main(String args[]) { public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(() -> {
public void run() { new EmulatorFrame(null).setVisible(true);
new EmulatorFrame().setVisible(true);
}
}); });
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
@ -165,15 +165,17 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
public javax.swing.JLayeredPane layers; public javax.swing.JLayeredPane layers;
public jace.ui.ScreenPanel screen; public jace.ui.ScreenPanel screen;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
Set<JLabel> previousIndicators = new HashSet<JLabel>(); Set<JLabel> previousIndicators = new HashSet<>();
@Override @Override
public void doRedrawIndicators(Set<ImageIcon> ind) { public void doRedrawIndicators(Set<ImageIcon> ind) {
synchronized (previousIndicators) { synchronized (previousIndicators) {
for (JLabel l : previousIndicators) { previousIndicators.stream().map((l) -> {
l.setVisible(false); l.setVisible(false);
return l;
}).forEach((l) -> {
layers.remove(l); layers.remove(l);
} });
previousIndicators.clear(); previousIndicators.clear();
} }
if (ind != null && !ind.isEmpty()) { if (ind != null && !ind.isEmpty()) {
@ -195,8 +197,8 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
label.setVisible(true); label.setVisible(true);
} }
} else { } else {
if (Computer.getComputer() != null && Computer.getComputer().video != null) { if (computer != null && computer.video != null) {
Computer.getComputer().video.forceRefresh(); computer.video.forceRefresh();
} }
// This was causing a whole screen flicker -- bad. // This was causing a whole screen flicker -- bad.
// screen.repaint(); // screen.repaint();
@ -208,16 +210,16 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
public void repaintIndicators() { public void repaintIndicators() {
synchronized (previousIndicators) { synchronized (previousIndicators) {
if (previousIndicators != null) { if (previousIndicators != null) {
for (JLabel l : previousIndicators) { previousIndicators.stream().forEach((l) -> {
Graphics g = l.getGraphics(); Graphics g = l.getGraphics();
if (g != null) { if (g != null) {
l.paint(g); l.paint(g);
} }
} });
} }
} }
} }
Map<ImageIcon, JLabel> indicatorCache = new HashMap<ImageIcon, JLabel>(); Map<ImageIcon, JLabel> indicatorCache = new HashMap<>();
private JLabel createIndicatorIcon(ImageIcon i) { private JLabel createIndicatorIcon(ImageIcon i) {
if (indicatorCache.containsKey(i)) { if (indicatorCache.containsKey(i)) {
@ -240,7 +242,7 @@ public class EmulatorFrame extends AbstractEmulatorFrame {
indicatorCache.put(i, renderedLabel); indicatorCache.put(i, renderedLabel);
return renderedLabel; return renderedLabel;
} }
Map<String, JFrame> modals = new HashMap<String, JFrame>(); Map<String, JFrame> modals = new HashMap<>();
@Override @Override
protected void displayModalDialog(final String name, JPanel ui, List<String> ancestors) { protected void displayModalDialog(final String name, JPanel ui, List<String> ancestors) {

View File

@ -91,10 +91,8 @@ public class MainFrame extends AbstractEmulatorFrame {
* @param args the command line arguments * @param args the command line arguments
*/ */
public static void main(String args[]) { public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(() -> {
public void run() { new MainFrame().setVisible(true);
new MainFrame().setVisible(true);
}
}); });
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables

View File

@ -18,6 +18,7 @@
*/ */
package jace.ui; package jace.ui;
import jace.Emulator;
import jace.core.Computer; import jace.core.Computer;
import java.awt.Canvas; import java.awt.Canvas;
import java.awt.Color; import java.awt.Color;
@ -31,15 +32,21 @@ import java.awt.Graphics;
*/ */
public class ScreenCanvas extends Canvas { public class ScreenCanvas extends Canvas {
Computer computer;
public ScreenCanvas() { public ScreenCanvas() {
setBackground(new Color(0, 0, 64)); setBackground(new Color(0, 0, 64));
setIgnoreRepaint(true); setIgnoreRepaint(true);
} }
public Computer getComputer() {
return Emulator.computer;
}
@Override @Override
public void paint(Graphics g) { public void paint(Graphics g) {
if (Computer.getComputer() != null) { if (getComputer() != null) {
Computer.getComputer().getVideo().forceRefresh(); getComputer().getVideo().forceRefresh();
} }
} }
} }

View File

@ -18,6 +18,7 @@
*/ */
package jace.ui; package jace.ui;
import jace.Emulator;
import jace.core.Computer; import jace.core.Computer;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
@ -35,11 +36,15 @@ public class ScreenPanel extends JPanel {
setBackground(new Color(0, 0, 64)); setBackground(new Color(0, 0, 64));
setOpaque(false); setOpaque(false);
} }
public Computer getComputer() {
return Emulator.computer;
}
@Override @Override
public void paint(Graphics g) { public void paint(Graphics g) {
if (Computer.getComputer() != null) { if (getComputer() != null) {
Computer.getComputer().getVideo().forceRefresh(); getComputer().getVideo().forceRefresh();
} }
} }
} }

View File

@ -1,5 +1,5 @@
#Generated by Maven #Generated by Maven
#Sun Sep 07 16:06:31 CDT 2014 #Wed Sep 17 00:59:53 CDT 2014
version=2.0-SNAPSHOT version=2.0-SNAPSHOT
groupId=org.badvision groupId=org.badvision
artifactId=jace artifactId=jace

View File

@ -63,7 +63,6 @@ jace/apple2e/Speaker$2.class
jace/cheat/MetaCheatForm.class jace/cheat/MetaCheatForm.class
jace/library/MediaEditUI$1.class jace/library/MediaEditUI$1.class
jace/cheat/PrinceOfPersiaCheats$5.class jace/cheat/PrinceOfPersiaCheats$5.class
.netbeans_automatic_build
jace/apple2e/SoftSwitches$3.class jace/apple2e/SoftSwitches$3.class
jace/library/MediaLibraryUI$tocOptions$1.class jace/library/MediaLibraryUI$tocOptions$1.class
jace/core/TimedDevice.class jace/core/TimedDevice.class