mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-28 23:49:20 +00:00
working on z80 sound worker
This commit is contained in:
parent
94bf30fa7e
commit
e4e59d6c0d
@ -214,6 +214,7 @@ div.bitmap_editor {
|
|||||||
<li><a class="dropdown-item" href="?platform=galaxian-scramble" id="item_platform_galaxian_scramble">Galaxian/Scramble</a></li>
|
<li><a class="dropdown-item" href="?platform=galaxian-scramble" id="item_platform_galaxian_scramble">Galaxian/Scramble</a></li>
|
||||||
<li><a class="dropdown-item" href="?platform=vector-z80color" id="item_platform_vector_z80color">Atari Color Vector (Z80)</a></li>
|
<li><a class="dropdown-item" href="?platform=vector-z80color" id="item_platform_vector_z80color">Atari Color Vector (Z80)</a></li>
|
||||||
<li><a class="dropdown-item" href="?platform=williams-z80" id="item_platform_williams_z80">Williams (Z80)</a></li>
|
<li><a class="dropdown-item" href="?platform=williams-z80" id="item_platform_williams_z80">Williams (Z80)</a></li>
|
||||||
|
<li><a class="dropdown-item" href="?platform=sound_williams-z80" id="item_platform_sound_williams_z80">Williams Sound (Z80)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown dropdown-submenu">
|
<li class="dropdown dropdown-submenu">
|
||||||
@ -315,6 +316,7 @@ Dest: $<span id="bitmap_editor_dest">0000/0</span>
|
|||||||
<script src="octokat.js/dist/octokat.js"></script>
|
<script src="octokat.js/dist/octokat.js"></script>
|
||||||
|
|
||||||
<script src="src/emu.js"></script>
|
<script src="src/emu.js"></script>
|
||||||
|
<script src="src/audio.js"></script>
|
||||||
<script src="src/util.js"></script>
|
<script src="src/util.js"></script>
|
||||||
<script src="src/disasm.js"></script>
|
<script src="src/disasm.js"></script>
|
||||||
<script src="src/ui.js"></script>
|
<script src="src/ui.js"></script>
|
||||||
|
17
presets/sound_williams-z80/minimal.c
Normal file
17
presets/sound_williams-z80/minimal.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
const __sfr __at (0x0) command;
|
||||||
|
__sfr __at (0x0) dac;
|
||||||
|
|
||||||
|
#define HALT __asm halt __endasm;
|
||||||
|
|
||||||
|
// press "2" or higher to activate...
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
char i;
|
||||||
|
char j;
|
||||||
|
if (command == 0) HALT;
|
||||||
|
for (i=0; i<255; i++) {
|
||||||
|
for (j=0; j<i; j++) dac=j^i;
|
||||||
|
}
|
||||||
|
HALT;
|
||||||
|
}
|
17
presets/sound_williams-z80/skeleton.sdcc
Normal file
17
presets/sound_williams-z80/skeleton.sdcc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
const __sfr __at (0x0) command;
|
||||||
|
__sfr __at (0x0) dac;
|
||||||
|
|
||||||
|
#define HALT __asm halt __endasm;
|
||||||
|
|
||||||
|
// press "2" or higher to activate...
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
char i;
|
||||||
|
char j;
|
||||||
|
if (command == 0) HALT;
|
||||||
|
for (i=0; i<255; i++) {
|
||||||
|
for (j=0; j<i; j++) dac=j^i;
|
||||||
|
}
|
||||||
|
HALT;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
306
src/audio.js
Normal file
306
src/audio.js
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var MasterAudio = function() {
|
||||||
|
this.master = new MasterChannel();
|
||||||
|
this.start = function() {
|
||||||
|
this.looper = new AudioLooper(512);
|
||||||
|
this.looper.setChannel(this.master);
|
||||||
|
this.looper.activate();
|
||||||
|
}
|
||||||
|
this.stop = function() {
|
||||||
|
this.looper.setChannel(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var AY38910_Audio = function(master) {
|
||||||
|
this.psg = new PsgDeviceChannel();
|
||||||
|
this.psg.setMode(PsgDeviceChannel.MODE_SIGNED);
|
||||||
|
this.psg.setDevice(PsgDeviceChannel.DEVICE_AY_3_8910);
|
||||||
|
master.master.addChannel(this.psg);
|
||||||
|
var curreg = 0;
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
for (var i=15; i>=0; i--) {
|
||||||
|
this.selectRegister(i);
|
||||||
|
this.setData(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.selectRegister = function(val) {
|
||||||
|
curreg = val & 0xf;
|
||||||
|
}
|
||||||
|
this.setData = function(val) {
|
||||||
|
this.psg.writeRegisterAY(curreg, val & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/POKEY
|
||||||
|
// https://user.xmission.com/~trevin/atari/pokey_regs.html
|
||||||
|
// http://krap.pl/mirrorz/atari/homepage.ntlworld.com/kryten_droid/Atari/800XL/atari_hw/pokey.htm
|
||||||
|
|
||||||
|
var POKEYDeviceChannel = function() {
|
||||||
|
|
||||||
|
/* definitions for AUDCx (D201, D203, D205, D207) */
|
||||||
|
var NOTPOLY5 = 0x80 /* selects POLY5 or direct CLOCK */
|
||||||
|
var POLY4 = 0x40 /* selects POLY4 or POLY17 */
|
||||||
|
var PURE = 0x20 /* selects POLY4/17 or PURE tone */
|
||||||
|
var VOL_ONLY = 0x10 /* selects VOLUME OUTPUT ONLY */
|
||||||
|
var VOLUME_MASK = 0x0f /* volume mask */
|
||||||
|
|
||||||
|
/* definitions for AUDCTL (D208) */
|
||||||
|
var POLY9 = 0x80 /* selects POLY9 or POLY17 */
|
||||||
|
var CH1_179 = 0x40 /* selects 1.78979 MHz for Ch 1 */
|
||||||
|
var CH3_179 = 0x20 /* selects 1.78979 MHz for Ch 3 */
|
||||||
|
var CH1_CH2 = 0x10 /* clocks channel 1 w/channel 2 */
|
||||||
|
var CH3_CH4 = 0x08 /* clocks channel 3 w/channel 4 */
|
||||||
|
var CH1_FILTER = 0x04 /* selects channel 1 high pass filter */
|
||||||
|
var CH2_FILTER = 0x02 /* selects channel 2 high pass filter */
|
||||||
|
var CLOCK_15 = 0x01 /* selects 15.6999kHz or 63.9210kHz */
|
||||||
|
|
||||||
|
/* for accuracy, the 64kHz and 15kHz clocks are exact divisions of
|
||||||
|
the 1.79MHz clock */
|
||||||
|
var DIV_64 = 28 /* divisor for 1.79MHz clock to 64 kHz */
|
||||||
|
var DIV_15 = 114 /* divisor for 1.79MHz clock to 15 kHz */
|
||||||
|
|
||||||
|
/* the size (in entries) of the 4 polynomial tables */
|
||||||
|
var POLY4_SIZE = 0x000f
|
||||||
|
var POLY5_SIZE = 0x001f
|
||||||
|
var POLY9_SIZE = 0x01ff
|
||||||
|
|
||||||
|
var POLY17_SIZE = 0x0001ffff /* else use the full 17 bits */
|
||||||
|
|
||||||
|
/* channel/chip definitions */
|
||||||
|
var CHAN1 = 0
|
||||||
|
var CHAN2 = 1
|
||||||
|
var CHAN3 = 2
|
||||||
|
var CHAN4 = 3
|
||||||
|
var CHIP1 = 0
|
||||||
|
var CHIP2 = 4
|
||||||
|
var CHIP3 = 8
|
||||||
|
var CHIP4 = 12
|
||||||
|
var SAMPLE = 127
|
||||||
|
|
||||||
|
var FREQ_17_EXACT = 1789790.0 /* exact 1.79 MHz clock freq */
|
||||||
|
var FREQ_17_APPROX = 1787520.0 /* approximate 1.79 MHz clock freq */
|
||||||
|
|
||||||
|
// LFSR sequences
|
||||||
|
var bit1 = [ 0,1 ];
|
||||||
|
var bit4 = [ 1,1,0,1,1,1,0,0,0,0,1,0,1,0,0 ];
|
||||||
|
var bit5 = [ 0,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,1 ];
|
||||||
|
var bit17 = new Uint8Array(1<<17);
|
||||||
|
var bit17_5 = new Uint8Array(1<<17);
|
||||||
|
var bit5_4 = new Uint8Array(1<<17);
|
||||||
|
for (var i=0; i<bit17.length; i++) {
|
||||||
|
bit17[i] = Math.random() > 0.5;
|
||||||
|
bit17_5[i] = bit17[i] & bit5[i % bit5.length];
|
||||||
|
bit5_4[i] = bit5[i % bit5.length] & bit4[i % bit4.length];
|
||||||
|
}
|
||||||
|
var wavetones = [
|
||||||
|
bit17_5, bit5, bit5_4, bit5,
|
||||||
|
bit17, bit1, bit4, bit1
|
||||||
|
];
|
||||||
|
|
||||||
|
// registers
|
||||||
|
var regs = new Uint8Array(16);
|
||||||
|
var counters = new Float32Array(4);
|
||||||
|
var deltas = new Float32Array(4);
|
||||||
|
var volume = new Float32Array(4);
|
||||||
|
var audc = new Uint8Array(4);
|
||||||
|
var waveforms = [bit1, bit1, bit1, bit1];
|
||||||
|
var buffer;
|
||||||
|
var sampleRate;
|
||||||
|
var clock, baseDelta;
|
||||||
|
var dirty = true;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
this.setBufferLength = function (length) {
|
||||||
|
buffer = new Int32Array(length);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getBuffer = function () {
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setSampleRate = function (rate) {
|
||||||
|
sampleRate = rate;
|
||||||
|
baseDelta = FREQ_17_EXACT / rate / 1.2; // TODO?
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateValues(addr) {
|
||||||
|
var ctrl = regs[8];
|
||||||
|
var base = (ctrl & CLOCK_15) ? DIV_15 : DIV_64;
|
||||||
|
var div;
|
||||||
|
var i = addr & 4;
|
||||||
|
var j = i>>1;
|
||||||
|
var k = i>>2;
|
||||||
|
if (ctrl & (CH1_CH2>>k)) {
|
||||||
|
if (ctrl & (CH1_179>>k))
|
||||||
|
div = regs[i+2] * 256 + regs[i+0] + 7;
|
||||||
|
else
|
||||||
|
div = (regs[i+2] * 256 + regs[i+0] + 1) * base;
|
||||||
|
deltas[j+1] = baseDelta / div;
|
||||||
|
deltas[j+0] = 0;
|
||||||
|
} else {
|
||||||
|
if (ctrl & (CH1_179>>k)) {
|
||||||
|
div = regs[i+0] + 4;
|
||||||
|
} else {
|
||||||
|
div = (regs[i+0] + 1) * base;
|
||||||
|
}
|
||||||
|
deltas[j+0] = baseDelta / div;
|
||||||
|
div = (regs[i+2] + 1) * base;
|
||||||
|
deltas[j+1] = baseDelta / div;
|
||||||
|
}
|
||||||
|
//console.log(addr, ctrl.toString(16), div, deltas[j+0], deltas[j+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setRegister = function(addr, value) {
|
||||||
|
addr &= 0xf;
|
||||||
|
value &= 0xff;
|
||||||
|
if (regs[addr] != value) {
|
||||||
|
regs[addr] = value;
|
||||||
|
switch (addr) {
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 6: // AUDF
|
||||||
|
case 8: // ctrl
|
||||||
|
dirty = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 7: // AUDC
|
||||||
|
volume[addr>>1] = value & 0xf;
|
||||||
|
waveforms[addr>>1] = wavetones[value>>5];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.generate = function (length) {
|
||||||
|
if (dirty) {
|
||||||
|
updateValues(0);
|
||||||
|
updateValues(4);
|
||||||
|
dirty = false;
|
||||||
|
}
|
||||||
|
for (var s=0; s<length; s+=2) {
|
||||||
|
var sample = 0;
|
||||||
|
for (var i=0; i<4; i++) {
|
||||||
|
var d = deltas[i];
|
||||||
|
var v = volume[i];
|
||||||
|
if (d > 0 && d < 1 && v > 0) {
|
||||||
|
var wav = waveforms[i];
|
||||||
|
var cnt = counters[i] += d;
|
||||||
|
if (cnt > POLY17_SIZE+1) {
|
||||||
|
counters[i] -= POLY17_SIZE+1;
|
||||||
|
}
|
||||||
|
var on = wav[Math.floor(cnt % wav.length)];
|
||||||
|
if (on) {
|
||||||
|
sample += v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sample *= 273;
|
||||||
|
buffer[s] = sample;
|
||||||
|
buffer[s+1] = sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////// CPU sound (unused)
|
||||||
|
|
||||||
|
var CPUSoundChannel = function(cpu, clockRate) {
|
||||||
|
var sampleRate;
|
||||||
|
var buffer;
|
||||||
|
var lastbufpos=0;
|
||||||
|
var curSample=0;
|
||||||
|
var clocksPerSample;
|
||||||
|
|
||||||
|
this.setBufferLength = function (length) {
|
||||||
|
buffer = new Int32Array(length);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getBuffer = function () {
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setSampleRate = function (rate) {
|
||||||
|
sampleRate = rate;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getSetDACFunction = function() {
|
||||||
|
return function(a,v) {
|
||||||
|
var bufpos = Math.floor(cpu.getTstates() / clocksPerSample);
|
||||||
|
while (lastbufpos < bufpos)
|
||||||
|
buffer[lastbufpos++] = curSample;
|
||||||
|
lastbufpos = bufpos;
|
||||||
|
curSample = v;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.generate = function (length) {
|
||||||
|
clocksPerSample = clockRate * 1.0 / sampleRate;
|
||||||
|
var clocks = Math.round(length * clocksPerSample);
|
||||||
|
if (cpu.getTstates && cpu.runFrame) {
|
||||||
|
cpu.setTstates(0);
|
||||||
|
lastbufpos = 0;
|
||||||
|
cpu.runFrame(cpu.getTstates() + totalClocks);
|
||||||
|
while (lastbufpos < length)
|
||||||
|
buffer[lastbufpos++] = curSample;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
////// Worker sound
|
||||||
|
|
||||||
|
var WorkerSoundChannel = function(worker) {
|
||||||
|
var sampleRate;
|
||||||
|
var output;
|
||||||
|
var pending = [];
|
||||||
|
var pendingLength = 0;
|
||||||
|
|
||||||
|
worker.onmessage = function(e) {
|
||||||
|
if (e && e.data && e.data.samples && output) {
|
||||||
|
pending.push(e.data.samples);
|
||||||
|
pendingLength += e.data.samples.length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setBufferLength = function (length) {
|
||||||
|
output = new Int16Array(length);
|
||||||
|
//worker.postMessage({bufferLength:length,numChannels:2});
|
||||||
|
pendingLength = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getBuffer = function () {
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setSampleRate = function (rate) {
|
||||||
|
sampleRate = rate;
|
||||||
|
worker.postMessage({sampleRate:rate});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.generate = function (length) {
|
||||||
|
if (pendingLength < length*3) {
|
||||||
|
//console.log(length, pendingLength);
|
||||||
|
output.fill(0);
|
||||||
|
return; // TODO: send sync msg?
|
||||||
|
}
|
||||||
|
for (var i=0; i<output.length;) {
|
||||||
|
if (pending.length == 0) break; // TODO?
|
||||||
|
var buf = pending.shift();
|
||||||
|
pendingLength -= buf.length;
|
||||||
|
var l = output.length-i;
|
||||||
|
if (buf.length < l) {
|
||||||
|
output.set(buf, i);
|
||||||
|
} else {
|
||||||
|
output.set(buf.slice(0, l), i);
|
||||||
|
pending.unshift(buf.slice(l));
|
||||||
|
pendingLength += buf.length-l;
|
||||||
|
}
|
||||||
|
i += buf.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
src/audio/testz80worker.html
Normal file
4
src/audio/testz80worker.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<script>
|
||||||
|
var worker = new Worker("./z80worker.js");
|
||||||
|
worker.postMessage({});
|
||||||
|
</script>
|
163
src/audio/z80worker.js
Normal file
163
src/audio/z80worker.js
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
|
||||||
|
Midway/Williams Audio Boards
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
6809 MEMORY MAP
|
||||||
|
|
||||||
|
Function Address R/W Data
|
||||||
|
---------------------------------------------------------------
|
||||||
|
Program RAM 0000-07FF R/W D0-D7
|
||||||
|
|
||||||
|
Music (YM-2151) 2000-2001 R/W D0-D7
|
||||||
|
|
||||||
|
6821 PIA 4000-4003 R/W D0-D7
|
||||||
|
|
||||||
|
HC55516 clock low, digit latch 6000 W D0
|
||||||
|
HC55516 clock high 6800 W xx
|
||||||
|
|
||||||
|
Bank select 7800 W D0-D2
|
||||||
|
|
||||||
|
Banked Program ROM 8000-FFFF R D0-D7
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
var window = {};
|
||||||
|
|
||||||
|
importScripts("../emu.js");
|
||||||
|
importScripts("../cpu/z80.js");
|
||||||
|
|
||||||
|
window.buildZ80({
|
||||||
|
applyContention: false
|
||||||
|
});
|
||||||
|
|
||||||
|
var cpu, ram, rom, membus, iobus;
|
||||||
|
var audio;
|
||||||
|
var command = 0;
|
||||||
|
var dac = 0;
|
||||||
|
var current_buffer;
|
||||||
|
var last_tstate;
|
||||||
|
|
||||||
|
var timer;
|
||||||
|
var curTime;
|
||||||
|
var timerPeriod = 20;
|
||||||
|
var sampleRate;
|
||||||
|
var numChannels = 2;
|
||||||
|
var bufferLength;
|
||||||
|
|
||||||
|
var cpuFrequency = 18432000/6; // 3.072 MHz
|
||||||
|
var cpuCyclesPerFrame = cpuFrequency/60;
|
||||||
|
var cpuAudioFactor = 32;
|
||||||
|
|
||||||
|
|
||||||
|
function fillBuffer() {
|
||||||
|
var t = cpu.getTstates() / cpuAudioFactor;
|
||||||
|
while (last_tstate < t) {
|
||||||
|
current_buffer[last_tstate*2] = dac;
|
||||||
|
current_buffer[last_tstate*2+1] = dac;
|
||||||
|
last_tstate++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
ram = new RAM(0x400);
|
||||||
|
rom = [0xe,0x0,0x6,0x0,0x78,0xb9,0x30,0x06,0xa9,0xd3,0x00,0x04,0x18,0xf6,0x0c,0x79,0xd6,0xff,0x38,0xee,0x76,0x18,0xea]; // TODO
|
||||||
|
membus = {
|
||||||
|
read: new AddressDecoder([
|
||||||
|
[0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : null; }],
|
||||||
|
[0x4000, 0x5fff, 0xfff, function(a) { return ram.mem[a]; }]
|
||||||
|
]),
|
||||||
|
write: new AddressDecoder([
|
||||||
|
[0x4000, 0x5fff, 0xfff, function(a,v) { ram.mem[a] = v; }],
|
||||||
|
]),
|
||||||
|
isContended: function() { return false; },
|
||||||
|
};
|
||||||
|
iobus = {
|
||||||
|
read: function(addr) {
|
||||||
|
return command & 0xff;
|
||||||
|
},
|
||||||
|
write: function(addr, val) {
|
||||||
|
dac = (val & 0xff) << 8;
|
||||||
|
fillBuffer();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cpu = window.Z80({
|
||||||
|
display: {},
|
||||||
|
memory: membus,
|
||||||
|
ioBus: iobus
|
||||||
|
});
|
||||||
|
current_buffer = new Int16Array(bufferLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
function timerCallback() {
|
||||||
|
cpu.setTstates(0);
|
||||||
|
last_tstate = 0;
|
||||||
|
var numStates = Math.floor(bufferLength * cpuAudioFactor / numChannels);
|
||||||
|
cpu.runFrame(numStates);
|
||||||
|
//console.log(numStates, cpu.getTstates());
|
||||||
|
cpu.setTstates(numStates); // TODO?
|
||||||
|
fillBuffer();
|
||||||
|
postMessage({samples:current_buffer});
|
||||||
|
if (!cpu.getHalted()) {
|
||||||
|
curTime += timerPeriod;
|
||||||
|
var dt = curTime - new Date().getTime();
|
||||||
|
if (dt < 0) dt = 0;
|
||||||
|
timer = setTimeout(timerCallback, dt);
|
||||||
|
} else {
|
||||||
|
timer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
if (!bufferLength) return;
|
||||||
|
cpu.reset();
|
||||||
|
if (!timer) {
|
||||||
|
curTime = new Date().getTime() - timerPeriod*4;
|
||||||
|
timerCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onmessage = function(e) {
|
||||||
|
if (e && e.data) {
|
||||||
|
if (e.data.command) {
|
||||||
|
command = e.data.command & 0xff;
|
||||||
|
reset();
|
||||||
|
} else if (e.data.sampleRate) {
|
||||||
|
console.log(e.data);
|
||||||
|
sampleRate = e.data.sampleRate;
|
||||||
|
bufferLength = numChannels*sampleRate*timerPeriod/1000;
|
||||||
|
start();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
0000 56 _main::
|
||||||
|
57 ;<stdin>:10:
|
||||||
|
0000 0E 00 [ 7] 58 ld c,#0x00
|
||||||
|
59 ;<stdin>:11:
|
||||||
|
0002 60 00111$:
|
||||||
|
0002 06 00 [ 7] 61 ld b,#0x00
|
||||||
|
0004 62 00104$:
|
||||||
|
0004 78 [ 4] 63 ld a,b
|
||||||
|
0005 B9 [ 4] 64 cp a,c
|
||||||
|
0006 30 06 [12] 65 jr NC,00107$
|
||||||
|
0008 A9 [ 4] 66 xor a, c
|
||||||
|
0009 D3 00 [11] 67 out (_dac),a
|
||||||
|
000B 04 [ 4] 68 inc b
|
||||||
|
000C 18 F6 [12] 69 jr 00104$
|
||||||
|
000E 70 00107$:
|
||||||
|
71 ;<stdin>:10:
|
||||||
|
000E 0C [ 4] 72 inc c
|
||||||
|
000F 79 [ 4] 73 ld a,c
|
||||||
|
0010 D6 FF [ 7] 74 sub a, #0xff
|
||||||
|
0012 38 EE [12] 75 jr C,00111$
|
||||||
|
76 ;<stdin>:13:
|
||||||
|
0014 18 EA [12] 77 jr _main
|
||||||
|
|
||||||
|
**/
|
259
src/emu.js
259
src/emu.js
@ -248,15 +248,19 @@ var SampleAudio = function(clockfreq) {
|
|||||||
var m = this.module;
|
var m = this.module;
|
||||||
if (!m) m = ape.srcElement.module;
|
if (!m) m = ape.srcElement.module;
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
|
if (m.callback) {
|
||||||
|
m.callback(lbuf);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
var buf = bufferlist[1];
|
var buf = bufferlist[1];
|
||||||
for (var i=0; i<lbuf.length; i++) {
|
for (var i=0; i<lbuf.length; i++) {
|
||||||
lbuf[i] = buf[i];
|
lbuf[i] = buf[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createContext() {
|
function createContext() {
|
||||||
var AudioContext = AudioContext || webkitAudioContext || mozAudioContext;
|
var AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
|
||||||
if (! AudioContext) {
|
if (! AudioContext) {
|
||||||
console.log("no web audio context");
|
console.log("no web audio context");
|
||||||
return;
|
return;
|
||||||
@ -355,257 +359,6 @@ function cpuStateToLongString_6502(c) {
|
|||||||
+ " Y " + hex(c.Y) + " " + "SP " + hex(c.SP) + "\n";
|
+ " Y " + hex(c.Y) + " " + "SP " + hex(c.SP) + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
var MasterAudio = function() {
|
|
||||||
this.master = new MasterChannel();
|
|
||||||
this.start = function() {
|
|
||||||
this.looper = new AudioLooper(256);
|
|
||||||
this.looper.setChannel(this.master);
|
|
||||||
this.looper.activate();
|
|
||||||
}
|
|
||||||
this.stop = function() {
|
|
||||||
this.looper.setChannel(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var AY38910_Audio = function(master) {
|
|
||||||
this.psg = new PsgDeviceChannel();
|
|
||||||
this.psg.setMode(PsgDeviceChannel.MODE_SIGNED);
|
|
||||||
this.psg.setDevice(PsgDeviceChannel.DEVICE_AY_3_8910);
|
|
||||||
master.master.addChannel(this.psg);
|
|
||||||
var curreg = 0;
|
|
||||||
|
|
||||||
this.reset = function() {
|
|
||||||
for (var i=15; i>=0; i--) {
|
|
||||||
this.selectRegister(i);
|
|
||||||
this.setData(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.selectRegister = function(val) {
|
|
||||||
curreg = val & 0xf;
|
|
||||||
}
|
|
||||||
this.setData = function(val) {
|
|
||||||
this.psg.writeRegisterAY(curreg, val & 0xff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/POKEY
|
|
||||||
// https://user.xmission.com/~trevin/atari/pokey_regs.html
|
|
||||||
// http://krap.pl/mirrorz/atari/homepage.ntlworld.com/kryten_droid/Atari/800XL/atari_hw/pokey.htm
|
|
||||||
|
|
||||||
var POKEYDeviceChannel = function() {
|
|
||||||
|
|
||||||
/* definitions for AUDCx (D201, D203, D205, D207) */
|
|
||||||
var NOTPOLY5 = 0x80 /* selects POLY5 or direct CLOCK */
|
|
||||||
var POLY4 = 0x40 /* selects POLY4 or POLY17 */
|
|
||||||
var PURE = 0x20 /* selects POLY4/17 or PURE tone */
|
|
||||||
var VOL_ONLY = 0x10 /* selects VOLUME OUTPUT ONLY */
|
|
||||||
var VOLUME_MASK = 0x0f /* volume mask */
|
|
||||||
|
|
||||||
/* definitions for AUDCTL (D208) */
|
|
||||||
var POLY9 = 0x80 /* selects POLY9 or POLY17 */
|
|
||||||
var CH1_179 = 0x40 /* selects 1.78979 MHz for Ch 1 */
|
|
||||||
var CH3_179 = 0x20 /* selects 1.78979 MHz for Ch 3 */
|
|
||||||
var CH1_CH2 = 0x10 /* clocks channel 1 w/channel 2 */
|
|
||||||
var CH3_CH4 = 0x08 /* clocks channel 3 w/channel 4 */
|
|
||||||
var CH1_FILTER = 0x04 /* selects channel 1 high pass filter */
|
|
||||||
var CH2_FILTER = 0x02 /* selects channel 2 high pass filter */
|
|
||||||
var CLOCK_15 = 0x01 /* selects 15.6999kHz or 63.9210kHz */
|
|
||||||
|
|
||||||
/* for accuracy, the 64kHz and 15kHz clocks are exact divisions of
|
|
||||||
the 1.79MHz clock */
|
|
||||||
var DIV_64 = 28 /* divisor for 1.79MHz clock to 64 kHz */
|
|
||||||
var DIV_15 = 114 /* divisor for 1.79MHz clock to 15 kHz */
|
|
||||||
|
|
||||||
/* the size (in entries) of the 4 polynomial tables */
|
|
||||||
var POLY4_SIZE = 0x000f
|
|
||||||
var POLY5_SIZE = 0x001f
|
|
||||||
var POLY9_SIZE = 0x01ff
|
|
||||||
|
|
||||||
var POLY17_SIZE = 0x0001ffff /* else use the full 17 bits */
|
|
||||||
|
|
||||||
/* channel/chip definitions */
|
|
||||||
var CHAN1 = 0
|
|
||||||
var CHAN2 = 1
|
|
||||||
var CHAN3 = 2
|
|
||||||
var CHAN4 = 3
|
|
||||||
var CHIP1 = 0
|
|
||||||
var CHIP2 = 4
|
|
||||||
var CHIP3 = 8
|
|
||||||
var CHIP4 = 12
|
|
||||||
var SAMPLE = 127
|
|
||||||
|
|
||||||
var FREQ_17_EXACT = 1789790.0 /* exact 1.79 MHz clock freq */
|
|
||||||
var FREQ_17_APPROX = 1787520.0 /* approximate 1.79 MHz clock freq */
|
|
||||||
|
|
||||||
// LFSR sequences
|
|
||||||
var bit1 = [ 0,1 ];
|
|
||||||
var bit4 = [ 1,1,0,1,1,1,0,0,0,0,1,0,1,0,0 ];
|
|
||||||
var bit5 = [ 0,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,1 ];
|
|
||||||
var bit17 = new Uint8Array(1<<17);
|
|
||||||
var bit17_5 = new Uint8Array(1<<17);
|
|
||||||
var bit5_4 = new Uint8Array(1<<17);
|
|
||||||
for (var i=0; i<bit17.length; i++) {
|
|
||||||
bit17[i] = Math.random() > 0.5;
|
|
||||||
bit17_5[i] = bit17[i] & bit5[i % bit5.length];
|
|
||||||
bit5_4[i] = bit5[i % bit5.length] & bit4[i % bit4.length];
|
|
||||||
}
|
|
||||||
var wavetones = [
|
|
||||||
bit17_5, bit5, bit5_4, bit5,
|
|
||||||
bit17, bit1, bit4, bit1
|
|
||||||
];
|
|
||||||
|
|
||||||
// registers
|
|
||||||
var regs = new Uint8Array(16);
|
|
||||||
var counters = new Float32Array(4);
|
|
||||||
var deltas = new Float32Array(4);
|
|
||||||
var volume = new Float32Array(4);
|
|
||||||
var audc = new Uint8Array(4);
|
|
||||||
var waveforms = [bit1, bit1, bit1, bit1];
|
|
||||||
var buffer;
|
|
||||||
var sampleRate = 44100;
|
|
||||||
var clock, baseDelta;
|
|
||||||
var dirty = true;
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
this.setBufferLength = function (length) {
|
|
||||||
buffer = new Int32Array(length);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getBuffer = function () {
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setSampleRate = function (rate) {
|
|
||||||
sampleRate = rate;
|
|
||||||
baseDelta = FREQ_17_EXACT / rate / 1.2; // TODO?
|
|
||||||
};
|
|
||||||
|
|
||||||
function updateValues(addr) {
|
|
||||||
var ctrl = regs[8];
|
|
||||||
var base = (ctrl & CLOCK_15) ? DIV_15 : DIV_64;
|
|
||||||
var div;
|
|
||||||
var i = addr & 4;
|
|
||||||
var j = i>>1;
|
|
||||||
var k = i>>2;
|
|
||||||
if (ctrl & (CH1_CH2>>k)) {
|
|
||||||
if (ctrl & (CH1_179>>k))
|
|
||||||
div = regs[i+2] * 256 + regs[i+0] + 7;
|
|
||||||
else
|
|
||||||
div = (regs[i+2] * 256 + regs[i+0] + 1) * base;
|
|
||||||
deltas[j+1] = baseDelta / div;
|
|
||||||
deltas[j+0] = 0;
|
|
||||||
} else {
|
|
||||||
if (ctrl & (CH1_179>>k)) {
|
|
||||||
div = regs[i+0] + 4;
|
|
||||||
} else {
|
|
||||||
div = (regs[i+0] + 1) * base;
|
|
||||||
}
|
|
||||||
deltas[j+0] = baseDelta / div;
|
|
||||||
div = (regs[i+2] + 1) * base;
|
|
||||||
deltas[j+1] = baseDelta / div;
|
|
||||||
}
|
|
||||||
//console.log(addr, ctrl.toString(16), div, deltas[j+0], deltas[j+1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setRegister = function(addr, value) {
|
|
||||||
addr &= 0xf;
|
|
||||||
value &= 0xff;
|
|
||||||
if (regs[addr] != value) {
|
|
||||||
regs[addr] = value;
|
|
||||||
switch (addr) {
|
|
||||||
case 0:
|
|
||||||
case 2:
|
|
||||||
case 4:
|
|
||||||
case 6: // AUDF
|
|
||||||
case 8: // ctrl
|
|
||||||
dirty = true;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 3:
|
|
||||||
case 5:
|
|
||||||
case 7: // AUDC
|
|
||||||
volume[addr>>1] = value & 0xf;
|
|
||||||
waveforms[addr>>1] = wavetones[value>>5];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.generate = function (length) {
|
|
||||||
if (dirty) {
|
|
||||||
updateValues(0);
|
|
||||||
updateValues(4);
|
|
||||||
dirty = false;
|
|
||||||
}
|
|
||||||
for (var s=0; s<length; s+=2) {
|
|
||||||
var sample = 0;
|
|
||||||
for (var i=0; i<4; i++) {
|
|
||||||
var d = deltas[i];
|
|
||||||
var v = volume[i];
|
|
||||||
if (d > 0 && d < 1 && v > 0) {
|
|
||||||
var wav = waveforms[i];
|
|
||||||
var cnt = counters[i] += d;
|
|
||||||
if (cnt > POLY17_SIZE+1) {
|
|
||||||
counters[i] -= POLY17_SIZE+1;
|
|
||||||
}
|
|
||||||
var on = wav[Math.floor(cnt % wav.length)];
|
|
||||||
if (on) {
|
|
||||||
sample += v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sample *= 273;
|
|
||||||
buffer[s] = sample;
|
|
||||||
buffer[s+1] = sample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////// CPU sound
|
|
||||||
|
|
||||||
var CPUSoundChannel = function(cpu, clockRate) {
|
|
||||||
var sampleRate;
|
|
||||||
var buffer;
|
|
||||||
var lastbufpos=0;
|
|
||||||
var curSample=0;
|
|
||||||
var clocksPerSample;
|
|
||||||
|
|
||||||
this.setBufferLength = function (length) {
|
|
||||||
buffer = new Int32Array(length);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getBuffer = function () {
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setSampleRate = function (rate) {
|
|
||||||
sampleRate = rate;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getSetDACFunction = function() {
|
|
||||||
return function(a,v) {
|
|
||||||
var bufpos = Math.floor(cpu.getTstates() / clocksPerSample);
|
|
||||||
while (lastbufpos < bufpos)
|
|
||||||
buffer[lastbufpos++] = curSample;
|
|
||||||
lastbufpos = bufpos;
|
|
||||||
curSample = v;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
this.generate = function (length) {
|
|
||||||
clocksPerSample = clockRate * 1.0 / sampleRate;
|
|
||||||
var clocks = Math.round(length * clocksPerSample);
|
|
||||||
if (cpu.getTstates && cpu.runFrame) {
|
|
||||||
cpu.setTstates(0);
|
|
||||||
lastbufpos = 0;
|
|
||||||
cpu.runFrame(cpu.getTstates() + totalClocks);
|
|
||||||
while (lastbufpos < length)
|
|
||||||
buffer[lastbufpos++] = curSample;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
////// 6502
|
////// 6502
|
||||||
|
|
||||||
var Base6502Platform = function() {
|
var Base6502Platform = function() {
|
||||||
|
159
src/platform/sound_williams.js
Normal file
159
src/platform/sound_williams.js
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var WILLIAMS_SOUND_PRESETS = [
|
||||||
|
{id:'minimal.c', name:'Minimal Test'},
|
||||||
|
];
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
|
||||||
|
Midway/Williams Audio Boards
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
6809 MEMORY MAP
|
||||||
|
|
||||||
|
Function Address R/W Data
|
||||||
|
---------------------------------------------------------------
|
||||||
|
Program RAM 0000-07FF R/W D0-D7
|
||||||
|
|
||||||
|
Music (YM-2151) 2000-2001 R/W D0-D7
|
||||||
|
|
||||||
|
6821 PIA 4000-4003 R/W D0-D7
|
||||||
|
|
||||||
|
HC55516 clock low, digit latch 6000 W D0
|
||||||
|
HC55516 clock high 6800 W xx
|
||||||
|
|
||||||
|
Bank select 7800 W D0-D2
|
||||||
|
|
||||||
|
Banked Program ROM 8000-FFFF R D0-D7
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
var WilliamsSoundPlatform = function(mainElement) {
|
||||||
|
var self = this;
|
||||||
|
this.__proto__ = new BaseZ80Platform();
|
||||||
|
|
||||||
|
var cpu, ram, rom, membus, iobus;
|
||||||
|
var audio, master;
|
||||||
|
var video, timer;
|
||||||
|
var command = 0;
|
||||||
|
var dac = 0;
|
||||||
|
var dac_float = 0.0
|
||||||
|
var current_buffer;
|
||||||
|
var last_tstate;
|
||||||
|
var pixels;
|
||||||
|
|
||||||
|
var cpuFrequency = 18432000/6; // 3.072 MHz
|
||||||
|
var cpuCyclesPerFrame = cpuFrequency/60;
|
||||||
|
var cpuAudioFactor = 32;
|
||||||
|
|
||||||
|
function fillBuffer() {
|
||||||
|
var t = cpu.getTstates() / cpuAudioFactor;
|
||||||
|
while (last_tstate < t) {
|
||||||
|
current_buffer[last_tstate++] = dac_float;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getPresets = function() {
|
||||||
|
return WILLIAMS_SOUND_PRESETS;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.start = function() {
|
||||||
|
ram = new RAM(0x400);
|
||||||
|
membus = {
|
||||||
|
read: new AddressDecoder([
|
||||||
|
[0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : null; }],
|
||||||
|
[0x4000, 0x5fff, 0xfff, function(a) { return ram.mem[a]; }]
|
||||||
|
]),
|
||||||
|
write: new AddressDecoder([
|
||||||
|
[0x4000, 0x5fff, 0xfff, function(a,v) { ram.mem[a] = v; }],
|
||||||
|
]),
|
||||||
|
isContended: function() { return false; },
|
||||||
|
};
|
||||||
|
iobus = {
|
||||||
|
read: function(addr) {
|
||||||
|
return command & 0xff;
|
||||||
|
},
|
||||||
|
write: function(addr, val) {
|
||||||
|
dac = val & 0xff;
|
||||||
|
dac_float = ((dac & 0x80) ? -256+dac : dac) / 128.0;
|
||||||
|
fillBuffer();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cpu = window.Z80({
|
||||||
|
display: {},
|
||||||
|
memory: membus,
|
||||||
|
ioBus: iobus
|
||||||
|
});
|
||||||
|
audio = new SampleAudio(cpuFrequency / cpuAudioFactor);
|
||||||
|
audio.callback = function(lbuf) {
|
||||||
|
if (self.isRunning()) {
|
||||||
|
cpu.setTstates(0);
|
||||||
|
current_buffer = lbuf;
|
||||||
|
last_tstate = 0;
|
||||||
|
self.runCPU(cpu, lbuf.length * cpuAudioFactor);
|
||||||
|
cpu.setTstates(lbuf.length * cpuAudioFactor); // TODO?
|
||||||
|
fillBuffer();
|
||||||
|
for (var i=0; i<256; i++) {
|
||||||
|
var y = Math.round((current_buffer[i] * 127) + 128);
|
||||||
|
pixels[i + y*256] = 0xff33ff33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
video = new RasterVideo(mainElement,256,256);
|
||||||
|
video.create();
|
||||||
|
video.setKeyboardEvents(function(key,code,flags) {
|
||||||
|
var intr = (key-49);
|
||||||
|
if (intr >= 0 && (flags & 1)) {
|
||||||
|
command = intr & 0xff;
|
||||||
|
cpu.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
pixels = video.getFrameData();
|
||||||
|
timer = new AnimationTimer(30, function() {
|
||||||
|
if (self.isRunning()) {
|
||||||
|
video.updateFrame();
|
||||||
|
pixels.fill(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getCPUState = function() {
|
||||||
|
return cpu.saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRunning = function() {
|
||||||
|
return timer.isRunning();
|
||||||
|
}
|
||||||
|
this.pause = function() {
|
||||||
|
timer.stop();
|
||||||
|
audio.stop();
|
||||||
|
}
|
||||||
|
this.resume = function() {
|
||||||
|
timer.start();
|
||||||
|
audio.start();
|
||||||
|
}
|
||||||
|
this.reset = function() {
|
||||||
|
cpu.reset();
|
||||||
|
if (!this.getDebugCallback()) cpu.setTstates(0); // TODO?
|
||||||
|
}
|
||||||
|
this.readAddress = function(addr) {
|
||||||
|
return membus.read(addr); // TODO?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PLATFORMS['sound_williams-z80'] = WilliamsSoundPlatform;
|
@ -25,6 +25,8 @@ var WilliamsPlatform = function(mainElement, proto) {
|
|||||||
var membus, iobus;
|
var membus, iobus;
|
||||||
var video_counter;
|
var video_counter;
|
||||||
|
|
||||||
|
var audio, worker, workerchannel;
|
||||||
|
|
||||||
var xtal = 12000000;
|
var xtal = 12000000;
|
||||||
var cpuFrequency = xtal/3/4;
|
var cpuFrequency = xtal/3/4;
|
||||||
var cpuCyclesPerFrame = cpuFrequency/60; // TODO
|
var cpuCyclesPerFrame = cpuFrequency/60; // TODO
|
||||||
@ -126,8 +128,9 @@ var WilliamsPlatform = function(mainElement, proto) {
|
|||||||
|
|
||||||
var iowrite_williams = new AddressDecoder([
|
var iowrite_williams = new AddressDecoder([
|
||||||
[0x0, 0xf, 0xf, setPalette],
|
[0x0, 0xf, 0xf, setPalette],
|
||||||
[0x804, 0x807, 0x3, function(a,v) { console.log('iowrite',a); }], // TODO: sound
|
[0x803, 0x803, 0xf, function(a,v) { if (worker) worker.postMessage({command:v}); }],
|
||||||
[0x80c, 0x80f, 0x3, function(a,v) { console.log('iowrite',a+4); }], // TODO: sound
|
//[0x804, 0x807, 0x3, function(a,v) { console.log('iowrite',a); }], // TODO: sound
|
||||||
|
//[0x80c, 0x80f, 0x3, function(a,v) { console.log('iowrite',a+4); }], // TODO: sound
|
||||||
[0x900, 0x9ff, 0, function(a,v) { banksel = v & 0x1; }],
|
[0x900, 0x9ff, 0, function(a,v) { banksel = v & 0x1; }],
|
||||||
[0xa00, 0xa07, 0x7, setBlitter],
|
[0xa00, 0xa07, 0x7, setBlitter],
|
||||||
[0xbff, 0xbff, 0, function(a,v) { if (v == 0x39) watchdog_counter = INITIAL_WATCHDOG; }],
|
[0xbff, 0xbff, 0, function(a,v) { if (v == 0x39) watchdog_counter = INITIAL_WATCHDOG; }],
|
||||||
@ -275,6 +278,12 @@ var WilliamsPlatform = function(mainElement, proto) {
|
|||||||
write: memwrite_williams,
|
write: memwrite_williams,
|
||||||
};
|
};
|
||||||
cpu = self.newCPU(membus);
|
cpu = self.newCPU(membus);
|
||||||
|
|
||||||
|
audio = new MasterAudio();
|
||||||
|
worker = new Worker("./src/audio/z80worker.js");
|
||||||
|
workerchannel = new WorkerSoundChannel(worker);
|
||||||
|
audio.master.addChannel(workerchannel);
|
||||||
|
|
||||||
video = new RasterVideo(mainElement, SCREEN_WIDTH, SCREEN_HEIGHT, {rotate:-90});
|
video = new RasterVideo(mainElement, SCREEN_WIDTH, SCREEN_HEIGHT, {rotate:-90});
|
||||||
video.create();
|
video.create();
|
||||||
$(video.canvas).click(function(e) {
|
$(video.canvas).click(function(e) {
|
||||||
@ -354,9 +363,11 @@ var WilliamsPlatform = function(mainElement, proto) {
|
|||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
audio.stop();
|
||||||
}
|
}
|
||||||
this.resume = function() {
|
this.resume = function() {
|
||||||
timer.start();
|
timer.start();
|
||||||
|
audio.start();
|
||||||
}
|
}
|
||||||
this.reset = function() {
|
this.reset = function() {
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
|
@ -37,6 +37,12 @@ var PLATFORM_PARAMS = {
|
|||||||
data_start: 0xe000,
|
data_start: 0xe000,
|
||||||
data_size: 0x2000,
|
data_size: 0x2000,
|
||||||
},
|
},
|
||||||
|
'sound_williams-z80': {
|
||||||
|
code_start: 0x0,
|
||||||
|
code_size: 0x4000,
|
||||||
|
data_start: 0x4000,
|
||||||
|
data_size: 0x1000,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var loaded = {}
|
var loaded = {}
|
||||||
|
Loading…
Reference in New Issue
Block a user