From f32009ca0baa3685b8c18c2d8113ce2a24be7e4b Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sun, 25 Aug 2019 17:17:03 -0400 Subject: [PATCH] log clocks at start of scanline; added everything to Platforms menu --- index.html | 10 +- src/devices.ts | 1 + src/platform/astrocade.ts | 772 +++++++++++++++++++------------------- src/platform/galaxian.ts | 4 +- src/views.ts | 20 +- 5 files changed, 410 insertions(+), 397 deletions(-) diff --git a/index.html b/index.html index 4f6c691c..d4505efa 100644 --- a/index.html +++ b/index.html @@ -147,13 +147,21 @@ if (window.location.host.endsWith('8bitworkshop.com')) { Game Consoles diff --git a/src/devices.ts b/src/devices.ts index 6cd5268c..0421868c 100644 --- a/src/devices.ts +++ b/src/devices.ts @@ -360,6 +360,7 @@ export abstract class BasicScanlineMachine extends BasicMachine implements Raste } this.drawScanline(); this.probe.logNewScanline(); + this.probe.logClocks(clock-endLineClock); } this.postFrame(); return clock; diff --git a/src/platform/astrocade.ts b/src/platform/astrocade.ts index 9004feda..03aca813 100644 --- a/src/platform/astrocade.ts +++ b/src/platform/astrocade.ts @@ -1,6 +1,6 @@ "use strict"; -import { Platform, BaseZ80Platform } from "../baseplatform"; +import { Platform, BaseZ80Platform } from "../baseplatform"; import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap } from "../emu"; import { hex, lzgmini, stringToByteArray, rgb2bgr, clamp } from "../util"; import { MasterAudio, AY38910_Audio } from "../audio"; @@ -8,23 +8,23 @@ import { MasterAudio, AY38910_Audio } from "../audio"; // http://metopal.com/projects/ballybook/doku.php const ASTROCADE_PRESETS = [ - {id:'01-helloworlds.asm', name:'Hello World'}, - {id:'02-telephone.asm', name:'Telephone'}, - {id:'03-horcbpal.asm', name:'Paddle Demo'}, - {id:'hello.c', name:'Hello Graphics'}, - {id:'lines.c', name:'Lines'}, - {id:'sprites.c', name:'Sprites'}, - {id:'vsync.c', name:'Sprites w/ VSYNC'}, - {id:'fastsprites.c', name:'Fast Sprites'}, - {id:'music.c', name:'Music'}, - {id:'rotate.c', name:'Rotate Op'}, - {id:'rainbow.c', name:'Rainbow'}, - {id:'cosmic.c', name:'Cosmic Impalas Game'}, - {id:'racing.c', name:'Pseudo 3-D Racing Game'}, + { id: '01-helloworlds.asm', name: 'Hello World' }, + { id: '02-telephone.asm', name: 'Telephone' }, + { id: '03-horcbpal.asm', name: 'Paddle Demo' }, + { id: 'hello.c', name: 'Hello Graphics' }, + { id: 'lines.c', name: 'Lines' }, + { id: 'sprites.c', name: 'Sprites' }, + { id: 'vsync.c', name: 'Sprites w/ VSYNC' }, + { id: 'fastsprites.c', name: 'Fast Sprites' }, + { id: 'music.c', name: 'Music' }, + { id: 'rotate.c', name: 'Rotate Op' }, + { id: 'rainbow.c', name: 'Rainbow' }, + { id: 'cosmic.c', name: 'Cosmic Impalas Game' }, + { id: 'racing.c', name: 'Pseudo 3-D Racing Game' }, ]; const ASTROCADE_BIOS_PRESETS = [ - {id:'bios.c', name:'BIOS'}, + { id: 'bios.c', name: 'BIOS' }, ]; // TODO: fix keys, more controllers, vibrato/noise, border color, debug info, rotate @@ -32,45 +32,45 @@ const ASTROCADE_BIOS_PRESETS = [ const ASTROCADE_KEYCODE_MAP = makeKeycodeMap([ // player 1 - [Keys.UP, 0x10, 0x1], - [Keys.DOWN, 0x10, 0x2], - [Keys.LEFT, 0x10, 0x4], + [Keys.UP, 0x10, 0x1], + [Keys.DOWN, 0x10, 0x2], + [Keys.LEFT, 0x10, 0x4], [Keys.RIGHT, 0x10, 0x8], - [Keys.A, 0x10, 0x10], + [Keys.A, 0x10, 0x10], // player 2 - [Keys.P2_UP, 0x11, 0x1], - [Keys.P2_DOWN, 0x11, 0x2], - [Keys.P2_LEFT, 0x11, 0x4], + [Keys.P2_UP, 0x11, 0x1], + [Keys.P2_DOWN, 0x11, 0x2], + [Keys.P2_LEFT, 0x11, 0x4], [Keys.P2_RIGHT, 0x11, 0x8], - [Keys.P2_A, 0x11, 0x10], + [Keys.P2_A, 0x11, 0x10], // keypad $14 - [Keys.VK_P, 0x14, 0x1], - [Keys.VK_SLASH, 0x14, 0x2], - [Keys.VK_X, 0x14, 0x4], + [Keys.VK_P, 0x14, 0x1], + [Keys.VK_SLASH, 0x14, 0x2], + [Keys.VK_X, 0x14, 0x4], [Keys.VK_MINUS, 0x14, 0x8], [Keys.VK_COMMA, 0x14, 0x10], - [Keys.VK_EQUALS,0x14, 0x20], + [Keys.VK_EQUALS, 0x14, 0x20], // keypad $15 - [Keys.VK_O, 0x15, 0x1], - [Keys.VK_L, 0x15, 0x2], - [Keys.VK_9, 0x15, 0x4], - [Keys.VK_6, 0x15, 0x8], - [Keys.VK_3, 0x15, 0x10], - [Keys.VK_PERIOD,0x15, 0x20], + [Keys.VK_O, 0x15, 0x1], + [Keys.VK_L, 0x15, 0x2], + [Keys.VK_9, 0x15, 0x4], + [Keys.VK_6, 0x15, 0x8], + [Keys.VK_3, 0x15, 0x10], + [Keys.VK_PERIOD, 0x15, 0x20], // keypad $16 - [Keys.VK_I, 0x16, 0x1], - [Keys.VK_K, 0x16, 0x2], - [Keys.VK_8, 0x16, 0x4], - [Keys.VK_5, 0x16, 0x8], - [Keys.VK_2, 0x16, 0x10], - [Keys.VK_0, 0x16, 0x20], + [Keys.VK_I, 0x16, 0x1], + [Keys.VK_K, 0x16, 0x2], + [Keys.VK_8, 0x16, 0x4], + [Keys.VK_5, 0x16, 0x8], + [Keys.VK_2, 0x16, 0x10], + [Keys.VK_0, 0x16, 0x20], // keypad $17 - [Keys.VK_U, 0x17, 0x1], - [Keys.VK_J, 0x17, 0x2], - [Keys.VK_7, 0x17, 0x4], - [Keys.VK_4, 0x17, 0x8], - [Keys.VK_1, 0x17, 0x10], - [Keys.VK_BACK_SLASH, 0x17, 0x20], + [Keys.VK_U, 0x17, 0x1], + [Keys.VK_J, 0x17, 0x2], + [Keys.VK_7, 0x17, 0x4], + [Keys.VK_4, 0x17, 0x8], + [Keys.VK_1, 0x17, 0x10], + [Keys.VK_BACK_SLASH, 0x17, 0x20], ]); const _BallyAstrocadePlatform = function(mainElement, arcade) { @@ -83,8 +83,8 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { const sheight = arcade ? 204 : 102; const swbytes = Math.floor(swidth / 4); const cpuFrequency = 1789000; - const cpuCyclesPerLine = Math.floor(cpuFrequency/(60*262.5)); - const cpuCyclesPerHBlank = Math.floor(cpuCyclesPerLine*0.33); + const cpuCyclesPerLine = Math.floor(cpuFrequency / (60 * 262.5)); + const cpuCyclesPerHBlank = Math.floor(cpuCyclesPerLine * 0.33); const cpuCyclesPerVisible = cpuCyclesPerLine - cpuCyclesPerHBlank; const INITIAL_WATCHDOG = 256; const PIXEL_ON = 0xffeeeeee; @@ -109,41 +109,41 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { var rotdata = new Uint8Array(4); var rotcount = 0; var intst = 0; - - function ramwrite(a:number, v:number) { + + function ramwrite(a: number, v: number) { // set RAM ram.mem[a] = v; // mark scanline as dirty - dirtylines[Math.floor((a & 0xfff)/swbytes)] = 1; + dirtylines[Math.floor((a & 0xfff) / swbytes)] = 1; // this was old behavior where we updated instantly // but it had problems if we had mid-screen palette changes //ramupdate(a, v); } - function ramupdate(a:number, v:number) { - var ofs = a*4+3; // 4 pixels per byte - for (var i=0; i<4; i++) { + function ramupdate(a: number, v: number) { + var ofs = a * 4 + 3; // 4 pixels per byte + for (var i = 0; i < 4; i++) { var lr = ((a % swbytes) >= (horcb & 0x3f)) ? 0 : 4; pixels[ofs--] = palette[lr + (v & 3)]; v >>= 2; } } - function refreshline(y:number) { - var ofs = y*swidth/4; - for (var i=0; i>= 4; - for (var i=0; i<4; i++) { - var pix = (v&1) ? ((xpand>>2)&3) : (xpand&3); - v2 |= pix << (i*2); + for (var i = 0; i < 4; i++) { + var pix = (v & 1) ? ((xpand >> 2) & 3) : (xpand & 3); + v2 |= pix << (i * 2); v >>= 1; } v = v2; @@ -155,9 +155,9 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { // drain buffer var sh = 2 * (~rotcount & 3); v = (((rotdata[3] >> sh) & 3) << 6) | - (((rotdata[2] >> sh) & 3) << 4) | - (((rotdata[1] >> sh) & 3) << 2) | - (((rotdata[0] >> sh) & 3) << 0); + (((rotdata[2] >> sh) & 3) << 4) | + (((rotdata[1] >> sh) & 3) << 2) | + (((rotdata[0] >> sh) & 3) << 0); } else { // fill buffer rotdata[rotcount & 3] = v; @@ -167,12 +167,12 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { // shift var sh = (magicop & 3) << 1; var v2 = (v >> sh) | shift2; - shift2 = (v << (8-sh)) & 0xff; + shift2 = (v << (8 - sh)) & 0xff; v = v2; } // flop if (magicop & 0x40) { - v = + v = ((v & 0x03) << 6) | ((v & 0x0c) << 2) | ((v & 0x30) >> 2) | @@ -193,15 +193,15 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { if (magicop & 0x20) v ^= oldv; // TODO: what if both? // upper 4 bits persist, lower are just since last write - intst = (intst & 0xf0) | icpt | (icpt<<4); + intst = (intst & 0xf0) | icpt | (icpt << 4); } // commit write to ram/screen ramwrite(a, v); } - function setpalette(a:number, v:number) { - palinds[a&7] = v&0xff; - palette[a&7] = ASTROCADE_PALETTE[v&0xff]; + function setpalette(a: number, v: number) { + palinds[a & 7] = v & 0xff; + palette[a & 7] = ASTROCADE_PALETTE[v & 0xff]; refreshall(); } @@ -214,327 +214,327 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { refreshlines = sheight; } - class BallyAstrocadePlatform extends BaseZ80Platform implements Platform { - - scanline : number; - poller; + class BallyAstrocadePlatform extends BaseZ80Platform implements Platform { - getPresets() { - return ASTROCADE_PRESETS; - } + scanline: number; + poller; - start = function() { - ram = new RAM(arcade ? 0x5000 : 0x1000); - //bios = padBytes(ASTROCADE_MINIMAL_BIOS, 0x2000); - bios = padBytes(new lzgmini().decode(stringToByteArray(atob(ASTROLIBRE_BIOS_LZG))), 0x2000); - if (!arcade) { - // game console - membus = { - read: newAddressDecoder([ - [0x0000, 0x1fff, 0x1fff, function(a) { return bios[a]; }], - [0x2000, 0x3fff, 0x1fff, function(a) { return rom ? rom[a] : 0; }], - [0x4000, 0x4fff, 0xfff, function(a) { return ram.mem[a]; }], - ]), - write: newAddressDecoder([ - [0x4000, 0x4fff, 0xfff, ramwrite], - [0x0000, 0x3fff, 0xfff, magicwrite], - ]), - // TODO: correct values? - isContended: () => { return true; }, - contend: (addr:number) => { return vidactive && addr >= 0x4000 ? 1 : 0; }, - }; - } else { - // arcade game - membus = { - read: newAddressDecoder([ - [0x4000, 0x7fff, 0x3fff, function(a) { return ram.mem[a]; }], // screen RAM - [0xd000, 0xdfff, 0xfff, function(a) { return ram.mem[a+0x4000]; }], // static RAM - [0x0000, 0xafff, 0xffff, function(a) { return rom ? rom[a] : 0; }], // ROM (0-3fff,8000-afff) - ]), - write: newAddressDecoder([ - [0x4000, 0x7fff, 0x3fff, ramwrite], - [0xd000, 0xdfff, 0xfff, function(a,v) { ramwrite(a+0x4000, v); } ], // static RAM - [0x0000, 0x3fff, 0x3fff, magicwrite], - ]), - isContended: () => { return true; }, - contend: (addr:number) => { return vidactive ? 1 : 0; }, - }; + getPresets() { + return ASTROCADE_PRESETS; } - iobus = { - isULAPort: function(addr) { - return false; // TODO? - }, - contend: function(addr) { - return 0; // TODO? - }, - read: function(addr) { - addr &= 0x1f; - var rtn; - switch (addr) { - case 8: - rtn = intst; - intst = 0; - break; - default: - rtn = inputs[addr]; - break; - // $10 = watchdog + + start = function() { + ram = new RAM(arcade ? 0x5000 : 0x1000); + //bios = padBytes(ASTROCADE_MINIMAL_BIOS, 0x2000); + bios = padBytes(new lzgmini().decode(stringToByteArray(atob(ASTROLIBRE_BIOS_LZG))), 0x2000); + if (!arcade) { + // game console + membus = { + read: newAddressDecoder([ + [0x0000, 0x1fff, 0x1fff, function(a) { return bios[a]; }], + [0x2000, 0x3fff, 0x1fff, function(a) { return rom ? rom[a] : 0; }], + [0x4000, 0x4fff, 0xfff, function(a) { return ram.mem[a]; }], + ]), + write: newAddressDecoder([ + [0x4000, 0x4fff, 0xfff, ramwrite], + [0x0000, 0x3fff, 0xfff, magicwrite], + ]), + // TODO: correct values? + isContended: () => { return true; }, + contend: (addr: number) => { return vidactive && addr >= 0x4000 ? 1 : 0; }, + }; + } else { + // arcade game + membus = { + read: newAddressDecoder([ + [0x4000, 0x7fff, 0x3fff, function(a) { return ram.mem[a]; }], // screen RAM + [0xd000, 0xdfff, 0xfff, function(a) { return ram.mem[a + 0x4000]; }], // static RAM + [0x0000, 0xafff, 0xffff, function(a) { return rom ? rom[a] : 0; }], // ROM (0-3fff,8000-afff) + ]), + write: newAddressDecoder([ + [0x4000, 0x7fff, 0x3fff, ramwrite], + [0xd000, 0xdfff, 0xfff, function(a, v) { ramwrite(a + 0x4000, v); }], // static RAM + [0x0000, 0x3fff, 0x3fff, magicwrite], + ]), + isContended: () => { return true; }, + contend: (addr: number) => { return vidactive ? 1 : 0; }, + }; + } + iobus = { + isULAPort: function(addr) { + return false; // TODO? + }, + contend: function(addr) { + return 0; // TODO? + }, + read: function(addr) { + addr &= 0x1f; + var rtn; + switch (addr) { + case 8: + rtn = intst; + intst = 0; + break; + default: + rtn = inputs[addr]; + break; + // $10 = watchdog + } + return rtn; + }, + write: function(addr, val) { + addr &= 0x1f; + val &= 0xff; + switch (addr) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + setpalette(addr, val); + break; + case 9: // HORCB (horizontal boundary byte) + horcb = val; + setbordercolor(); + refreshall(); + break; + case 0xa: // VERBL (vertical blank) + verbl = arcade ? val : val >> 1; + refreshall(); + break; + case 0xb: // OTIR (set palette) + var c = cpu.saveState(); + //console.log(c.BC>>8, c.HL); + setpalette((c.BC >> 8) - 1, membus.read(c.HL)); + break; + case 0xc: // magic register + magicop = val; + shift2 = 0; + rotcount = 0; + xplower = false; + break; + case 0xd: // INFBK (interrupt feedback) + infbk = val; + break; + case 0xe: // INMOD (interrupt enable) + inmod = val; + break; + case 0xf: // INLIN (interrupt line) + inlin = arcade ? val : val >> 1; + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + psg.setACRegister(addr, val); + break; + case 0x18: + var c = cpu.saveState(); + psg.setACRegister((c.BC >> 8) - 1, membus.read(c.HL)); + break; + case 0x19: // XPAND + xpand = val; + break; + default: + console.log('IO write', hex(addr, 4), hex(val, 2)); + break; + } } - return rtn; - }, - write: function(addr, val) { - addr &= 0x1f; - val &= 0xff; - switch (addr) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - setpalette(addr,val); - break; - case 9: // HORCB (horizontal boundary byte) - horcb = val; - setbordercolor(); - refreshall(); - break; - case 0xa: // VERBL (vertical blank) - verbl = arcade ? val : val >> 1; - refreshall(); - break; - case 0xb: // OTIR (set palette) - var c = cpu.saveState(); - //console.log(c.BC>>8, c.HL); - setpalette((c.BC>>8)-1, membus.read(c.HL)); - break; - case 0xc: // magic register - magicop = val; - shift2 = 0; - rotcount = 0; - xplower = false; - break; - case 0xd: // INFBK (interrupt feedback) - infbk = val; - break; - case 0xe: // INMOD (interrupt enable) - inmod = val; - break; - case 0xf: // INLIN (interrupt line) - inlin = arcade ? val : val >> 1; - break; - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - psg.setACRegister(addr, val); - break; - case 0x18: - var c = cpu.saveState(); - psg.setACRegister((c.BC>>8)-1, membus.read(c.HL)); - break; - case 0x19: // XPAND - xpand = val; - break; - default: - console.log('IO write', hex(addr,4), hex(val,2)); - break; + }; + cpu = this.newCPU(membus, iobus, { applyContention: true }); + audio = new MasterAudio(); + psg = new AstrocadeAudio(audio); + video = new RasterVideo(mainElement, swidth, sheight, {}); + video.create(); + video.setupMouseEvents(); + var idata = video.getFrameData(); + this.poller = setKeyboardFromMap(video, inputs, ASTROCADE_KEYCODE_MAP); + pixels = video.getFrameData(); + timer = new AnimationTimer(60, this.nextFrame.bind(this)); + // default palette + for (var i = 0; i < 8; i++) { + palinds[i] = i; + palette[i] = ASTROCADE_PALETTE[i]; + } + } + + readAddress(addr) { + return membus.read(addr); + } + + loadControls() { + inputs[0x1c] = video.paddle_x & 0xff; + inputs[0x1d] = video.paddle_y & 0xff; + } + + pollControls() { this.poller.poll(); } + + advance(novideo: boolean) { + this.scanline = 0; + var extra = 0; // keep track of spare cycles + for (var sl = 0; sl < 131; sl++) { + // double scanlines in consumer mode + for (var i = 0; i < 2; i++) { + // simulate contention during visible part of scanline + vidactive = sl < verbl; + extra = this.runCPU(cpu, cpuCyclesPerVisible - extra); + vidactive = false; + extra = this.runCPU(cpu, cpuCyclesPerHBlank - extra); + this.scanline++; } - } - }; - cpu = this.newCPU(membus, iobus, {applyContention:true}); - audio = new MasterAudio(); - psg = new AstrocadeAudio(audio); - video = new RasterVideo(mainElement,swidth,sheight,{}); - video.create(); - video.setupMouseEvents(); - var idata = video.getFrameData(); - this.poller = setKeyboardFromMap(video, inputs, ASTROCADE_KEYCODE_MAP); - pixels = video.getFrameData(); - timer = new AnimationTimer(60, this.nextFrame.bind(this)); - // default palette - for (var i=0; i<8; i++) { - palinds[i] = i; - palette[i] = ASTROCADE_PALETTE[i]; + // interrupt + if (sl == inlin && (inmod & 0x8)) { + cpu.retryInterrupts = !(inmod & 0x4); + cpu.interrupt(infbk); + } + // refresh this line in frame buffer? + if (sl < sheight && refreshlines > 0) { + dirtylines[sl] = 0; + refreshline(sl); + refreshlines--; + } + else if (dirtylines[sl]) { + dirtylines[sl] = 0; + refreshline(sl); + } + } + if (!novideo) { + video.updateFrame(0, 0, 0, 0, swidth, verbl); + video.clearRect(0, verbl, swidth, sheight - verbl); + this.loadControls(); + } + /* + if (watchdog_counter-- <= 0) { + console.log("WATCHDOG FIRED"); // TODO: alert on video + this.reset(); + } + */ } - } - readAddress(addr) { - return membus.read(addr); - } + getRasterScanline() { return this.scanline; } - loadControls() { - inputs[0x1c] = video.paddle_x & 0xff; - inputs[0x1d] = video.paddle_y & 0xff; - } - - pollControls() { this.poller.poll(); } - - advance(novideo : boolean) { - this.scanline = 0; - var extra = 0; // keep track of spare cycles - for (var sl=0; sl<131; sl++) { - // double scanlines in consumer mode - for (var i=0; i<2; i++) { - // simulate contention during visible part of scanline - vidactive = sl < verbl; - extra = this.runCPU(cpu, cpuCyclesPerVisible - extra); - vidactive = false; - extra = this.runCPU(cpu, cpuCyclesPerHBlank - extra); - this.scanline++; - } - // interrupt - if (sl == inlin && (inmod & 0x8)) { - cpu.retryInterrupts = !(inmod & 0x4); - cpu.interrupt(infbk); - } - // refresh this line in frame buffer? - if (sl < sheight && refreshlines>0) { - dirtylines[sl] = 0; - refreshline(sl); - refreshlines--; - } - else if (dirtylines[sl]) { - dirtylines[sl] = 0; - refreshline(sl); - } - } - if (!novideo) { - video.updateFrame(0, 0, 0, 0, swidth, verbl); - video.clearRect(0, verbl, swidth, sheight-verbl); - this.loadControls(); - } - /* - if (watchdog_counter-- <= 0) { - console.log("WATCHDOG FIRED"); // TODO: alert on video + loadROM(title, data) { + rom = padBytes(data, arcade ? 0xb000 : 0x2000); this.reset(); } - */ - } - - getRasterScanline() { return this.scanline; } - loadROM(title, data) { - rom = padBytes(data, arcade ? 0xb000 : 0x2000); - this.reset(); - } - - loadBIOS(title, data) { - bios = padBytes(data, 0x2000); - this.reset(); - } - - loadState(state) { - cpu.loadState(state.c); - ram.mem.set(state.b); - palette.set(state.palette); - palinds.set(state.palinds); - magicop = state.magicop; - xpand = state.xpand; - xplower = state.xplower; - shift2 = state.shift2; - horcb = state.horcb; - inmod = state.inmod; - inlin = state.inlin; - infbk = state.infbk; - verbl = state.verbl; - rotcount = state.rotcount; - rotdata.set(state.rotdata); - intst = state.intst; - this.scanline = state.sl; - this.loadControlsState(state); - refreshall(); - } - saveState() { - return { - c: this.getCPUState(), - b: ram.mem.slice(0), - in: inputs.slice(0), - palette: palette.slice(0), - palinds: palinds.slice(0), - magicop: magicop, - xpand: xpand, - xplower: xplower, - shift2: shift2, - horcb: horcb, - inmod: inmod, - inlin: inlin, - infbk: infbk, - verbl: verbl, - rotcount: rotcount, - rotdata: rotdata.slice(0), - intst: intst, - sl: this.scanline, - }; - } - loadControlsState(state) { - inputs.set(state.in); - } - saveControlsState() { - return { - in:inputs.slice(0) - }; - } - getCPUState() { - return cpu.saveState(); - } - - isRunning() { - return timer && timer.isRunning(); - } - pause() { - timer.stop(); - audio.stop(); - } - resume() { - timer.start(); - audio.start(); - } - reset() { - cpu.reset(); - psg.reset(); - // TODO? - magicop = xpand = inmod = inlin = infbk = shift2 = horcb = 0; - verbl = sheight; - xplower = false; - //watchdog_counter = INITIAL_WATCHDOG; - } - getDebugCategories() { - return super.getDebugCategories().concat(['Astro']); - } - getDebugInfo(category, state) { - switch (category) { - case 'Astro': return this.toLongString(state); - default: return super.getDebugInfo(category, state); + loadBIOS(title, data) { + bios = padBytes(data, 0x2000); + this.reset(); } - } - toLongString(st) { - var s = ""; - s += " Scan Y: " + st.sl; - s += "\n INLIN: " + st.inlin; - s += "\n VERBL: " + st.verbl; - s += "\nMAGICOP: $" + hex(st.magicop); - s += "\n XPAND: $" + hex(st.xpand); - s += "\nXPLOWER: " + st.xplower; - s += "\n SHIFT2: $" + hex(st.shift2); - s += "\n HORCB: $" + hex(st.horcb); - s += "\n INMOD: $" + hex(st.inmod); - s += "\n INFBK: $" + hex(st.infbk); - s += "\n INTST: $" + hex(st.intst); // intercept status - s += "\nPalette: "; - for (var i=0; i<8; i++) - s += hex(palinds[i]); - s += "\n"; - return s; - } - } + loadState(state) { + cpu.loadState(state.c); + ram.mem.set(state.b); + palette.set(state.palette); + palinds.set(state.palinds); + magicop = state.magicop; + xpand = state.xpand; + xplower = state.xplower; + shift2 = state.shift2; + horcb = state.horcb; + inmod = state.inmod; + inlin = state.inlin; + infbk = state.infbk; + verbl = state.verbl; + rotcount = state.rotcount; + rotdata.set(state.rotdata); + intst = state.intst; + this.scanline = state.sl; + this.loadControlsState(state); + refreshall(); + } + saveState() { + return { + c: this.getCPUState(), + b: ram.mem.slice(0), + in: inputs.slice(0), + palette: palette.slice(0), + palinds: palinds.slice(0), + magicop: magicop, + xpand: xpand, + xplower: xplower, + shift2: shift2, + horcb: horcb, + inmod: inmod, + inlin: inlin, + infbk: infbk, + verbl: verbl, + rotcount: rotcount, + rotdata: rotdata.slice(0), + intst: intst, + sl: this.scanline, + }; + } + loadControlsState(state) { + inputs.set(state.in); + } + saveControlsState() { + return { + in: inputs.slice(0) + }; + } + getCPUState() { + return cpu.saveState(); + } + + isRunning() { + return timer && timer.isRunning(); + } + pause() { + timer.stop(); + audio.stop(); + } + resume() { + timer.start(); + audio.start(); + } + reset() { + cpu.reset(); + psg.reset(); + // TODO? + magicop = xpand = inmod = inlin = infbk = shift2 = horcb = 0; + verbl = sheight; + xplower = false; + //watchdog_counter = INITIAL_WATCHDOG; + } + getDebugCategories() { + return super.getDebugCategories().concat(['Astro']); + } + getDebugInfo(category, state) { + switch (category) { + case 'Astro': return this.toLongString(state); + default: return super.getDebugInfo(category, state); + } + } + toLongString(st) { + var s = ""; + s += " Scan Y: " + st.sl; + s += "\n INLIN: " + st.inlin; + s += "\n VERBL: " + st.verbl; + s += "\nMAGICOP: $" + hex(st.magicop); + s += "\n XPAND: $" + hex(st.xpand); + s += "\nXPLOWER: " + st.xplower; + s += "\n SHIFT2: $" + hex(st.shift2); + s += "\n HORCB: $" + hex(st.horcb); + s += "\n INMOD: $" + hex(st.inmod); + s += "\n INFBK: $" + hex(st.infbk); + s += "\n INTST: $" + hex(st.intst); // intercept status + s += "\nPalette: "; + for (var i = 0; i < 8; i++) + s += hex(palinds[i]); + s += "\n"; + return s; + } + + } return new BallyAstrocadePlatform(); } @@ -542,7 +542,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) { // TODO: https://github.com/mamedev/mame/blob/master/src/devices/sound/astrocde.cpp class AstrocadeAudio extends AY38910_Audio { - setACRegister(addr : number, val : number) { + setACRegister(addr: number, val: number) { addr &= 0x7; val &= 0xff; switch (addr) { @@ -553,17 +553,17 @@ class AstrocadeAudio extends AY38910_Audio { case 1: case 2: case 3: - var i = (addr-1)*2; - var j = val*2+1; - this.psg.writeRegisterAY(i, j&0xff); // freq lo - this.psg.writeRegisterAY(i+1, (j>>8)&0xff); // freq hi + var i = (addr - 1) * 2; + var j = val * 2 + 1; + this.psg.writeRegisterAY(i, j & 0xff); // freq lo + this.psg.writeRegisterAY(i + 1, (j >> 8) & 0xff); // freq hi break; case 5: this.psg.writeRegisterAY(10, val & 0xf); // tone c vol break; case 6: this.psg.writeRegisterAY(8, val & 0xf); // tone a vol - this.psg.writeRegisterAY(9, (val>>4) & 0xf); // tone b vol + this.psg.writeRegisterAY(9, (val >> 4) & 0xf); // tone b vol break; } } @@ -596,9 +596,9 @@ PLATFORMS['astrocade-bios'] = _BallyAstrocadeBIOSPlatform; PLATFORMS['astrocade-arcade'] = _BallyArcadePlatform; //http://glankonian.com/~lance/astrocade_palette.html -var ASTROCADE_PALETTE = [0x000000,0x242424,0x484848,0x6D6D6D,0x919191,0xB6B6B6,0xDADADA,0xFFFFFF,0x2500BB,0x4900E0,0x6E11FF,0x9235FF,0xB75AFF,0xDB7EFF,0xFFA3FF,0xFFC7FF,0x4900B0,0x6D00D5,0x9201F9,0xB625FF,0xDA4AFF,0xFF6EFF,0xFF92FF,0xFFB7FF,0x6A009F,0x8E00C3,0xB300E7,0xD718FF,0xFB3CFF,0xFF61FF,0xFF85FF,0xFFA9FF,0x870087,0xAB00AB,0xD000D0,0xF40EF4,0xFF32FF,0xFF56FF,0xFF7BFF,0xFF9FFF,0x9F006A,0xC3008E,0xE700B3,0xFF07D7,0xFF2CFB,0xFF50FF,0xFF74FF,0xFF99FF,0xB00049,0xD5006D,0xF90092,0xFF05B6,0xFF29DA,0xFF4DFF,0xFF72FF,0xFF96FF,0xBB0025,0xE00049,0xFF006E,0xFF0692,0xFF2AB7,0xFF4FDB,0xFF73FF,0xFF98FF,0xBF0000,0xE30024,0xFF0048,0xFF0B6D,0xFF3091,0xFF54B6,0xFF79DA,0xFF9DFF,0xBB0000,0xE00000,0xFF0023,0xFF1447,0xFF396C,0xFF5D90,0xFF82B5,0xFFA6D9,0xB00000,0xD50000,0xF90000,0xFF2124,0xFF4548,0xFF6A6C,0xFF8E91,0xFFB3B5,0x9F0000,0xC30000,0xE70C00,0xFF3003,0xFF5527,0xFF794B,0xFF9E70,0xFFC294,0x870000,0xAB0000,0xD01E00,0xF44200,0xFF670A,0xFF8B2E,0xFFAF53,0xFFD477,0x6A0000,0x8E0D00,0xB33100,0xD75600,0xFB7A00,0xFF9E17,0xFFC33B,0xFFE75F,0x490000,0x6D2100,0x924500,0xB66A00,0xDA8E00,0xFFB305,0xFFD729,0xFFFC4E,0x251100,0x493500,0x6E5A00,0x927E00,0xB7A300,0xDBC700,0xFFEB1E,0xFFFF43,0x002500,0x244900,0x486D00,0x6D9200,0x91B600,0xB6DB00,0xDAFF1B,0xFFFF3F,0x003700,0x005B00,0x238000,0x47A400,0x6CC900,0x90ED00,0xB5FF1E,0xD9FF43,0x004700,0x006C00,0x009000,0x24B400,0x48D900,0x6CFD05,0x91FF29,0xB5FF4E,0x005500,0x007900,0x009D00,0x03C200,0x27E600,0x4BFF17,0x70FF3B,0x94FF5F,0x005F00,0x008300,0x00A800,0x00CC00,0x0AF00A,0x2EFF2E,0x53FF53,0x77FF77,0x006500,0x008A00,0x00AE00,0x00D203,0x00F727,0x17FF4B,0x3BFF70,0x5FFF94,0x006800,0x008C00,0x00B100,0x00D524,0x00F948,0x05FF6C,0x29FF91,0x4EFFB5,0x006600,0x008B00,0x00AF23,0x00D447,0x00F86C,0x00FF90,0x1EFFB5,0x43FFD9,0x006100,0x008524,0x00AA48,0x00CE6D,0x00F391,0x00FFB6,0x1BFFDA,0x3FFFFE,0x005825,0x007C49,0x00A16E,0x00C592,0x00EAB7,0x00FFDB,0x1EFFFF,0x43FFFF,0x004B49,0x00706D,0x009492,0x00B9B6,0x00DDDA,0x05FFFF,0x29FFFF,0x4EFFFF,0x003C6A,0x00608E,0x0085B3,0x00A9D7,0x00CEFB,0x17F2FF,0x3BFFFF,0x5FFFFF,0x002A87,0x004FAB,0x0073D0,0x0097F4,0x0ABCFF,0x2EE0FF,0x53FFFF,0x77FFFF,0x00179F,0x003BC3,0x0060E7,0x0384FF,0x27A8FF,0x4BCDFF,0x70F1FF,0x94FFFF,0x0002B0,0x0027D5,0x004BF9,0x2470FF,0x4894FF,0x6CB9FF,0x91DDFF,0xB5FFFF,0x0000BB,0x0013E0,0x2337FF,0x475BFF,0x6C80FF,0x90A4FF,0xB5C9FF,0xD9EDFF]; +var ASTROCADE_PALETTE = [0x000000, 0x242424, 0x484848, 0x6D6D6D, 0x919191, 0xB6B6B6, 0xDADADA, 0xFFFFFF, 0x2500BB, 0x4900E0, 0x6E11FF, 0x9235FF, 0xB75AFF, 0xDB7EFF, 0xFFA3FF, 0xFFC7FF, 0x4900B0, 0x6D00D5, 0x9201F9, 0xB625FF, 0xDA4AFF, 0xFF6EFF, 0xFF92FF, 0xFFB7FF, 0x6A009F, 0x8E00C3, 0xB300E7, 0xD718FF, 0xFB3CFF, 0xFF61FF, 0xFF85FF, 0xFFA9FF, 0x870087, 0xAB00AB, 0xD000D0, 0xF40EF4, 0xFF32FF, 0xFF56FF, 0xFF7BFF, 0xFF9FFF, 0x9F006A, 0xC3008E, 0xE700B3, 0xFF07D7, 0xFF2CFB, 0xFF50FF, 0xFF74FF, 0xFF99FF, 0xB00049, 0xD5006D, 0xF90092, 0xFF05B6, 0xFF29DA, 0xFF4DFF, 0xFF72FF, 0xFF96FF, 0xBB0025, 0xE00049, 0xFF006E, 0xFF0692, 0xFF2AB7, 0xFF4FDB, 0xFF73FF, 0xFF98FF, 0xBF0000, 0xE30024, 0xFF0048, 0xFF0B6D, 0xFF3091, 0xFF54B6, 0xFF79DA, 0xFF9DFF, 0xBB0000, 0xE00000, 0xFF0023, 0xFF1447, 0xFF396C, 0xFF5D90, 0xFF82B5, 0xFFA6D9, 0xB00000, 0xD50000, 0xF90000, 0xFF2124, 0xFF4548, 0xFF6A6C, 0xFF8E91, 0xFFB3B5, 0x9F0000, 0xC30000, 0xE70C00, 0xFF3003, 0xFF5527, 0xFF794B, 0xFF9E70, 0xFFC294, 0x870000, 0xAB0000, 0xD01E00, 0xF44200, 0xFF670A, 0xFF8B2E, 0xFFAF53, 0xFFD477, 0x6A0000, 0x8E0D00, 0xB33100, 0xD75600, 0xFB7A00, 0xFF9E17, 0xFFC33B, 0xFFE75F, 0x490000, 0x6D2100, 0x924500, 0xB66A00, 0xDA8E00, 0xFFB305, 0xFFD729, 0xFFFC4E, 0x251100, 0x493500, 0x6E5A00, 0x927E00, 0xB7A300, 0xDBC700, 0xFFEB1E, 0xFFFF43, 0x002500, 0x244900, 0x486D00, 0x6D9200, 0x91B600, 0xB6DB00, 0xDAFF1B, 0xFFFF3F, 0x003700, 0x005B00, 0x238000, 0x47A400, 0x6CC900, 0x90ED00, 0xB5FF1E, 0xD9FF43, 0x004700, 0x006C00, 0x009000, 0x24B400, 0x48D900, 0x6CFD05, 0x91FF29, 0xB5FF4E, 0x005500, 0x007900, 0x009D00, 0x03C200, 0x27E600, 0x4BFF17, 0x70FF3B, 0x94FF5F, 0x005F00, 0x008300, 0x00A800, 0x00CC00, 0x0AF00A, 0x2EFF2E, 0x53FF53, 0x77FF77, 0x006500, 0x008A00, 0x00AE00, 0x00D203, 0x00F727, 0x17FF4B, 0x3BFF70, 0x5FFF94, 0x006800, 0x008C00, 0x00B100, 0x00D524, 0x00F948, 0x05FF6C, 0x29FF91, 0x4EFFB5, 0x006600, 0x008B00, 0x00AF23, 0x00D447, 0x00F86C, 0x00FF90, 0x1EFFB5, 0x43FFD9, 0x006100, 0x008524, 0x00AA48, 0x00CE6D, 0x00F391, 0x00FFB6, 0x1BFFDA, 0x3FFFFE, 0x005825, 0x007C49, 0x00A16E, 0x00C592, 0x00EAB7, 0x00FFDB, 0x1EFFFF, 0x43FFFF, 0x004B49, 0x00706D, 0x009492, 0x00B9B6, 0x00DDDA, 0x05FFFF, 0x29FFFF, 0x4EFFFF, 0x003C6A, 0x00608E, 0x0085B3, 0x00A9D7, 0x00CEFB, 0x17F2FF, 0x3BFFFF, 0x5FFFFF, 0x002A87, 0x004FAB, 0x0073D0, 0x0097F4, 0x0ABCFF, 0x2EE0FF, 0x53FFFF, 0x77FFFF, 0x00179F, 0x003BC3, 0x0060E7, 0x0384FF, 0x27A8FF, 0x4BCDFF, 0x70F1FF, 0x94FFFF, 0x0002B0, 0x0027D5, 0x004BF9, 0x2470FF, 0x4894FF, 0x6CB9FF, 0x91DDFF, 0xB5FFFF, 0x0000BB, 0x0013E0, 0x2337FF, 0x475BFF, 0x6C80FF, 0x90A4FF, 0xB5C9FF, 0xD9EDFF]; // swap palette RGB to BGR -for (var i=0; i<256; i++) { +for (var i = 0; i < 256; i++) { var x = ASTROCADE_PALETTE[i]; ASTROCADE_PALETTE[i] = rgb2bgr(x) | 0xff000000; } diff --git a/src/platform/galaxian.ts b/src/platform/galaxian.ts index 8c11d7cf..29d28667 100644 --- a/src/platform/galaxian.ts +++ b/src/platform/galaxian.ts @@ -231,8 +231,8 @@ const _GalaxianPlatform = function(mainElement, options) { read: newAddressDecoder([ [0x0000, 0x3fff, 0, function(a) { return rom ? rom[a] : null; }], [0x4000, 0x47ff, 0x7ff, function(a) { return ram.mem[a]; }], - // [0x4800, 0x4fff, 0x3ff, function(a) { return vram.mem[a]; }], - // [0x5000, 0x5fff, 0xff, function(a) { return oram.mem[a]; }], + [0x4800, 0x4fff, 0x3ff, function(a) { return vram.mem[a]; }], + [0x5000, 0x5fff, 0xff, function(a) { return oram.mem[a]; }], [0x7000, 0x7000, 0, function(a) { watchdog_counter = INITIAL_WATCHDOG; }], [0x7800, 0x7800, 0, function(a) { watchdog_counter = INITIAL_WATCHDOG; }], //[0x8000, 0x820f, 0, function(a) { return noise(); }], // TODO: remove diff --git a/src/views.ts b/src/views.ts index 03b21250..c92cc62d 100644 --- a/src/views.ts +++ b/src/views.ts @@ -1041,12 +1041,12 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase { } getOpRGB(op:number) : number { switch (op) { - case ProbeFlags.EXECUTE: return 0x0f3f0f; - case ProbeFlags.MEM_READ: return 0x3f0101; - case ProbeFlags.MEM_WRITE: return 0x000f3f; - case ProbeFlags.IO_READ: return 0x001f01; - case ProbeFlags.IO_WRITE: return 0x003f3f; - case ProbeFlags.INTERRUPT: return 0x3f3f00; + case ProbeFlags.EXECUTE: return 0x0f3f0f; + case ProbeFlags.MEM_READ: return 0x3f0101; + case ProbeFlags.MEM_WRITE: return 0x010f3f; + case ProbeFlags.IO_READ: return 0x001f01; + case ProbeFlags.IO_WRITE: return 0x017f7f; + case ProbeFlags.INTERRUPT: return 0x3f3f00; default: return 0; } } @@ -1091,8 +1091,12 @@ export class RasterPCHeatMapView extends ProbeBitmapViewBase implements ProjectV drawEvent(op, addr, col, row) { // if (op != ProbeFlags.EXECUTE) return; var iofs = col + row * this.canvas.width; - var rgb = addr << 8; - this.datau32[iofs] = rgb | 0xff000000; + //var rgb = addr << 8; + var rgb = this.getOpRGB(op) << 1; + var data = this.datau32[iofs]; + rgb |= addr & 0x3f3f; + data = data | rgb | 0xff000000; + this.datau32[iofs] = data; } }