From 43f65b99aede520bdb01249622707b113fc379a8 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 24 Aug 2019 21:11:38 -0400 Subject: [PATCH] cleaned up galaxian platform --- src/platform/galaxian.ts | 634 ++++++++++++++++++++------------------- 1 file changed, 322 insertions(+), 312 deletions(-) diff --git a/src/platform/galaxian.ts b/src/platform/galaxian.ts index bba08b2d..8569ff2c 100644 --- a/src/platform/galaxian.ts +++ b/src/platform/galaxian.ts @@ -1,163 +1,143 @@ -"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 } from "../util"; import { MasterAudio, AY38910_Audio } from "../audio"; const GALAXIAN_PRESETS = [ - {id:'gfxtest.c', name:'Graphics Test'}, - {id:'shoot2.c', name:'Solarian Game'}, + { id: 'gfxtest.c', name: 'Graphics Test' }, + { id: 'shoot2.c', name: 'Solarian Game' }, ]; const GALAXIAN_KEYCODE_MAP = makeKeycodeMap([ - [Keys.A, 0, 0x10], // P1 - [Keys.LEFT, 0, 0x4], + [Keys.A, 0, 0x10], // P1 + [Keys.LEFT, 0, 0x4], [Keys.RIGHT, 0, 0x8], - [Keys.P2_A, 1, 0x10], // P2 - [Keys.P2_LEFT, 1, 0x4], + [Keys.P2_A, 1, 0x10], // P2 + [Keys.P2_LEFT, 1, 0x4], [Keys.P2_RIGHT, 1, 0x8], [Keys.SELECT, 0, 0x1], - [Keys.START, 1, 0x1], + [Keys.START, 1, 0x1], [Keys.VK_2, 1, 0x2], ]); const SCRAMBLE_KEYCODE_MAP = makeKeycodeMap([ - [Keys.UP, 0, -0x1], // P1 - [Keys.B, 0, -0x2], // fire - [Keys.VK_7, 0, -0x4], // credit - [Keys.A, 0, -0x8], // bomb - [Keys.RIGHT, 0, -0x10], - [Keys.LEFT, 0, -0x20], - [Keys.VK_6, 0, -0x40], - [Keys.SELECT, 0, -0x80], - [Keys.START, 1, -0x80], - [Keys.VK_2, 1, -0x40], - [Keys.DOWN, 2, -0x40], + [Keys.UP, 0, -0x1], // P1 + [Keys.B, 0, -0x2], // fire + [Keys.VK_7, 0, -0x4], // credit + [Keys.A, 0, -0x8], // bomb + [Keys.RIGHT, 0, -0x10], + [Keys.LEFT, 0, -0x20], + [Keys.VK_6, 0, -0x40], + [Keys.SELECT, 0, -0x80], + [Keys.START, 1, -0x80], + [Keys.VK_2, 1, -0x40], + [Keys.DOWN, 2, -0x40], //[Keys.VK_UP, 2, -0x10], ]); +const GalaxianVideo = function(rom:Uint8Array, vram:RAM, oram:RAM, palette:Uint32Array, options) { -const _GalaxianPlatform = function(mainElement, options) { - options = options || {}; - var romSize = options.romSize || 0x4000; var gfxBase = options.gfxBase || 0x2800; - var palBase = options.palBase || 0x3800; - var keyMap = options.keyMap || GALAXIAN_KEYCODE_MAP; - var missileWidth = options.missileWidth || 4; - var missileOffset = options.missileOffset || 0; - - var cpu; - var ram, vram, oram : RAM; - var membus, iobus, rom, palette, outlatches; - var video, audio, timer, pixels; - var psg1, psg2; - var inputs; - var interruptEnabled = 0; - var starsEnabled = 0; - var watchdog_counter; - var frameCounter = 0; - - var XTAL = 18432000.0; - var scanlinesPerFrame = 264; - var cpuFrequency = XTAL/6; // 3.072 MHz - var hsyncFrequency = XTAL/3/192/2; // 16 kHz - var vsyncFrequency = hsyncFrequency/132/2; // 60.606060 Hz - var vblankDuration = 1/vsyncFrequency * (20/132); // 2500 us - var cpuCyclesPerLine = cpuFrequency/hsyncFrequency; - var INITIAL_WATCHDOG = 8; - var showOffscreenObjects = false; + this.missileWidth = options.missileWidth || 4; + this.missileOffset = options.missileOffset || 0; + this.showOffscreenObjects = false; + this.frameCounter = 0; + this.starsEnabled = 0; var stars = []; - for (var i=0; i<256; i++) + for (var i = 0; i < 256; i++) stars[i] = noise(); - function drawScanline(pixels, sl) { - if (sl < 16 && !showOffscreenObjects) return; // offscreen - if (sl >= 240 && !showOffscreenObjects) return; // offscreen + this.advanceFrame = function() { + this.frameCounter = (this.frameCounter + 1) & 0xff; + } + + this.drawScanline = function(pixels, sl) { + if (sl < 16 && !this.showOffscreenObjects) return; // offscreen + if (sl >= 240 && !this.showOffscreenObjects) return; // offscreen // draw tiles - var pixofs = sl*264; - var outi = pixofs; // starting output pixel in frame buffer - for (var xx=0; xx<32; xx++) { + var pixofs = sl * 264; + var outi = pixofs; // starting output pixel in frame buffer + for (var xx = 0; xx < 32; xx++) { var xofs = xx; - var scroll = oram.mem[xofs*2]; // even entries control scroll position - var attrib = oram.mem[xofs*2+1]; // odd entries control the color base + var scroll = oram.mem[xofs * 2]; // even entries control scroll position + var attrib = oram.mem[xofs * 2 + 1]; // odd entries control the color base var sl2 = (sl + scroll) & 0xff; - var vramofs = (sl2>>3)<<5; // offset in VRAM + var vramofs = (sl2 >> 3) << 5; // offset in VRAM var yy = sl2 & 7; // y offset within tile - var tile = vram.mem[vramofs+xofs]; // TODO: why undefined? - var color0 = (attrib & 7) << 2; - var addr = gfxBase+(tile<<3)+yy; - var data1 = rom[addr]; - var data2 = rom[addr+0x800]; - for (var i=0; i<8; i++) { - var bm = 128>>i; - var color = color0 + ((data1&bm)?1:0) + ((data2&bm)?2:0); + var tile = vram.mem[vramofs + xofs]; // TODO: why undefined? + var color0 = (attrib & 7) << 2; + var addr = gfxBase + (tile << 3) + yy; + var data1 = rom[addr]; + var data2 = rom[addr + 0x800]; + for (var i = 0; i < 8; i++) { + var bm = 128 >> i; + var color = color0 + ((data1 & bm) ? 1 : 0) + ((data2 & bm) ? 2 : 0); pixels[outi] = palette[color]; outi++; } - } + } // draw sprites - for (var sprnum=7; sprnum>=0; sprnum--) { - var base = (sprnum<<2) + 0x40; + for (var sprnum = 7; sprnum >= 0; sprnum--) { + var base = (sprnum << 2) + 0x40; var base0 = oram.mem[base]; - var sy = 240 - (base0 - ((sprnum<3)?1:0)); // the first three sprites match against y-1 + var sy = 240 - (base0 - ((sprnum < 3) ? 1 : 0)); // the first three sprites match against y-1 var yy = (sl - sy); if (yy >= 0 && yy < 16) { - var sx = oram.mem[base+3] + 1; // +1 pixel offset from tiles - if (sx == 0 && !showOffscreenObjects) + var sx = oram.mem[base + 3] + 1; // +1 pixel offset from tiles + if (sx == 0 && !this.showOffscreenObjects) continue; // drawn off-buffer - var code = oram.mem[base+1]; + var code = oram.mem[base + 1]; var flipx = code & 0x40; // TODO: flipx if (code & 0x80) // flipy - yy = 15-yy; + yy = 15 - yy; code &= 0x3f; - var color0 = (oram.mem[base+2] & 7) << 2; - var color0 = 0; - var addr = gfxBase+(code<<5)+(yy<8?yy:yy+8); + var color0 = (oram.mem[base + 2] & 7) << 2; + var addr = gfxBase + (code << 5) + (yy < 8 ? yy : yy + 8); outi = pixofs + sx; //<< 1 var data1 = rom[addr]; - var data2 = rom[addr+0x800]; - for (var i=0; i<8; i++) { - var bm = 128>>i; - var color = ((data1&bm)?1:0) + ((data2&bm)?2:0); + var data2 = rom[addr + 0x800]; + for (var i = 0; i < 8; i++) { + var bm = 128 >> i; + var color = ((data1 & bm) ? 1 : 0) + ((data2 & bm) ? 2 : 0); if (color) - pixels[flipx?(outi+15-i):(outi+i)] = palette[color0 + color]; + pixels[flipx ? (outi + 15 - i) : (outi + i)] = palette[color0 + color]; } - var data1 = rom[addr+8]; - var data2 = rom[addr+0x808]; - for (var i=0; i<8; i++) { - var bm = 128>>i; - var color = ((data1&bm)?1:0) + ((data2&bm)?2:0); + var data1 = rom[addr + 8]; + var data2 = rom[addr + 0x808]; + for (var i = 0; i < 8; i++) { + var bm = 128 >> i; + var color = ((data1 & bm) ? 1 : 0) + ((data2 & bm) ? 2 : 0); if (color) - pixels[flipx?(outi+7-i):(outi+i+8)] = palette[color0 + color]; + pixels[flipx ? (outi + 7 - i) : (outi + i + 8)] = palette[color0 + color]; } } } // draw bullets/shells var shell = 0xff; var missile = 0xff; - for (var which=0; which<8; which++) { - var sy = oram.mem[0x60 + (which<<2)+1]; - if (((sy + sl - ((which<3)?1:0))&0xff) == 0xff) { + for (var which = 0; which < 8; which++) { + var sy = oram.mem[0x60 + (which << 2) + 1]; + if (((sy + sl - ((which < 3) ? 1 : 0)) & 0xff) == 0xff) { if (which != 7) shell = which; else missile = which; } } - for (var i=0; i<2; i++) { + for (var i = 0; i < 2; i++) { which = i ? missile : shell; if (which != 0xff) { - var sx = 255 - oram.mem[0x60 + (which<<2)+3]; - var outi = pixofs+sx-missileOffset; + var sx = 255 - oram.mem[0x60 + (which << 2) + 3]; + var outi = pixofs + sx - this.missileOffset; var col = which == 7 ? 0xffffff00 : 0xffffffff; - for (var j=0; j> 7) & 1; - return (bit << 5) | ((bit^1) << 7); - } - - const bitcolors = [ - 0x000021, 0x000047, 0x000097, // red - 0x002100, 0x004700, 0x009700, // green - 0x510000, 0xae0000 // blue - ]; - - class GalaxianPlatform extends BaseZ80Platform implements Platform { - - scanline : number; - poller; - - getPresets() { - return GALAXIAN_PRESETS; + return (bit << 5) | ((bit ^ 1) << 7); } - start() { - ram = new RAM(0x800); - vram = new RAM(0x400); - oram = new RAM(0x100); - outlatches = new RAM(0x8); - if (options.scramble) { - inputs = [0xff,0xfc,0xf1]; - membus = { - 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]; }], - [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 - [0x8100, 0x8100, 0, function(a) { return inputs[0]; }], - [0x8101, 0x8101, 0, function(a) { return inputs[1]; }], - [0x8102, 0x8102, 0, function(a) { return inputs[2] | scramble_protection_alt_r(); }], - [0x8202, 0x8202, 0, function(a) { return m_protection_result; }], // scramble (protection) - [0x9100, 0x9100, 0, function(a) { return inputs[0]; }], - [0x9101, 0x9101, 0, function(a) { return inputs[1]; }], - [0x9102, 0x9102, 0, function(a) { return inputs[2] | scramble_protection_alt_r(); }], - [0x9212, 0x9212, 0, function(a) { return m_protection_result; }], // scramble (protection) - //[0, 0xffff, 0, function(a) { console.log(hex(a)); return 0; }] - ]), - write: newAddressDecoder([ - [0x4000, 0x47ff, 0x7ff, function(a,v) { ram.mem[a] = v; }], - [0x4800, 0x4fff, 0x3ff, function(a,v) { vram.mem[a] = v; }], - [0x5000, 0x5fff, 0xff, function(a,v) { oram.mem[a] = v; }], - [0x6801, 0x6801, 0, function(a,v) { interruptEnabled = v & 1; /*console.log(a,v,cpu.getPC().toString(16));*/ }], - [0x6802, 0x6802, 0, function(a,v) { /* TODO: coin counter */ }], - [0x6803, 0x6803, 0, function(a,v) { /* TODO: backgroundColor = (v & 1) ? 0xFF000056 : 0xFF000000; */ }], - [0x6804, 0x6804, 0, function(a,v) { starsEnabled = v & 1; }], - [0x6808, 0x6808, 0, function(a,v) { missileWidth = v; }], // not on h/w - [0x6809, 0x6809, 0, function(a,v) { missileOffset = v; }], // not on h/w - [0x8202, 0x8202, 0, scramble_protection_w], - //[0x8100, 0x8103, 0, function(a,v){ /* PPI 0 */ }], - //[0x8200, 0x8203, 0, function(a,v){ /* PPI 1 */ }], - //[0, 0xffff, 0, function(a,v) { console.log(hex(a),hex(v)); }] - ]), - }; - } else { - inputs = [0xe,0x8,0x0]; - membus = { - read: newAddressDecoder([ - [0x0000, 0x3fff, 0, function(a) { return rom ? rom[a] : null; }], - [0x4000, 0x47ff, 0x3ff, function(a) { return ram.mem[a]; }], - [0x5000, 0x57ff, 0x3ff, function(a) { return vram.mem[a]; }], - [0x5800, 0x5fff, 0xff, function(a) { return oram.mem[a]; }], - [0x6000, 0x6000, 0, function(a) { return inputs[0]; }], - [0x6800, 0x6800, 0, function(a) { return inputs[1]; }], - [0x7000, 0x7000, 0, function(a) { return inputs[2]; }], - [0x7800, 0x7800, 0, function(a) { watchdog_counter = INITIAL_WATCHDOG; }], - ]), - write: newAddressDecoder([ - [0x4000, 0x47ff, 0x3ff, function(a,v) { ram.mem[a] = v; }], - [0x5000, 0x57ff, 0x3ff, function(a,v) { vram.mem[a] = v; }], - [0x5800, 0x5fff, 0xff, function(a,v) { oram.mem[a] = v; }], - //[0x6004, 0x6007, 0x3, function(a,v) { }], // lfo freq - //[0x6800, 0x6807, 0x7, function(a,v) { }], // sound - //[0x7800, 0x7800, 0x7, function(a,v) { }], // pitch - [0x6000, 0x6003, 0x3, function(a,v) { outlatches.mem[a] = v; }], - [0x7001, 0x7001, 0, function(a,v) { interruptEnabled = v & 1; }], - [0x7004, 0x7004, 0, function(a,v) { starsEnabled = v & 1; }], - ]), - isContended: function() { return false; }, - }; + const bitcolors = [ + 0x000021, 0x000047, 0x000097, // red + 0x002100, 0x004700, 0x009700, // green + 0x510000, 0xae0000 // blue + ]; + + class GalaxianPlatform extends BaseZ80Platform implements Platform { + + scanline: number; + poller; + + getPresets() { + return GALAXIAN_PRESETS; } - audio = new MasterAudio(); - psg1 = new AY38910_Audio(audio); - psg2 = new AY38910_Audio(audio); - iobus = { - read: function(addr) { - return 0; - }, - write: function(addr, val) { - if (addr & 0x1) { psg1.selectRegister(val & 0xf); }; - if (addr & 0x2) { psg1.setData(val); }; - if (addr & 0x4) { psg2.selectRegister(val & 0xf); }; - if (addr & 0x8) { psg2.setData(val); }; - } - }; - cpu = this.newCPU(membus, iobus); - video = new RasterVideo(mainElement,264,264,{rotate:90}); - video.create(); - var idata = video.getFrameData(); - this.poller = setKeyboardFromMap(video, inputs, keyMap); - pixels = video.getFrameData(); - timer = new AnimationTimer(60, this.nextFrame.bind(this)); - } - - pollControls() { this.poller.poll(); } - readAddress(a) { - return (a == 0x7000 || a == 0x7800) ? null : membus.read(a); // ignore watchdog - } - - advance(novideo : boolean) { - for (var sl=0; sl