import { Probeable } from "../common/devices"; import { dumpRAM, KeyFlags } from "../common/emu"; import { hex, lpad } from "../common/util"; // https://www.c64-wiki.com/wiki/C64 // http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt // http://www.zimmers.net/cbmpics/cbm/c64/c64prg.txt // http://sta.c64.org/cbm64mem.html // http://hitmen.c02.at/temp/palstuff/ //// WASM Machine import { Machine } from "../common/baseplatform"; import { TrapCondition } from "../common/devices"; import { BaseWASMMachine } from "../common/wasmplatform"; export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeable { numTotalScanlines = 312; cpuCyclesPerLine = 63; prgstart : number; joymask0 = 0; joymask1 = 0; loadBIOS(srcArray: Uint8Array) { var patch1ofs = 0xea24 - 0xe000 + 0x3000; /*if (srcArray[patch1ofs] == 0x02)*/ srcArray[patch1ofs] = 0x60; // cursor move, KIL -> RTS super.loadBIOS(srcArray); } reset() { super.reset(); // clear keyboard for (var ch=0; ch<128; ch++) { this.exports.machine_key_up(this.sys, ch); } // load rom if (this.romptr && this.romlen) { this.exports.machine_load_rom(this.sys, this.romptr, this.romlen); this.prgstart = this.romarr[0] + (this.romarr[1]<<8); // get load address // look for BASIC program start if (this.prgstart == 0x801) { this.prgstart = this.romarr[2] + (this.romarr[3]<<8) + 2; // point to after BASIC program console.log("prgstart", hex(this.prgstart)); } // is program loaded into RAM? if (this.prgstart < 0x8000) { // advance BIOS a few frames this.exports.machine_exec(this.sys, 250000); // type in command (SYS 2061) var cmd = "SYS "+this.prgstart+"\r"; for (var i=0; i , case 191: key = flags & KeyFlags.Shift ? 0x3f : 0x2f; break; // ? / case 222: key = flags & KeyFlags.Shift ? 0x22 : 0x27; break; // " ' case 219: key = flags & KeyFlags.Shift ? 0x7b : 0x5b; break; // [ case 221: key = flags & KeyFlags.Shift ? 0x7d : 0x5d; break; // ] case 48: if (flags & KeyFlags.Shift) key = 0x29; break; // ) case 49: if (flags & KeyFlags.Shift) key = 0x21; break; // ! case 50: if (flags & KeyFlags.Shift) key = 0x40; break; // @ case 51: if (flags & KeyFlags.Shift) key = 0x23; break; // # case 52: if (flags & KeyFlags.Shift) key = 0x24; break; // $ case 53: if (flags & KeyFlags.Shift) key = 0x25; break; // % case 54: if (flags & KeyFlags.Shift) key = 0x5e; break; // ^ case 55: if (flags & KeyFlags.Shift) key = 0x26; break; // & case 56: if (flags & KeyFlags.Shift) key = 0x2a; break; // * case 57: if (flags & KeyFlags.Shift) key = 0x28; break; // ( case 59: if (flags & KeyFlags.Shift) key = 0x3a; break; // ; case 61: if (flags & KeyFlags.Shift) key = 0x2b; break; // + case 173: key = flags & KeyFlags.Shift ? 0x5f : 0x2d; break; // _ - } if (flags & KeyFlags.KeyDown) { this.exports.machine_key_down(this.sys, key); this.joymask0 |= mask; this.joymask1 |= mask2; } else if (flags & KeyFlags.KeyUp) { this.exports.machine_key_up(this.sys, key); this.joymask0 &= ~mask; this.joymask1 &= ~mask2; } this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1); } getRasterLine() { return this.exports.machine_get_raster_line(this.sys); } getDebugStateOffset(index: number) { var p = this.exports.machine_get_debug_pointer(this.sys, index); return p - this.sys; } getDebugCategories() { return ['CPU','ZPRAM','Stack','PLA','CIA','VIC','SID']; } getDebugInfo(category:string, state:any) { switch (category) { case 'PLA': { let s = ""; let iomapped = state.pla[0]; let port = state.pla[3]; s += `$0000 - $9FFF RAM\n`; s += `$A000 - $BFFF ${(port&3)==3 ? 'BASIC ROM' : 'RAM'}\n`; s += `$C000 - $CFFF RAM\n`; s += `$D000 - $DFFF ${iomapped ? 'I/O' : (port&3)!=0 ? 'CHAR ROM' : 'RAM'}\n`; s += `$E000 - $FFFF ${(port&2)==2 ? 'KERNAL ROM' : 'RAM'}\n`; return s; } case 'CIA': { let s = ""; for (let i=0; i<2; i++) { let m = i ? state.cia2 : state.cia1; s += `CIA ${i+1}\n`; s += ` A: Data ${hex(m[0])} DDR ${hex(m[1])} Input ${hex(m[2])}`; s += ` Timer ${hex(m[10]+m[11]*256, 4)}\n`; s += ` B: Data ${hex(m[4])} DDR ${hex(m[5])} Input ${hex(m[6])}`; s += ` Timer ${hex(m[10+10]+m[11+10]*256, 4)}\n`; //s += ` IMR ${hex(m[48])} ICR ${hex(m[50])}\n` } return s; } case 'VIC': { let m = state.vic; let s = ''; let vicbank = ((state.cia2[0] & 3) ^ 3) * 0x4000; let charmem = vicbank + (state.vic[0x18] & 14) * 0x400; let screen = vicbank + (state.vic[0x18] >> 4) * 0x400; let isbitmap = state.vic[0x11] & 0x20; let ischar = (state.cia2[0]&1)==1 && (state.vic[0x18]&12)==4; s += `Scanline: ${lpad(this.getRasterLine(),3)} `; if (state.vic[0x11] & 0x20) s += ' BITMAP'; else s += ' CHAR'; if (state.vic[0x16] & 0x10) s += ' MULTICOLOR'; if (state.vic[0x11] & 0x40) s += ' EXTENDED'; s += "\n"; s += `VIC Bank: $${hex(vicbank,4)} Scrn: $${hex(screen,4)} `; if (isbitmap) s += `Bitmap: $${hex(charmem&0xe000,4)}` else if (ischar) s += `Char: ROM $${hex(charmem,4)}`; else s += `Char: $${hex(charmem,4)}`; s += "\n"; s += `Scroll X:${state.vic[0x16] & 7} Y:${state.vic[0x11] & 7}\n`; s += dumpRAM(m, 0xd000, 64); return s; } case 'SID': { let m = state.sid; let s = '' s += dumpRAM(m, 0xd400, 32); return s; } } } }