From c5e4622480a0e2f0e1b23255332ebfd37e4b2bb8 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Wed, 18 Jan 2017 12:08:15 -0500 Subject: [PATCH] AY-3-8910 example (konamisound) using tss library --- index.html | 6 ++ src/platform/galaxian.js | 2 +- src/platform/konamisound.js | 153 ++++++++++++++++++++++++++++++++++++ test/cli/testdecoder.js | 2 +- test/cli/worker.js | 107 ------------------------- test/cli/z80/z80test.js | 46 ++++++++--- 6 files changed, 196 insertions(+), 120 deletions(-) create mode 100644 src/platform/konamisound.js delete mode 100644 test/cli/worker.js diff --git a/index.html b/index.html index bf8271c6..31c70de9 100644 --- a/index.html +++ b/index.html @@ -273,6 +273,12 @@ canvas.pixelated { + + + + + + diff --git a/src/platform/galaxian.js b/src/platform/galaxian.js index 36d17f40..052afda9 100644 --- a/src/platform/galaxian.js +++ b/src/platform/galaxian.js @@ -12,7 +12,7 @@ var GalaxianPlatform = function(mainElement) { this.__proto__ = new BaseZ80Platform(); var cpu, ram, vram, oram, membus, iobus, rom, palette, outlatches; - var video, audio, timer, pixels, displayPCs; + var video, audio, timer, pixels; var inputs = [0xe,0x8,0x0]; var interruptEnabled = 0; var starsEnabled = 0; diff --git a/src/platform/konamisound.js b/src/platform/konamisound.js new file mode 100644 index 00000000..89fef5db --- /dev/null +++ b/src/platform/konamisound.js @@ -0,0 +1,153 @@ +"use strict"; +var KONAMISOUND_PRESETS = [ +]; + +// TODO: global??? +window.buildZ80({ + applyContention: false +}); + +var KonamiSoundPlatform = function(mainElement) { + var self = this; + this.__proto__ = new BaseZ80Platform(); + + var cpu, ram, rom, membus, iobus; + var audio, master; + var video, timer; + var interruptPending = 0; + var psgRegister = 0; + var psg; + + var cpuFrequency = 14318000/8; + var ioTimerFrequency = 1789750 / 1280; + var cpuCyclesPerFrame = cpuFrequency/60; + var cpuCyclesPerTimer = cpuFrequency/ioTimerFrequency; + + this.getPresets = function() { + return KONAMISOUND_PRESETS; + } + + this.start = function() { + ram = new RAM(0x400); + membus = { + read: new AddressDecoder([ + [0x0000, 0x3fff, 0x1fff, function(a) { return rom ? rom[a] : null; }], + [0x4000, 0x5fff, 0x3ff, function(a) { return ram.mem[a]; }] + ]), + write: new AddressDecoder([ + [0x4000, 0x5fff, 0x3ff, function(a,v) { ram.mem[a] = v; }], + [0x6000, 0x6fff, 0, function(a,v) { }], + ]), + isContended: function() { return false; }, + }; + iobus = { + read: function(addr) { + if (addr & 0x40) { + if (psgRegister == 0xf) { // timer + var bit = (cpu.getTstates() / cpuCyclesPerTimer) & 1; + return bit << 3; + } + return psg.readRegister(psgRegister) & 0xff; + } + return 0; + }, + write: function(addr, val) { + if (addr & 0x80) { + psgRegister = val & 0xf; + //console.log('PSG reg', psgRegister); + } + if (addr & 0x40) { + psg.writeRegisterAY(psgRegister, val & 0xff); + //console.log('PSG write', psgRegister, val); + } + } + }; + cpu = window.Z80({ + display: {}, + memory: membus, + ioBus: iobus + }); + psg = new PsgDeviceChannel(); + master = new MasterChannel(); + psg.setMode(PsgDeviceChannel.MODE_SIGNED); + psg.setDevice(PsgDeviceChannel.DEVICE_AY_3_8910); + master.addChannel(psg); + audio = new AudioLooper(512); + audio.setChannel(master); + //audio = new SampleAudio(psg.sampleRate); + video = new RasterVideo(mainElement,256,256); + video.create(); + video.setKeyboardEvents(function(key,code,flags) { + var intr = (key-49); + if (intr >= 0 && (flags & 1)) { + psg.writeRegister(14, intr); + psg.writeRegister(15, 0x80); + cpu.setIFF1(1); + cpu.requestInterrupt(0x38); + /* + console.log(cpu.saveState()); + console.log(hex(intr * 8), cpu.getIFF1(), cpu.getIM()); + cpu.runFrame(cpu.getTstates() + 1); + console.log(cpu.saveState()); + */ + } + }); + timer = new AnimationTimer(60, function() { + if (!self.isRunning()) + return; + var debugCond = self.getDebugCallback(); + var targetTstates = cpu.getTstates() + cpuCyclesPerFrame; + if (debugCond) { + while (cpu.getTstates() < targetTstates) { + if (debugCond && debugCond()) { debugCond = null; } + cpu.runFrame(cpu.getTstates() + 1); + } + } else { + cpu.runFrame(targetTstates); + } + }); + } + + this.loadROM = function(title, data) { + rom = padBytes(data, 0x4000); + cpu.reset(); + } + + this.loadState = function(state) { + cpu.loadState(state.c); + ram.mem.set(state.b); + } + this.saveState = function() { + return { + c:self.getCPUState(), + b:ram.mem.slice(0), + }; + } + this.getRAMForState = function(state) { + return ram.mem; + } + this.getCPUState = function() { + return cpu.saveState(); + } + + this.isRunning = function() { + return timer.isRunning(); + } + this.pause = function() { + timer.stop(); + //audio.stop(); + } + this.resume = function() { + timer.start(); + audio.activate(); + } + this.reset = function() { + cpu.reset(); + if (!this.getDebugCallback()) cpu.setTstates(0); // TODO? + } + this.readAddress = function(addr) { + return membus.read(addr); // TODO? + } +} + +PLATFORMS['konamisound'] = KonamiSoundPlatform; diff --git a/test/cli/testdecoder.js b/test/cli/testdecoder.js index 44308fa7..5c3c42ca 100644 --- a/test/cli/testdecoder.js +++ b/test/cli/testdecoder.js @@ -15,7 +15,7 @@ function assertEquals(a,b) { assert(a==b, a + " != " + b); } -describe('Test address decoder', function() { +describe('Address decoder', function() { it('Should work empty', function() { var decoder = new AddressDecoder([]); assertEquals(0, decoder(0x1234)); diff --git a/test/cli/worker.js b/test/cli/worker.js deleted file mode 100644 index a4c56c7f..00000000 --- a/test/cli/worker.js +++ /dev/null @@ -1,107 +0,0 @@ - -var assert = require('assert'); -var fs = require('fs'); -var vm = require('vm'); -var worker = {}; - -var includeInThisContext = function(path) { - var code = fs.readFileSync(path); - vm.runInThisContext(code, path); -}; - -global.importScripts = function(path) { - includeInThisContext('src/worker/'+path); -} - -function Blob(blob) { - this.size = blob.length; - this.length = blob.length; - this.slice = function(a,b) { - var data = blob.slice(a,b); - var b = new Blob(data); - //console.log(a, b, data.length, data.slice(0,64)); - //console.log(new Error().stack); - return b; - } - this.asArrayBuffer = function() { - var buf = new ArrayBuffer(blob.length); - var arr = new Uint8Array(buf); - for (var i=0; i\nint main() {\nint x=1;\nprintf("%d",x);\nreturn x+2;\n}', 'apple2', done, 2947, 4); - }); - it('should NOT assemble Z80ASM', function(done) { - compile('z80asm', 'ddwiuweq', 'none', done, 0, 0, 1); - }); - it('should assemble Z80ASM', function(done) { - compile('z80asm', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', 'spaceinv', done, 4, 2, 0); - }); - it('should NOT compile SDCC', function(done) { - compile('sdcc', 'foobar', 'spaceinv', done, 0, 0, 1); - }); - it('should assemble SDASZ80', function(done) { - compile('sdcc', '\tMODULE test\n\tXREF _puts\n\tld hl,$0000\n\tret\n', 'spaceinv', done, 8192, 2, 1); - }); - it('should compile SDCC', function(done) { - compile('sdcc', 'int foo=0;\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'spaceinv', done, 8192, 3, 0); - }); -}); diff --git a/test/cli/z80/z80test.js b/test/cli/z80/z80test.js index 1975968b..1ae33d8f 100644 --- a/test/cli/z80/z80test.js +++ b/test/cli/z80/z80test.js @@ -1,9 +1,10 @@ "use strict"; +global.window = global; + require('../../../src/cpu/z80.js'); var _global = window; - _global.buildZ80({ applyContention: true }); @@ -200,13 +201,36 @@ var testsIn = fs.readFileSync('test/cli/z80/tests.in', {encoding:'utf8'}).split( var testsExpected = fs.readFileSync('test/cli/z80/tests.expected', {encoding:'utf8'}).split('\n\n'); assert(testsIn.length == testsExpected.length); -describe('Z80 CPU', function() { - it('should execute test cases', function() { - for (var iter=0; iter