Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Clean up, timing based on clock rather than drawing as quickly as pos…

…sible, partitioned audio channels into dummy modules
  • Loading branch information...
commit 77b3a51cdb296c9eb55501318a89cbe7a3a0f475 1 parent e812690
@asterick authored
View
1  index.html
@@ -30,7 +30,6 @@
><li><a class='button' id="stop" href="javascript:void 0">Stop</a></li
><li><a class='button' id="reset" href="javascript:void 0">Reset</a></li
><li><a class='button' id="step" href="javascript:void 0">Step</a></li
- ><li><a class='button' id="frame" href="javascript:void 0">Frame</a></li
><li><a class='button' id="stop_predictions" href='javascript:void 0'>Disable predictions</a></li>
</ul>
View
172 src/chips/audio.js
@@ -1,172 +0,0 @@
-define([
- "chips/registers"
-], function (registers) {
- var BUFFER_LENGTH = 2048;
-
- function Audio(cpu) {
- this.cpu = cpu;
- this.wavetable = new Uint8Array(16);
-
- if (this.context) {
- this.node = this.context.createJavaScriptNode(BUFFER_LENGTH);
- this.node.onaudioprocess = this.$('process');
- }
- }
-
- Audio.prototype.clock = function (ticks) {
- };
-
- Audio.prototype.reset = function () {
- var self = this;
-
- this.NR50 = 0;
- this.NR51 = 0;
-
- function delegate(i) {
- self.cpu.registers.read[registers.AUD3WAVERAM0+i] = function () {
- return self.wavetable[i];
- };
- self.cpu.registers.write[registers.AUD3WAVERAM0+i] = function (d) {
- self.cpu.catchUp();
- self.wavetable[i] = d;
- };
- }
- for (var i = 0; i < 16; i++) { delegate(i); }
-
- this.cpu.registers.read[registers.NR10] = this.$('read_NR10');
- this.cpu.registers.read[registers.NR11] = this.$('read_NR11');
- this.cpu.registers.read[registers.NR12] = this.$('read_NR12');
- this.cpu.registers.read[registers.NR14] = this.$('read_NR14');
-
- this.cpu.registers.read[registers.NR21] = this.$('read_NR21');
- this.cpu.registers.read[registers.NR22] = this.$('read_NR22');
- this.cpu.registers.read[registers.NR24] = this.$('read_NR24');
-
- this.cpu.registers.read[registers.NR30] = this.$('read_NR30');
- this.cpu.registers.read[registers.NR31] = this.$('read_NR31');
- this.cpu.registers.read[registers.NR32] = this.$('read_NR32');
- this.cpu.registers.read[registers.NR34] = this.$('read_NR34');
-
- this.cpu.registers.read[registers.NR41] = this.$('read_NR41');
- this.cpu.registers.read[registers.NR42] = this.$('read_NR42');
- this.cpu.registers.read[registers.NR43] = this.$('read_NR43');
- this.cpu.registers.read[registers.NR44] = this.$('read_NR44');
-
- this.cpu.registers.read[registers.NR50] = this.$('read_NR50');
- this.cpu.registers.read[registers.NR51] = this.$('read_NR51');
- this.cpu.registers.read[registers.NR52] = this.$('read_NR52');
-
- this.cpu.registers.write[registers.NR10] = this.$('write_NR10');
- this.cpu.registers.write[registers.NR11] = this.$('write_NR11');
- this.cpu.registers.write[registers.NR12] = this.$('write_NR12');
- this.cpu.registers.write[registers.NR13] = this.$('write_NR13');
- this.cpu.registers.write[registers.NR14] = this.$('write_NR14');
-
- this.cpu.registers.write[registers.NR21] = this.$('write_NR21');
- this.cpu.registers.write[registers.NR22] = this.$('write_NR22');
- this.cpu.registers.write[registers.NR23] = this.$('write_NR23');
- this.cpu.registers.write[registers.NR24] = this.$('write_NR24');
-
- this.cpu.registers.write[registers.NR30] = this.$('write_NR30');
- this.cpu.registers.write[registers.NR31] = this.$('write_NR31');
- this.cpu.registers.write[registers.NR32] = this.$('write_NR32');
- this.cpu.registers.write[registers.NR33] = this.$('write_NR33');
- this.cpu.registers.write[registers.NR34] = this.$('write_NR34');
-
- this.cpu.registers.write[registers.NR41] = this.$('write_NR41');
- this.cpu.registers.write[registers.NR42] = this.$('write_NR42');
- this.cpu.registers.write[registers.NR43] = this.$('write_NR43');
- this.cpu.registers.write[registers.NR44] = this.$('write_NR44');
-
- this.cpu.registers.write[registers.NR50] = this.$('write_NR50');
- this.cpu.registers.write[registers.NR51] = this.$('write_NR51');
- this.cpu.registers.write[registers.NR52] = this.$('write_NR52');
- };
-
- // Don't assume audio is available,
- Audio.prototype.context =
- window.webkitAudioContext && (new webkitAudioContext());
-
- Audio.prototype.mute = function () {
- if (!this.node) { return ; }
-
- this.node.disconnect();
- };
-
- Audio.prototype.play = function () {
- if (!this.node) { return ; }
-
- this.node.connect(this.context.destination);
- };
-
- Audio.prototype.process = function (e) {
- var left = e.outputBuffer.getChannelData(0),
- right = e.outputBuffer.getChannelData(1),
- length = left.length;
-
- for (var i = 0; i < length; i++) { left[i] = right[i] = 0; }
- }
-
- // --- Register map
- Audio.prototype.write_NR10 = function (d) {};
- Audio.prototype.write_NR11 = function (d) {};
- Audio.prototype.write_NR12 = function (d) {};
- Audio.prototype.write_NR13 = function (d) {};
- Audio.prototype.write_NR14 = function (d) {};
-
- Audio.prototype.write_NR21 = function (d) {};
- Audio.prototype.write_NR22 = function (d) {};
- Audio.prototype.write_NR23 = function (d) {};
- Audio.prototype.write_NR24 = function (d) {};
-
- Audio.prototype.write_NR30 = function (d) {};
- Audio.prototype.write_NR31 = function (d) {};
- Audio.prototype.write_NR32 = function (d) {};
- Audio.prototype.write_NR33 = function (d) {};
- Audio.prototype.write_NR34 = function (d) {};
-
- Audio.prototype.write_NR41 = function (d) {};
- Audio.prototype.write_NR42 = function (d) {};
- Audio.prototype.write_NR43 = function (d) {};
- Audio.prototype.write_NR44 = function (d) {};
-
- Audio.prototype.read_NR10 = function () { return 0; };
- Audio.prototype.read_NR11 = function () { return 0; };
- Audio.prototype.read_NR12 = function () { return 0; };
- Audio.prototype.read_NR14 = function () { return 0; };
-
- Audio.prototype.read_NR21 = function () { return 0; };
- Audio.prototype.read_NR22 = function () { return 0; };
- Audio.prototype.read_NR24 = function () { return 0; };
-
- Audio.prototype.read_NR30 = function () { return 0; };
- Audio.prototype.read_NR31 = function () { return 0; };
- Audio.prototype.read_NR32 = function () { return 0; };
- Audio.prototype.read_NR34 = function () { return 0; };
-
- Audio.prototype.read_NR41 = function () { return 0; };
- Audio.prototype.read_NR42 = function () { return 0; };
- Audio.prototype.read_NR43 = function () { return 0; };
- Audio.prototype.read_NR44 = function () { return 0; };
-
- // --- Control registers
- Audio.prototype.write_NR50 = function (d) {
- this.NR50 = d;
- };
- Audio.prototype.write_NR51 = function (d) {
- this.NR51 = d;
- };
- Audio.prototype.write_NR52 = function (d) {
-
- };
-
- Audio.prototype.read_NR50 = function () {
- return this.NR50;
- };
- Audio.prototype.read_NR51 = function () {
- return this.NR51;
- };
- Audio.prototype.read_NR52 = function () { return 0; };
-
- return Audio;
-});
View
145 src/chips/audio/audio.js
@@ -0,0 +1,145 @@
+define([
+ "chips/registers",
+ "chips/audio/square",
+ "chips/audio/waveform",
+ "chips/audio/noise"
+], function (registers, SquareChannel, WaveformChannel, NoiseChannel) {
+ var BUFFER_LENGTH = 2048,
+ FRAME_COUNTER = 16384;
+
+ /*
+ 8 cycles between frequency steps
+ 4 cycles between wave table steps
+ 16 cycles between noise table steps
+ 32768 cycles between length checks
+ 65535 cycles between sweep counters
+ 131072 cycles between envelope checks
+
+ Frame counter period (16384 cycles)
+ */
+
+ function Audio(cpu) {
+ this.cpu = cpu;
+ this.square1 = new SquareChannel();
+ this.square2 = new SquareChannel();
+ this.waveform = new WaveformChannel();
+ this.noise = new NoiseChannel();
+
+ if (this.context) {
+ this.node = this.context.createJavaScriptNode(BUFFER_LENGTH);
+ this.node.onaudioprocess = this.$('process');
+ }
+ }
+
+ Audio.prototype.clock = function (ticks) {
+ };
+
+ Audio.prototype.reset = function () {
+ var self = this;
+
+ this.NR50 = 0;
+ this.NR51 = 0;
+
+ this.cpu.registers.read.copy(registers.AUD3WAVERAM0, this.waveform.wavetable.read);
+ this.cpu.registers.write.copy(registers.AUD3WAVERAM0, this.waveform.wavetable.write);
+
+ // --- Square register channels
+ this.cpu.registers.write[registers.NR10] = this.square1.$('write_sweep');
+ this.cpu.registers.write[registers.NR11] = this.square1.$('write_length');
+ this.cpu.registers.write[registers.NR12] = this.square1.$('write_volume');
+ this.cpu.registers.write[registers.NR13] = this.square1.$('write_freq_lo');
+ this.cpu.registers.write[registers.NR14] = this.square1.$('write_freq_hi');
+
+ this.cpu.registers.read[registers.NR10] = this.square1.$('read_sweep');
+ this.cpu.registers.read[registers.NR11] = this.square1.$('read_length');
+ this.cpu.registers.read[registers.NR12] = this.square1.$('read_volume');
+ this.cpu.registers.read[registers.NR14] = this.square1.$('read_freq_hi');
+
+ this.cpu.registers.write[registers.NR21] = this.square2.$('write_length');
+ this.cpu.registers.write[registers.NR22] = this.square2.$('write_volume');
+ this.cpu.registers.write[registers.NR23] = this.square2.$('write_freq_lo');
+ this.cpu.registers.write[registers.NR24] = this.square2.$('write_freq_hi');
+
+ this.cpu.registers.read[registers.NR21] = this.square2.$('read_length');
+ this.cpu.registers.read[registers.NR22] = this.square2.$('read_volume');
+ this.cpu.registers.read[registers.NR24] = this.square2.$('read_freq_hi');
+
+ // --- Waveform Channel
+ this.cpu.registers.write[registers.NR30] = this.waveform.$('write_enable');
+ this.cpu.registers.write[registers.NR31] = this.waveform.$('write_length');
+ this.cpu.registers.write[registers.NR32] = this.waveform.$('write_level');
+ this.cpu.registers.write[registers.NR33] = this.waveform.$('write_freq_lo');
+ this.cpu.registers.write[registers.NR34] = this.waveform.$('write_freq_hi');
+
+ this.cpu.registers.read[registers.NR30] = this.waveform.$('read_enable');
+ this.cpu.registers.read[registers.NR31] = this.waveform.$('read_length');
+ this.cpu.registers.read[registers.NR32] = this.waveform.$('read_level');
+ this.cpu.registers.read[registers.NR34] = this.waveform.$('read_freq_hi');
+
+ // --- Noise Channel
+ this.cpu.registers.write[registers.NR41] = this.noise.$('write_length');
+ this.cpu.registers.write[registers.NR42] = this.noise.$('write_volume');
+ this.cpu.registers.write[registers.NR43] = this.noise.$('write_poly');
+ this.cpu.registers.write[registers.NR44] = this.noise.$('write_control');
+
+ this.cpu.registers.read[registers.NR41] = this.noise.$('read_length');
+ this.cpu.registers.read[registers.NR42] = this.noise.$('read_volume');
+ this.cpu.registers.read[registers.NR43] = this.noise.$('read_poly');
+ this.cpu.registers.read[registers.NR44] = this.noise.$('read_control');
+
+ // --- Control registers
+ this.cpu.registers.write[registers.NR50] = this.$('write_NR50');
+ this.cpu.registers.write[registers.NR51] = this.$('write_NR51');
+ this.cpu.registers.write[registers.NR52] = this.$('write_NR52');
+
+ this.cpu.registers.read[registers.NR50] = this.$('read_NR50');
+ this.cpu.registers.read[registers.NR51] = this.$('read_NR51');
+ this.cpu.registers.read[registers.NR52] = this.$('read_NR52');
+ };
+
+ // Don't assume audio is available,
+ Audio.prototype.context =
+ window.webkitAudioContext && (new webkitAudioContext());
+
+ Audio.prototype.mute = function () {
+ if (!this.node) { return ; }
+
+ this.node.disconnect();
+ };
+
+ Audio.prototype.play = function () {
+ if (!this.node) { return ; }
+
+ this.node.connect(this.context.destination);
+ };
+
+ Audio.prototype.process = function (e) {
+ var left = e.outputBuffer.getChannelData(0),
+ right = e.outputBuffer.getChannelData(1),
+ length = left.length;
+
+ for (var i = 0; i < length; i++) { left[i] = right[i] = 0; }
+ }
+
+ // --- Control registers
+ Audio.prototype.write_NR50 = function (d) {
+ this.NR50 = d;
+ };
+ Audio.prototype.write_NR51 = function (d) {
+ this.NR51 = d;
+ };
+ Audio.prototype.write_NR52 = function (d) {
+ };
+
+ Audio.prototype.read_NR50 = function () {
+ return this.NR50;
+ };
+ Audio.prototype.read_NR51 = function () {
+ return this.NR51;
+ };
+ Audio.prototype.read_NR52 = function () {
+ return 0;
+ };
+
+ return Audio;
+});
View
35 src/chips/audio/noise.js
@@ -0,0 +1,35 @@
+define([], function () {
+ function NoiseChannel() {
+ this.wavetable = ramBlock(0x16);
+ }
+
+ NoiseChannel.prototype.reset = function () {
+ };
+
+ NoiseChannel.prototype.clock = function (ticks) {
+ };
+
+ // --- Registers
+ NoiseChannel.prototype.write_length = function (d) {
+ };
+ NoiseChannel.prototype.write_volume = function (d) {
+ };
+ NoiseChannel.prototype.write_poly = function (d) {
+ };
+ NoiseChannel.prototype.write_control = function (d) {
+ };
+ NoiseChannel.prototype.read_length = function () {
+ return 0;
+ };
+ NoiseChannel.prototype.read_volume = function () {
+ return 0;
+ };
+ NoiseChannel.prototype.read_poly = function () {
+ return 0;
+ };
+ NoiseChannel.prototype.read_control = function () {
+ return 0;
+ };
+
+ return NoiseChannel;
+});
View
37 src/chips/audio/square.js
@@ -0,0 +1,37 @@
+define([], function () {
+ function SquareChannel() {
+ }
+
+ SquareChannel.prototype.reset = function () {
+ };
+
+ SquareChannel.prototype.clock = function (ticks) {
+ };
+
+ // --- Registers
+ SquareChannel.prototype.write_sweep = function (d) {
+ };
+ SquareChannel.prototype.write_length = function (d) {
+ };
+ SquareChannel.prototype.write_volume = function (d) {
+ };
+ SquareChannel.prototype.write_freq_lo = function (d) {
+ };
+ SquareChannel.prototype.write_freq_hi = function (d) {
+ };
+
+ SquareChannel.prototype.read_sweep = function () {
+ return 0;
+ };
+ SquareChannel.prototype.read_length = function () {
+ return 0;
+ };
+ SquareChannel.prototype.read_volume = function () {
+ return 0;
+ };
+ SquareChannel.prototype.read_freq_hi = function () {
+ return 0;
+ };
+
+ return SquareChannel;
+});
View
37 src/chips/audio/waveform.js
@@ -0,0 +1,37 @@
+define([], function () {
+ function WaveformChannel() {
+ this.wavetable = ramBlock(0x16);
+ }
+
+ WaveformChannel.prototype.reset = function () {
+ };
+
+ WaveformChannel.prototype.clock = function (ticks) {
+ };
+
+ // --- Registers
+ WaveformChannel.prototype.write_enable = function (d) {
+ };
+ WaveformChannel.prototype.write_length = function (d) {
+ };
+ WaveformChannel.prototype.write_level = function (d) {
+ };
+ WaveformChannel.prototype.write_freq_lo = function (d) {
+ };
+ WaveformChannel.prototype.write_freq_hi = function (d) {
+ };
+ WaveformChannel.prototype.read_enable = function () {
+ return 0;
+ };
+ WaveformChannel.prototype.read_length = function () {
+ return 0;
+ };
+ WaveformChannel.prototype.read_level = function () {
+ return 0;
+ };
+ WaveformChannel.prototype.read_freq_hi = function () {
+ return 0;
+ };
+
+ return WaveformChannel;
+});
View
7 src/chips/core.js
@@ -4,7 +4,7 @@ define([
"chips/joypad",
"chips/bios",
"chips/video/gpu",
- "chips/audio",
+ "chips/audio/audio",
"chips/registers"
], function(Timer, WorkRam, Joypad, BIOS, GPU, Audio, registers) {
function CPU(context) {
@@ -218,10 +218,7 @@ define([
};
// --- Step the CPU to the next event point
- CPU.prototype.step = function () {
- // Try to run up to the end of the frame
- var frameCycles = this.gpu.predictEndOfFrame();
-
+ CPU.prototype.step = function (frameCycles) {
while( frameCycles > 0 )
{
var clockRate = this.doubleSpeed ? 4 : 8;
View
11 src/chips/video/gpu.js
@@ -97,13 +97,10 @@ define([
this.mode0IRQ = false;
this.write_VBK(0);
-
- for( var i = 0; i < 0xA0; i++ )
- {
- this.cpu.read[0xFE][i] = this.oamMemory.read[i];
- this.cpu.write[0xFE][i] = this.oamMemory.write[i];
- }
-
+
+ this.cpu.read[0xFE].copy(0, this.oamMemory.read);
+ this.cpu.write[0xFE].copy(0, this.oamMemory.write);
+
this.cpu.registers.write[registers.DMA] = this.$('write_DMA');
this.cpu.registers.read[registers.LCDC] = this.$('read_LCDC');
View
39 src/jsboy.js
@@ -7,23 +7,36 @@ define([
this.cpu = new CPU(context);
var running = false;
- Object.defineProperty(this, 'running', {
+ Object.defineProperty(jsboy.prototype, 'running', {
get: function () {
return running;
},
set: function (state) {
- if (this.running === state) { return ; }
+ if (running === state) { return ; }
+
+ var requestAnimationFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame,
+ lastTime = (new Date()).getTime(),
+ fraction = 0,
+ self = this;
if (running = state) {
- var requestAnimationFrame = window.requestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.msRequestAnimationFrame,
- self = this,
- nextFrame = function () {
- self.step();
- if (running) { requestAnimationFrame(nextFrame); }
- };
+ function nextFrame() {
+ if (!running) { return ; }
+
+ var nextTime = (new Date()).getTime(),
+ ticks = nextTime - lastTime,
+ advance = Math.min(150000, ticks * 8388.608 + fraction),
+ cycles = Math.floor(advance);
+
+ fraction = advance - cycles;
+ lastTime = nextTime;
+
+ requestAnimationFrame(nextFrame);
+ self.cpu.step(cycles);
+ };
requestAnimationFrame(nextFrame);
}
@@ -43,10 +56,6 @@ define([
this.cpu.close();
}
- jsboy.prototype.step = function () {
- this.cpu.step();
- }
-
jsboy.prototype.singleStep = function () {
this.cpu.singleStep();
}
View
4 src/main.js
@@ -143,10 +143,6 @@ requirejs([
runtime.singleStep();
update();
});
- $("#frame").click(function () {
- runtime.step();
- update();
- });
$("#stop_predictions").click(function () {
runtime.cpu.predictEvent = function () { return 0; };
});
View
5 src/util/helper.js
@@ -12,10 +12,7 @@ var TIMER = 4;
var RUMBLE = 8;
Object.prototype.$ = function (name) {
- var self = this,
- call = this[name];
-
- return function () { return call.apply(self,arguments); }
+ return this[name].bind(this);
};
function log (/*...*/) {
Please sign in to comment.
Something went wrong with that request. Please try again.