From 5970ae5bcc31737498afed872bbaca6b61ab35f4 Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Thu, 27 Jan 2022 00:22:59 -0800 Subject: [PATCH 1/6] apple2: implement loadBIOS / apple2.rom --- src/machine/apple2.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index 4ad7845e..005039d8 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -1,6 +1,6 @@ import { MOS6502, MOS6502State } from "../common/cpu/MOS6502"; -import { Bus, BasicScanlineMachine, SavesState } from "../common/devices"; +import { Bus, BasicScanlineMachine, SavesState, AcceptsBIOS } from "../common/devices"; import { KeyFlags } from "../common/emu"; // TODO import { hex, lzgmini, stringToByteArray, RGBA, printFlags } from "../common/util"; @@ -33,7 +33,7 @@ interface SlotDevice extends Bus { readConst(address: number) : number; } -export class AppleII extends BasicScanlineMachine { +export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { // approx: http://www.cs.columbia.edu/~sedwards/apple2fpga/ cpuFrequency = 1022727; @@ -88,9 +88,7 @@ export class AppleII extends BasicScanlineMachine { constructor() { super(); - this.bios = new lzgmini().decode(stringToByteArray(atob(APPLEIIGO_LZG))); - this.bios[0x39a] = 0x60; // $d39a = RTS - this.ram.set(this.bios, 0xd000); + this.loadBIOS(new lzgmini().decode(stringToByteArray(atob(APPLEIIGO_LZG)))); this.ram[0xbf00] = 0x4c; // fake DOS detect for C this.ram[0xbf6f] = 0x01; // fake DOS detect for C this.connectCPUMemoryBus(this); @@ -131,6 +129,11 @@ export class AppleII extends BasicScanlineMachine { loadControlsState(s:AppleIIControlsState) { this.kbdlatch = s.kbdlatch; } + loadBIOS(data, title?) { + this.bios = Uint8Array.from(data); + this.bios[0x39a] = 0x60; // $d39a = RTS + this.ram.set(this.bios, 0xd000); + } loadROM(data) { if (data.length == 35*16*256) { // is it a disk image? var diskii = new DiskII(this, data); From 8e3f92909866d8fcaf5f4bec21c5e0515007cde6 Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Thu, 27 Jan 2022 01:54:57 -0800 Subject: [PATCH 2/6] apple2: allow mis-sized BIOS files --- src/machine/apple2.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index 005039d8..a42393b3 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -130,9 +130,13 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { this.kbdlatch = s.kbdlatch; } loadBIOS(data, title?) { + if (data.length != 0x3000) { + console.log(`apple2 loadBIOS !!!WARNING!!!: BIOS wants length 0x3000, but BIOS '${title}' has length 0x${data.length.toString(16)}`); + console.log("will load BIOS to end of memory anyway..."); + } this.bios = Uint8Array.from(data); - this.bios[0x39a] = 0x60; // $d39a = RTS - this.ram.set(this.bios, 0xd000); + this.bios[0xD39A - (0x10000 - this.bios.length)] = 0x60; // $d39a = RTS + this.ram.set(this.bios, 0x10000 - this.bios.length); } loadROM(data) { if (data.length == 35*16*256) { // is it a disk image? @@ -167,7 +171,7 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { return this.ram[address]; } else if (address >= 0xd000) { if (!this.auxRAMselected) - return this.bios[address - 0xd000]; + return this.bios[address - (0x10000 - this.bios.length)]; else if (address >= 0xe000) return this.ram[address]; else From c58d999ee496c3ed9f0878d5c7473df295cd9c98 Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Thu, 27 Jan 2022 19:42:32 -0800 Subject: [PATCH 3/6] apple2 fakeDrive: PROM bytes on read, JMP on exec --- src/machine/apple2.ts | 52 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index a42393b3..21581da4 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -66,17 +66,47 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { // fake disk drive that loads program into RAM fakeDrive : SlotDevice = { readROM: (a) => { - switch (a) { - // JMP VM_BASE - case 0: { - // load program into RAM - if (this.rom) - this.ram.set(this.rom.slice(HDR_SIZE), PGM_BASE); - return 0x4c; - } - case 1: return VM_BASE&0xff; - case 2: return (VM_BASE>>8)&0xff; - default: return 0; + var pc = this.cpu.getPC(); + if (pc >= 0xC600 && pc < 0xC700) { + // We're reading code to EXECUTE. + // Load the built program directly into memory, and "read" + // a JMP directly to it. + //console.log(`fakeDrive (EXEC): ${a.toString(16)}`); + switch (a) { + // JMP VM_BASE + case 0: + // SHOULD load program into RAM here, but have to do it + // below instead. + return 0; + case 1: return VM_BASE&0xff; + case 2: return (VM_BASE>>8)&0xff; + default: return 0; + } + } + else { + // We're reading code, but not executing it. + // This is probably the Monitor routine to identify whether + // this slot is a Disk ][ drive, so... give it what it wants. + //console.log(`fakeDrive (NOEX): ${a.toString(16)}`); + switch (a) { + case 0: + // Actually, if we get here, we probably ARE being + // executed. For some reason, the instruction at $C600 + // gets read for execution, BEFORE the PC gets set to + // the correct location. So we handle loading the program + // into RAM and returning the JMP here, instead of above + // where it would otherwise belong. + if (this.rom) { + console.log(`Loading program into Apple ][ RAM at \$${PGM_BASE.toString(16)}`); + this.ram.set(this.rom.slice(HDR_SIZE), PGM_BASE); + } + return 0x4c; // JMP + case 1: return 0x20; + case 3: return 0x00; + case 5: return 0x03; + case 7: return 0x3c; + default: return 0; + } } }, readConst: (a) => { From 7071f70bb21bf9f0509899a0b38347aa4618f675 Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Thu, 27 Jan 2022 19:43:52 -0800 Subject: [PATCH 4/6] apple2: force hard resets, fixing loadROM --- src/machine/apple2.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index 21581da4..ba2b2912 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -182,6 +182,8 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { this.auxRAMselected = false; this.auxRAMbank = 1; this.writeinhibit = true; + this.ram.fill(0, 0x300, 0x400); // Clear soft-reset vector + // (force hard reset) this.skipboot(); } skipboot() { From fc59dd30c303bb1718236635cf12ed00b8a662df Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Thu, 27 Jan 2022 22:53:57 -0800 Subject: [PATCH 5/6] apple2: repair "DOS fake" bytes after loadROM --- src/machine/apple2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index ba2b2912..d6a9acd9 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -119,8 +119,6 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { constructor() { super(); this.loadBIOS(new lzgmini().decode(stringToByteArray(atob(APPLEIIGO_LZG)))); - this.ram[0xbf00] = 0x4c; // fake DOS detect for C - this.ram[0xbf6f] = 0x01; // fake DOS detect for C this.connectCPUMemoryBus(this); } saveState() : AppleIIState { @@ -167,6 +165,8 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { this.bios = Uint8Array.from(data); this.bios[0xD39A - (0x10000 - this.bios.length)] = 0x60; // $d39a = RTS this.ram.set(this.bios, 0x10000 - this.bios.length); + this.ram[0xbf00] = 0x4c; // fake DOS detect for C + this.ram[0xbf6f] = 0x01; // fake DOS detect for C } loadROM(data) { if (data.length == 35*16*256) { // is it a disk image? From 3681bc65e8d9a1c7882a3c17f749d6455d6a863f Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Fri, 28 Jan 2022 23:32:10 -0800 Subject: [PATCH 6/6] apple2: don't modify uploaded ROMs with RTS byte --- src/machine/apple2.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/machine/apple2.ts b/src/machine/apple2.ts index d6a9acd9..37a635c6 100644 --- a/src/machine/apple2.ts +++ b/src/machine/apple2.ts @@ -120,6 +120,11 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { super(); this.loadBIOS(new lzgmini().decode(stringToByteArray(atob(APPLEIIGO_LZG)))); this.connectCPUMemoryBus(this); + // This line is inappropriate for real ROMs, but was there for + // the APPLE][GO ROM, so keeping it only in the constructor, for + // that special case (in case it really is important for this + // address to be an RTS). + this.bios[0xD39A - (0x10000 - this.bios.length)] = 0x60; // $d39a = RTS } saveState() : AppleIIState { // TODO: automagic @@ -163,7 +168,6 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS { console.log("will load BIOS to end of memory anyway..."); } this.bios = Uint8Array.from(data); - this.bios[0xD39A - (0x10000 - this.bios.length)] = 0x60; // $d39a = RTS this.ram.set(this.bios, 0x10000 - this.bios.length); this.ram[0xbf00] = 0x4c; // fake DOS detect for C this.ram[0xbf6f] = 0x01; // fake DOS detect for C