mirror of
https://github.com/badvision/jace.git
synced 2025-02-17 08:30:53 +00:00
Fixed some edge case language card issues and implemented false reads for absolute indexed addressing modes, improved test coverage
This commit is contained in:
parent
1c26ecad3d
commit
519c561537
@ -414,6 +414,8 @@ public class MOS65C02 extends CPU {
|
|||||||
ABSOLUTE_X(3, "$~2~1,X", (cpu) -> {
|
ABSOLUTE_X(3, "$~2~1,X", (cpu) -> {
|
||||||
int address2 = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
int address2 = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||||
int address = 0x0FFFF & (address2 + cpu.X);
|
int address = 0x0FFFF & (address2 + cpu.X);
|
||||||
|
// False read
|
||||||
|
cpu.getMemory().read(address, TYPE.READ_DATA, true, false);
|
||||||
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (address2 & 0x00ff00));
|
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (address2 & 0x00ff00));
|
||||||
cpu.setPageBoundaryApplied(true);
|
cpu.setPageBoundaryApplied(true);
|
||||||
return address;
|
return address;
|
||||||
@ -421,6 +423,8 @@ public class MOS65C02 extends CPU {
|
|||||||
ABSOLUTE_Y(3, "$~2~1,Y", (cpu) -> {
|
ABSOLUTE_Y(3, "$~2~1,Y", (cpu) -> {
|
||||||
int address2 = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
int address2 = cpu.getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
|
||||||
int address = 0x0FFFF & (address2 + cpu.Y);
|
int address = 0x0FFFF & (address2 + cpu.Y);
|
||||||
|
// False read
|
||||||
|
cpu.getMemory().read(address, TYPE.READ_DATA, true, false);
|
||||||
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (address2 & 0x00ff00));
|
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (address2 & 0x00ff00));
|
||||||
cpu.setPageBoundaryApplied(true);
|
cpu.setPageBoundaryApplied(true);
|
||||||
return address;
|
return address;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package jace.apple2e.softswitch;
|
package jace.apple2e.softswitch;
|
||||||
|
|
||||||
|
import jace.core.RAMEvent;
|
||||||
import jace.core.RAMEvent.TYPE;
|
import jace.core.RAMEvent.TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,32 +24,30 @@ import jace.core.RAMEvent.TYPE;
|
|||||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||||
*/
|
*/
|
||||||
public class Memory2SoftSwitch extends MemorySoftSwitch {
|
public class Memory2SoftSwitch extends MemorySoftSwitch {
|
||||||
public Memory2SoftSwitch(String name, int offAddress, int onAddress, int queryAddress, TYPE changeType, Boolean initalState) {
|
|
||||||
super(name, offAddress, onAddress, queryAddress, changeType, initalState);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Memory2SoftSwitch(String name, int[] offAddrs, int[] onAddrs, int[] queryAddrs, TYPE changeType, Boolean initalState) {
|
public Memory2SoftSwitch(String name, int[] offAddrs, int[] onAddrs, int[] queryAddrs, TYPE changeType, Boolean initalState) {
|
||||||
super(name, offAddrs, onAddrs, queryAddrs, changeType, initalState);
|
super(name, offAddrs, onAddrs, queryAddrs, changeType, initalState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The switch must be set true two times in a row before it will actually be set.
|
int readCount = 0;
|
||||||
int count = 0;
|
|
||||||
@Override
|
@Override
|
||||||
public void setState(boolean newState) {
|
public void setState(boolean newState, RAMEvent e) {
|
||||||
if (!newState) {
|
if (!newState) {
|
||||||
count = 0;
|
super.setState(false);
|
||||||
super.setState(newState);
|
readCount = 0;
|
||||||
} else {
|
} else {
|
||||||
count++;
|
if (e.getType().isRead()) {
|
||||||
if (count >= 2) {
|
readCount++;
|
||||||
super.setState(newState);
|
} else {
|
||||||
count = 0;
|
readCount = 0;
|
||||||
|
}
|
||||||
|
if (readCount >= 2) {
|
||||||
|
super.setState(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getName()+(getState()?":1":":0")+"~~"+count;
|
return getName()+(getState()?":1":":0")+"~~"+readCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -114,8 +114,7 @@ public abstract class SoftSwitch {
|
|||||||
@Override
|
@Override
|
||||||
protected void doEvent(RAMEvent e) {
|
protected void doEvent(RAMEvent e) {
|
||||||
if (!exclusionActivate.contains(e.getAddress())) {
|
if (!exclusionActivate.contains(e.getAddress())) {
|
||||||
// System.out.println("Access to "+Integer.toHexString(e.getAddress())+" ENABLES switch "+getName());
|
setState(!getState(), e);
|
||||||
setState(!getState());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -148,7 +147,7 @@ public abstract class SoftSwitch {
|
|||||||
}
|
}
|
||||||
if (!exclusionActivate.contains(e.getAddress())) {
|
if (!exclusionActivate.contains(e.getAddress())) {
|
||||||
// System.out.println("Access to "+Integer.toHexString(e.getAddress())+" ENABLES switch "+getName());
|
// System.out.println("Access to "+Integer.toHexString(e.getAddress())+" ENABLES switch "+getName());
|
||||||
setState(true);
|
setState(true, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -177,7 +176,7 @@ public abstract class SoftSwitch {
|
|||||||
@Override
|
@Override
|
||||||
protected void doEvent(RAMEvent e) {
|
protected void doEvent(RAMEvent e) {
|
||||||
if (!exclusionDeactivate.contains(e.getAddress())) {
|
if (!exclusionDeactivate.contains(e.getAddress())) {
|
||||||
setState(false);
|
setState(false, e);
|
||||||
// System.out.println("Access to "+Integer.toHexString(e.getAddress())+" disables switch "+getName());
|
// System.out.println("Access to "+Integer.toHexString(e.getAddress())+" disables switch "+getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,6 +249,12 @@ public abstract class SoftSwitch {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Most softswitches act the same regardless of the ram event triggering them
|
||||||
|
// But some softswitches are a little tricky (such as language card write) and need to assert extra conditions
|
||||||
|
public void setState(boolean newState, RAMEvent e) {
|
||||||
|
setState(newState);
|
||||||
|
}
|
||||||
|
|
||||||
public void setState(boolean newState) {
|
public void setState(boolean newState) {
|
||||||
if (inhibit()) {
|
if (inhibit()) {
|
||||||
return;
|
return;
|
||||||
|
@ -246,10 +246,10 @@ public class TestProgram {
|
|||||||
private void handleTrace(byte val) {
|
private void handleTrace(byte val) {
|
||||||
if (val == (byte)0x01) {
|
if (val == (byte)0x01) {
|
||||||
System.out.println("Trace on");
|
System.out.println("Trace on");
|
||||||
Full65C02Test.cpu.setTraceEnabled(true);
|
Emulator.withComputer(c->c.getCpu().setTraceEnabled(true));
|
||||||
} else {
|
} else {
|
||||||
System.out.println("Trace off");
|
System.out.println("Trace off");
|
||||||
Full65C02Test.cpu.setTraceEnabled(false);
|
Emulator.withComputer(c->c.getCpu().setTraceEnabled(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +274,13 @@ public class TestProgram {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TestProgram assertEquals(String message) {
|
||||||
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||||
|
String caller = stackTrace[2].toString();
|
||||||
|
_test(TestProgram.INDENT + TestProgram.Flag.IS_ZERO.code, message + "<<" + caller + ">>");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TestProgram assertFlags(TestProgram.Flag... flags) {
|
public TestProgram assertFlags(TestProgram.Flag... flags) {
|
||||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||||
String caller = stackTrace[2].toString();
|
String caller = stackTrace[2].toString();
|
||||||
@ -372,7 +379,11 @@ public class TestProgram {
|
|||||||
+throwError %s
|
+throwError %s
|
||||||
+ ; >> Test """.formatted(condition, code, errorNum));
|
+ ; >> Test """.formatted(condition, code, errorNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TestProgram throwError(String error) {
|
||||||
|
_test("", error);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Note the current breakpoint, helpful in understanding error locations
|
* Note the current breakpoint, helpful in understanding error locations
|
||||||
*
|
*
|
||||||
@ -447,6 +458,12 @@ public class TestProgram {
|
|||||||
for (int i=0; i < maxTicks; i++) {
|
for (int i=0; i < maxTicks; i++) {
|
||||||
cpu.doTick();
|
cpu.doTick();
|
||||||
tickCount++;
|
tickCount++;
|
||||||
|
if (cpu.interruptSignalled) {
|
||||||
|
if (lastError == null) {
|
||||||
|
lastError = new ProgramException("Interrupt signalled by BRK opcode", lastBreakpoint);
|
||||||
|
}
|
||||||
|
programReportedError=true;
|
||||||
|
}
|
||||||
if (programReportedError) {
|
if (programReportedError) {
|
||||||
throw lastError;
|
throw lastError;
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,22 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import jace.Emulator;
|
import jace.Emulator;
|
||||||
|
import jace.ProgramException;
|
||||||
|
import jace.TestProgram;
|
||||||
import jace.apple2e.MOS65C02;
|
import jace.apple2e.MOS65C02;
|
||||||
import jace.apple2e.RAM128k;
|
import jace.apple2e.RAM128k;
|
||||||
|
import jace.apple2e.SoftSwitches;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that memory listeners fire appropriately.
|
* Test that memory listeners fire appropriately.
|
||||||
@ -37,14 +45,36 @@ public class MemoryTest {
|
|||||||
static Computer computer;
|
static Computer computer;
|
||||||
static MOS65C02 cpu;
|
static MOS65C02 cpu;
|
||||||
static RAM128k ram;
|
static RAM128k ram;
|
||||||
|
static String MEMORY_TEST_COMMONS;
|
||||||
|
static String MACHINE_IDENTIFICATION;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setupClass() {
|
public static void setupClass() throws IOException, URISyntaxException {
|
||||||
initComputer();
|
initComputer();
|
||||||
SoundMixer.MUTE = true;
|
SoundMixer.MUTE = true;
|
||||||
computer = Emulator.withComputer(c->c, null);
|
computer = Emulator.withComputer(c->c, null);
|
||||||
cpu = (MOS65C02) computer.getCpu();
|
cpu = (MOS65C02) computer.getCpu();
|
||||||
ram = (RAM128k) computer.getMemory();
|
ram = (RAM128k) computer.getMemory();
|
||||||
|
ram.addExecutionTrap("COUT intercept", 0x0FDF0, (e)->{
|
||||||
|
char c = (char) (cpu.A & 0x07f);
|
||||||
|
if (c == '\r') {
|
||||||
|
System.out.println();
|
||||||
|
} else {
|
||||||
|
System.out.print(c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
MEMORY_TEST_COMMONS = Files.readString(Paths.get(MemoryTest.class.getResource("/jace/memory_test_commons.asm").toURI()));
|
||||||
|
MACHINE_IDENTIFICATION = Files.readString(Paths.get(MemoryTest.class.getResource("/jace/machine_identification.asm").toURI()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
computer.pause();
|
||||||
|
cpu.clearState();
|
||||||
|
// Reset softswitches
|
||||||
|
for (SoftSwitches softswitch : SoftSwitches.values()) {
|
||||||
|
softswitch.getSwitch().reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -152,5 +182,324 @@ public class MemoryTest {
|
|||||||
assertEquals("Should have no writes for 0x0100", 0, writeEventCaught.get());
|
assertEquals("Should have no writes for 0x0100", 0, writeEventCaught.get());
|
||||||
assertEquals("Should have read event for 0x0100", 1, readAnyEventCaught.get());
|
assertEquals("Should have read event for 0x0100", 1, readAnyEventCaught.get());
|
||||||
assertEquals("Should have execute for 0x0100", 1, executeEventCaught.get());
|
assertEquals("Should have execute for 0x0100", 1, executeEventCaught.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted version of the Apple II Family Identification Program from:
|
||||||
|
* http://www.1000bit.it/support/manuali/apple/technotes/misc/tn.misc.02.html00
|
||||||
|
*
|
||||||
|
* Adapted to ACME by Zellyn Hunter
|
||||||
|
*
|
||||||
|
* @throws ProgramException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void machineIdentificationTEst() throws ProgramException {
|
||||||
|
TestProgram memoryDetectTestProgram = new TestProgram(MEMORY_TEST_COMMONS);
|
||||||
|
memoryDetectTestProgram.add(MACHINE_IDENTIFICATION);
|
||||||
|
// Assert this is an Apple //e
|
||||||
|
memoryDetectTestProgram.assertAddrVal(0x0800, 0x04);
|
||||||
|
// Assert this is an enhanced revision
|
||||||
|
memoryDetectTestProgram.assertAddrVal(0x0801, 0x02);
|
||||||
|
// Aser this is a 128k machine
|
||||||
|
memoryDetectTestProgram.assertAddrVal(0x0802, 128);
|
||||||
|
memoryDetectTestProgram.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapted from Zellyn Hunder's language card test:
|
||||||
|
* https://github.com/zellyn/a2audit/blob/main/audit/langcard.asm
|
||||||
|
*
|
||||||
|
* Adjusted to use JACE hooks to perform assertions and error reporting
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void languageCardBankswitchTest() throws ProgramException {
|
||||||
|
TestProgram lcTestProgram = new TestProgram(MEMORY_TEST_COMMONS);
|
||||||
|
lcTestProgram.add("""
|
||||||
|
;; Setup - store differing values in bank first and second banked areas.
|
||||||
|
lda $C08B ; Read and write bank 1
|
||||||
|
lda $C08B
|
||||||
|
lda #$11
|
||||||
|
sta $D17B ; $D17B is $53 in Apple II/plus/e/enhanced
|
||||||
|
cmp $D17B
|
||||||
|
""")
|
||||||
|
.assertEquals("E0004: We tried to put the language card into read bank 1, write bank 1, but failed to write.")
|
||||||
|
.add("""
|
||||||
|
lda #$33
|
||||||
|
sta $FE1F ; FE1F is $60 in Apple II/plus/e/enhanced
|
||||||
|
cmp $FE1F
|
||||||
|
""")
|
||||||
|
//
|
||||||
|
.assertEquals("E0005: We tried to put the language card into read RAM, write RAM, but failed to write.")
|
||||||
|
.add("""
|
||||||
|
lda $C083 ; Read and write bank 2
|
||||||
|
lda $C083
|
||||||
|
lda #$22
|
||||||
|
sta $D17B
|
||||||
|
cmp $D17B
|
||||||
|
""")
|
||||||
|
.assertEquals("E0006: We tried to put the language card into read bank 2, write bank 2, but failed to write.")
|
||||||
|
.add("""
|
||||||
|
lda $C08B ; Read and write bank 1 with single access (only one needed if banked in already)
|
||||||
|
lda #$11
|
||||||
|
cmp $D17B
|
||||||
|
""")
|
||||||
|
.assertEquals("E000D: We tried to put the language card into read bank 1, but failed to read.")
|
||||||
|
.add("""
|
||||||
|
lda $C081 ; Read ROM with single access (only one needed to bank out)
|
||||||
|
lda #$53
|
||||||
|
cmp $D17B
|
||||||
|
""")
|
||||||
|
.assertEquals("E000E: We tried to put the language card into read ROM, but failed to read (from ROM).")
|
||||||
|
.add("""
|
||||||
|
;;; Main data-driven test. PCL,PCH holds the address of the next
|
||||||
|
;;; data-driven test routine. We expect the various softswitches
|
||||||
|
;;; to be reset each time we loop at .ddloop.
|
||||||
|
.datadriventests
|
||||||
|
lda #<.tests
|
||||||
|
sta PCL
|
||||||
|
lda #>.tests
|
||||||
|
sta PCH
|
||||||
|
;;; Main data-drive-test loop.
|
||||||
|
.ddloop
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
;; Initialize to known state:
|
||||||
|
;; - $11 in $D17B bank 1 (ROM: $53)
|
||||||
|
;; - $22 in $D17B bank 2 (ROM: $53)
|
||||||
|
;; - $33 in $FE1F (ROM: $60)
|
||||||
|
lda $C08B ; Read and write bank 1
|
||||||
|
lda $C08B
|
||||||
|
lda #$11
|
||||||
|
sta $D17B
|
||||||
|
lda #$33
|
||||||
|
sta $FE1F
|
||||||
|
lda $C083 ; Read and write bank 2
|
||||||
|
lda $C083
|
||||||
|
lda #$22
|
||||||
|
sta $D17B
|
||||||
|
lda $C080
|
||||||
|
|
||||||
|
jmp (PCL) ; Jump to test routine
|
||||||
|
|
||||||
|
|
||||||
|
;; Test routine will JSR back to here, so the check data address is on the stack.
|
||||||
|
|
||||||
|
.test ;; ... test the quintiple of test values
|
||||||
|
inc $D17B
|
||||||
|
inc $FE1F
|
||||||
|
|
||||||
|
;; pull address off of stack: it points just below check data for this test.
|
||||||
|
pla
|
||||||
|
sta .checkdata
|
||||||
|
pla
|
||||||
|
sta .checkdata+1
|
||||||
|
|
||||||
|
;; .checkdata now points to d17b-current,fe1f-current,bank1,bank2,fe1f-ram test quintiple
|
||||||
|
|
||||||
|
;; Test current $D17B
|
||||||
|
jsr NEXTCHECK
|
||||||
|
cmp $D17B
|
||||||
|
beq +
|
||||||
|
lda $D17B
|
||||||
|
pha
|
||||||
|
jsr .printseq
|
||||||
|
+print
|
||||||
|
!text "$D17B TO CONTAIN $"
|
||||||
|
+printed
|
||||||
|
jsr CURCHECK
|
||||||
|
jsr PRBYTE
|
||||||
|
+print
|
||||||
|
!text ", GOT $"
|
||||||
|
+printed
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT
|
||||||
|
jmp .datatesturl
|
||||||
|
|
||||||
|
+ ;; Test current $FE1F
|
||||||
|
jsr NEXTCHECK
|
||||||
|
cmp $FE1F
|
||||||
|
beq +
|
||||||
|
lda $FE1F
|
||||||
|
pha
|
||||||
|
jsr .printseq
|
||||||
|
+print
|
||||||
|
!text "$FE1F=$"
|
||||||
|
+printed
|
||||||
|
jsr CURCHECK
|
||||||
|
jsr PRBYTE
|
||||||
|
+print
|
||||||
|
!text ", GOT $"
|
||||||
|
+printed
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT
|
||||||
|
jmp .datatesturl
|
||||||
|
|
||||||
|
+ ;; Test bank 1 $D17B
|
||||||
|
lda $C088
|
||||||
|
jsr NEXTCHECK
|
||||||
|
cmp $D17B
|
||||||
|
beq +
|
||||||
|
lda $D17B
|
||||||
|
pha
|
||||||
|
jsr .printseq
|
||||||
|
+print
|
||||||
|
!text "$D17B IN RAM BANK 1 TO CONTAIN $"
|
||||||
|
+printed
|
||||||
|
jsr CURCHECK
|
||||||
|
jsr PRBYTE
|
||||||
|
+print
|
||||||
|
!text ", GOT $"
|
||||||
|
+printed
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT
|
||||||
|
jmp .datatesturl
|
||||||
|
|
||||||
|
+ ;; Test bank 2 $D17B
|
||||||
|
lda $C080
|
||||||
|
jsr NEXTCHECK
|
||||||
|
cmp $D17B
|
||||||
|
beq +
|
||||||
|
lda $D17B
|
||||||
|
pha
|
||||||
|
jsr .printseq
|
||||||
|
+print
|
||||||
|
!text "$D17B IN RAM BANK 2 TO CONTAIN $"
|
||||||
|
+printed
|
||||||
|
jsr CURCHECK
|
||||||
|
jsr PRBYTE
|
||||||
|
+print
|
||||||
|
!text ", GOT $"
|
||||||
|
+printed
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT
|
||||||
|
jmp .datatesturl
|
||||||
|
|
||||||
|
+ ;; Test RAM $FE1F
|
||||||
|
lda $C080
|
||||||
|
jsr NEXTCHECK
|
||||||
|
cmp $FE1F
|
||||||
|
beq +
|
||||||
|
lda $FE1F
|
||||||
|
pha
|
||||||
|
jsr .printseq
|
||||||
|
+print
|
||||||
|
!text "RAM $FE1F=$"
|
||||||
|
+printed
|
||||||
|
jsr CURCHECK
|
||||||
|
jsr PRBYTE
|
||||||
|
+print
|
||||||
|
!text ", GOT $"
|
||||||
|
+printed
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT
|
||||||
|
jmp .datatesturl
|
||||||
|
|
||||||
|
+ ;; Jump PCL,PCH up to after the test data, and loop.
|
||||||
|
jsr NEXTCHECK
|
||||||
|
bne +
|
||||||
|
+success
|
||||||
|
+ ldx .checkdata
|
||||||
|
ldy .checkdata+1
|
||||||
|
stx PCL
|
||||||
|
sty PCH
|
||||||
|
jmp .ddloop
|
||||||
|
|
||||||
|
.datatesturl
|
||||||
|
""")
|
||||||
|
.throwError("E0007: This is a data-driven test of Language Card operation. We initialize $D17B in RAM bank 1 to $11, $D17B in RAM bank 2 to $22, and $FE1F in RAM to $33. Then, we perform a testdata-driven sequence of LDA and STA to the $C08X range. Finally we (try to) increment $D17B and $FE1F. Then we test (a) the current live value in $D17B, (b) the current live value in $FE1F, (c) the RAM bank 1 value of $D17B, (d) the RAM bank 2 value of $D17B, and (e) the RAM value of $FE1F, to see whether they match expected values. $D17B is usually $53 in ROM, and $FE1F is usally $60. For more information on the operation of the language card soft-switches, see Understanding the Apple IIe, by James Fielding Sather, Pg 5-24.")
|
||||||
|
.add("""
|
||||||
|
rts
|
||||||
|
|
||||||
|
.printseq
|
||||||
|
+print
|
||||||
|
!text "AFTER SEQUENCE OF:",$8D,"- LDA $C080",$8D
|
||||||
|
+printed
|
||||||
|
jsr PRINTTEST
|
||||||
|
+print
|
||||||
|
!text "- INC $D17B",$8D,"- INC $FE1F",$8D,"EXPECTED "
|
||||||
|
+printed
|
||||||
|
rts
|
||||||
|
|
||||||
|
.tests
|
||||||
|
;; Format:
|
||||||
|
;; Sequence of test instructions, finishing with `jsr .test`.
|
||||||
|
;; - quint: expected current $d17b and fe1f, then d17b in bank1, d17b in bank 2, and fe1f
|
||||||
|
;; (All sequences start with lda $C080, just to reset things to a known state.)
|
||||||
|
;; 0-byte to terminate tests.
|
||||||
|
|
||||||
|
lda $C088 ; Read $C088 (RAM read, write protected)
|
||||||
|
jsr .test ;
|
||||||
|
!byte $11, $33, $11, $22, $33 ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $22, $33, $11, $22, $33 ;
|
||||||
|
lda $C081 ; Read $C081 (ROM read, write disabled)
|
||||||
|
jsr .test ;
|
||||||
|
!byte $53, $60, $11, $22, $33
|
||||||
|
lda $C081 ; Read $C081, $C089 (ROM read, bank 1 write)
|
||||||
|
lda $C089 ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $53, $60, $54, $22, $61
|
||||||
|
lda $C081 ; Read $C081, $C081 (read ROM, write RAM bank 2)
|
||||||
|
lda $C081 ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $53, $60, $11, $54, $61
|
||||||
|
lda $C081 ; Read $C081, $C081, write $C081 (read ROM, write RAM bank bank 2)
|
||||||
|
lda $C081 ; See https://github.com/zellyn/a2audit/issues/3
|
||||||
|
sta $C081 ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $53, $60, $11, $54, $61
|
||||||
|
lda $C081 ; Read $C081, $C081; write $C081, $C081
|
||||||
|
lda $C081 ; See https://github.com/zellyn/a2audit/issues/4
|
||||||
|
sta $C081 ;
|
||||||
|
sta $C081 ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $53, $60, $11, $54, $61
|
||||||
|
lda $C08B ; Read $C08B (read RAM bank 1, no write)
|
||||||
|
jsr .test ;
|
||||||
|
!byte $11, $33, $11, $22, $33
|
||||||
|
lda $C083 ; Read $C083 (read RAM bank 2, no write)
|
||||||
|
jsr .test ;
|
||||||
|
!byte $22, $33, $11, $22, $33
|
||||||
|
lda $C08B ; Read $C08B, $C08B (read/write RAM bank 1)
|
||||||
|
lda $C08B ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $12, $34, $12, $22, $34
|
||||||
|
lda $C08F ; Read $C08F, $C087 (read/write RAM bank 2)
|
||||||
|
lda $C087 ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $23, $34, $11, $23, $34
|
||||||
|
lda $C087 ; Read $C087, read $C08D (read ROM, write bank 1)
|
||||||
|
lda $C08D ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $53, $60, $54, $22, $61
|
||||||
|
lda $C08B ; Read $C08B, write $C08B, read $C08B (read RAM bank 1, no write)
|
||||||
|
sta $C08B ; (this one is tricky: reset WRTCOUNT by writing halfway)
|
||||||
|
lda $C08B ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $11, $33, $11, $22, $33
|
||||||
|
sta $C08B ; Write $C08B, write $C08B, read $C08B (read RAM bank 1, no write)
|
||||||
|
sta $C08B ;
|
||||||
|
lda $C08B ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $11, $33, $11, $22, $33
|
||||||
|
clc ; Read $C083, $C083 (read/write RAM bank 2)
|
||||||
|
ldx #0 ; Uses "6502 false read"
|
||||||
|
inc $C083,x ;
|
||||||
|
jsr .test ;
|
||||||
|
!byte $23, $34, $11, $23, $34
|
||||||
|
!byte 0
|
||||||
|
""")
|
||||||
|
.runForTicks(10000000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
396
src/test/resources/jace/machine_identification.asm
Normal file
396
src/test/resources/jace/machine_identification.asm
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
JSR IDENTIFY
|
||||||
|
JMP END_DETECT_PROGRAM
|
||||||
|
;;; From http://www.1000bit.it/support/manuali/apple/technotes/misc/tn.misc.02.html
|
||||||
|
;;; *********************************************
|
||||||
|
;;; * *
|
||||||
|
;;; * Apple II Family Identification Program *
|
||||||
|
;;; * *
|
||||||
|
;;; * Version 2.2 *
|
||||||
|
;;; * *
|
||||||
|
;;; * March, 1990 *
|
||||||
|
;;; * *
|
||||||
|
;;; * Includes support for the Apple IIe Card *
|
||||||
|
;;; * for the Macintosh LC. *
|
||||||
|
;;; * *
|
||||||
|
;;; *********************************************
|
||||||
|
|
||||||
|
; First, some global equates for the routine:
|
||||||
|
IIplain = $01 ;Apple II
|
||||||
|
IIplus = $02 ;Apple II+
|
||||||
|
IIIem = $03 ;Apple /// in emulation mode
|
||||||
|
IIe = $04 ;Apple IIe
|
||||||
|
IIc = $05 ;Apple IIc
|
||||||
|
IIeCard = $06 ;Apple IIe Card for the Macintosh LC
|
||||||
|
|
||||||
|
.safe = $0001 ;start of code relocated to zp
|
||||||
|
.location = $06 ;zero page location to use
|
||||||
|
|
||||||
|
.test1 = $AA ;test byte #1
|
||||||
|
.test2 = $55 ;lsr of test1
|
||||||
|
.test3 = $88 ;test byte #3
|
||||||
|
.test4 = $EE ;test byte #4
|
||||||
|
|
||||||
|
.begpage1 = $400 ;beginning of text page 1
|
||||||
|
.begpage2 = $800 ;beginning of text page 2
|
||||||
|
.begsprse = $C00 ;byte after text page 2
|
||||||
|
|
||||||
|
.clr80col = $C000 ;disable 80-column store
|
||||||
|
.set80col = $C001 ;enable 80-column store
|
||||||
|
.rdmainram = $C002 ;read main ram
|
||||||
|
.rdcardram = $C003 ;read aux ram
|
||||||
|
.wrmainram = $C004 ;write main ram
|
||||||
|
.wrcardram = $C005 ;write aux ram
|
||||||
|
.rdramrd = $C013 ;are we reading aux ram?
|
||||||
|
.rdaltzp = $C016 ;are we reading aux zero page?
|
||||||
|
.rd80col = $C018 ;are we using 80-columns?
|
||||||
|
.rdtext = $C01A ;read if text is displayed
|
||||||
|
.rdpage2 = $C01C ;read if page 2 is displayed
|
||||||
|
.txtclr = $C050 ;switch in graphics
|
||||||
|
.txtset = $C051 ;switch in text
|
||||||
|
.txtpage1 = $C054 ;switch in page 1
|
||||||
|
.txtpage2 = $C055 ;switch in page 2
|
||||||
|
.ramin = $C080 ;read LC bank 2, write protected
|
||||||
|
.romin = $C081 ;read ROM, 2 reads write enable LC
|
||||||
|
.lcbank1 = $C08B ;LC bank 1 enable
|
||||||
|
|
||||||
|
.lc1 = $E000 ;bytes to save for LC
|
||||||
|
.lc2 = $D000 ;save/restore routine
|
||||||
|
.lc3 = $D400
|
||||||
|
.lc4 = $D800
|
||||||
|
|
||||||
|
.idroutine = $FE1F ;IIgs id routine
|
||||||
|
|
||||||
|
; Start by saving the state of the language card banks and
|
||||||
|
; by switching in main ROM.
|
||||||
|
|
||||||
|
IDENTIFY
|
||||||
|
php ;save the processor state
|
||||||
|
sei ;before disabling interrupts
|
||||||
|
lda .lc1 ;save four bytes from
|
||||||
|
sta .save ;ROM/RAM area for later
|
||||||
|
lda .lc2 ;restoring of RAM/ROM
|
||||||
|
sta .save+1 ;to original condition
|
||||||
|
lda .lc3
|
||||||
|
sta .save+2
|
||||||
|
lda .lc4
|
||||||
|
sta .save+3
|
||||||
|
lda $C081 ;read ROM
|
||||||
|
lda $C081
|
||||||
|
lda #0 ;start by assuming unknown machine
|
||||||
|
sta MACHINE
|
||||||
|
sta ROMLEVEL
|
||||||
|
.IdStart
|
||||||
|
lda .location ;save zero page locations
|
||||||
|
sta .save+4 ;for later restoration
|
||||||
|
lda .location+1
|
||||||
|
sta .save+5
|
||||||
|
lda #$FB ;all ID bytes are in page $FB
|
||||||
|
sta .location+1 ;save in zero page as high byte
|
||||||
|
ldx #0 ;init pointer to start of ID table
|
||||||
|
.loop lda .IDTable,x ;get the machine we are testing for
|
||||||
|
sta MACHINE ;and save it
|
||||||
|
lda .IDTable+1,x ;get the ROM level we are testing for
|
||||||
|
sta ROMLEVEL ;and save it
|
||||||
|
ora MACHINE ;are both zero?
|
||||||
|
beq .matched ;yes - at end of list - leave
|
||||||
|
|
||||||
|
.loop2 inx ;bump index to loc/byte pair to test
|
||||||
|
inx
|
||||||
|
lda .IDTable,x ;get the byte that should be in ROM
|
||||||
|
beq .matched ;if zero, we're at end of list
|
||||||
|
sta .location ;save in zero page
|
||||||
|
|
||||||
|
ldy #0 ;init index for indirect addressing
|
||||||
|
lda .IDTable+1,x ;get the byte that should be in ROM
|
||||||
|
cmp (.location),y ;is it there?
|
||||||
|
beq .loop2 ;yes, so keep on looping
|
||||||
|
|
||||||
|
.loop3 inx ;we didn't match. Scoot to the end of the
|
||||||
|
inx ;line in the ID table so we can start
|
||||||
|
lda .IDTable,x ;checking for another machine
|
||||||
|
bne .loop3
|
||||||
|
inx ;point to start of next line
|
||||||
|
bne .loop ;should always be taken
|
||||||
|
|
||||||
|
.matched ; anop
|
||||||
|
|
||||||
|
; Here we check the 16-bit ID routine at idroutine ($FE1F). If it
|
||||||
|
; returns with carry clear, we call it again in 16-bit
|
||||||
|
; mode to provide more information on the machine.
|
||||||
|
|
||||||
|
!cpu 65816 {
|
||||||
|
.idIIgs
|
||||||
|
sec ;set the carry bit
|
||||||
|
jsr .idroutine ;Apple IIgs ID Routine
|
||||||
|
bcc .idIIgs2 ;it's a IIgs or equivalent
|
||||||
|
jmp .IIgsOut ;nope, go check memory
|
||||||
|
.idIIgs2
|
||||||
|
lda MACHINE ;get the value for machine
|
||||||
|
ora #$80 ;and set the high bit
|
||||||
|
sta MACHINE ;put it back
|
||||||
|
clc ;get ready to switch into native mode
|
||||||
|
xce
|
||||||
|
php ;save the processor status
|
||||||
|
rep #$30 ;sets 16-bit registers
|
||||||
|
!al { ;longa on
|
||||||
|
!rl { ;longi on
|
||||||
|
jsr .idroutine ;call the ID routine again
|
||||||
|
sta .IIgsA ;16-bit store!
|
||||||
|
stx .IIgsX ;16-bit store!
|
||||||
|
sty .IIgsY ;16-bit store!
|
||||||
|
plp ;restores 8-bit registers
|
||||||
|
xce ;switches back to whatever it was before
|
||||||
|
} ;longi off
|
||||||
|
} ;longa off
|
||||||
|
|
||||||
|
ldy .IIgsY ;get the ROM vers number (starts at 0)
|
||||||
|
cpy #$02 ;is it ROM 01 or 00?
|
||||||
|
bcs .idIIgs3 ;if not, don't increment
|
||||||
|
iny ;bump it up for romlevel
|
||||||
|
.idIIgs3
|
||||||
|
sty ROMLEVEL ;and put it there
|
||||||
|
cpy #$01 ;is it the first ROM?
|
||||||
|
bne .IIgsOut ;no, go on with things
|
||||||
|
lda .IIgsY+1 ;check the other byte too
|
||||||
|
bne .IIgsOut ;nope, it's a IIgs successor
|
||||||
|
lda #$7F ;fix faulty ROM 00 on the IIgs
|
||||||
|
sta .IIgsA
|
||||||
|
.IIgsOut ; anop
|
||||||
|
}
|
||||||
|
|
||||||
|
;;; ******************************************
|
||||||
|
;;; * This part of the code checks for the *
|
||||||
|
;;; * memory configuration of the machine. *
|
||||||
|
;;; * If it's a IIgs, we've already stored *
|
||||||
|
;;; * the total memory from above. If it's *
|
||||||
|
;;; * a IIc or a IIe Card, we know it's *
|
||||||
|
;;; * 128K; if it's a ][+, we know it's at *
|
||||||
|
;;; * least 48K and maybe 64K. We won't *
|
||||||
|
;;; * check for less than 48K, since that's *
|
||||||
|
;;; * a really rare circumstance. *
|
||||||
|
;;; ******************************************
|
||||||
|
|
||||||
|
.exit lda MACHINE ;get the machine kind
|
||||||
|
bmi .exit128 ;it's a 16-bit machine (has 128K)
|
||||||
|
cmp #IIc ;is it a IIc?
|
||||||
|
beq .exit128 ;yup, it's got 128K
|
||||||
|
cmp #IIeCard ;is it a IIe Card?
|
||||||
|
beq .exit128 ;yes, it's got 128K
|
||||||
|
cmp #IIe ;is it a IIe?
|
||||||
|
bne .contexit ;yes, go muck with aux memory
|
||||||
|
jmp .muckaux
|
||||||
|
.contexit
|
||||||
|
cmp #IIIem ;is it a /// in emulation?
|
||||||
|
bne .exitII ;nope, it's a ][ or ][+
|
||||||
|
lda #48 ;/// emulation has 48K
|
||||||
|
jmp .exita
|
||||||
|
.exit128
|
||||||
|
lda #128 ;128K
|
||||||
|
.exita sta MEMORY
|
||||||
|
.exit1 lda .lc1 ;time to restore the LC
|
||||||
|
cmp .save ;if all 4 bytes are the same
|
||||||
|
bne .exit2 ;then LC was never on so
|
||||||
|
lda .lc2 ;do nothing
|
||||||
|
cmp .save+1
|
||||||
|
bne .exit2
|
||||||
|
lda .lc3
|
||||||
|
cmp .save+2
|
||||||
|
bne .exit2
|
||||||
|
lda .lc4
|
||||||
|
cmp .save+3
|
||||||
|
beq .exit6
|
||||||
|
.exit2 lda $C088 ;no match! so turn first LC
|
||||||
|
lda .lc1 ;bank on and check
|
||||||
|
cmp .save
|
||||||
|
beq .exit3
|
||||||
|
lda $C080
|
||||||
|
jmp .exit6
|
||||||
|
.exit3 lda .lc2
|
||||||
|
cmp .save+1 ;if all locations check
|
||||||
|
beq .exit4 ;then do more more else
|
||||||
|
lda $C080 ;turn on bank 2
|
||||||
|
jmp .exit6
|
||||||
|
.exit4 lda .lc3 ;check second byte in bank 1
|
||||||
|
cmp .save+2
|
||||||
|
beq .exit5
|
||||||
|
lda $C080 ;select bank 2
|
||||||
|
jmp .exit6
|
||||||
|
.exit5 lda .lc4 ;check third byte in bank 1
|
||||||
|
cmp .save+3
|
||||||
|
beq .exit6
|
||||||
|
lda $C080 ;select bank 2
|
||||||
|
.exit6 plp ;restore interrupt status
|
||||||
|
lda .save+4 ;put zero page back
|
||||||
|
sta .location
|
||||||
|
lda .save+5 ;like we found it
|
||||||
|
sta .location+1
|
||||||
|
rts ;and go home.
|
||||||
|
|
||||||
|
.exitII
|
||||||
|
lda .lcbank1 ;force in language card
|
||||||
|
lda .lcbank1 ;bank 1
|
||||||
|
ldx .lc2 ;save the byte there
|
||||||
|
lda #.test1 ;use this as a test byte
|
||||||
|
sta .lc2
|
||||||
|
eor .lc2 ;if the same, should return zero
|
||||||
|
bne .noLC
|
||||||
|
lsr .lc2 ;check twice just to be sure
|
||||||
|
lda #.test2 ;this is the shifted value
|
||||||
|
eor .lc2 ;here's the second check
|
||||||
|
bne .noLC
|
||||||
|
stx .lc2 ;put it back!
|
||||||
|
lda #64 ;there's 64K here
|
||||||
|
jmp .exita
|
||||||
|
.noLC lda #48 ;no restore - no LC!
|
||||||
|
jmp .exita ;and get out of here
|
||||||
|
|
||||||
|
.muckaux
|
||||||
|
ldx .rdtext ;remember graphics in X
|
||||||
|
lda .rdpage2 ;remember current video display
|
||||||
|
asl ;in the carry bit
|
||||||
|
lda #.test3 ;another test character
|
||||||
|
bit .rd80col ;remember video mode in N
|
||||||
|
sta .set80col ;enable 80-column store
|
||||||
|
php ;save N and C flags
|
||||||
|
sta .txtpage2 ;set page two
|
||||||
|
sta .txtset ;set text
|
||||||
|
ldy .begpage1 ;save first character
|
||||||
|
sta .begpage1 ;and replace it with test character
|
||||||
|
lda .begpage1 ;get it back
|
||||||
|
sty .begpage1 ;and put back what was there
|
||||||
|
plp
|
||||||
|
bcs .muck2 ;stay in page 2
|
||||||
|
sta .txtpage1 ;restore page 1
|
||||||
|
.muck1 bmi .muck2 ;stay in 80-columns
|
||||||
|
sta $c000 ;turn off 80-columns
|
||||||
|
.muck2 tay ;save returned character
|
||||||
|
txa ;get graphics/text setting
|
||||||
|
bmi .muck3
|
||||||
|
sta .txtclr ;turn graphics back on
|
||||||
|
.muck3 cpy #.test3 ;finally compare it
|
||||||
|
bne .nocard ;no 80-column card!
|
||||||
|
lda .rdramrd ;is aux memory being read?
|
||||||
|
bmi .muck128 ;yup, there's 128K!
|
||||||
|
lda .rdaltzp ;is aux zero page used?
|
||||||
|
bmi .muck128 ;yup!
|
||||||
|
ldy #.done-.start
|
||||||
|
.move ldx .start-1,y ;swap section of zero page
|
||||||
|
lda <.safe-1,y ;code needing safe location during
|
||||||
|
stx <.safe-1,y ;reading of aux mem
|
||||||
|
sta .start-1,Y
|
||||||
|
dey
|
||||||
|
bne .move
|
||||||
|
jmp .safe ;jump to safe ground
|
||||||
|
.back php ;save status
|
||||||
|
ldy #.done-.start ;move zero page back
|
||||||
|
.move2 lda .start-1,y
|
||||||
|
sta .safe-1,y
|
||||||
|
dey
|
||||||
|
bne .move2
|
||||||
|
pla
|
||||||
|
bcs .noaux
|
||||||
|
.isaux jmp .muck128 ;there is 128K
|
||||||
|
|
||||||
|
;;; * You can put your own routine at "noaux" if you wish to
|
||||||
|
;;; * distinguish between 64K without an 80-column card and
|
||||||
|
;;; * 64K with an 80-column card.
|
||||||
|
|
||||||
|
.noaux ; anop
|
||||||
|
.nocard lda #64 ;only 64K
|
||||||
|
jmp .exita
|
||||||
|
.muck128
|
||||||
|
jmp .exit128 ;there's 128K
|
||||||
|
|
||||||
|
;;; * This is the routine run in the safe area not affected
|
||||||
|
;;; * by bank-switching the main and aux RAM.
|
||||||
|
|
||||||
|
.start lda #.test4 ;yet another test byte
|
||||||
|
sta .wrcardram ;write to aux while on main zero page
|
||||||
|
sta .rdcardram ;read aux ram as well
|
||||||
|
sta .begpage2 ;check for sparse memory mapping
|
||||||
|
lda .begsprse ;if sparse, these will be the same
|
||||||
|
cmp #.test4 ;value since they're 1K apart
|
||||||
|
bne .auxmem ;yup, there's 128K!
|
||||||
|
asl .begsprse ;may have been lucky so we'll
|
||||||
|
lda .begpage2 ;change the value and see what happens
|
||||||
|
cmp .begsprse
|
||||||
|
bne .auxmem
|
||||||
|
sec ;oops, no auxiliary memory
|
||||||
|
bcs .goback
|
||||||
|
.auxmem clc
|
||||||
|
.goback sta .wrmainram ;write main RAM
|
||||||
|
sta .rdmainram ;read main RAM
|
||||||
|
jmp .back ;continue with program in main mem
|
||||||
|
.done nop ;end of relocated program marker
|
||||||
|
|
||||||
|
|
||||||
|
;;; * The storage locations for the returned machine ID:
|
||||||
|
|
||||||
|
.IIgsA !word 0 ;16-bit field
|
||||||
|
.IIgsX !word 0 ;16-bit field
|
||||||
|
.IIgsY !word 0 ;16-bit field
|
||||||
|
.save !fill 6,0 ;six bytes for saved data
|
||||||
|
|
||||||
|
.IDTable
|
||||||
|
;dc I1'1,1' ;Apple ][
|
||||||
|
;dc H'B3 38 00'
|
||||||
|
!byte 1,1
|
||||||
|
!byte $B3,$38,0
|
||||||
|
|
||||||
|
;dc I1'2,1' ;Apple ][+
|
||||||
|
;dc H'B3 EA 1E AD 00'
|
||||||
|
!byte 2,1
|
||||||
|
!byte $B3,$EA,$1E,$AD,0
|
||||||
|
|
||||||
|
;dc I1'3,1' ;Apple /// (emulation)
|
||||||
|
;dc H'B3 EA 1E 8A 00'
|
||||||
|
!byte 3,1
|
||||||
|
!byte $B3,$EA,$1E,$8A,0
|
||||||
|
|
||||||
|
;dc I1'4,1' ;Apple IIe (original)
|
||||||
|
;dc H'B3 06 C0 EA 00'
|
||||||
|
!byte 4,1
|
||||||
|
!byte $B3,$06,$C0,$EA,0
|
||||||
|
|
||||||
|
; Note: You must check for the Apple IIe Card BEFORE you
|
||||||
|
; check for the enhanced Apple IIe since the first
|
||||||
|
; two identification bytes are the same.
|
||||||
|
|
||||||
|
;dc I1'6,1' ;Apple IIe Card for the Macintosh LC (1st release)
|
||||||
|
;dc H'B3 06 C0 E0 DD 02 BE 00 00'
|
||||||
|
!byte 6,1
|
||||||
|
!byte $B3,$06,$C0,$E0,$DD,$02,$BE,$00,0
|
||||||
|
|
||||||
|
;dc I1'4,2' ;Apple IIe (enhanced)
|
||||||
|
;dc H'B3 06 C0 E0 00'
|
||||||
|
!byte 4,2
|
||||||
|
!byte $B3,$06,$C0,$E0,0
|
||||||
|
|
||||||
|
;dc I1'5,1' ;Apple IIc (original)
|
||||||
|
;dc H'B3 06 C0 00 BF FF 00'
|
||||||
|
!byte 5,1
|
||||||
|
!byte $B3,$06,$C0,$00,$BF,$FF,0
|
||||||
|
|
||||||
|
;dc I1'5,2' ;Apple IIc (3.5 ROM)
|
||||||
|
;dc H'B3 06 C0 00 BF 00 00'
|
||||||
|
!byte 5,2
|
||||||
|
!byte $B3,$06,$C0,$00,$BF,$00,0
|
||||||
|
|
||||||
|
;dc I1'5,3' ;Apple IIc (Mem. Exp)
|
||||||
|
;dc H'B3 06 C0 00 BF 03 00'
|
||||||
|
!byte 5,3
|
||||||
|
!byte $B3,$06,$C0,$00,$BF,$03,0
|
||||||
|
|
||||||
|
;dc I1'5,4' ;Apple IIc (Rev. Mem. Exp.)
|
||||||
|
;dc H'B3 06 C0 00 BF 04 00'
|
||||||
|
!byte 5,4
|
||||||
|
!byte $B3,$06,$C0,$00,$BF,$04,0
|
||||||
|
|
||||||
|
;dc I1'5,5' ;Apple IIc Plus
|
||||||
|
;dc H'B3 06 C0 00 BF 05 00'
|
||||||
|
!byte 5,5
|
||||||
|
!byte $B3,$06,$C0,$00,$BF,$05,0
|
||||||
|
|
||||||
|
;dc I1'0,0' ;end of table
|
||||||
|
!byte 0,0
|
||||||
|
END_DETECT_PROGRAM
|
204
src/test/resources/jace/memory_test_commons.asm
Normal file
204
src/test/resources/jace/memory_test_commons.asm
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
jmp START
|
||||||
|
MACHINE = $800 ;the type of Apple II
|
||||||
|
ROMLEVEL = $801 ;which revision of the machine
|
||||||
|
MEMORY = $802 ;how much memory (up to 128K)
|
||||||
|
|
||||||
|
LCRESULT = $10
|
||||||
|
LCRESULT1 = $11
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta LCRESULT
|
||||||
|
|
||||||
|
;; Zero-page locations.
|
||||||
|
SCRATCH = $1
|
||||||
|
SCRATCH2 = $2
|
||||||
|
SCRATCH3 = $3
|
||||||
|
LCRESULT = $10
|
||||||
|
LCRESULT1 = $11
|
||||||
|
AUXRESULT = $12
|
||||||
|
SOFTSWITCHRESULT = $13
|
||||||
|
|
||||||
|
CSW = $36
|
||||||
|
KSW = $38
|
||||||
|
|
||||||
|
PCL=$3A
|
||||||
|
PCH=$3B
|
||||||
|
A1L=$3C
|
||||||
|
A1H=$3D
|
||||||
|
A2L=$3E
|
||||||
|
A2H=$3F
|
||||||
|
A3L=$40
|
||||||
|
A3H=$41
|
||||||
|
A4L=$42
|
||||||
|
A4H=$43
|
||||||
|
|
||||||
|
!addr tmp0 = $f9
|
||||||
|
!addr tmp1 = $fa
|
||||||
|
!addr tmp2 = $fb
|
||||||
|
!addr tmp3 = $fc
|
||||||
|
!addr tmp4 = $fd
|
||||||
|
!addr tmp5 = $fe
|
||||||
|
!addr tmp6 = $ff
|
||||||
|
.checkdata = tmp1
|
||||||
|
|
||||||
|
STRINGS = $8000
|
||||||
|
!set LASTSTRING = STRINGS
|
||||||
|
|
||||||
|
KBD = $C000
|
||||||
|
KBDSTRB = $C010
|
||||||
|
|
||||||
|
;; Monitor locations.
|
||||||
|
;HOME = $FC58
|
||||||
|
COUT = $FDED
|
||||||
|
COUT1 = $FDF0
|
||||||
|
KEYIN = $FD1B
|
||||||
|
CROUT = $FD8E
|
||||||
|
PRBYTE = $FDDA
|
||||||
|
PRNTYX = $F940
|
||||||
|
|
||||||
|
;; Softswitch locations.
|
||||||
|
RESET_80STORE = $C000
|
||||||
|
SET_80STORE = $C001
|
||||||
|
READ_80STORE = $C018
|
||||||
|
|
||||||
|
RESET_RAMRD = $C002
|
||||||
|
SET_RAMRD = $C003
|
||||||
|
READ_RAMRD = $C013
|
||||||
|
|
||||||
|
RESET_RAMWRT = $C004
|
||||||
|
SET_RAMWRT = $C005
|
||||||
|
READ_RAMWRT = $C014
|
||||||
|
|
||||||
|
RESET_INTCXROM = $C006
|
||||||
|
SET_INTCXROM = $C007
|
||||||
|
READ_INTCXROM = $C015
|
||||||
|
|
||||||
|
RESET_ALTZP = $C008
|
||||||
|
SET_ALTZP = $C009
|
||||||
|
READ_ALTZP = $C016
|
||||||
|
|
||||||
|
RESET_SLOTC3ROM = $C00A
|
||||||
|
SET_SLOTC3ROM = $C00B
|
||||||
|
READ_SLOTC3ROM = $C017
|
||||||
|
|
||||||
|
RESET_80COL = $C00C
|
||||||
|
SET_80COL = $C00D
|
||||||
|
READ_80COL = $C01F
|
||||||
|
|
||||||
|
RESET_ALTCHRSET = $C00E
|
||||||
|
SET_ALTCHRSET = $C00F
|
||||||
|
READ_ALTCHRSET = $C01E
|
||||||
|
|
||||||
|
RESET_TEXT = $C050
|
||||||
|
SET_TEXT = $C051
|
||||||
|
READ_TEXT = $C01A
|
||||||
|
|
||||||
|
RESET_MIXED = $C052
|
||||||
|
SET_MIXED = $C053
|
||||||
|
READ_MIXED = $C01B
|
||||||
|
|
||||||
|
RESET_PAGE2 = $C054
|
||||||
|
SET_PAGE2 = $C055
|
||||||
|
READ_PAGE2 = $C01C
|
||||||
|
|
||||||
|
RESET_HIRES = $C056
|
||||||
|
SET_HIRES = $C057
|
||||||
|
READ_HIRES = $C01D
|
||||||
|
|
||||||
|
RESET_AN3 = $C05E
|
||||||
|
SET_AN3 = $C05F
|
||||||
|
|
||||||
|
RESET_INTC8ROM = $CFFF
|
||||||
|
|
||||||
|
;; Readable things without corresponding set/reset pairs.
|
||||||
|
READ_HRAM_BANK2 = $C011
|
||||||
|
READ_HRAMRD = $C012
|
||||||
|
READ_VBL = $C019
|
||||||
|
|
||||||
|
print
|
||||||
|
lda $C081
|
||||||
|
lda $C081
|
||||||
|
pla
|
||||||
|
sta getch+1
|
||||||
|
pla
|
||||||
|
sta getch+2
|
||||||
|
- inc getch+1
|
||||||
|
bne getch
|
||||||
|
inc getch+2
|
||||||
|
getch lda $FEED ; FEED gets modified
|
||||||
|
beq +
|
||||||
|
jsr COUT
|
||||||
|
jmp -
|
||||||
|
+ rts
|
||||||
|
|
||||||
|
PRINTTEST
|
||||||
|
-
|
||||||
|
ldy #0
|
||||||
|
lda (PCL),y
|
||||||
|
cmp #$20
|
||||||
|
beq +++
|
||||||
|
lda #'-'
|
||||||
|
jsr COUT
|
||||||
|
lda #' '
|
||||||
|
jsr COUT
|
||||||
|
ldx #0
|
||||||
|
lda (PCL,x)
|
||||||
|
jsr $f88e
|
||||||
|
ldx #3
|
||||||
|
jsr $f8ea
|
||||||
|
jsr $f953
|
||||||
|
sta PCL
|
||||||
|
sty PCH
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT
|
||||||
|
jmp -
|
||||||
|
+++ rts
|
||||||
|
|
||||||
|
;;; Increment .checkdata pointer to the next memory location, and load
|
||||||
|
;;; it into the accumulator. X and Y are preserved.
|
||||||
|
NEXTCHECK
|
||||||
|
inc .checkdata
|
||||||
|
bne CURCHECK
|
||||||
|
inc .checkdata+1
|
||||||
|
CURCHECK
|
||||||
|
sty SCRATCH
|
||||||
|
ldy #0
|
||||||
|
lda (.checkdata),y
|
||||||
|
ldy SCRATCH
|
||||||
|
ora #0
|
||||||
|
rts
|
||||||
|
|
||||||
|
!macro print {
|
||||||
|
jsr LASTSTRING
|
||||||
|
!set TEMP = *
|
||||||
|
* = LASTSTRING
|
||||||
|
jsr print
|
||||||
|
}
|
||||||
|
!macro printed {
|
||||||
|
!byte 0
|
||||||
|
!set LASTSTRING=*
|
||||||
|
* = TEMP
|
||||||
|
}
|
||||||
|
|
||||||
|
START
|
||||||
|
;;; Reset all soft-switches to known-good state. Burns $300 and $301 in main mem.
|
||||||
|
RESETALL
|
||||||
|
; The COUT hook isn't set up yet, so the monitor routine will crash unless we set it up
|
||||||
|
lda #<COUT1
|
||||||
|
sta CSW
|
||||||
|
lda #>COUT1
|
||||||
|
sta CSW+1
|
||||||
|
sta RESET_RAMRD
|
||||||
|
sta RESET_RAMWRT
|
||||||
|
;; Save return address in X and A, in case we switch zero-page memory.
|
||||||
|
sta RESET_80STORE
|
||||||
|
sta RESET_INTCXROM
|
||||||
|
sta RESET_ALTZP
|
||||||
|
sta RESET_SLOTC3ROM
|
||||||
|
sta RESET_INTC8ROM
|
||||||
|
sta RESET_80COL
|
||||||
|
sta RESET_ALTCHRSET
|
||||||
|
sta SET_TEXT
|
||||||
|
sta RESET_MIXED
|
||||||
|
sta RESET_PAGE2
|
||||||
|
sta RESET_HIRES
|
Loading…
x
Reference in New Issue
Block a user