2014-09-07 21:10:04 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
* MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
package jace.apple2e;
|
|
|
|
|
|
|
|
import jace.Emulator;
|
|
|
|
import jace.cheat.Cheats;
|
|
|
|
import jace.config.ClassSelection;
|
|
|
|
import jace.config.ConfigurableField;
|
|
|
|
import jace.core.Card;
|
|
|
|
import jace.core.Computer;
|
|
|
|
import jace.core.Motherboard;
|
|
|
|
import jace.core.RAM;
|
|
|
|
import jace.core.RAMEvent;
|
|
|
|
import jace.core.RAMListener;
|
|
|
|
import jace.state.Stateful;
|
|
|
|
import jace.core.Video;
|
|
|
|
import jace.hardware.CardDiskII;
|
|
|
|
import jace.hardware.CardExt80Col;
|
|
|
|
import jace.hardware.ConsoleProbe;
|
|
|
|
import jace.hardware.Joystick;
|
2015-04-12 03:20:14 +00:00
|
|
|
import jace.hardware.NoSlotClock;
|
2014-09-07 21:10:04 +00:00
|
|
|
import jace.hardware.massStorage.CardMassStorage;
|
|
|
|
import java.io.IOException;
|
2014-09-18 04:09:57 +00:00
|
|
|
import java.lang.reflect.InvocationTargetException;
|
2014-09-07 21:10:04 +00:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
2014-09-20 16:10:49 +00:00
|
|
|
import java.util.Optional;
|
2015-08-12 05:09:15 +00:00
|
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
|
|
import java.util.concurrent.ScheduledFuture;
|
|
|
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
2014-09-07 21:10:04 +00:00
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apple2e is a computer with a 65c02 CPU, 128k of bankswitched ram,
|
|
|
|
* double-hires graphics, and up to seven peripheral I/O cards installed. Pause
|
|
|
|
* and resume are implemented by the Motherboard class. This class provides
|
|
|
|
* overall configuration of the computer, but the actual operation of the
|
|
|
|
* computer and its timing characteristics are managed in the Motherboard class.
|
|
|
|
*
|
2014-09-18 04:09:57 +00:00
|
|
|
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
2014-09-07 21:10:04 +00:00
|
|
|
*/
|
|
|
|
@Stateful
|
|
|
|
public class Apple2e extends Computer {
|
|
|
|
|
|
|
|
static int IRQ_VECTOR = 0x003F2;
|
|
|
|
@ConfigurableField(name = "Slot 1", shortName = "s1card")
|
|
|
|
public ClassSelection card1 = new ClassSelection(Card.class, null);
|
|
|
|
@ConfigurableField(name = "Slot 2", shortName = "s2card")
|
|
|
|
public ClassSelection card2 = new ClassSelection(Card.class, null);
|
|
|
|
@ConfigurableField(name = "Slot 3", shortName = "s3card")
|
|
|
|
public ClassSelection card3 = new ClassSelection(Card.class, null);
|
|
|
|
@ConfigurableField(name = "Slot 4", shortName = "s4card")
|
|
|
|
public ClassSelection card4 = new ClassSelection(Card.class, null);
|
|
|
|
@ConfigurableField(name = "Slot 5", shortName = "s5card")
|
|
|
|
public ClassSelection card5 = new ClassSelection(Card.class, null);
|
|
|
|
@ConfigurableField(name = "Slot 6", shortName = "s6card")
|
|
|
|
public ClassSelection card6 = new ClassSelection(Card.class, CardDiskII.class);
|
|
|
|
@ConfigurableField(name = "Slot 7", shortName = "s7card")
|
|
|
|
public ClassSelection card7 = new ClassSelection(Card.class, CardMassStorage.class);
|
|
|
|
@ConfigurableField(name = "Debug rom", shortName = "debugRom", description = "Use debugger //e rom")
|
|
|
|
public boolean useDebugRom = false;
|
|
|
|
@ConfigurableField(name = "Console probe", description = "Enable console redirection (experimental!)")
|
|
|
|
public boolean useConsoleProbe = false;
|
|
|
|
private ConsoleProbe probe = new ConsoleProbe();
|
|
|
|
@ConfigurableField(name = "Helpful hints", shortName = "hints")
|
|
|
|
public boolean enableHints = true;
|
|
|
|
@ConfigurableField(name = "Renderer", shortName = "video", description = "Video rendering implementation")
|
|
|
|
public ClassSelection videoRenderer = new ClassSelection(Video.class, VideoNTSC.class);
|
|
|
|
@ConfigurableField(name = "Aux Ram", shortName = "ram", description = "Aux ram card")
|
|
|
|
public ClassSelection ramCard = new ClassSelection(RAM128k.class, CardExt80Col.class);
|
2015-03-29 05:24:07 +00:00
|
|
|
@ConfigurableField(name = "Joystick 1 Enabled", shortName = "joy1", description = "If unchecked, then there is no joystick support.", enablesDevice = true)
|
2015-08-13 06:13:52 +00:00
|
|
|
public boolean joy1enabled = true;
|
2015-03-29 05:24:07 +00:00
|
|
|
@ConfigurableField(name = "Joystick 2 Enabled", shortName = "joy2", description = "If unchecked, then there is no joystick support.", enablesDevice = true)
|
|
|
|
public boolean joy2enabled = false;
|
2015-04-12 03:20:14 +00:00
|
|
|
@ConfigurableField(name = "No-Slot Clock Enabled", shortName = "clock", description = "If checked, no-slot clock will be enabled", enablesDevice = true)
|
|
|
|
public boolean clockEnabled = true;
|
2015-03-29 05:24:07 +00:00
|
|
|
|
2014-09-07 21:10:04 +00:00
|
|
|
public Joystick joystick1;
|
|
|
|
public Joystick joystick2;
|
|
|
|
@ConfigurableField(name = "Activate Cheats", shortName = "cheat", defaultValue = "")
|
|
|
|
public ClassSelection cheatEngine = new ClassSelection(Cheats.class, null);
|
|
|
|
public Cheats activeCheatEngine = null;
|
2015-04-12 03:20:14 +00:00
|
|
|
public NoSlotClock clock;
|
2014-09-07 21:10:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new instance of Apple2e
|
|
|
|
*/
|
|
|
|
public Apple2e() {
|
|
|
|
super();
|
|
|
|
try {
|
|
|
|
reconfigure();
|
2014-09-18 04:09:57 +00:00
|
|
|
setCpu(new MOS65C02(this));
|
2014-09-07 21:10:04 +00:00
|
|
|
reinitMotherboard();
|
|
|
|
} catch (Throwable t) {
|
|
|
|
System.err.println("Unable to initalize virtual machine");
|
|
|
|
t.printStackTrace(System.err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getName() {
|
|
|
|
return "Computer (Apple //e)";
|
|
|
|
}
|
|
|
|
|
|
|
|
private void reinitMotherboard() {
|
|
|
|
if (motherboard != null && motherboard.isRunning()) {
|
|
|
|
motherboard.suspend();
|
|
|
|
}
|
2015-08-13 06:12:09 +00:00
|
|
|
motherboard = new Motherboard(this, motherboard);
|
|
|
|
reconfigure();
|
2014-09-07 21:10:04 +00:00
|
|
|
motherboard.reconfigure();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void coldStart() {
|
2014-09-18 04:09:57 +00:00
|
|
|
pause();
|
2014-09-07 21:10:04 +00:00
|
|
|
reinitMotherboard();
|
|
|
|
for (SoftSwitches s : SoftSwitches.values()) {
|
|
|
|
s.getSwitch().reset();
|
|
|
|
}
|
|
|
|
getMemory().configureActiveMemory();
|
|
|
|
getVideo().configureVideoMode();
|
2014-09-20 16:10:49 +00:00
|
|
|
for (Optional<Card> c : getMemory().getAllCards()) {
|
|
|
|
c.ifPresent(Card::reset);
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
2015-08-12 02:06:37 +00:00
|
|
|
reboot();
|
2014-09-18 04:09:57 +00:00
|
|
|
resume();
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void reboot() {
|
|
|
|
RAM r = getMemory();
|
|
|
|
r.write(IRQ_VECTOR, (byte) 0x00, false, true);
|
|
|
|
r.write(IRQ_VECTOR + 1, (byte) 0x00, false, true);
|
|
|
|
r.write(IRQ_VECTOR + 2, (byte) 0x00, false, true);
|
|
|
|
warmStart();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void warmStart() {
|
2014-09-18 04:09:57 +00:00
|
|
|
boolean restart = pause();
|
2014-09-07 21:10:04 +00:00
|
|
|
for (SoftSwitches s : SoftSwitches.values()) {
|
|
|
|
s.getSwitch().reset();
|
|
|
|
}
|
|
|
|
getMemory().configureActiveMemory();
|
|
|
|
getVideo().configureVideoMode();
|
|
|
|
getCpu().reset();
|
2014-09-20 16:10:49 +00:00
|
|
|
for (Optional<Card> c : getMemory().getAllCards()) {
|
|
|
|
c.ifPresent(Card::reset);
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
getCpu().resume();
|
2014-09-18 04:09:57 +00:00
|
|
|
resume();
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
|
2014-09-18 04:09:57 +00:00
|
|
|
private void insertCard(Class<? extends Card> type, int slot) throws NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
|
2015-03-15 05:28:31 +00:00
|
|
|
if (getMemory().getCard(slot).isPresent()) {
|
|
|
|
if (getMemory().getCard(slot).get().getClass().equals(type)) {
|
2014-09-07 21:10:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
getMemory().removeCard(slot);
|
|
|
|
}
|
|
|
|
if (type != null) {
|
|
|
|
try {
|
2014-09-18 04:09:57 +00:00
|
|
|
Card card = type.getConstructor(Computer.class).newInstance(this);
|
|
|
|
getMemory().addCard(card, slot);
|
2014-09-07 21:10:04 +00:00
|
|
|
} catch (InstantiationException | IllegalAccessException ex) {
|
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public final void reconfigure() {
|
2014-09-18 04:09:57 +00:00
|
|
|
boolean restart = pause();
|
2014-09-07 21:10:04 +00:00
|
|
|
|
|
|
|
super.reconfigure();
|
2014-09-18 04:09:57 +00:00
|
|
|
|
2014-09-07 21:10:04 +00:00
|
|
|
RAM128k currentMemory = (RAM128k) getMemory();
|
2015-03-29 05:24:07 +00:00
|
|
|
if (currentMemory != null && ramCard.getValue() != null && !(currentMemory.getClass().equals(ramCard.getValue()))) {
|
2014-09-07 21:10:04 +00:00
|
|
|
try {
|
2014-09-18 04:53:59 +00:00
|
|
|
RAM128k newMemory = (RAM128k) ramCard.getValue().getConstructor(Computer.class).newInstance(this);
|
2014-09-07 21:10:04 +00:00
|
|
|
newMemory.copyFrom(currentMemory);
|
|
|
|
setMemory(newMemory);
|
2014-09-18 04:53:59 +00:00
|
|
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex) {
|
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (getMemory() == null) {
|
|
|
|
try {
|
2014-09-18 04:53:59 +00:00
|
|
|
currentMemory = (RAM128k) ramCard.getValue().getConstructor(Computer.class).newInstance(this);
|
|
|
|
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException ex) {
|
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
} catch (IllegalArgumentException | InvocationTargetException ex) {
|
2014-09-07 21:10:04 +00:00
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
setMemory(currentMemory);
|
|
|
|
for (SoftSwitches s : SoftSwitches.values()) {
|
2014-09-18 04:09:57 +00:00
|
|
|
s.getSwitch().register(this);
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currentMemory.reconfigure();
|
2015-04-12 03:20:14 +00:00
|
|
|
|
|
|
|
if (motherboard != null) {
|
|
|
|
if (joy1enabled) {
|
|
|
|
if (joystick1 == null) {
|
|
|
|
joystick1 = new Joystick(0, this);
|
|
|
|
motherboard.miscDevices.add(joystick1);
|
|
|
|
joystick1.attach();
|
|
|
|
}
|
|
|
|
} else if (joystick1 != null) {
|
|
|
|
joystick1.detach();
|
|
|
|
motherboard.miscDevices.remove(joystick1);
|
|
|
|
joystick1 = null;
|
2015-03-29 05:24:07 +00:00
|
|
|
}
|
2015-04-12 03:20:14 +00:00
|
|
|
|
|
|
|
if (joy2enabled) {
|
|
|
|
if (joystick2 == null) {
|
|
|
|
joystick2 = new Joystick(1, this);
|
|
|
|
motherboard.miscDevices.add(joystick2);
|
|
|
|
joystick2.attach();
|
|
|
|
}
|
|
|
|
} else if (joystick2 != null) {
|
|
|
|
joystick2.detach();
|
|
|
|
motherboard.miscDevices.remove(joystick2);
|
|
|
|
joystick2 = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clockEnabled) {
|
|
|
|
if (clock == null) {
|
|
|
|
clock = new NoSlotClock(this);
|
|
|
|
motherboard.miscDevices.add(clock);
|
|
|
|
clock.attach();
|
|
|
|
}
|
|
|
|
} else if (clock != null) {
|
|
|
|
motherboard.miscDevices.remove(clock);
|
|
|
|
clock.detach();
|
|
|
|
clock = null;
|
2015-03-29 05:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-07 21:10:04 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
if (useConsoleProbe) {
|
|
|
|
probe.init(this);
|
|
|
|
} else {
|
|
|
|
probe.shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useDebugRom) {
|
|
|
|
loadRom("jace/data/apple2e_debug.rom");
|
|
|
|
} else {
|
|
|
|
loadRom("jace/data/apple2e.rom");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getVideo() == null || getVideo().getClass() != videoRenderer.getValue()) {
|
|
|
|
if (getVideo() != null) {
|
|
|
|
getVideo().suspend();
|
|
|
|
}
|
|
|
|
try {
|
2014-09-18 04:53:59 +00:00
|
|
|
setVideo((Video) videoRenderer.getValue().getConstructor(Computer.class).newInstance(this));
|
2014-09-07 21:10:04 +00:00
|
|
|
getVideo().configureVideoMode();
|
|
|
|
getVideo().reconfigure();
|
|
|
|
Emulator.resizeVideo();
|
|
|
|
getVideo().resume();
|
|
|
|
} catch (InstantiationException | IllegalAccessException ex) {
|
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
2014-09-18 04:53:59 +00:00
|
|
|
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
|
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-18 04:09:57 +00:00
|
|
|
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);
|
|
|
|
}
|
2014-09-07 21:10:04 +00:00
|
|
|
if (enableHints) {
|
|
|
|
enableHints();
|
|
|
|
} else {
|
|
|
|
disableHints();
|
|
|
|
}
|
|
|
|
getMemory().configureActiveMemory();
|
|
|
|
|
|
|
|
if (cheatEngine.getValue() == null) {
|
|
|
|
if (activeCheatEngine != null) {
|
|
|
|
activeCheatEngine.detach();
|
|
|
|
}
|
|
|
|
activeCheatEngine = null;
|
|
|
|
} else {
|
|
|
|
boolean startCheats = true;
|
|
|
|
if (activeCheatEngine != null) {
|
|
|
|
if (activeCheatEngine.getClass().equals(cheatEngine.getValue())) {
|
|
|
|
startCheats = false;
|
|
|
|
} else {
|
|
|
|
activeCheatEngine.detach();
|
|
|
|
activeCheatEngine = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (startCheats) {
|
|
|
|
try {
|
2015-08-13 07:50:27 +00:00
|
|
|
activeCheatEngine = (Cheats) cheatEngine.getValue().getConstructor(Computer.class).newInstance(this);
|
|
|
|
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
|
2014-09-07 21:10:04 +00:00
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
}
|
|
|
|
activeCheatEngine.attach();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
}
|
|
|
|
if (restart) {
|
2014-09-18 04:09:57 +00:00
|
|
|
resume();
|
2014-09-07 21:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void doPause() {
|
|
|
|
if (motherboard == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
motherboard.pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void doResume() {
|
|
|
|
if (motherboard == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
motherboard.resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean isRunning() {
|
|
|
|
if (motherboard == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return motherboard.isRunning() && !motherboard.isPaused;
|
|
|
|
}
|
|
|
|
private List<RAMListener> hints = new ArrayList<>();
|
|
|
|
|
2015-08-12 05:09:15 +00:00
|
|
|
ScheduledExecutorService animationTimer = new ScheduledThreadPoolExecutor(1);
|
|
|
|
Runnable drawHints = () -> {
|
|
|
|
if (getCpu().getProgramCounter() >> 8 != 0x0c6) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int row = 2;
|
|
|
|
for (String s : new String[]{
|
|
|
|
" Welcome to",
|
|
|
|
" _ __ ___ ____ ",
|
|
|
|
" | | / /\\ / / ` | |_ ",
|
|
|
|
" \\_|_| /_/--\\ \\_\\_, |_|__ ",
|
|
|
|
"",
|
|
|
|
" Java Apple Computer Emulator",
|
|
|
|
"",
|
|
|
|
" Presented by BLuRry",
|
|
|
|
" http://goo.gl/SnzqG",
|
|
|
|
"",
|
|
|
|
"To insert a disk, please drag it over",
|
|
|
|
"this window and drop on the desired",
|
|
|
|
"drive icon.",
|
|
|
|
"",
|
|
|
|
"Press CTRL+SHIFT+C for configuration.",
|
|
|
|
"Press CTRL+SHIFT+I for IDE window.",
|
|
|
|
"",
|
|
|
|
"O-A: Alt/Option",
|
|
|
|
"C-A: Shortcut/Command",
|
|
|
|
"Reset: Delete/Backspace"
|
|
|
|
}) {
|
|
|
|
int addr = 0x0401 + VideoDHGR.calculateTextOffset(row++);
|
|
|
|
for (char c : s.toCharArray()) {
|
|
|
|
getMemory().write(addr++, (byte) (c | 0x080), false, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
int animAddr, animCycleNumber;
|
|
|
|
byte animOldValue;
|
|
|
|
final String animation = "+xX*+-";
|
|
|
|
ScheduledFuture animationSchedule;
|
|
|
|
Runnable doAnimation = () -> {
|
|
|
|
if (animAddr == 0 || animCycleNumber >= animation.length()) {
|
|
|
|
if (animAddr > 0) {
|
|
|
|
getMemory().write(animAddr, animOldValue, true, true);
|
|
|
|
}
|
|
|
|
int animX = (int) (Math.random() * 24.0) + 7;
|
|
|
|
int animY = (int) (Math.random() * 3.0) + 3;
|
|
|
|
animAddr = 0x0400 + VideoDHGR.calculateTextOffset(animY) + animX;
|
|
|
|
animOldValue = getMemory().readRaw(animAddr);
|
|
|
|
animCycleNumber = 0;
|
|
|
|
}
|
|
|
|
if (getCpu().getProgramCounter() >> 8 == 0x0c6) {
|
|
|
|
getMemory().write(animAddr, (byte) (animation.charAt(animCycleNumber) | 0x080), true, true);
|
|
|
|
animCycleNumber++;
|
|
|
|
} else {
|
|
|
|
getMemory().write(animAddr, animOldValue, true, true);
|
|
|
|
animationSchedule.cancel(false);
|
|
|
|
animAddr = 0;
|
|
|
|
}
|
|
|
|
};
|
2015-02-21 16:52:26 +00:00
|
|
|
|
2014-09-07 21:10:04 +00:00
|
|
|
private void enableHints() {
|
|
|
|
if (hints.isEmpty()) {
|
2015-08-16 03:57:49 +00:00
|
|
|
hints.add(getMemory().observe(RAMEvent.TYPE.EXECUTE, 0x0FB63, (e)->{
|
|
|
|
animationTimer.schedule(drawHints, 1, TimeUnit.SECONDS);
|
|
|
|
animationSchedule =
|
2015-08-12 05:09:15 +00:00
|
|
|
animationTimer.scheduleAtFixedRate(doAnimation, 1250, 100, TimeUnit.MILLISECONDS);
|
2015-08-16 03:57:49 +00:00
|
|
|
}));
|
2014-09-07 21:10:04 +00:00
|
|
|
// Latch to the PRODOS SYNTAX CHECK parser
|
|
|
|
/*
|
|
|
|
hints.add(new RAMListener(RAMEvent.TYPE.EXECUTE, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
|
|
|
@Override
|
|
|
|
protected void doConfig() {setScopeStart(0x0a685);}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void doEvent(RAMEvent e) {
|
|
|
|
String in = "";
|
|
|
|
for (int i=0x0200; i < 0x0300; i++) {
|
|
|
|
char c = (char) (getMemory().readRaw(i) & 0x07f);
|
|
|
|
if (c == 0x0d) break;
|
|
|
|
in += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
System.err.println("Intercepted command: "+in);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void disableHints() {
|
|
|
|
hints.stream().forEach((hint) -> {
|
|
|
|
getMemory().removeListener(hint);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getShortName() {
|
|
|
|
return "computer";
|
|
|
|
}
|
2015-08-12 05:09:15 +00:00
|
|
|
}
|