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
FloppyDisk theDisk = null;
try {
theDisk = new FloppyDisk(in);
theDisk = new FloppyDisk(in, null);
} catch (IOException ex) {
System.out.println("Couldn't read disk image");
ex.printStackTrace();
return;
}
if (!writeNibblized) {

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,8 +36,12 @@ import jace.config.Reconfigurable;
*/
@Stateful
public abstract class Device implements Reconfigurable {
protected Computer computer;
public Device(Computer computer) {
this.computer = computer;
}
// Number of cycles to do nothing (for cpu/video cycle accuracy)
@Stateful
private int waitCycles = 0;
@Stateful

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,10 +18,10 @@
*/
package jace.library;
import jace.Emulator;
import jace.config.ConfigurableField;
import jace.config.Reconfigurable;
import jace.core.Card;
import jace.core.Computer;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@ -50,14 +50,17 @@ public class MediaLibrary implements Reconfigurable {
@ConfigurableField(category = "Library", defaultValue = "true", name = "Keep local copy", description = "Automatically download and save local copies of disks when written.")
public static boolean CREATE_LOCAL_ON_SAVE = true;
@Override
public String getName() {
return "Media Library";
}
@Override
public String getShortName() {
return "media";
}
@Override
public void reconfigure() {
rebuildDriveList();
}
@ -76,7 +79,7 @@ public class MediaLibrary implements Reconfigurable {
return;
}
userInterface.Drives.removeAll();
for (Card card : Computer.getComputer().memory.getAllCards()) {
for (Card card : Emulator.computer.memory.getAllCards()) {
if (card == null || !(card instanceof MediaConsumerParent)) {
continue;
}

View File

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

View File

@ -31,12 +31,49 @@ import jace.hardware.CardMockingboard;
*/
public class PlaybackEngine extends Computer {
Motherboard motherboard = new Motherboard();
CardMockingboard mockingboard = new CardMockingboard();
Computer dummyComputer = new Computer() {
@Override
public void coldStart() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void warmStart() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
protected boolean isRunning() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
protected void doPause() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
protected void doResume() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String getName() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String getShortName() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
};
Motherboard motherboard = new Motherboard(dummyComputer);
CardMockingboard mockingboard = new CardMockingboard(dummyComputer);
public PlaybackEngine() {
setMemory(new CardExt80Col());
setCpu(new MOS65C02());
setMemory(new CardExt80Col(dummyComputer));
setCpu(new MOS65C02(dummyComputer));
getMemory().addCard(mockingboard, 5);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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