From 93aff314c8d8087ede06fcee4529c10d99601114 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Mon, 13 Jul 2020 21:14:47 -0500 Subject: [PATCH] c64, zx: added probe buffer support, need to log scanlines --- res/c64.wasm | Bin 97967 -> 104104 bytes res/zx.wasm | Bin 72098 -> 74480 bytes src/common/baseplatform.ts | 19 +- src/common/devices.ts | 2 + src/common/recorder.ts | 3 + src/machine/c64.ts | 573 ++----------------------------------- src/machine/zx.ts | 10 +- src/platform/c64.ts | 14 +- 8 files changed, 48 insertions(+), 573 deletions(-) diff --git a/res/c64.wasm b/res/c64.wasm index a0d04fe4496e14e7d050d31c25ba7c42ba7d75a5..10e9d2078bbc5d04592e16cd242f9531b2aff926 100755 GIT binary patch literal 104104 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 ibMwv(oA21Pao~}M*M?o2w-ep8?!N(qFi~{? delta 26367 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 AE&u=k diff --git a/src/common/baseplatform.ts b/src/common/baseplatform.ts index 0165351a..569ebcf8 100644 --- a/src/common/baseplatform.ts +++ b/src/common/baseplatform.ts @@ -965,7 +965,7 @@ export function lookupSymbol(platform:Platform, addr:number, extra:boolean) { /// new Machine platform adapters import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsKeyInput, SavesState, SavesInputState, HasCPU, TrapCondition, CPU } from "./devices"; -import { Probeable, RasterFrameBased, AcceptsPaddleInput, SampledAudioSink } from "./devices"; +import { Probeable, RasterFrameBased, AcceptsPaddleInput, SampledAudioSink, ProbeAll, NullProbe } from "./devices"; import { SampledAudio } from "./audio"; import { ProbeRecorder } from "./recorder"; @@ -1205,6 +1205,7 @@ export abstract class BaseWASMMachine { romarr : Uint8Array; audio : SampledAudioSink; audioarr : Float32Array; + probe : ProbeAll; abstract getCPUState() : CpuState; @@ -1235,7 +1236,7 @@ export abstract class BaseWASMMachine { var wasmResult = await WebAssembly.instantiate(wasmCompiled); this.instance = wasmResult; this.exports = wasmResult.exports; - this.exports.memory.grow(32); + this.exports.memory.grow(64); // TODO: need more when probing? // fetch BIOS var biosResponse = await fetch('res/'+this.prefix+'.bios'); var biosBinary = await biosResponse.arrayBuffer(); @@ -1347,5 +1348,19 @@ export abstract class BaseWASMMachine { this.syncAudio(); return i; } + copyProbeData() { + if (this.probe && !(this.probe instanceof NullProbe)) { + var datalen = this.exports.machine_get_probe_buffer_size(); + var dataaddr = this.exports.machine_get_probe_buffer_address(); + // TODO: more efficient way to put into probe + var databuf = new Uint32Array(this.exports.memory.buffer, dataaddr, datalen); + this.probe.logNewFrame(); // TODO: machine should do this + for (var i=0; i= this.buf.length) return; diff --git a/src/machine/c64.ts b/src/machine/c64.ts index f7ba94e1..a259eaa3 100644 --- a/src/machine/c64.ts +++ b/src/machine/c64.ts @@ -1,6 +1,6 @@ import { MOS6502, MOS6502State } from "../common/cpu/MOS6502"; -import { BasicMachine, RasterFrameBased, Bus, ProbeAll } from "../common/devices"; +import { BasicMachine, RasterFrameBased, Bus, ProbeAll, Probeable, NullProbe } from "../common/devices"; import { KeyFlags, newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler, EmuHalt, dumpRAM } from "../common/emu"; import { lzgmini, stringToByteArray, hex, rgb2bgr } from "../common/util"; @@ -10,566 +10,15 @@ import { lzgmini, stringToByteArray, hex, rgb2bgr } from "../common/util"; // http://sta.c64.org/cbm64mem.html // http://hitmen.c02.at/temp/palstuff/ -// native JS emulator (NOT USED) - -const KEYBOARD_ROW_0 = 0; -const SWCHA = 8; -const SWCHB = 9; -const INPT0 = 10; - -const C64_KEYCODE_MAP = makeKeycodeMap([ - [Keys.A, INPT0+0, 0x80], - [Keys.B, INPT0+1, 0x80], - [Keys.SELECT, SWCHB, -0x02], - [Keys.START, SWCHB, -0x01], - [Keys.UP, SWCHA, -0x10], - [Keys.DOWN, SWCHA, -0x20], - [Keys.LEFT, SWCHA, -0x40], - [Keys.RIGHT, SWCHA, -0x80], - - [Keys.P2_A, INPT0+2, 0x80], - [Keys.P2_B, INPT0+3, 0x80], - //[Keys.P2_SELECT, 1, 2], - //[Keys.P2_START, 1, 3], - [Keys.P2_UP, SWCHA, -0x01], - [Keys.P2_DOWN, SWCHA, -0x02], - [Keys.P2_LEFT, SWCHA, -0x04], - [Keys.P2_RIGHT, SWCHA, -0x08], -]); - -const C64_KEYMATRIX_NOSHIFT = [ - Keys.VK_DELETE, Keys.VK_ENTER, Keys.VK_RIGHT, Keys.VK_F10, Keys.VK_F2, Keys.VK_F4, Keys.VK_F8, Keys.VK_DOWN, - Keys.VK_3, Keys.VK_W, Keys.VK_A, Keys.VK_4, Keys.VK_Z, Keys.VK_S, Keys.VK_E, Keys.VK_SHIFT, - Keys.VK_5, Keys.VK_R, Keys.VK_D, Keys.VK_6, Keys.VK_C, Keys.VK_F, Keys.VK_T, Keys.VK_X, - Keys.VK_7, Keys.VK_Y, Keys.VK_G, Keys.VK_8, Keys.VK_B, Keys.VK_H, Keys.VK_U, Keys.VK_V, - Keys.VK_9, Keys.VK_I, Keys.VK_J, Keys.VK_0, Keys.VK_M, Keys.VK_K, Keys.VK_O, Keys.VK_N, - null/*Keys.VK_PLUS*/, Keys.VK_P, Keys.VK_L, Keys.VK_MINUS, Keys.VK_PERIOD, null/*Keys.VK_COLON*/, null/*Keys.VK_AT*/, Keys.VK_COMMA, - null/*Keys.VK_POUND*/, null/*TIMES*/, Keys.VK_SEMICOLON, Keys.VK_HOME, Keys.VK_SHIFT/*right*/, Keys.VK_EQUALS, Keys.VK_TILDE, Keys.VK_SLASH, - Keys.VK_1, Keys.VK_LEFT, Keys.VK_CONTROL, Keys.VK_2, Keys.VK_SPACE, Keys.VK_ALT, Keys.VK_Q, null/*STOP*/, -]; - -// CIA -// TODO: https://www.c64-wiki.com/wiki/CIA - -class CIA { - regs = new Uint8Array(0x10); - - reset() { - this.regs.fill(0); - } - read(a : number) : number { - return this.regs[a] | 0; - } - write(a : number, v : number) { - this.regs[a] = v; - } -} - -// VIC-II chip - -class VIC_II { - platform : C64; - scanline : number = 0; - regs = new Uint8Array(0x40); // 64 bytes - cram = new Uint8Array(0x400); // color RAM - pixels = new Uint8Array(numVisiblePixels); // output pixel buffer - cycle : number = 0; - vc : number = 0; - vcbase : number = 0; - rc : number = 0; - vmli : number = 0; // TODO: we don't use - - constructor(platform) { - this.platform = platform; - } - reset() { - this.regs.fill(0); - this.cram.fill(0); - this.vc = 0; - this.vcbase = 0; - this.rc = 0; - this.vmli = 0; - } - read(a : number) : number { - switch (a) { - case 0x12: return this.scanline; - } - return this.regs[a] | 0; - } - write(a : number, v : number) { - this.regs[a] = v; - } - setScanline(sl : number) { - this.scanline = sl; - // interrupt? - if (sl == (this.regs[0x12] | ((this.regs[0x11]&0x80)<<1))) { - this.regs[0x19] |= 0x81; - } - // reset pixel clock - this.cycle = 0; - // reset VCBASE - if (sl < firstScanline) this.vcbase = 0; - // clear pixel buffer w/ background - this.pixels.fill(this.regs[0x21]); - } - saveState() { - return { - regs: this.regs.slice(0), - cram: this.cram.slice(0) - }; - } - loadState(s) { - for (let i=0; i<32; i++) - this.write(i, s.regs[i]); - this.cram.set(s.cram); - } - c_access() : number { - let vm = this.regs[0x18]; - let vadr = (this.vc & 0x3ff) | ((vm & 0xf0) << 6); - //this.platform.profiler && this.platform.profiler.logRead(vadr); - return this.platform.readVRAMAddress(vadr) | (this.cram[vadr & 0x3ff] << 8); - } - g_access(data : number) : number { - let cb = this.regs[0x18]; - let vadr = (this.rc & 7) | ((data & 0xff) << 3) | ((cb & 0xe) << 10); - this.vc = (this.vc + 1) & 0x3ff; - //this.vcbase = (this.vcbase + 1) & 0x3ff; - //this.platform.profiler && this.platform.profiler.logRead(vadr); - return this.platform.readVRAMAddress(vadr); - } - getx() : number { - // TODO: left border 0x1f, 0x18 - return (this.cycle - 16)*8 + numBorderPixels; - } - clockPulse() { - switch (this.cycle) { - case 14: - this.vc = this.vcbase; - //console.log("VC ->",hex(this.vc)); - this.vmli = 0; - break; - case 58: - if (this.rc == 7) { - this.vcbase = this.vc; - //console.log("VCBASE",hex(this.vc)); - // TODO - } - this.rc = (this.rc + 1) & 7; - break; - } - let x = this.getx(); - if (this.cycle >= 16 && this.cycle < 56) { - var cdata = this.c_access(); - let gdata = this.g_access(cdata); - let fgcol = cdata >> 8; - let bgcol = this.regs[0x21]; - for (let i=0; i<8; i++) { - this.pixels[x+i] = (gdata & 0x80) ? fgcol : bgcol; - gdata <<= 1; - } - } - this.cycle++; - } - doDMA() { - // TODO - //let bus = this.platform.bus; - //let profiler = this.platform.profiler; - if (true) { //this.isDMAEnabled()) { - } - return 0; //TODO - } - doInterrupt() : boolean { - return false; // TODO - } - static stateToLongString(state) : string { - let s = ""; - s += dumpRAM(state.regs, 0, 64); - //s += "\nScanline: " + state.scanline; - //s += "\n DLL: $" + hex((state.regs[0x0c] << 8) + state.regs[0x10],4) + " @ $" + hex(state.dll,4); - return s; - } -} - -const cpuFrequency = 10227273; // NTSC -const linesPerFrame = 263; // (6567R8) -const firstScanline = 0x30; -const lastScanline = 0xf7; -const numVisibleLines = 235; // (6567R8) -const numScreenPixels = 320; -const numBorderPixels = 16; -const numVisiblePixels = numScreenPixels+numBorderPixels*2; // (6567R8) -const cpuClocksPerLine = 65; // 65*8 (6567R8) -const cpuClocksPreDMA = 7; // TODO -const audioOversample = 4; -const audioSampleRate = linesPerFrame*60*audioOversample; - -export class C64 extends BasicMachine implements RasterFrameBased { - - cpuFrequency = cpuFrequency; - canvasWidth = numVisiblePixels; - overscan = true; - numTotalScanlines = linesPerFrame; - numVisibleScanlines = numVisibleLines; - defaultROMSize = 0x6000; - cpuCyclesPerLine = 65; // 65*8 (6567R8) - cpuCyclesPreDMA = 7; // TODO - sampleRate = audioSampleRate; - - cpu : MOS6502; - ram : Uint8Array; - rom : Uint8Array; // cartridge ROM - bios : Uint8Array; - vic : VIC_II = new VIC_II(this); - cia1 : CIA = new CIA(); - cia2 : CIA = new CIA(); - probeDMABus; - lastFrameCycles : number = 0; - - enableKERNAL : boolean = true; - enableIO : boolean = true; - enableBASIC : boolean = true; - enableCART : boolean = true; - - constructor() { - super(); - this.cpu = new MOS6502(); - this.ram = new Uint8Array(0x10000); // 64 KB, of course - this.bios = new lzgmini().decode(stringToByteArray(atob(C64_BIOS_LZG))); // BASIC-CHAR-KERNAL ROMs - this.connectCPUMemoryBus(this); - this.probeDMABus = this.probeIOBus(this); - this.handler = newKeyboardHandler(this.inputs, C64_KEYCODE_MAP, this.getKeyboardFunction(), true); - } - - read = newAddressDecoder([ - [0x8000, 0x9fff, 0x1fff, (a) => { return this.enableCART ? (this.rom&&this.rom[a]) : this.ram[a|0x8000]; }], // CART ROM - [0xa000, 0xbfff, 0x1fff, (a) => { return this.enableBASIC ? this.bios[a] : this.ram[a|0xa000]; }], // BASIC ROM - [0xd000, 0xdfff, 0xfff, (a) => { return !this.enableIO ? this.bios[a + 0x2000] : this.readIO(a) }], // CHAR ROM - [0xe000, 0xffff, 0x1fff, (a) => { return this.enableKERNAL ? this.bios[a + 0x3000] : this.ram[a|0xe000]; }], // KERNAL ROM - [0x0000, 0xffff, 0xffff, (a) => { return this.ram[a]; }], - ]); - - write = newAddressDecoder([ - [0x0000, 0x0001, 0xffff, (a,v) => { this.write6510(a,v); }], - [0xd000, 0xdfff, 0xfff, (a,v) => { this.writeIO(a,v); }], - [0x0000, 0xffff, 0xffff, (a,v) => { this.ram[a] = v; }], - ]); - - getKeyboardMap() { return null; /* TODO: C64_KEYCODE_MAP;*/ } - - // http://map.grauw.nl/articles/keymatrix.php - // https://codebase64.org/doku.php?id=base:reading_the_keyboard - // http://www.c64os.com/post?p=45 - // https://www.c64-wiki.com/wiki/Keyboard - - getKeyboardFunction() { - return (o,key,code,flags) => { - //console.log(o,key,code,flags); - var keymap = C64_KEYMATRIX_NOSHIFT; - for (var i=0; i> 3; - let col = i & 7; - // is column selected? - if (flags & KeyFlags.KeyDown) { - this.inputs[KEYBOARD_ROW_0 + row] |= (1<>8); - switch (page) { - case 0x0: case 0x1: case 0x2: case 0x3: - this.vic.write(a & 0x3f, v); - break; - case 0x8: case 0x9: case 0xa: case 0xb: - this.vic.cram[a & 0x3ff] = v; - break; - case 0xc: - this.cia1.write(a & 0xf, v); - break; - case 0xd: - this.cia2.write(a & 0xf, v); - break; - default: - return; //TODO - } - } - - readIO(a:number) : number { - //this.profiler && this.profiler.logRead(a+0xd000); - var page = (a>>8); - switch (page) { - case 0x0: case 0x1: case 0x2: case 0x3: // VIC-II - return this.vic.read(a & 0x3f); - case 0x8: case 0x9: case 0xa: case 0xb: - return this.vic.cram[a & 0x3ff]; - case 0xc: - switch (a & 0xf) { - // scan keyboard matrix for CIA 1 - // CIA 1 regs: [00, 00, ff, 00] or [ff, 00, ff, 00] - // http://www.c64os.com/post?p=45 - case 0x1: - let cols = 0; - for (let i=0; i<8; i++) - if ((this.cia1.regs[0] & (1<= 0x1000 && a < 0x2000) && (bank == 0 || bank == 2)) return this.bios[0x1000 + a]; // CHAR ROM - else return this.ram[a]; - } - - advanceFrame(trap) : number { - var idata = this.pixels; - var iofs = 0; - var vicClocks = cpuClocksPreDMA; - var fc = 0; - this.probe.logNewFrame(); - // visible lines - for (var sl=0; sl= firstScanline && sl <= lastScanline; - // iterate CPU with free clocks - while (vicClocks > 0) { - // next CPU clock - vicClocks--; - if (trap && trap()) { - trap = null; - sl = 999; - break; - } - if (visible) this.vic.clockPulse(); // VIC first - this.advanceCPU(); - fc++; - } - vicClocks += cpuClocksPerLine; - if (visible) { - // do DMA for scanline? - vicClocks -= this.vic.doDMA(); - } - // copy line to frame buffer - if (idata && sl > firstScanline-24 && iofs < idata.length) { - for (var i=0; i> 8; - } else { - // assume cartridge ROM - this.rom = padBytes(data, this.defaultROMSize); - } - this.reset(); - } - - // BASIC (0x2000 bytes) - // CHAR (0x1000 bytes) - // KERNAL (0x2000 bytes) - loadBIOS(data) { - this.bios = padBytes(data, 0x5000); - this.reset(); - } - - reset() { - super.reset(); - this.vic.reset(); - this.cia1.reset(); - this.cia2.reset(); - this.write6510(0, 0xff); - this.inputs.fill(0x0); - } - - // TODO: don't log if profiler active - readConst(addr : number) { - return this.read(addr) | 0; - } - - loadState(state) { - this.cpu.loadState(state.c); - this.ram.set(state.ram); - this.vic.loadState(state.vic); - this.loadControlsState(state); - } - saveState() { - return { - c:this.getCPUState(), - ram:this.ram.slice(0), - vic:this.vic.saveState(), - inputs:this.inputs.slice(0) - }; - } - - loadControlsState(state) { - this.inputs.set(state.inputs); - } - - saveControlsState() { - return { - inputs:this.inputs.slice(0) - }; - } - - getCPUState() { - return this.cpu.saveState(); - } - - getRasterScanline() { - return this.vic.scanline; - } - - getDebugCategories() { - return ['CPU','Stack','VIC-II']; - } - getDebugInfo(category, state) { - switch (category) { - case 'VIC-II': return VIC_II.stateToLongString(state.vic); - } - } - -} - - -const VIC_NTSC_RGB = [ - 0x000000, - 0xFFFFFF, - 0x880000, - 0xAAFFEE, - 0xCC44CC, - 0x00CC55, - 0x00CC55, - 0xEEEE77, - 0xDD8855, - 0x664400, - 0xFF7777, - 0x333333, - 0x777777, - 0xAAFF66, - 0x0088FF, - 0xBBBBBB, -]; - -var COLORS_RGBA = new Uint32Array(256); -var COLORS_WEB = []; -for (var i=0; i<256; i++) { - COLORS_RGBA[i] = rgb2bgr(VIC_NTSC_RGB[i & 15]) | 0xff000000; - COLORS_WEB[i] = "#"+hex(VIC_NTSC_RGB[i & 15],6); -} - -// bank-switching table -// TODO: https://www.c64-wiki.com/wiki/Bank_Switching - -enum BankSwitchFlags { - LORAM=1, HIRAM=2, CHAREN=4, _GAME=8, _EXROM=16 -}; - -enum Bank { - NONE, RAM, IO, CART_ROM_LO, CART_ROM_HI, CHAR_ROM, KERN_ROM, BASIC_ROM -}; - -function getBankMapping(flags:number, region:number) : Bank { - return BANK_TABLE[flags & 0x1f][region]; -}; - -const BANK_TABLE : Bank[][] = [ - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.CART_ROM_HI, Bank.RAM, Bank.CHAR_ROM, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.CART_ROM_LO, Bank.CART_ROM_HI, Bank.RAM, Bank.CHAR_ROM, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.IO, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.CART_ROM_HI, Bank.RAM, Bank.IO, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.CART_ROM_LO, Bank.CART_ROM_HI, Bank.RAM, Bank.IO, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.CHAR_ROM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.CHAR_ROM, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.CART_ROM_LO, Bank.BASIC_ROM, Bank.RAM, Bank.CHAR_ROM, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.IO, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.IO, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.CART_ROM_LO, Bank.BASIC_ROM, Bank.RAM, Bank.IO, Bank.KERN_ROM ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.NONE, Bank.CART_ROM_LO, Bank.NONE, Bank.NONE, Bank.IO, Bank.CART_ROM_HI ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.CHAR_ROM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.CHAR_ROM, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.BASIC_ROM, Bank.RAM, Bank.CHAR_ROM, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.IO, Bank.RAM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.RAM, Bank.IO, Bank.KERN_ROM ], - [ Bank.RAM, Bank.RAM, Bank.RAM, Bank.BASIC_ROM, Bank.RAM, Bank.IO, Bank.KERN_ROM ], -]; - -// https://github.com/MEGA65/open-roms -var C64_BIOS_LZG = `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`; - //// WASM Machine import { Machine, BaseWASMMachine } from "../common/baseplatform"; import { TrapCondition } from "../common/devices"; -export class C64_WASMMachine extends BaseWASMMachine implements Machine { +export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeable { + + numTotalScanlines = 312; + cpuCyclesPerLine = 63; prgstart : number; joymask0 = 0; @@ -616,9 +65,18 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine { this.exports.machine_tick(this.sys); } } + // TODO: shouldn't we return here @ start of frame? + // and stop probing } advanceFrame(trap: TrapCondition) : number { - return super.advanceFrameClock(trap, 19656+295); // TODO: can we sync with VSYNC? + // TODO: does this sync with VSYNC? + var scanline = this.exports.machine_get_raster_line(this.sys); + var clocks = Math.floor((this.numTotalScanlines - scanline) * (19656+295) / this.numTotalScanlines); + var probing = this.probe != null; + if (probing) this.exports.machine_reset_probe_buffer(); + var clocks = super.advanceFrameClock(trap, clocks); + if (probing) this.copyProbeData(); + return clocks; } getCPUState() { this.exports.machine_save_cpu_state(this.sys, this.cpustateptr); @@ -691,4 +149,5 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine { } this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1); } + } diff --git a/src/machine/zx.ts b/src/machine/zx.ts index ddce22c7..0cfd04d6 100644 --- a/src/machine/zx.ts +++ b/src/machine/zx.ts @@ -11,6 +11,9 @@ import { TrapCondition } from "../common/devices"; export class ZX_WASMMachine extends BaseWASMMachine implements Machine { + numTotalScanlines = 312; + cpuCyclesPerLine = 224; + joymask0 = 0; reset() { @@ -34,7 +37,12 @@ export class ZX_WASMMachine extends BaseWASMMachine implements Machine { } } advanceFrame(trap: TrapCondition) : number { - return super.advanceFrameClock(trap, Math.floor(1000000 / 50)); // TODO: use ticks, not msec + //var scanline = this.exports.machine_get_raster_line(this.sys); + var probing = this.probe != null; + if (probing) this.exports.machine_reset_probe_buffer(); + var clocks = super.advanceFrameClock(trap, Math.floor(1000000 / 50)); // TODO: use ticks, not msec + if (probing) this.copyProbeData(); + return clocks; } /* z80_tick_t tick_cb; // 0 diff --git a/src/platform/c64.ts b/src/platform/c64.ts index df894651..3c936876 100644 --- a/src/platform/c64.ts +++ b/src/platform/c64.ts @@ -1,5 +1,5 @@ -import { C64, C64_WASMMachine } from "../machine/c64"; +import { C64_WASMMachine } from "../machine/c64"; import { Platform, Base6502MachinePlatform, getToolForFilename_6502, getOpcodeMetadata_6502 } from "../common/baseplatform"; import { PLATFORMS } from "../common/emu"; @@ -37,17 +37,6 @@ const C64_MEMORY_MAP = { main:[ {name:'KERNAL ROM', start:0xe000,size:0x2000,type:'rom'}, ] } -// native C64 platform (NOT USED) -class C64Platform extends Base6502MachinePlatform implements Platform { - - newMachine() { return new C64(); } - getPresets() { return C64_PRESETS; } - getDefaultExtension() { return ".c"; }; - readAddress(a) { return this.machine.readConst(a); } - loadBIOS(bios) { this.machine.loadBIOS(bios); } - getMemoryMap() { return C64_MEMORY_MAP; } -} - // WASM C64 platform class C64WASMPlatform extends Base6502MachinePlatform implements Platform { @@ -76,4 +65,3 @@ class C64WASMPlatform extends Base6502MachinePlatform implement PLATFORMS['c64'] = C64WASMPlatform; PLATFORMS['c64.wasm'] = C64WASMPlatform; -PLATFORMS['c64.js'] = C64Platform;