"sourcesContent": ["\nimport { MOS6502, MOS6502State } from \"../common/cpu/MOS6502\";\nimport { Bus, BasicScanlineMachine, SavesState, AcceptsBIOS } from \"../common/devices\";\nimport { KeyFlags } from \"../common/emu\"; // TODO\nimport { hex, lzgmini, stringToByteArray, RGBA, printFlags } from \"../common/util\";\n\n// TODO: read prodos/ca65 header?\nconst VM_BASE = 0x803; // where to JMP after pr#6\nconst LOAD_BASE = VM_BASE;\nconst PGM_BASE = VM_BASE;\nconst HDR_SIZE = PGM_BASE - LOAD_BASE;\n\ninterface AppleIIStateBase {\n ram : Uint8Array;\n soundstate : number;\n auxRAMselected,writeinhibit : boolean;\n auxRAMbank : number;\n}\n\ninterface AppleIIControlsState {\n inputs : Uint8Array; // unused?\n kbdlatch : number;\n}\n\ninterface AppleIIState extends AppleIIStateBase, AppleIIControlsState {\n c : MOS6502State;\n grswitch : number;\n slots: SlotDevice[];\n}\n\ninterface SlotDevice extends Bus {\n readROM(address: number) : number;\n readConst(address: number) : number;\n}\n\nexport class AppleII extends BasicScanlineMachine implements AcceptsBIOS {\n\n // approx: http://www.cs.columbia.edu/~sedwards/apple2fpga/\n cpuFrequency = 1022727;\n sampleRate = this.cpuFrequency;\n cpuCyclesPerLine = 65;\n cpuCyclesPerFrame = this.cpuCyclesPerLine * 262;\n canvasWidth = 280;\n numVisibleScanlines = 192;\n numTotalScanlines = 262;\n defaultROMSize = 0xbf00-0x803; // TODO\n\n ram = new Uint8Array(0x13000); // 64K + 16K LC RAM - 4K hardware + 12K ROM\n bios : Uint8Array;\n cpu = new MOS6502();\n grdirty = new Array(0xc000 >> 7);\n grparams = {dirty:this.grdirty, grswitch:GR_TXMODE, mem:this.ram};\n ap2disp;\n kbdlatch = 0;\n soundstate = 0;\n // language card switches\n auxRAMselected = false;\n auxRAMbank = 1;\n writeinhibit = true;\n // value to add when reading & writing each of these banks\n // bank 1 is E000-FFFF, bank 2 is D000-DFFF\n bank2rdoffset=0;\n bank2wroffset=0;\n // disk II\n slots : SlotDevice[] = new Array(8);\n // fake disk drive that loads program into RAM\n fakeDrive : SlotDevice = {\n readROM: (a) => {\n var pc = this.cpu.getPC();\n if (pc >= 0xC600 && pc < 0xC700) {\n // We're reading code to EXECUTE.\n // Load the built program directly into memory, and \"read\"\n // a JMP directly to it.\n //console.log(`fakeDrive (EXEC): ${a.toString(16)}`);\n switch (a) {\n // JMP VM_BASE\n case 0:\n // SHOULD load program into RAM here, but have to do it\n // below instead.\n return 0;\n case 1: return VM_BASE&0xff;\n case 2: return (VM_BASE>>8)&0xff;\n default: return 0;\n }\n }\n else {\n // We're reading code, but not executing it.\n // This is probably the Monitor routine to identify whether\n // this slot is a Disk ][ drive, so... give it what it wants.\n //console.log(`fakeDrive (NOEX): ${a.toString(16)}`);\n switch (a) {\n case 0:\n // Actually, if we get here, we probably ARE being\n // executed. For some reason, the instruction at $C600\n // gets read for execution, BEFORE the PC gets set to\n // the correct location. So we handle loading the program\n // into RAM and returning the JMP here, instead of above\n // where it would otherwise belong.\n if (this.rom) {\n console.log(`Loading program into Apple ][ RAM at \\$${PGM_BASE.toString(16)}`);\n this.ram.set(this.rom.slice(HDR_SIZE), PGM_BASE);\n }\n return 0x4c; // JMP\n case 1: return 0x20;\n case 3: return 0x00;\n case 5: return 0x03;\n case 7: return 0x3c;\n default: return 0;\n }\n }\n },\n readConst: (a) => {\n return 0;\n },\n read: (a) => { return this.floatbus(); },\n write: (a,v) => { }\n };\n\n constructor() {\n super();\n this.load