function GameBoyAdvanceIO() { // Video this.DISPCNT = 0x000; this.GREENSWP = 0x002; this.DISPSTAT = 0x004; this.VCOUNT = 0x006; this.BG0CNT = 0x008; this.BG1CNT = 0x00A; this.BG2CNT = 0x00C; this.BG3CNT = 0x00E; this.BG0HOFS = 0x010; this.BG0VOFS = 0x012; this.BG1HOFS = 0x014; this.BG1VOFS = 0x016; this.BG2HOFS = 0x018; this.BG2VOFS = 0x01A; this.BG3HOFS = 0x01C; this.BG3VOFS = 0x01E; this.BG2PA = 0x020; this.BG2PB = 0x022; this.BG2PC = 0x024; this.BG2PD = 0x026; this.BG2X_LO = 0x028; this.BG2X_HI = 0x02A; this.BG2Y_LO = 0x02C; this.BG2Y_HI = 0x02E; this.BG3PA = 0x030; this.BG3PB = 0x032; this.BG3PC = 0x034; this.BG3PD = 0x036; this.BG3X_LO = 0x038; this.BG3X_HI = 0x03A; this.BG3Y_LO = 0x03C; this.BG3Y_HI = 0x03E; this.WIN0H = 0x040; this.WIN1H = 0x042; this.WIN0V = 0x044; this.WIN1V = 0x046; this.WININ = 0x048; this.WINOUT = 0x04A; this.MOSAIC = 0x04C; this.BLDCNT = 0x050; this.BLDALPHA = 0x052; this.BLDY = 0x054; // Sound this.SOUND1CNT_LO = 0x060; this.SOUND1CNT_HI = 0x062; this.SOUND1CNT_X = 0x064; this.SOUND2CNT_LO = 0x068; this.SOUND2CNT_HI = 0x06C; this.SOUND3CNT_LO = 0x070; this.SOUND3CNT_HI = 0x072; this.SOUND3CNT_X = 0x074; this.SOUND4CNT_LO = 0x078; this.SOUND4CNT_HI = 0x07C; this.SOUNDCNT_LO = 0x080; this.SOUNDCNT_HI = 0x082; this.SOUNDCNT_X = 0x084; this.SOUNDBIAS = 0x088; this.WAVE_RAM0_LO = 0x090; this.WAVE_RAM0_HI = 0x092; this.WAVE_RAM1_LO = 0x094; this.WAVE_RAM1_HI = 0x096; this.WAVE_RAM2_LO = 0x098; this.WAVE_RAM2_HI = 0x09A; this.WAVE_RAM3_LO = 0x09C; this.WAVE_RAM3_HI = 0x09E; this.FIFO_A_LO = 0x0A0; this.FIFO_A_HI = 0x0A2; this.FIFO_B_LO = 0x0A4; this.FIFO_B_HI = 0x0A6; // DMA this.DMA0SAD_LO = 0x0B0; this.DMA0SAD_HI = 0x0B2; this.DMA0DAD_LO = 0x0B4; this.DMA0DAD_HI = 0x0B6; this.DMA0CNT_LO = 0x0B8; this.DMA0CNT_HI = 0x0BA; this.DMA1SAD_LO = 0x0BC; this.DMA1SAD_HI = 0x0BE; this.DMA1DAD_LO = 0x0C0; this.DMA1DAD_HI = 0x0C2; this.DMA1CNT_LO = 0x0C4; this.DMA1CNT_HI = 0x0C6; this.DMA2SAD_LO = 0x0C8; this.DMA2SAD_HI = 0x0CA; this.DMA2DAD_LO = 0x0CC; this.DMA2DAD_HI = 0x0CE; this.DMA2CNT_LO = 0x0D0; this.DMA2CNT_HI = 0x0D2; this.DMA3SAD_LO = 0x0D4; this.DMA3SAD_HI = 0x0D6; this.DMA3DAD_LO = 0x0D8; this.DMA3DAD_HI = 0x0DA; this.DMA3CNT_LO = 0x0DC; this.DMA3CNT_HI = 0x0DE; // Timers this.TM0CNT_LO = 0x100; this.TM0CNT_HI = 0x102; this.TM1CNT_LO = 0x104; this.TM1CNT_HI = 0x106; this.TM2CNT_LO = 0x108; this.TM2CNT_HI = 0x10A; this.TM3CNT_LO = 0x10C; this.TM3CNT_HI = 0x10E; // SIO (note: some of these are repeated) this.SIODATA32_LO = 0x120; this.SIOMULTI0 = 0x120; this.SIODATA32_HI = 0x122; this.SIOMULTI1 = 0x122; this.SIOMULTI2 = 0x124; this.SIOMULTI3 = 0x126; this.SIOCNT = 0x128; this.SIOMLT_SEND = 0x12A; this.SIODATA8 = 0x12A; this.RCNT = 0x134; this.JOYCNT = 0x140; this.JOY_RECV = 0x150; this.JOY_TRANS = 0x154; this.JOYSTAT = 0x158; // Keypad this.KEYINPUT = 0x130; this.KEYCNT = 0x132; // Interrupts, etc this.IE = 0x200; this.IF = 0x202; this.WAITCNT = 0x204; this.IME = 0x208; this.POSTFLG = 0x300; this.HALTCNT = 0x301; this.DEFAULT_DISPCNT = 0x0080; this.DEFAULT_SOUNDBIAS = 0x200; this.DEFAULT_BGPA = 1; this.DEFAULT_BGPD = 1; this.DEFAULT_RCNT = 0x8000; }; GameBoyAdvanceIO.prototype.clear = function() { this.registers = new Uint16Array(this.cpu.mmu.SIZE_IO); this.registers[this.DISPCNT >> 1] = this.DEFAULT_DISPCNT; this.registers[this.SOUNDBIAS >> 1] = this.DEFAULT_SOUNDBIAS; this.registers[this.BG2PA >> 1] = this.DEFAULT_BGPA; this.registers[this.BG2PD >> 1] = this.DEFAULT_BGPD; this.registers[this.BG3PA >> 1] = this.DEFAULT_BGPA; this.registers[this.BG3PD >> 1] = this.DEFAULT_BGPD; this.registers[this.RCNT >> 1] = this.DEFAULT_RCNT; }; GameBoyAdvanceIO.prototype.freeze = function() { return { 'registers': Serializer.prefix(this.registers.buffer) }; }; GameBoyAdvanceIO.prototype.defrost = function(frost) { this.registers = new Uint16Array(frost.registers); // Video registers don't serialize themselves // 将背景和背景类似的layer数据写回 for (var i = 0; i < this.registers.length; i += 2 ) { this.store16(i, this.registers[i >> 1]); } }; GameBoyAdvanceIO.prototype.load8 = function(offset) { throw 'Unimplmeneted unaligned I/O access'; } GameBoyAdvanceIO.prototype.load16 = function(offset) { return (this.loadU16(offset) << 16) >> 16; } GameBoyAdvanceIO.prototype.load32 = function(offset) { offset &= 0xFFFFFFFC; switch (offset) { case this.DMA0CNT_LO: case this.DMA1CNT_LO: case this.DMA2CNT_LO: case this.DMA3CNT_LO: return this.loadU16(offset | 2) << 16; case this.IME: return this.loadU16(offset) & 0xFFFF; case this.JOY_RECV: case this.JOY_TRANS: this.core.STUB('Unimplemented JOY register read: 0x' + offset.toString(16)); return 0; } return this.loadU16(offset) | (this.loadU16(offset | 2) << 16); }; GameBoyAdvanceIO.prototype.loadU8 = function(offset) { var odd = offset & 0x0001; var value = this.loadU16(offset & 0xFFFE); return (value >>> (odd << 3)) & 0xFF; } GameBoyAdvanceIO.prototype.loadU16 = function(offset) { switch (offset) { case this.DISPCNT: case this.BG0CNT: case this.BG1CNT: case this.BG2CNT: case this.BG3CNT: case this.WININ: case this.WINOUT: case this.SOUND1CNT_LO: case this.SOUND3CNT_LO: case this.SOUNDCNT_LO: case this.SOUNDCNT_HI: case this.SOUNDBIAS: case this.BLDCNT: case this.BLDALPHA: case this.TM0CNT_HI: case this.TM1CNT_HI: case this.TM2CNT_HI: case this.TM3CNT_HI: case this.DMA0CNT_HI: case this.DMA1CNT_HI: case this.DMA2CNT_HI: case this.DMA3CNT_HI: case this.RCNT: case this.WAITCNT: case this.IE: case this.IF: case this.IME: case this.POSTFLG: // Handled transparently by the written registers break; // Video case this.DISPSTAT: return this.registers[offset >> 1] | this.video.readDisplayStat(); case this.VCOUNT: return this.video.vcount; // Sound case this.SOUND1CNT_HI: case this.SOUND2CNT_LO: return this.registers[offset >> 1] & 0xFFC0; case this.SOUND1CNT_X: case this.SOUND2CNT_HI: case this.SOUND3CNT_X: return this.registers[offset >> 1] & 0x4000; case this.SOUND3CNT_HI: return this.registers[offset >> 1] & 0xE000; case this.SOUND4CNT_LO: return this.registers[offset >> 1] & 0xFF00; case this.SOUND4CNT_HI: return this.registers[offset >> 1] & 0x40FF; case this.SOUNDCNT_X: this.core.STUB('Unimplemented sound register read: SOUNDCNT_X'); return this.registers[offset >> 1] | 0x0000; // Timers case this.TM0CNT_LO: return this.cpu.irq.timerRead(0); case this.TM1CNT_LO: return this.cpu.irq.timerRead(1); case this.TM2CNT_LO: return this.cpu.irq.timerRead(2); case this.TM3CNT_LO: return this.cpu.irq.timerRead(3); // SIO case this.SIOCNT: return this.sio.readSIOCNT(); case this.KEYINPUT: this.keypad.pollGamepads(); return this.keypad.currentDown; case this.KEYCNT: this.core.STUB('Unimplemented I/O register read: KEYCNT'); return 0; case this.BG0HOFS: case this.BG0VOFS: case this.BG1HOFS: case this.BG1VOFS: case this.BG2HOFS: case this.BG2VOFS: case this.BG3HOFS: case this.BG3VOFS: case this.BG2PA: case this.BG2PB: case this.BG2PC: case this.BG2PD: case this.BG3PA: case this.BG3PB: case this.BG3PC: case this.BG3PD: case this.BG2X_LO: case this.BG2X_HI: case this.BG2Y_LO: case this.BG2Y_HI: case this.BG3X_LO: case this.BG3X_HI: case this.BG3Y_LO: case this.BG3Y_HI: case this.WIN0H: case this.WIN1H: case this.WIN0V: case this.WIN1V: case this.BLDY: case this.DMA0SAD_LO: case this.DMA0SAD_HI: case this.DMA0DAD_LO: case this.DMA0DAD_HI: case this.DMA0CNT_LO: case this.DMA1SAD_LO: case this.DMA1SAD_HI: case this.DMA1DAD_LO: case this.DMA1DAD_HI: case this.DMA1CNT_LO: case this.DMA2SAD_LO: case this.DMA2SAD_HI: case this.DMA2DAD_LO: case this.DMA2DAD_HI: case this.DMA2CNT_LO: case this.DMA3SAD_LO: case this.DMA3SAD_HI: case this.DMA3DAD_LO: case this.DMA3DAD_HI: case this.DMA3CNT_LO: case this.FIFO_A_LO: case this.FIFO_A_HI: case this.FIFO_B_LO: case this.FIFO_B_HI: this.core.WARN('Read for write-only register: 0x' + offset.toString(16)); return this.core.mmu.badMemory.loadU16(0); case this.MOSAIC: this.core.WARN('Read for write-only register: 0x' + offset.toString(16)); return 0; case this.SIOMULTI0: case this.SIOMULTI1: case this.SIOMULTI2: case this.SIOMULTI3: return this.sio.read((offset - this.SIOMULTI0) >> 1); case this.SIODATA8: this.core.STUB('Unimplemented SIO register read: 0x' + offset.toString(16)); return 0; case this.JOYCNT: case this.JOYSTAT: this.core.STUB('Unimplemented JOY register read: 0x' + offset.toString(16)); return 0; default: this.core.WARN('Bad I/O register read: 0x' + offset.toString(16)); return this.core.mmu.badMemory.loadU16(0); } return this.registers[offset >> 1]; }; GameBoyAdvanceIO.prototype.store8 = function(offset, value) { switch (offset) { case this.WININ: this.value & 0x3F; break; case this.WININ | 1: this.value & 0x3F; break; case this.WINOUT: this.value & 0x3F; break; case this.WINOUT | 1: this.value & 0x3F; break; case this.SOUND1CNT_LO: case this.SOUND1CNT_LO | 1: case this.SOUND1CNT_HI: case this.SOUND1CNT_HI | 1: case this.SOUND1CNT_X: case this.SOUND1CNT_X | 1: case this.SOUND2CNT_LO: case this.SOUND2CNT_LO | 1: case this.SOUND2CNT_HI: case this.SOUND2CNT_HI | 1: case this.SOUND3CNT_LO: case this.SOUND3CNT_LO | 1: case this.SOUND3CNT_HI: case this.SOUND3CNT_HI | 1: case this.SOUND3CNT_X: case this.SOUND3CNT_X | 1: case this.SOUND4CNT_LO: case this.SOUND4CNT_LO | 1: case this.SOUND4CNT_HI: case this.SOUND4CNT_HI | 1: case this.SOUNDCNT_LO: case this.SOUNDCNT_LO | 1: case this.SOUNDCNT_X: case this.IF: case this.IME: break; case this.SOUNDBIAS | 1: this.STUB_REG('sound', offset); break; case this.HALTCNT: value &= 0x80; if (!value) { this.core.irq.halt(); } else { this.core.STUB('Stop'); } return; default: this.STUB_REG('8-bit I/O', offset); break; } if (offset & 1) { value <<= 8; value |= (this.registers[offset >> 1] & 0x00FF); } else { value &= 0x00FF; value |= (this.registers[offset >> 1] & 0xFF00); } this.store16(offset & 0xFFFFFFE, value); }; GameBoyAdvanceIO.prototype.store16 = function(offset, value) { // console.log('GameBoyAdvanceIO store16', offset, value); switch (offset) { // Video case this.DISPCNT: this.video.renderPath.writeDisplayControl(value); break; case this.DISPSTAT: value &= this.video.DISPSTAT_MASK; this.video.writeDisplayStat(value); break; case this.BG0CNT: this.video.renderPath.writeBackgroundControl(0, value); break; case this.BG1CNT: this.video.renderPath.writeBackgroundControl(1, value); break; case this.BG2CNT: this.video.renderPath.writeBackgroundControl(2, value); break; case this.BG3CNT: this.video.renderPath.writeBackgroundControl(3, value); break; case this.BG0HOFS: this.video.renderPath.writeBackgroundHOffset(0, value); break; case this.BG0VOFS: this.video.renderPath.writeBackgroundVOffset(0, value); break; case this.BG1HOFS: this.video.renderPath.writeBackgroundHOffset(1, value); break; case this.BG1VOFS: this.video.renderPath.writeBackgroundVOffset(1, value); break; case this.BG2HOFS: this.video.renderPath.writeBackgroundHOffset(2, value); break; case this.BG2VOFS: this.video.renderPath.writeBackgroundVOffset(2, value); break; case this.BG3HOFS: this.video.renderPath.writeBackgroundHOffset(3, value); break; case this.BG3VOFS: this.video.renderPath.writeBackgroundVOffset(3, value); break; case this.BG2X_LO: this.video.renderPath.writeBackgroundRefX(2, (this.registers[(offset >> 1) | 1] << 16) | value); break; case this.BG2X_HI: this.video.renderPath.writeBackgroundRefX(2, this.registers[(offset >> 1) ^ 1] | (value << 16)); break; case this.BG2Y_LO: this.video.renderPath.writeBackgroundRefY(2, (this.registers[(offset >> 1) | 1] << 16) | value); break; case this.BG2Y_HI: this.video.renderPath.writeBackgroundRefY(2, this.registers[(offset >> 1) ^ 1] | (value << 16)); break; case this.BG2PA: this.video.renderPath.writeBackgroundParamA(2, value); break; case this.BG2PB: this.video.renderPath.writeBackgroundParamB(2, value); break; case this.BG2PC: this.video.renderPath.writeBackgroundParamC(2, value); break; case this.BG2PD: this.video.renderPath.writeBackgroundParamD(2, value); break; case this.BG3X_LO: this.video.renderPath.writeBackgroundRefX(3, (this.registers[(offset >> 1) | 1] << 16) | value); break; case this.BG3X_HI: this.video.renderPath.writeBackgroundRefX(3, this.registers[(offset >> 1) ^ 1] | (value << 16)); break; case this.BG3Y_LO: this.video.renderPath.writeBackgroundRefY(3, (this.registers[(offset >> 1) | 1] << 16) | value); break; case this.BG3Y_HI: this.video.renderPath.writeBackgroundRefY(3, this.registers[(offset >> 1) ^ 1] | (value << 16)); break; case this.BG3PA: this.video.renderPath.writeBackgroundParamA(3, value); break; case this.BG3PB: this.video.renderPath.writeBackgroundParamB(3, value); break; case this.BG3PC: this.video.renderPath.writeBackgroundParamC(3, value); break; case this.BG3PD: this.video.renderPath.writeBackgroundParamD(3, value); break; case this.WIN0H: this.video.renderPath.writeWin0H(value); break; case this.WIN1H: this.video.renderPath.writeWin1H(value); break; case this.WIN0V: this.video.renderPath.writeWin0V(value); break; case this.WIN1V: this.video.renderPath.writeWin1V(value); break; case this.WININ: value &= 0x3F3F; this.video.renderPath.writeWinIn(value); break; case this.WINOUT: value &= 0x3F3F; this.video.renderPath.writeWinOut(value); break; case this.BLDCNT: value &= 0x7FFF; this.video.renderPath.writeBlendControl(value); break; case this.BLDALPHA: value &= 0x1F1F; this.video.renderPath.writeBlendAlpha(value); break; case this.BLDY: value &= 0x001F; this.video.renderPath.writeBlendY(value); break; case this.MOSAIC: this.video.renderPath.writeMosaic(value); break; // Sound case this.SOUND1CNT_LO: value &= 0x007F; this.audio.writeSquareChannelSweep(0, value); break; case this.SOUND1CNT_HI: this.audio.writeSquareChannelDLE(0, value); break; case this.SOUND1CNT_X: value &= 0xC7FF; this.audio.writeSquareChannelFC(0, value); value &= ~0x8000; break; case this.SOUND2CNT_LO: this.audio.writeSquareChannelDLE(1, value); break; case this.SOUND2CNT_HI: value &= 0xC7FF; this.audio.writeSquareChannelFC(1, value); value &= ~0x8000; break; case this.SOUND3CNT_LO: value &= 0x00E0; this.audio.writeChannel3Lo(value); break; case this.SOUND3CNT_HI: value &= 0xE0FF; this.audio.writeChannel3Hi(value); break; case this.SOUND3CNT_X: value &= 0xC7FF; this.audio.writeChannel3X(value); value &= ~0x8000; break; case this.SOUND4CNT_LO: value &= 0xFF3F; this.audio.writeChannel4LE(value); break; case this.SOUND4CNT_HI: value &= 0xC0FF; this.audio.writeChannel4FC(value); value &= ~0x8000; break; case this.SOUNDCNT_LO: value &= 0xFF77; this.audio.writeSoundControlLo(value); break; case this.SOUNDCNT_HI: value &= 0xFF0F; this.audio.writeSoundControlHi(value); break; case this.SOUNDCNT_X: value &= 0x0080; this.audio.writeEnable(value); break; case this.WAVE_RAM0_LO: case this.WAVE_RAM0_HI: case this.WAVE_RAM1_LO: case this.WAVE_RAM1_HI: case this.WAVE_RAM2_LO: case this.WAVE_RAM2_HI: case this.WAVE_RAM3_LO: case this.WAVE_RAM3_HI: this.audio.writeWaveData(offset - this.WAVE_RAM0_LO, value, 2); break; // DMA case this.DMA0SAD_LO: case this.DMA0DAD_LO: case this.DMA1SAD_LO: case this.DMA1DAD_LO: case this.DMA2SAD_LO: case this.DMA2DAD_LO: case this.DMA3SAD_LO: case this.DMA3DAD_LO: this.store32(offset, (this.registers[(offset >> 1) + 1] << 16) | value); return; case this.DMA0SAD_HI: case this.DMA0DAD_HI: case this.DMA1SAD_HI: case this.DMA1DAD_HI: case this.DMA2SAD_HI: case this.DMA2DAD_HI: case this.DMA3SAD_HI: case this.DMA3DAD_HI: this.store32(offset - 2, this.registers[(offset >> 1) - 1] | (value << 16)); return; case this.DMA0CNT_LO: this.cpu.irq.dmaSetWordCount(0, value); break; case this.DMA0CNT_HI: // The DMA registers need to set the values before writing the control, as writing the // control can synchronously trigger a DMA transfer this.registers[offset >> 1] = value & 0xFFE0; this.cpu.irq.dmaWriteControl(0, value); return; case this.DMA1CNT_LO: this.cpu.irq.dmaSetWordCount(1, value); break; case this.DMA1CNT_HI: this.registers[offset >> 1] = value & 0xFFE0; this.cpu.irq.dmaWriteControl(1, value); return; case this.DMA2CNT_LO: this.cpu.irq.dmaSetWordCount(2, value); break; case this.DMA2CNT_HI: this.registers[offset >> 1] = value & 0xFFE0; this.cpu.irq.dmaWriteControl(2, value); return; case this.DMA3CNT_LO: this.cpu.irq.dmaSetWordCount(3, value); break; case this.DMA3CNT_HI: this.registers[offset >> 1] = value & 0xFFE0; this.cpu.irq.dmaWriteControl(3, value); return; // Timers case this.TM0CNT_LO: this.cpu.irq.timerSetReload(0, value); return; case this.TM1CNT_LO: this.cpu.irq.timerSetReload(1, value); return; case this.TM2CNT_LO: this.cpu.irq.timerSetReload(2, value); return; case this.TM3CNT_LO: this.cpu.irq.timerSetReload(3, value); return; case this.TM0CNT_HI: value &= 0x00C7 this.cpu.irq.timerWriteControl(0, value); break; case this.TM1CNT_HI: value &= 0x00C7 this.cpu.irq.timerWriteControl(1, value); break; case this.TM2CNT_HI: value &= 0x00C7 this.cpu.irq.timerWriteControl(2, value); break; case this.TM3CNT_HI: value &= 0x00C7 this.cpu.irq.timerWriteControl(3, value); break; // SIO case this.SIOMULTI0: case this.SIOMULTI1: case this.SIOMULTI2: case this.SIOMULTI3: case this.SIODATA8: this.STUB_REG('SIO', offset); break; case this.RCNT: this.sio.setMode(((value >> 12) & 0xC) | ((this.registers[this.SIOCNT >> 1] >> 12) & 0x3)); this.sio.writeRCNT(value); break; case this.SIOCNT: this.sio.setMode(((value >> 12) & 0x3) | ((this.registers[this.RCNT >> 1] >> 12) & 0xC)); this.sio.writeSIOCNT(value); return; case this.JOYCNT: case this.JOYSTAT: this.STUB_REG('JOY', offset); break; // Misc case this.IE: value &= 0x3FFF; this.cpu.irq.setInterruptsEnabled(value); break; case this.IF: this.cpu.irq.dismissIRQs(value); return; case this.WAITCNT: value &= 0xDFFF; this.cpu.mmu.adjustTimings(value); break; case this.IME: value &= 0x0001; this.cpu.irq.masterEnable(value); break; default: this.STUB_REG('I/O', offset); } this.registers[offset >> 1] = value; }; GameBoyAdvanceIO.prototype.store32 = function(offset, value) { switch (offset) { case this.BG2X_LO: value &= 0x0FFFFFFF; this.video.renderPath.writeBackgroundRefX(2, value); break; case this.BG2Y_LO: value &= 0x0FFFFFFF; this.video.renderPath.writeBackgroundRefY(2, value); break; case this.BG3X_LO: value &= 0x0FFFFFFF; this.video.renderPath.writeBackgroundRefX(3, value); break; case this.BG3Y_LO: value &= 0x0FFFFFFF; this.video.renderPath.writeBackgroundRefY(3, value); break; case this.DMA0SAD_LO: this.cpu.irq.dmaSetSourceAddress(0, value); break; case this.DMA0DAD_LO: this.cpu.irq.dmaSetDestAddress(0, value); break; case this.DMA1SAD_LO: this.cpu.irq.dmaSetSourceAddress(1, value); break; case this.DMA1DAD_LO: this.cpu.irq.dmaSetDestAddress(1, value); break; case this.DMA2SAD_LO: this.cpu.irq.dmaSetSourceAddress(2, value); break; case this.DMA2DAD_LO: this.cpu.irq.dmaSetDestAddress(2, value); break; case this.DMA3SAD_LO: this.cpu.irq.dmaSetSourceAddress(3, value); break; case this.DMA3DAD_LO: this.cpu.irq.dmaSetDestAddress(3, value); break; case this.FIFO_A_LO: this.audio.appendToFifoA(value); return; case this.FIFO_B_LO: this.audio.appendToFifoB(value); return; // High bits of this write should be ignored case this.IME: this.store16(offset, value & 0xFFFF); return; case this.JOY_RECV: case this.JOY_TRANS: this.STUB_REG('JOY', offset); return; default: this.store16(offset, value & 0xFFFF); this.store16(offset | 2, value >>> 16); return; } this.registers[offset >> 1] = value & 0xFFFF; this.registers[(offset >> 1) + 1] = value >>> 16; }; GameBoyAdvanceIO.prototype.invalidatePage = function(address) {}; GameBoyAdvanceIO.prototype.STUB_REG = function(type, offset) { this.core.STUB('Unimplemented ' + type + ' register write: ' + offset.toString(16)); };