diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index ddf1c18d..69d32806 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -6,7 +6,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "097.16"; + static const string Version = "097.17"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/gba/apu/apu.cpp b/higan/gba/apu/apu.cpp index 22835cf6..e03f223f 100644 --- a/higan/gba/apu/apu.cpp +++ b/higan/gba/apu/apu.cpp @@ -2,7 +2,6 @@ namespace GameBoyAdvance { -#include "registers.cpp" #include "mmio.cpp" #include "square.cpp" #include "square1.cpp" @@ -84,7 +83,8 @@ auto APU::power() -> void { fifo[0].power(); fifo[1].power(); - regs.bias = 0x0200; + regs.bias.amplitude = 0; + regs.bias.level = 0x200; for(uint n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this; } diff --git a/higan/gba/apu/mmio.cpp b/higan/gba/apu/mmio.cpp index 7a4e53ed..16dadb77 100644 --- a/higan/gba/apu/mmio.cpp +++ b/higan/gba/apu/mmio.cpp @@ -2,215 +2,234 @@ auto APU::read(uint32 addr) -> uint8 { switch(addr) { //NR10 - case 0x04000060: return square1.read(0); - case 0x04000061: return 0u; + case 0x0400'0060: return square1.read(0); + case 0x0400'0061: return 0; //NR11 + NR12 - case 0x04000062: return square1.read(1); - case 0x04000063: return square1.read(2); + case 0x0400'0062: return square1.read(1); + case 0x0400'0063: return square1.read(2); //NR13 + NR14 - case 0x04000064: return square1.read(3); - case 0x04000065: return square1.read(4); + case 0x0400'0064: return square1.read(3); + case 0x0400'0065: return square1.read(4); //NR21 + NR22 - case 0x04000068: return square2.read(1); - case 0x04000069: return square2.read(2); + case 0x0400'0068: return square2.read(1); + case 0x0400'0069: return square2.read(2); //NR23 + NR24 - case 0x0400006c: return square2.read(3); - case 0x0400006d: return square2.read(4); + case 0x0400'006c: return square2.read(3); + case 0x0400'006d: return square2.read(4); //NR30 - case 0x04000070: return wave.read(0); - case 0x04000071: return 0u; + case 0x0400'0070: return wave.read(0); + case 0x0400'0071: return 0; //NR31 + NR32 - case 0x04000072: return wave.read(1); - case 0x04000073: return wave.read(2); + case 0x0400'0072: return wave.read(1); + case 0x0400'0073: return wave.read(2); //NR33 + NR34 - case 0x04000074: return wave.read(3); - case 0x04000075: return wave.read(4); + case 0x0400'0074: return wave.read(3); + case 0x0400'0075: return wave.read(4); //NR41 + NR42 - case 0x04000078: return noise.read(1); - case 0x04000079: return noise.read(2); + case 0x0400'0078: return noise.read(1); + case 0x0400'0079: return noise.read(2); //NR43 + NR44 - case 0x0400007c: return noise.read(3); - case 0x0400007d: return noise.read(4); + case 0x0400'007c: return noise.read(3); + case 0x0400'007d: return noise.read(4); //NR50 + NR51 - case 0x04000080: return sequencer.read(0); - case 0x04000081: return sequencer.read(1); + case 0x0400'0080: return sequencer.read(0); + case 0x0400'0081: return sequencer.read(1); //SOUND_CNT_H - case 0x04000082: - return (fifo[1].volume << 3) | (fifo[0].volume << 2) | (sequencer.volume << 0); - case 0x04000083: - return (fifo[1].timer << 6) | (fifo[1].lenable << 5) | (fifo[1].renable << 4) - | (fifo[0].timer << 2) | (fifo[0].lenable << 1) | (fifo[0].renable << 0); + case 0x0400'0082: return ( + sequencer.volume << 0 + | fifo[0].volume << 2 + | fifo[1].volume << 3 + ); + + case 0x0400'0083: return ( + fifo[0].renable << 0 + | fifo[0].lenable << 1 + | fifo[0].timer << 2 + | fifo[1].renable << 4 + | fifo[1].lenable << 5 + | fifo[1].timer << 6 + ); //NR52 - case 0x04000084: return sequencer.read(2); - case 0x04000085: return 0u; + case 0x0400'0084: return sequencer.read(2); + case 0x0400'0085: return 0; //SOUNDBIAS - case 0x04000088: return regs.bias >> 0; - case 0x04000089: return regs.bias >> 8; + case 0x0400'0088: return ( + regs.bias.level.bits(0,7) + ); + case 0x0400'0089: return ( + regs.bias.level.bits(8,9) + | regs.bias.amplitude << 6 + ); //WAVE_RAM0_L - case 0x04000090: return wave.readram( 0); - case 0x04000091: return wave.readram( 1); + case 0x0400'0090: return wave.readram( 0); + case 0x0400'0091: return wave.readram( 1); //WAVE_RAM0_H - case 0x04000092: return wave.readram( 2); - case 0x04000093: return wave.readram( 3); + case 0x0400'0092: return wave.readram( 2); + case 0x0400'0093: return wave.readram( 3); //WAVE_RAM1_L - case 0x04000094: return wave.readram( 4); - case 0x04000095: return wave.readram( 5); + case 0x0400'0094: return wave.readram( 4); + case 0x0400'0095: return wave.readram( 5); //WAVE_RAM1_H - case 0x04000096: return wave.readram( 6); - case 0x04000097: return wave.readram( 7); + case 0x0400'0096: return wave.readram( 6); + case 0x0400'0097: return wave.readram( 7); //WAVE_RAM2_L - case 0x04000098: return wave.readram( 8); - case 0x04000099: return wave.readram( 9); + case 0x0400'0098: return wave.readram( 8); + case 0x0400'0099: return wave.readram( 9); //WAVE_RAM2_H - case 0x0400009a: return wave.readram(10); - case 0x0400009b: return wave.readram(11); + case 0x0400'009a: return wave.readram(10); + case 0x0400'009b: return wave.readram(11); //WAVE_RAM3_L - case 0x0400009c: return wave.readram(12); - case 0x0400009d: return wave.readram(13); + case 0x0400'009c: return wave.readram(12); + case 0x0400'009d: return wave.readram(13); //WAVE_RAM3_H - case 0x0400009e: return wave.readram(14); - case 0x0400009f: return wave.readram(15); + case 0x0400'009e: return wave.readram(14); + case 0x0400'009f: return wave.readram(15); } return 0u; } -auto APU::write(uint32 addr, uint8 byte) -> void { +auto APU::write(uint32 addr, uint8 data) -> void { switch(addr) { //NR10 - case 0x04000060: return square1.write(0, byte); - case 0x04000061: return; + case 0x0400'0060: return square1.write(0, data); + case 0x0400'0061: return; //NR11 + NR12 - case 0x04000062: return square1.write(1, byte); - case 0x04000063: return square1.write(2, byte); + case 0x0400'0062: return square1.write(1, data); + case 0x0400'0063: return square1.write(2, data); //NR13 + NR14 - case 0x04000064: return square1.write(3, byte); - case 0x04000065: return square1.write(4, byte); + case 0x0400'0064: return square1.write(3, data); + case 0x0400'0065: return square1.write(4, data); //NR21 + NR22 - case 0x04000068: return square2.write(1, byte); - case 0x04000069: return square2.write(2, byte); + case 0x0400'0068: return square2.write(1, data); + case 0x0400'0069: return square2.write(2, data); //NR23 + NR24 - case 0x0400006c: return square2.write(3, byte); - case 0x0400006d: return square2.write(4, byte); + case 0x0400'006c: return square2.write(3, data); + case 0x0400'006d: return square2.write(4, data); //NR30 - case 0x04000070: return wave.write(0, byte); - case 0x04000071: return; + case 0x0400'0070: return wave.write(0, data); + case 0x0400'0071: return; //NR31 + NR32 - case 0x04000072: return wave.write(1, byte); - case 0x04000073: return wave.write(2, byte); + case 0x0400'0072: return wave.write(1, data); + case 0x0400'0073: return wave.write(2, data); //NR33 + NR34 - case 0x04000074: return wave.write(3, byte); - case 0x04000075: return wave.write(4, byte); + case 0x0400'0074: return wave.write(3, data); + case 0x0400'0075: return wave.write(4, data); //NR41 + NR42 - case 0x04000078: return noise.write(1, byte); - case 0x04000079: return noise.write(2, byte); + case 0x0400'0078: return noise.write(1, data); + case 0x0400'0079: return noise.write(2, data); //NR43 + NR44 - case 0x0400007c: return noise.write(3, byte); - case 0x0400007d: return noise.write(4, byte); + case 0x0400'007c: return noise.write(3, data); + case 0x0400'007d: return noise.write(4, data); //NR50 + NR51 - case 0x04000080: return sequencer.write(0, byte); - case 0x04000081: return sequencer.write(1, byte); + case 0x0400'0080: return sequencer.write(0, data); + case 0x0400'0081: return sequencer.write(1, data); //SOUND_CNT_H - case 0x04000082: - sequencer.volume = byte >> 0; - fifo[0].volume = byte >> 2; - fifo[1].volume = byte >> 3; + case 0x0400'0082: + sequencer.volume = data.bits(0,1); + fifo[0].volume = data.bit (2); + fifo[1].volume = data.bit (3); return; - case 0x04000083: - fifo[0].renable = byte >> 0; - fifo[0].lenable = byte >> 1; - fifo[0].timer = byte >> 2; - if(byte & 1 << 3) fifo[0].reset(); - fifo[1].renable = byte >> 4; - fifo[1].lenable = byte >> 5; - fifo[1].timer = byte >> 6; - if(byte & 1 << 7) fifo[1].reset(); + case 0x0400'0083: + fifo[0].renable = data.bit(0); + fifo[0].lenable = data.bit(1); + fifo[0].timer = data.bit(2); + if(data.bit(3)) fifo[0].reset(); + fifo[1].renable = data.bit(4); + fifo[1].lenable = data.bit(5); + fifo[1].timer = data.bit(6); + if(data.bit(7)) fifo[1].reset(); return; //NR52 - case 0x04000084: return sequencer.write(2, byte); - case 0x04000085: return; + case 0x0400'0084: return sequencer.write(2, data); + case 0x0400'0085: return; //SOUNDBIAS - case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return; - case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return; + case 0x0400'0088: + regs.bias.level.bits(0,7) = data; + return; + case 0x0400'0089: + regs.bias.level.bits(8,9) = data.bits(0,1); + regs.bias.amplitude = data.bits(6,7); + return; //WAVE_RAM0_L - case 0x04000090: return wave.writeram( 0, byte); - case 0x04000091: return wave.writeram( 1, byte); + case 0x0400'0090: return wave.writeram( 0, data); + case 0x0400'0091: return wave.writeram( 1, data); //WAVE_RAM0_H - case 0x04000092: return wave.writeram( 2, byte); - case 0x04000093: return wave.writeram( 3, byte); + case 0x0400'0092: return wave.writeram( 2, data); + case 0x0400'0093: return wave.writeram( 3, data); //WAVE_RAM1_L - case 0x04000094: return wave.writeram( 4, byte); - case 0x04000095: return wave.writeram( 5, byte); + case 0x0400'0094: return wave.writeram( 4, data); + case 0x0400'0095: return wave.writeram( 5, data); //WAVE_RAM1_H - case 0x04000096: return wave.writeram( 6, byte); - case 0x04000097: return wave.writeram( 7, byte); + case 0x0400'0096: return wave.writeram( 6, data); + case 0x0400'0097: return wave.writeram( 7, data); //WAVE_RAM2_L - case 0x04000098: return wave.writeram( 8, byte); - case 0x04000099: return wave.writeram( 9, byte); + case 0x0400'0098: return wave.writeram( 8, data); + case 0x0400'0099: return wave.writeram( 9, data); //WAVE_RAM2_H - case 0x0400009a: return wave.writeram(10, byte); - case 0x0400009b: return wave.writeram(11, byte); + case 0x0400'009a: return wave.writeram(10, data); + case 0x0400'009b: return wave.writeram(11, data); //WAVE_RAM3_L - case 0x0400009c: return wave.writeram(12, byte); - case 0x0400009d: return wave.writeram(13, byte); + case 0x0400'009c: return wave.writeram(12, data); + case 0x0400'009d: return wave.writeram(13, data); //WAVE_RAM3_H - case 0x0400009e: return wave.writeram(14, byte); - case 0x0400009f: return wave.writeram(15, byte); + case 0x0400'009e: return wave.writeram(14, data); + case 0x0400'009f: return wave.writeram(15, data); //FIFO_A_L //FIFO_A_H - case 0x040000a0: case 0x040000a1: - case 0x040000a2: case 0x040000a3: - return fifo[0].write(byte); + case 0x0400'00a0: case 0x0400'00a1: + case 0x0400'00a2: case 0x0400'00a3: + return fifo[0].write(data); //FIFO_B_L //FIFO_B_H - case 0x040000a4: case 0x040000a5: - case 0x040000a6: case 0x040000a7: - return fifo[1].write(byte); + case 0x0400'00a4: case 0x0400'00a5: + case 0x0400'00a6: case 0x0400'00a7: + return fifo[1].write(data); } } diff --git a/higan/gba/apu/registers.cpp b/higan/gba/apu/registers.cpp deleted file mode 100644 index 1fbc06a5..00000000 --- a/higan/gba/apu/registers.cpp +++ /dev/null @@ -1,12 +0,0 @@ -APU::Registers::SoundBias::operator uint16_t() const { - return ( - (level << 0) - | (amplitude << 14) - ); -} - -auto APU::Registers::SoundBias::operator=(uint16 source) -> uint16 { - level = (source >> 0) & 1023; - amplitude = (source >> 14) & 3; - return operator uint16_t(); -} diff --git a/higan/gba/apu/registers.hpp b/higan/gba/apu/registers.hpp index 4079149c..1f9a45d6 100644 --- a/higan/gba/apu/registers.hpp +++ b/higan/gba/apu/registers.hpp @@ -2,10 +2,6 @@ struct Registers { struct SoundBias { uint10 level; uint2 amplitude; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const SoundBias&) -> SoundBias& = delete; } bias; uint clock; diff --git a/higan/gba/cpu/cpu.cpp b/higan/gba/cpu/cpu.cpp index 97c166b6..1e36862e 100644 --- a/higan/gba/cpu/cpu.cpp +++ b/higan/gba/cpu/cpu.cpp @@ -2,7 +2,6 @@ namespace GameBoyAdvance { -#include "registers.cpp" #include "prefetch.cpp" #include "bus.cpp" #include "mmio.cpp" @@ -16,21 +15,21 @@ CPU::CPU() { iwram = new uint8[ 32 * 1024]; ewram = new uint8[256 * 1024]; - regs.dma[0].source.bits(27); regs.dma[0].run.source.bits(27); - regs.dma[0].target.bits(27); regs.dma[0].run.target.bits(27); - regs.dma[0].length.bits(14); regs.dma[0].run.length.bits(14); + regs.dma[0].source.resize(27); regs.dma[0].run.source.resize(27); + regs.dma[0].target.resize(27); regs.dma[0].run.target.resize(27); + regs.dma[0].length.resize(14); regs.dma[0].run.length.resize(14); - regs.dma[1].source.bits(28); regs.dma[1].run.source.bits(28); - regs.dma[1].target.bits(27); regs.dma[1].run.target.bits(27); - regs.dma[1].length.bits(14); regs.dma[1].run.length.bits(14); + regs.dma[1].source.resize(28); regs.dma[1].run.source.resize(28); + regs.dma[1].target.resize(27); regs.dma[1].run.target.resize(27); + regs.dma[1].length.resize(14); regs.dma[1].run.length.resize(14); - regs.dma[2].source.bits(28); regs.dma[2].run.source.bits(28); - regs.dma[2].target.bits(27); regs.dma[2].run.target.bits(27); - regs.dma[2].length.bits(14); regs.dma[2].run.length.bits(14); + regs.dma[2].source.resize(28); regs.dma[2].run.source.resize(28); + regs.dma[2].target.resize(27); regs.dma[2].run.target.resize(27); + regs.dma[2].length.resize(14); regs.dma[2].run.length.resize(14); - regs.dma[3].source.bits(28); regs.dma[3].run.source.bits(28); - regs.dma[3].target.bits(28); regs.dma[3].run.target.bits(28); - regs.dma[3].length.bits(16); regs.dma[3].run.length.bits(16); + regs.dma[3].source.resize(28); regs.dma[3].run.source.resize(28); + regs.dma[3].target.resize(28); regs.dma[3].run.target.resize(28); + regs.dma[3].length.resize(16); regs.dma[3].run.length.resize(16); } CPU::~CPU() { @@ -56,7 +55,7 @@ auto CPU::main() -> void { processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag); if(regs.mode == Registers::Mode::Stop) { - if((regs.irq.enable.keypad & regs.irq.flag.keypad) == 0) { + if(!(regs.irq.enable & regs.irq.flag & Interrupt::Keypad)) { sync_step(16); //STOP does not advance timers } else { regs.mode = Registers::Mode::Normal; @@ -67,7 +66,7 @@ auto CPU::main() -> void { dma_run(); if(regs.mode == Registers::Mode::Halt) { - if((regs.irq.enable & regs.irq.flag) == 0) { + if(!(regs.irq.enable & regs.irq.flag)) { step(16); } else { regs.mode = Registers::Mode::Normal; @@ -101,7 +100,7 @@ auto CPU::keypad_run() -> void { if(regs.keypad.control.condition == 0) test |= input; if(regs.keypad.control.condition == 1) test &= input; } - if(test) regs.irq.flag.keypad = true; + if(test) regs.irq.flag |= Interrupt::Keypad; } auto CPU::power() -> void { @@ -116,7 +115,14 @@ auto CPU::power() -> void { dma.target = 0; dma.length = 0; dma.data = 0; - dma.control = 0; + dma.control.targetmode = 0; + dma.control.sourcemode = 0; + dma.control.repeat = 0; + dma.control.size = 0; + dma.control.drq = 0; + dma.control.timingmode = 0; + dma.control.irq = 0; + dma.control.enable = 0; dma.pending = 0; dma.run.target = 0; dma.run.source = 0; @@ -126,17 +132,30 @@ auto CPU::power() -> void { timer.period = 0; timer.reload = 0; timer.pending = false; - timer.control = 0; + timer.control.frequency = 0; + timer.control.cascade = 0; + timer.control.irq = 0; + timer.control.enable = 0; } - regs.keypad.control = 0; + for(auto& flag : regs.keypad.control.flag) flag = 0; + regs.keypad.control.enable = 0; + regs.keypad.control.condition = 0; regs.ime = 0; regs.irq.enable = 0; regs.irq.flag = 0; - regs.wait.control = 0; + for(auto& nwait : regs.wait.control.nwait) nwait = 0; + for(auto& swait : regs.wait.control.swait) swait = 0; + regs.wait.control.phi = 0; + regs.wait.control.prefetch = 0; + regs.wait.control.gametype = 0; regs.postboot = 0; regs.mode = Registers::Mode::Normal; regs.clock = 0; - regs.memory.control = 0x0d00'0020; + regs.memory.control.disable = 0; + regs.memory.control.unknown1 = 0; + regs.memory.control.ewram = 1; + regs.memory.control.ewramwait = 13; + regs.memory.control.unknown2 = 0; pending.dma.vblank = 0; pending.dma.hblank = 0; diff --git a/higan/gba/cpu/cpu.hpp b/higan/gba/cpu/cpu.hpp index dcb6a107..89129e8c 100644 --- a/higan/gba/cpu/cpu.hpp +++ b/higan/gba/cpu/cpu.hpp @@ -2,6 +2,25 @@ struct CPU : Processor::ARM, Thread, MMIO { using ARM::read; using ARM::write; + struct Interrupt { + enum : uint { + VBlank = 0x0001, + HBlank = 0x0002, + VCoincidence = 0x0004, + Timer0 = 0x0008, + Timer1 = 0x0010, + Timer2 = 0x0020, + Timer3 = 0x0040, + Serial = 0x0080, + DMA0 = 0x0100, + DMA1 = 0x0200, + DMA2 = 0x0400, + DMA3 = 0x0800, + Keypad = 0x1000, + Cartridge = 0x2000, + }; + }; + #include "registers.hpp" #include "prefetch.hpp" #include "state.hpp" diff --git a/higan/gba/cpu/dma.cpp b/higan/gba/cpu/dma.cpp index 240cdf84..a9a7a3af 100644 --- a/higan/gba/cpu/dma.cpp +++ b/higan/gba/cpu/dma.cpp @@ -7,8 +7,8 @@ auto CPU::dma_run() -> void { auto& dma = regs.dma[n]; if(dma.pending) { dma_exec(dma); - if(dma.control.irq) regs.irq.flag.dma[n] = 1; - if(dma.control.drq && n == 3) regs.irq.flag.cartridge = 1; + if(dma.control.irq) regs.irq.flag |= Interrupt::DMA0 << n; + if(dma.control.drq && n == 3) regs.irq.flag |= Interrupt::Cartridge; transferred = true; break; } diff --git a/higan/gba/cpu/mmio.cpp b/higan/gba/cpu/mmio.cpp index 9ddbc4c9..28a526b6 100644 --- a/higan/gba/cpu/mmio.cpp +++ b/higan/gba/cpu/mmio.cpp @@ -1,321 +1,415 @@ auto CPU::read(uint32 addr) -> uint8 { - uint8 result = 0; + auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; }; + auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; }; switch(addr) { - //DMA0CNT_H - //DMA1CNT_H - //DMA2CNT_H - //DMA3CNT_H - case 0x040000ba: case 0x040000bb: - case 0x040000c6: case 0x040000c7: - case 0x040000d2: case 0x040000d3: - case 0x040000de: case 0x040000df: { - auto& dma = regs.dma[(addr - 0x040000ba) / 12]; - unsigned shift = (addr & 1) * 8; - return dma.control >> shift; - } + //DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H + case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de: return ( + dma().control.targetmode << 5 + | dma().control.sourcemode.bit(0) << 7 + ); + case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: return ( + dma().control.sourcemode.bit(1) << 0 + | dma().control.repeat << 1 + | dma().control.size << 2 + | dma().control.drq << 3 + | dma().control.timingmode << 4 + | dma().control.irq << 6 + | dma().control.enable << 7 + ); - //TM0CNT_L - //TM1CNT_L - //TM2CNT_L - //TM3CNT_L - case 0x04000100: case 0x04000101: - case 0x04000104: case 0x04000105: - case 0x04000108: case 0x04000109: - case 0x0400010c: case 0x0400010d: { - auto& timer = regs.timer[(addr >> 2) & 3]; - unsigned shift = (addr & 1) * 8; - return timer.period >> shift; - } + //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L + case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: return timer().period.byte(0); + case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: return timer().period.byte(1); - //TIM0CNT_H - case 0x04000102: case 0x04000103: - case 0x04000106: case 0x04000107: - case 0x0400010a: case 0x0400010b: - case 0x0400010e: case 0x0400010f: { - auto& timer = regs.timer[(addr >> 2) & 3]; - unsigned shift = (addr & 1) * 8; - return timer.control >> shift; - } + //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H + case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: return ( + timer().control.frequency << 0 + | timer().control.cascade << 2 + | timer().control.irq << 6 + | timer().control.enable << 7 + ); + case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: return 0; - //SIOMULTI0 (SIODATA32_L) - //SIOMULTI1 (SIODATA32_H) - //SIOMULTI2 - //SIOMULTI3 - case 0x04000120: case 0x04000121: - case 0x04000122: case 0x04000123: - case 0x04000124: case 0x04000125: - case 0x04000126: case 0x04000127: { - if(auto data = player.read()) return data() >> ((addr & 3) << 3); - unsigned shift = (addr & 1) * 8; - auto& data = regs.serial.data[(addr >> 1) & 3]; - return data >> shift; + //SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3 + case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126: { + if(auto data = player.read()) return data().byte(addr.bits(0,1)); + return regs.serial.data[addr.bits(1,2)].byte(0); + } + case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127: { + if(auto data = player.read()) return data().byte(addr.bits(0,1)); + return regs.serial.data[addr.bits(1,2)].byte(1); } //SIOCNT - case 0x04000128: return regs.serial.control >> 0; - case 0x04000129: return regs.serial.control >> 8; + case 0x0400'0128: return ( + regs.serial.control.shiftclockselect << 0 + | regs.serial.control.shiftclockfrequency << 1 + | regs.serial.control.transferenablereceive << 2 + | regs.serial.control.transferenablesend << 3 + | regs.serial.control.startbit << 7 + ); + case 0x0400'0129: return ( + regs.serial.control.transferlength << 4 + | regs.serial.control.irqenable << 6 + ); //SIOMLT_SEND (SIODATA8) - case 0x0400012a: return regs.serial.data8; - case 0x0400012b: return 0u; + case 0x0400'012a: return regs.serial.data8; + case 0x0400'012b: return 0; //KEYINPUT - case 0x04000130: + case 0x04000130: { if(auto result = player.keyinput()) return result() >> 0; - for(unsigned n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, n) << n; + uint8 result = 0; + for(uint n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, n) << n; if((result & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously return result ^ 0xff; - case 0x04000131: + } + case 0x04000131: { if(auto result = player.keyinput()) return result() >> 8; + uint8 result = 0; result |= interface->inputPoll(0, 0, 8) << 0; result |= interface->inputPoll(0, 0, 9) << 1; return result ^ 0x03; + } //KEYCNT - case 0x04000132: return regs.keypad.control >> 0; - case 0x04000133: return regs.keypad.control >> 8; + case 0x0400'0132: return ( + regs.keypad.control.flag[0] << 0 + | regs.keypad.control.flag[1] << 1 + | regs.keypad.control.flag[2] << 2 + | regs.keypad.control.flag[3] << 3 + | regs.keypad.control.flag[4] << 4 + | regs.keypad.control.flag[5] << 5 + | regs.keypad.control.flag[6] << 6 + | regs.keypad.control.flag[7] << 7 + ); + case 0x0400'0133: return ( + regs.keypad.control.flag[8] << 0 + | regs.keypad.control.flag[9] << 1 + | regs.keypad.control.enable << 6 + | regs.keypad.control.condition << 7 + ); //RCNT - case 0x04000134: return regs.joybus.settings >> 0; - case 0x04000135: return regs.joybus.settings >> 8; + case 0x0400'0134: return ( + regs.joybus.settings.sc << 0 + | regs.joybus.settings.sd << 1 + | regs.joybus.settings.si << 2 + | regs.joybus.settings.so << 3 + | regs.joybus.settings.scmode << 4 + | regs.joybus.settings.sdmode << 5 + | regs.joybus.settings.simode << 6 + | regs.joybus.settings.somode << 7 + ); + case 0x0400'0135: return ( + regs.joybus.settings.irqenable << 0 + | regs.joybus.settings.mode << 6 + ); //JOYCNT - case 0x04000140: return regs.joybus.control >> 0; - case 0x04000141: return regs.joybus.control >> 8; + case 0x0400'0140: return ( + regs.joybus.control.resetsignal << 0 + | regs.joybus.control.receivecomplete << 1 + | regs.joybus.control.sendcomplete << 2 + | regs.joybus.control.irqenable << 6 + ); + case 0x0400'0141: return 0; + case 0x0400'0142: return 0; + case 0x0400'0143: return 0; - //JOY_RECV_L - //JOY_RECV_H - case 0x04000150: return regs.joybus.receive >> 0; - case 0x04000151: return regs.joybus.receive >> 8; - case 0x04000152: return regs.joybus.receive >> 16; - case 0x04000153: return regs.joybus.receive >> 24; + //JOY_RECV_L, JOY_RECV_H + case 0x0400'0150: return regs.joybus.receive.byte(0); + case 0x0400'0151: return regs.joybus.receive.byte(1); + case 0x0400'0152: return regs.joybus.receive.byte(2); + case 0x0400'0153: return regs.joybus.receive.byte(3); - //JOY_TRANS_L - //JOY_TRANS_H - case 0x04000154: return regs.joybus.transmit >> 0; - case 0x04000155: return regs.joybus.transmit >> 8; - case 0x04000156: return regs.joybus.transmit >> 16; - case 0x04000157: return regs.joybus.transmit >> 24; + //JOY_TRANS_L, JOY_TRANS_H + case 0x0400'0154: return regs.joybus.transmit.byte(0); + case 0x0400'0155: return regs.joybus.transmit.byte(1); + case 0x0400'0156: return regs.joybus.transmit.byte(2); + case 0x0400'0157: return regs.joybus.transmit.byte(3); //JOYSTAT - case 0x04000158: return regs.joybus.status >> 0; - case 0x04000159: return regs.joybus.status >> 8; + case 0x0400'0158: return ( + regs.joybus.status.receiveflag << 1 + | regs.joybus.status.sendflag << 3 + | regs.joybus.status.generalflag << 4 + ); + case 0x0400'0159: return 0; + case 0x0400'015a: return 0; + case 0x0400'015b: return 0; //IE - case 0x04000200: return regs.irq.enable >> 0; - case 0x04000201: return regs.irq.enable >> 8; + case 0x0400'0200: return regs.irq.enable.byte(0); + case 0x0400'0201: return regs.irq.enable.byte(1); //IF - case 0x04000202: return regs.irq.flag >> 0; - case 0x04000203: return regs.irq.flag >> 8; + case 0x0400'0202: return regs.irq.flag.byte(0); + case 0x0400'0203: return regs.irq.flag.byte(1); //WAITCNT - case 0x04000204: return regs.wait.control >> 0; - case 0x04000205: return regs.wait.control >> 8; + case 0x0400'0204: return ( + regs.wait.control.nwait[3] << 0 + | regs.wait.control.nwait[0] << 2 + | regs.wait.control.swait[0] << 4 + | regs.wait.control.nwait[1] << 5 + | regs.wait.control.swait[1] << 7 + ); + case 0x0400'0205: return ( + regs.wait.control.nwait[2] << 0 + | regs.wait.control.swait[2] << 2 + | regs.wait.control.phi << 3 + | regs.wait.control.prefetch << 6 + | regs.wait.control.gametype << 7 + ); //IME - case 0x04000208: return regs.ime; - case 0x04000209: return 0u; + case 0x0400'0208: return regs.ime; + case 0x0400'0209: return 0; //POSTFLG + HALTCNT - case 0x04000300: return regs.postboot; - case 0x04000301: return 0u; + case 0x0400'0300: return regs.postboot; + case 0x0400'0301: return 0; //MEMCNT_L - case 0x04000800: return regs.memory.control >> 0; - case 0x04000801: return regs.memory.control >> 8; + case 0x0400'0800: return ( + regs.memory.control.disable << 0 + | regs.memory.control.unknown1 << 1 + | regs.memory.control.ewram << 5 + ); + case 0x0400'0801: return 0; //MEMCNT_H - case 0x04000802: return regs.memory.control >> 16; - case 0x04000803: return regs.memory.control >> 24; + case 0x0400'0802: return 0; + case 0x0400'0803: return ( + regs.memory.control.ewramwait << 0 + | regs.memory.control.unknown2 << 4 + ); } - return 0u; + return 0; } -auto CPU::write(uint32 addr, uint8 byte) -> void { +auto CPU::write(uint32 addr, uint8 data) -> void { + auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; }; + auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; }; + switch(addr) { - //DMA0SAD - //DMA1SAD - //DMA2SAD - //DMA3SAD - case 0x040000b0: case 0x040000b1: case 0x040000b2: case 0x040000b3: - case 0x040000bc: case 0x040000bd: case 0x040000be: case 0x040000bf: - case 0x040000c8: case 0x040000c9: case 0x040000ca: case 0x040000cb: - case 0x040000d4: case 0x040000d5: case 0x040000d6: case 0x040000d7: { - auto& dma = regs.dma[(addr - 0x040000b0) / 12]; - unsigned shift = (addr & 3) * 8; - dma.source = (dma.source & ~(255 << shift)) | (byte << shift); - return; - } + //DMA0SAD, DMA1SAD, DMA2SAD, DMA3SAD + case 0x0400'00b0: case 0x0400'00bc: case 0x0400'00c8: case 0x0400'00d4: dma().source.byte(0) = data; return; + case 0x0400'00b1: case 0x0400'00bd: case 0x0400'00c9: case 0x0400'00d5: dma().source.byte(1) = data; return; + case 0x0400'00b2: case 0x0400'00be: case 0x0400'00ca: case 0x0400'00d6: dma().source.byte(2) = data; return; + case 0x0400'00b3: case 0x0400'00bf: case 0x0400'00cb: case 0x0400'00d7: dma().source.byte(3) = data; return; - //DMA0DAD - //DMA1DAD - //DMA2DAD - //DMA3DAD - case 0x040000b4: case 0x040000b5: case 0x040000b6: case 0x040000b7: - case 0x040000c0: case 0x040000c1: case 0x040000c2: case 0x040000c3: - case 0x040000cc: case 0x040000cd: case 0x040000ce: case 0x040000cf: - case 0x040000d8: case 0x040000d9: case 0x040000da: case 0x040000db: { - auto& dma = regs.dma[(addr - 0x040000b4) / 12]; - unsigned shift = (addr & 3) * 8; - dma.target = (dma.target & ~(255 << shift)) | (byte << shift); - return; - } + //DMA0DAD, DMA1DAD, DMA2DAD, DMA3DAD + case 0x0400'00b4: case 0x0400'00c0: case 0x0400'00cc: case 0x0400'00d8: dma().target.byte(0) = data; return; + case 0x0400'00b5: case 0x0400'00c1: case 0x0400'00cd: case 0x0400'00d9: dma().target.byte(1) = data; return; + case 0x0400'00b6: case 0x0400'00c2: case 0x0400'00ce: case 0x0400'00da: dma().target.byte(2) = data; return; + case 0x0400'00b7: case 0x0400'00c3: case 0x0400'00cf: case 0x0400'00db: dma().target.byte(3) = data; return; - //DMA0CNT_L - //DMA1CNT_L - //DMA2CNT_L - //DMA3CNT_L - case 0x040000b8: case 0x040000b9: - case 0x040000c4: case 0x040000c5: - case 0x040000d0: case 0x040000d1: - case 0x040000dc: case 0x040000dd: { - auto& dma = regs.dma[(addr - 0x040000b8) / 12]; - unsigned shift = (addr & 1) * 8; - dma.length = (dma.length & ~(255 << shift)) | (byte << shift); - return; - } + //DMA0CNT_L, DMA1CNT_L, DMA2CNT_L, DMA3CNT_L + case 0x0400'00b8: case 0x0400'00c4: case 0x0400'00d0: case 0x0400'00dc: dma().length.byte(0) = data; return; + case 0x0400'00b9: case 0x0400'00c5: case 0x0400'00d1: case 0x0400'00dd: dma().length.byte(1) = data; return; - //DMA0CNT_H - //DMA1CNT_H - //DMA2CNT_H - //DMA3CNT_H - case 0x040000ba: case 0x040000bb: - case 0x040000c6: case 0x040000c7: - case 0x040000d2: case 0x040000d3: - case 0x040000de: case 0x040000df: { - if(addr == 0x040000bb || addr == 0x040000c7 || addr == 0x040000d3) byte &= 0xf7; //gamepak DRQ valid for DMA3 only - auto& dma = regs.dma[(addr - 0x040000ba) / 12]; - unsigned shift = (addr & 1) * 8; - bool enable = dma.control.enable; - dma.control = (dma.control & ~(255 << shift)) | (byte << shift); - if(enable == 0 && dma.control.enable) { - if(dma.control.timingmode == 0) dma.pending = true; //immediate transfer mode - dma.run.target = dma.target; - dma.run.source = dma.source; - dma.run.length = dma.length; - } else if(dma.control.enable == 0) { - dma.pending = false; + //DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H + case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de: + dma().control.targetmode = data.bits(5,6); + dma().control.sourcemode.bit(0) = data.bit (7); + return; + case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: { + bool enable = dma().control.enable; + if(addr != 0x0400'00df) data.bit(3) = 0; //gamepad DRQ valid for DMA3 only + + dma().control.sourcemode.bit(1) = data.bit (0); + dma().control.repeat = data.bit (1); + dma().control.size = data.bit (2); + dma().control.drq = data.bit (3); + dma().control.timingmode = data.bits(4,5); + dma().control.irq = data.bit (6); + dma().control.enable = data.bit (7); + + if(!enable && dma().control.enable) { //0->1 transition + if(dma().control.timingmode == 0) dma().pending = true; //immediate transfer mode + dma().run.target = dma().target; + dma().run.source = dma().source; + dma().run.length = dma().length; + } else if(!dma().control.enable) { + dma().pending = false; } return; } - //TM0CNT_L - //TM1CNT_L - //TM2CNT_L - //TM3CNT_L - case 0x04000100: case 0x04000101: - case 0x04000104: case 0x04000105: - case 0x04000108: case 0x04000109: - case 0x0400010c: case 0x0400010d: { - auto& timer = regs.timer[(addr >> 2) & 3]; - unsigned shift = (addr & 1) * 8; - timer.reload = (timer.reload & ~(255 << shift)) | (byte << shift); - return; - } + //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L + case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: timer().reload.byte(0) = data; return; + case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: timer().reload.byte(1) = data; return; - //TM0CNT_H - //TM1CNT_H - //TM2CNT_H - //TM3CNT_H - case 0x04000102: - case 0x04000106: - case 0x0400010a: - case 0x0400010e: { - auto& timer = regs.timer[(addr >> 2) & 3]; - bool enable = timer.control.enable; - timer.control = byte; - if(enable == 0 && timer.control.enable == 1) { - timer.pending = true; + //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H + case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: { + bool enable = timer().control.enable; + + timer().control.frequency = data.bits(0,1); + timer().control.cascade = data.bit (2); + timer().control.irq = data.bit (6); + timer().control.enable = data.bit (7); + + if(!enable && timer().control.enable) { //0->1 transition + timer().pending = true; } return; } - - //SIOMULTI0 (SIODATA32_L) - //SIOMULTI1 (SIODATA32_H) - //SIOMULTI2 - //SIOMULTI3 - case 0x04000120: case 0x04000121: - case 0x04000122: case 0x04000123: - case 0x04000124: case 0x04000125: - case 0x04000126: case 0x04000127: { - player.write(byte, addr & 3); - auto& data = regs.serial.data[(addr >> 1) & 3]; - unsigned shift = (addr & 1) * 8; - data = (data & ~(255 << shift)) | (byte << shift); + case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: + return; + + //SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3 + case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126: + player.write(addr.bits(0,1), data); + regs.serial.data[addr.bits(1,2)].byte(0) = data; + return; + case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127: + player.write(addr.bits(0,1), data); + regs.serial.data[addr.bits(1,2)].byte(1) = data; return; - } //SIOCNT - case 0x04000128: regs.serial.control = (regs.serial.control & 0xff00) | (byte << 0); return; - case 0x04000129: regs.serial.control = (regs.serial.control & 0x00ff) | (byte << 8); return; + case 0x0400'0128: + regs.serial.control.shiftclockselect = data.bit(0); + regs.serial.control.shiftclockfrequency = data.bit(1); + regs.serial.control.transferenablereceive = data.bit(2); + regs.serial.control.transferenablesend = data.bit(3); + regs.serial.control.startbit = data.bit(7); + return; + case 0x0400'0129: + regs.serial.control.transferlength = data.bit(4); + regs.serial.control.irqenable = data.bit(6); + return; //SIOMLT_SEND (SIODATA8) - case 0x0400012a: regs.serial.data8 = byte; return; - case 0x0400012b: return; + case 0x0400'012a: regs.serial.data8 = data; return; + case 0x0400'012b: return; //KEYCNT - case 0x04000132: regs.keypad.control = (regs.keypad.control & 0xff00) | (byte << 0); return; - case 0x04000133: regs.keypad.control = (regs.keypad.control & 0x00ff) | (byte << 8); return; + case 0x0400'0132: + regs.keypad.control.flag[0] = data.bit(0); + regs.keypad.control.flag[1] = data.bit(1); + regs.keypad.control.flag[2] = data.bit(2); + regs.keypad.control.flag[3] = data.bit(3); + regs.keypad.control.flag[4] = data.bit(4); + regs.keypad.control.flag[5] = data.bit(5); + regs.keypad.control.flag[6] = data.bit(6); + regs.keypad.control.flag[7] = data.bit(7); + return; + case 0x0400'0133: + regs.keypad.control.flag[8] = data.bit(0); + regs.keypad.control.flag[9] = data.bit(1); + regs.keypad.control.enable = data.bit(6); + regs.keypad.control.condition = data.bit(7); + return; //RCNT - case 0x04000134: regs.joybus.settings = (regs.joybus.settings & 0xff00) | (byte << 0); return; - case 0x04000135: regs.joybus.settings = (regs.joybus.settings & 0x00ff) | (byte << 8); return; + case 0x0400'0134: + regs.joybus.settings.sc = data.bit(0); + regs.joybus.settings.sd = data.bit(1); + regs.joybus.settings.si = data.bit(2); + regs.joybus.settings.so = data.bit(3); + regs.joybus.settings.scmode = data.bit(4); + regs.joybus.settings.sdmode = data.bit(5); + regs.joybus.settings.simode = data.bit(6); + regs.joybus.settings.somode = data.bit(7); + return; + case 0x0400'0135: + regs.joybus.settings.irqenable = data.bit (0); + regs.joybus.settings.mode = data.bits(6,7); + return; //JOYCNT - case 0x04000140: regs.joybus.control = (regs.joybus.control & 0xff00) | (byte << 0); return; - case 0x04000141: regs.joybus.control = (regs.joybus.control & 0x00ff) | (byte << 8); return; + case 0x0400'0140: + regs.joybus.control.resetsignal = data.bit(0); + regs.joybus.control.receivecomplete = data.bit(1); + regs.joybus.control.sendcomplete = data.bit(2); + regs.joybus.control.irqenable = data.bit(6); + return; + case 0x0400'0141: return; + case 0x0400'0142: return; + case 0x0400'0143: return; //JOY_RECV_L //JOY_RECV_H - case 0x04000150: regs.joybus.receive = (regs.joybus.receive & 0xffffff00) | (byte << 0); return; - case 0x04000151: regs.joybus.receive = (regs.joybus.receive & 0xffff00ff) | (byte << 8); return; - case 0x04000152: regs.joybus.receive = (regs.joybus.receive & 0xff00ffff) | (byte << 16); return; - case 0x04000153: regs.joybus.receive = (regs.joybus.receive & 0x00ffffff) | (byte << 24); return; + case 0x0400'0150: regs.joybus.receive.byte(0) = data; return; + case 0x0400'0151: regs.joybus.receive.byte(1) = data; return; + case 0x0400'0152: regs.joybus.receive.byte(2) = data; return; + case 0x0400'0153: regs.joybus.receive.byte(3) = data; return; //JOY_TRANS_L //JOY_TRANS_H - case 0x04000154: regs.joybus.transmit = (regs.joybus.transmit & 0xffffff00) | (byte << 0); return; - case 0x04000155: regs.joybus.transmit = (regs.joybus.transmit & 0xffff00ff) | (byte << 8); return; - case 0x04000156: regs.joybus.transmit = (regs.joybus.transmit & 0xff00ffff) | (byte << 16); return; - case 0x04000157: regs.joybus.transmit = (regs.joybus.transmit & 0x00ffffff) | (byte << 24); return; + case 0x0400'0154: regs.joybus.transmit.byte(0) = data; return; + case 0x0400'0155: regs.joybus.transmit.byte(1) = data; return; + case 0x0400'0156: regs.joybus.transmit.byte(2) = data; return; + case 0x0400'0157: regs.joybus.transmit.byte(3) = data; return; //JOYSTAT - case 0x04000158: regs.joybus.status = (regs.joybus.status & 0xff00) | (byte << 0); return; - case 0x04000159: regs.joybus.status = (regs.joybus.status & 0x00ff) | (byte << 8); return; + case 0x0400'0158: + regs.joybus.status.receiveflag = data.bit (1); + regs.joybus.status.sendflag = data.bit (3); + regs.joybus.status.generalflag = data.bits(4,5); + return; + case 0x0400'0159: return; //IE - case 0x04000200: regs.irq.enable = (regs.irq.enable & 0xff00) | (byte << 0); return; - case 0x04000201: regs.irq.enable = (regs.irq.enable & 0x00ff) | (byte << 8); return; + case 0x0400'0200: regs.irq.enable.byte(0) = data; return; + case 0x0400'0201: regs.irq.enable.byte(1) = data; return; //IF - case 0x04000202: regs.irq.flag = regs.irq.flag & ~(byte << 0); return; - case 0x04000203: regs.irq.flag = regs.irq.flag & ~(byte << 8); return; + case 0x0400'0202: regs.irq.flag.byte(0) = regs.irq.flag.byte(0) & ~data; return; + case 0x0400'0203: regs.irq.flag.byte(1) = regs.irq.flag.byte(1) & ~data; return; //WAITCNT - case 0x04000204: regs.wait.control = (regs.wait.control & 0xff00) | ((byte & 0xff) << 0); return; - case 0x04000205: regs.wait.control = (regs.wait.control & 0x00ff) | ((byte & 0x7f) << 8); return; + case 0x0400'0204: + regs.wait.control.swait[3] = data.bit (0); //todo: is this correct? + regs.wait.control.nwait[3] = data.bits(0,1); + regs.wait.control.nwait[0] = data.bits(2,3); + regs.wait.control.swait[0] = data.bit (4); + regs.wait.control.nwait[1] = data.bits(5,6); + regs.wait.control.swait[1] = data.bit (7); + return; + case 0x0400'0205: + regs.wait.control.nwait[2] = data.bits(0,1); + regs.wait.control.swait[2] = data.bit (2); + regs.wait.control.phi = data.bit (3); + regs.wait.control.prefetch = data.bit (6); + regs.wait.control.gametype = data.bit (7); + return; //IME - case 0x04000208: regs.ime = byte >> 0; return; - case 0x04000209: return; + case 0x0400'0208: regs.ime = data.bit(0); return; + case 0x0400'0209: return; //POSTFLG, HALTCNT - case 0x04000300: regs.postboot |= byte >> 0; return; - case 0x04000301: regs.mode = byte & 0x80 ? Registers::Mode::Stop : Registers::Mode::Halt; return; + case 0x0400'0300: + if(data.bit(0)) regs.postboot = 1; + return; + case 0x0400'0301: + regs.mode = data.bit(7) ? Registers::Mode::Stop : Registers::Mode::Halt; + return; //MEMCNT_L //MEMCNT_H - case 0x04000800: regs.memory.control = (regs.memory.control & 0xffffff00) | (byte << 0); return; - case 0x04000801: regs.memory.control = (regs.memory.control & 0xffff00ff) | (byte << 8); return; - case 0x04000802: regs.memory.control = (regs.memory.control & 0xff00ffff) | (byte << 16); return; - case 0x04000803: regs.memory.control = (regs.memory.control & 0x00ffffff) | (byte << 24); return; + case 0x0400'0800: + regs.memory.control.disable = data.bit (0); + regs.memory.control.unknown1 = data.bits(1,3); + regs.memory.control.ewram = data.bit (5); + return; + case 0x0400'0801: return; + case 0x0400'0802: return; + case 0x0400'0803: + regs.memory.control.ewramwait = data.bits(0,3); + regs.memory.control.unknown2 = data.bits(4,7); + return; } } diff --git a/higan/gba/cpu/registers.cpp b/higan/gba/cpu/registers.cpp deleted file mode 100644 index d12e0f82..00000000 --- a/higan/gba/cpu/registers.cpp +++ /dev/null @@ -1,244 +0,0 @@ -CPU::Registers::DMAControl::operator uint16_t() const { - return ( - (targetmode << 5) - | (sourcemode << 7) - | (repeat << 9) - | (size << 10) - | (drq << 11) - | (timingmode << 12) - | (irq << 14) - | (enable << 15) - ); -} - -auto CPU::Registers::DMAControl::operator=(uint16 source) -> uint16 { - targetmode = source >> 5; - sourcemode = source >> 7; - repeat = source >> 9; - size = source >> 10; - drq = source >> 11; - timingmode = source >> 12; - irq = source >> 14; - enable = source >> 15; - return operator uint16_t(); -} - -CPU::Registers::TimerControl::operator uint16_t() const { - return ( - (frequency << 0) - | (cascade << 2) - | (irq << 6) - | (enable << 7) - ); -} - -auto CPU::Registers::TimerControl::operator=(uint16 source) -> uint16 { - frequency = source >> 0; - cascade = source >> 2; - irq = source >> 6; - enable = source >> 7; - return operator uint16_t(); -} - -CPU::Registers::SerialControl::operator uint16_t() const { - return ( - (shiftclockselect << 0) - | (shiftclockfrequency << 1) - | (transferenablereceive << 2) - | (transferenablesend << 3) - | (startbit << 7) - | (transferlength << 12) - | (irqenable << 14) - ); -} - -auto CPU::Registers::SerialControl::operator=(uint16 source) -> uint16 { - shiftclockselect = source >> 0; - shiftclockfrequency = source >> 1; - transferenablereceive = source >> 2; - transferenablesend = source >> 3; - startbit = source >> 7; - transferlength = source >> 12; - irqenable = source >> 14; - return operator uint16_t(); -} - -CPU::Registers::KeypadControl::operator uint16_t() const { - return ( - (flag[0] << 0) - | (flag[1] << 1) - | (flag[2] << 2) - | (flag[3] << 3) - | (flag[4] << 4) - | (flag[5] << 5) - | (flag[6] << 6) - | (flag[7] << 7) - | (flag[8] << 8) - | (flag[9] << 9) - | (enable << 14) - | (condition << 15) - ); -} - -auto CPU::Registers::KeypadControl::operator=(uint16 source) -> uint16 { - flag[0] = source >> 0; - flag[1] = source >> 1; - flag[2] = source >> 2; - flag[3] = source >> 3; - flag[4] = source >> 4; - flag[5] = source >> 5; - flag[6] = source >> 6; - flag[7] = source >> 7; - flag[8] = source >> 8; - flag[9] = source >> 9; - enable = source >> 14; - condition = source >> 15; - return operator uint16_t(); -} - -CPU::Registers::JoybusSettings::operator uint16_t() const { - return ( - (sc << 0) - | (sd << 1) - | (si << 2) - | (so << 3) - | (scmode << 4) - | (sdmode << 5) - | (simode << 6) - | (somode << 7) - | (irqenable << 8) - | (mode << 14) - ); -} - -auto CPU::Registers::JoybusSettings::operator=(uint16 source) -> uint16 { - sc = source >> 0; - sd = source >> 1; - si = source >> 2; - so = source >> 3; - scmode = source >> 4; - sdmode = source >> 5; - simode = source >> 6; - somode = source >> 7; - irqenable = source >> 8; - mode = source >> 14; - return operator uint16_t(); -} - -CPU::Registers::JoybusControl::operator uint16_t() const { - return ( - (resetsignal << 0) - | (receivecomplete << 1) - | (sendcomplete << 2) - | (irqenable << 6) - ); -} - -auto CPU::Registers::JoybusControl::operator=(uint16 source) -> uint16 { - resetsignal = source >> 0; - receivecomplete = source >> 1; - sendcomplete = source >> 2; - irqenable = source >> 6; - return operator uint16_t(); -} - -CPU::Registers::JoybusStatus::operator uint16_t() const { - return ( - (receiveflag << 1) - | (sendflag << 3) - | (generalflag << 4) - ); -} - -auto CPU::Registers::JoybusStatus::operator=(uint16 source) -> uint16 { - receiveflag = source >> 1; - sendflag = source >> 3; - generalflag = source >> 4; - return operator uint16_t(); -} - -CPU::Registers::Interrupt::operator uint16_t() const { - return ( - (vblank << 0) - | (hblank << 1) - | (vcoincidence << 2) - | (timer[0] << 3) - | (timer[1] << 4) - | (timer[2] << 5) - | (timer[3] << 6) - | (serial << 7) - | (dma[0] << 8) - | (dma[1] << 9) - | (dma[2] << 10) - | (dma[3] << 11) - | (keypad << 12) - | (cartridge << 13) - ); -} - -auto CPU::Registers::Interrupt::operator=(uint16 source) -> uint16 { - vblank = source >> 0; - hblank = source >> 1; - vcoincidence = source >> 2; - timer[0] = source >> 3; - timer[1] = source >> 4; - timer[2] = source >> 5; - timer[3] = source >> 6; - serial = source >> 7; - dma[0] = source >> 8; - dma[1] = source >> 9; - dma[2] = source >> 10; - dma[3] = source >> 11; - keypad = source >> 12; - cartridge = source >> 13; - return operator uint16_t(); -} - -CPU::Registers::WaitControl::operator uint16_t() const { - return ( - (nwait[3] << 0) - | (nwait[0] << 2) - | (swait[0] << 4) - | (nwait[1] << 5) - | (swait[1] << 7) - | (nwait[2] << 8) - | (swait[2] << 10) - | (phi << 11) - | (prefetch << 14) - | (gametype << 15) - ); -} - -auto CPU::Registers::WaitControl::operator=(uint16 source) -> uint16 { - nwait[3] = (source >> 0) & 3; - nwait[0] = (source >> 2) & 3; - swait[0] = (source >> 4) & 1; - nwait[1] = (source >> 5) & 3; - swait[1] = (source >> 7) & 1; - nwait[2] = (source >> 8) & 3; - swait[2] = (source >> 10) & 1; - phi = (source >> 11) & 3; - prefetch = (source >> 14) & 1; - gametype = (source >> 15) & 1; - swait[3] = nwait[3]; - return operator uint16_t(); -} - -CPU::Registers::MemoryControl::operator uint32_t() const { - return ( - (disable << 0) - | (unknown1 << 1) - | (ewram << 5) - | (ewramwait << 24) - | (unknown2 << 28) - ); -} - -auto CPU::Registers::MemoryControl::operator=(uint32 source) -> uint32 { - disable = source >> 0; - unknown1 = source >> 1; - ewram = source >> 5; - ewramwait = source >> 24; - unknown2 = source >> 28; - return operator uint32_t(); -} diff --git a/higan/gba/cpu/registers.hpp b/higan/gba/cpu/registers.hpp index a9f06786..6c3c72f7 100644 --- a/higan/gba/cpu/registers.hpp +++ b/higan/gba/cpu/registers.hpp @@ -1,185 +1,116 @@ struct Registers { - struct DMAControl { - uint2 targetmode; - uint2 sourcemode; - uint1 repeat; - uint1 size; - uint1 drq; - uint2 timingmode; - uint1 irq; - uint1 enable; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const DMAControl&) -> DMAControl& = delete; - }; - struct DMA { - varuint_t source; - varuint_t target; - varuint_t length; + VariadicNatural source; + VariadicNatural target; + VariadicNatural length; uint32 data; - DMAControl control; + struct Control { + uint2 targetmode; + uint2 sourcemode; + uint1 repeat; + uint1 size; + uint1 drq; + uint2 timingmode; + uint1 irq; + uint1 enable; + } control; //internal bool pending; struct Run { - varuint_t target; - varuint_t source; - varuint_t length; + VariadicNatural target; + VariadicNatural source; + VariadicNatural length; } run; } dma[4]; - struct TimerControl { - uint2 frequency; - uint1 cascade; - uint1 irq; - uint1 enable; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const TimerControl&) -> TimerControl& = delete; - }; - struct Timer { uint16 period; uint16 reload; bool pending; - TimerControl control; + struct Control { + uint2 frequency; + uint1 cascade; + uint1 irq; + uint1 enable; + } control; } timer[4]; - struct SerialControl { - uint1 shiftclockselect; - uint1 shiftclockfrequency; - uint1 transferenablereceive; - uint1 transferenablesend; - uint1 startbit; - uint1 transferlength; - uint1 irqenable; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const SerialControl&) -> SerialControl& = delete; - }; - struct Serial { uint16 data[4]; - SerialControl control; + struct Control { + uint1 shiftclockselect; + uint1 shiftclockfrequency; + uint1 transferenablereceive; + uint1 transferenablesend; + uint1 startbit; + uint1 transferlength; + uint1 irqenable; + } control; uint8 data8; } serial; - struct KeypadControl { - uint1 flag[10]; - uint1 enable; - uint1 condition; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const KeypadControl&) -> KeypadControl& = delete; - }; - struct Keypad { - KeypadControl control; + struct Control { + uint1 flag[10]; + uint1 enable; + uint1 condition; + } control; } keypad; - struct JoybusSettings { - uint1 sc; - uint1 sd; - uint1 si; - uint1 so; - uint1 scmode; - uint1 sdmode; - uint1 simode; - uint1 somode; - uint1 irqenable; - uint2 mode; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const JoybusSettings&) -> JoybusSettings& = delete; - }; - - struct JoybusControl { - uint1 resetsignal; - uint1 receivecomplete; - uint1 sendcomplete; - uint1 irqenable; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const JoybusControl&) -> JoybusControl& = delete; - }; - - struct JoybusStatus { - uint1 receiveflag; - uint1 sendflag; - uint2 generalflag; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const JoybusStatus&) -> JoybusStatus& = delete; - }; - struct Joybus { - JoybusSettings settings; - JoybusControl control; + struct Settings { + uint1 sc; + uint1 sd; + uint1 si; + uint1 so; + uint1 scmode; + uint1 sdmode; + uint1 simode; + uint1 somode; + uint1 irqenable; + uint2 mode; + } settings; + struct Control { + uint1 resetsignal; + uint1 receivecomplete; + uint1 sendcomplete; + uint1 irqenable; + } control; uint32 receive; uint32 transmit; - JoybusStatus status; + struct Status { + uint1 receiveflag; + uint1 sendflag; + uint2 generalflag; + } status; } joybus; uint1 ime; - struct Interrupt { - uint1 vblank; - uint1 hblank; - uint1 vcoincidence; - uint1 timer[4]; - uint1 serial; - uint1 dma[4]; - uint1 keypad; - uint1 cartridge; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const Interrupt&) -> Interrupt& = delete; - }; - struct IRQ { - Interrupt enable; - Interrupt flag; + uint16 enable; + uint16 flag; } irq; - struct WaitControl { - uint2 nwait[4]; - uint1 swait[4]; - uint2 phi; - uint1 prefetch; - uint1 gametype; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const WaitControl&) -> WaitControl& = delete; - }; - struct Wait { - WaitControl control; + struct Control { + uint2 nwait[4]; + uint1 swait[4]; + uint2 phi; + uint1 prefetch; + uint1 gametype; + } control; } wait; - struct MemoryControl { - uint1 disable; - uint3 unknown1; - uint1 ewram; - uint4 ewramwait; - uint4 unknown2; - - operator uint32_t() const; - auto operator=(uint32 source) -> uint32; - auto operator=(const MemoryControl&) -> MemoryControl& = delete; - }; - struct Memory { - MemoryControl control; + struct Control { + uint1 disable; + uint3 unknown1; + uint1 ewram; + uint4 ewramwait; + uint4 unknown2; + } control; } memory; uint1 postboot; diff --git a/higan/gba/cpu/serialization.cpp b/higan/gba/cpu/serialization.cpp index dd3f53fa..2b292bdc 100644 --- a/higan/gba/cpu/serialization.cpp +++ b/higan/gba/cpu/serialization.cpp @@ -72,23 +72,8 @@ auto CPU::serialize(serializer& s) -> void { s.integer(regs.ime); - s.integer(regs.irq.enable.vblank); - s.integer(regs.irq.enable.hblank); - s.integer(regs.irq.enable.vcoincidence); - for(auto& flag : regs.irq.enable.timer) s.integer(flag); - s.integer(regs.irq.enable.serial); - for(auto& flag : regs.irq.enable.dma) s.integer(flag); - s.integer(regs.irq.enable.keypad); - s.integer(regs.irq.enable.cartridge); - - s.integer(regs.irq.flag.vblank); - s.integer(regs.irq.flag.hblank); - s.integer(regs.irq.flag.vcoincidence); - for(auto& flag : regs.irq.flag.timer) s.integer(flag); - s.integer(regs.irq.flag.serial); - for(auto& flag : regs.irq.flag.dma) s.integer(flag); - s.integer(regs.irq.flag.keypad); - s.integer(regs.irq.flag.cartridge); + s.integer(regs.irq.enable); + s.integer(regs.irq.flag); for(auto& flag : regs.wait.control.nwait) s.integer(flag); for(auto& flag : regs.wait.control.swait) s.integer(flag); diff --git a/higan/gba/cpu/timer.cpp b/higan/gba/cpu/timer.cpp index b05d59e7..09a7e74b 100644 --- a/higan/gba/cpu/timer.cpp +++ b/higan/gba/cpu/timer.cpp @@ -28,7 +28,7 @@ auto CPU::timer_increment(uint n) -> void { if(++timer.period == 0) { timer.period = timer.reload; - if(timer.control.irq) regs.irq.flag.timer[n] = 1; + if(timer.control.irq) regs.irq.flag |= Interrupt::Timer0 << n; if(apu.fifo[0].timer == n) timer_fifo_run(0); if(apu.fifo[1].timer == n) timer_fifo_run(1); diff --git a/higan/gba/player/player.cpp b/higan/gba/player/player.cpp index 80a69f75..0c1d39fa 100644 --- a/higan/gba/player/player.cpp +++ b/higan/gba/player/player.cpp @@ -31,7 +31,26 @@ auto Player::frame() -> void { if(!status.enable) return; - if(cpu.regs.joybus.settings == 0x0000 && cpu.regs.serial.control == 0x5088) { + //todo: verify which settings are actually required + //values were taken from observing GBP-compatible games + if(!cpu.regs.joybus.settings.sc + && !cpu.regs.joybus.settings.sd + && !cpu.regs.joybus.settings.si + && !cpu.regs.joybus.settings.so + && !cpu.regs.joybus.settings.scmode + && !cpu.regs.joybus.settings.sdmode + && !cpu.regs.joybus.settings.simode + && !cpu.regs.joybus.settings.somode + && !cpu.regs.joybus.settings.irqenable + && !cpu.regs.joybus.settings.mode + && !cpu.regs.serial.control.shiftclockselect + && !cpu.regs.serial.control.shiftclockfrequency + && !cpu.regs.serial.control.transferenablereceive + && cpu.regs.serial.control.transferenablesend + && cpu.regs.serial.control.startbit + && cpu.regs.serial.control.transferlength + && cpu.regs.serial.control.irqenable + ) { status.packet = (status.packet + 1) % 17; switch(status.packet) { case 0: status.send = 0x0000494e; break; @@ -52,7 +71,7 @@ auto Player::frame() -> void { case 15: status.send = 0x30000003; break; case 16: status.send = 0x30000003; break; } - cpu.regs.irq.flag.serial = true; + cpu.regs.irq.flag |= CPU::Interrupt::Serial; } } @@ -72,7 +91,7 @@ auto Player::read() -> maybe { return nothing; } -auto Player::write(uint8 byte, uint2 addr) -> void { +auto Player::write(uint2 addr, uint8 byte) -> void { if(!status.enable) return; uint shift = addr << 3; diff --git a/higan/gba/player/player.hpp b/higan/gba/player/player.hpp index 56377645..8e65cd0e 100644 --- a/higan/gba/player/player.hpp +++ b/higan/gba/player/player.hpp @@ -16,7 +16,7 @@ struct Player { auto keyinput() -> maybe; auto read() -> maybe; - auto write(uint8 byte, uint2 addr) -> void; + auto write(uint2 addr, uint8 byte) -> void; auto serialize(serializer& s) -> void; }; diff --git a/higan/gba/ppu/mmio.cpp b/higan/gba/ppu/mmio.cpp index 46f5c280..698b0b48 100644 --- a/higan/gba/ppu/mmio.cpp +++ b/higan/gba/ppu/mmio.cpp @@ -2,44 +2,44 @@ auto PPU::read(uint32 addr) -> uint8 { switch(addr) { //DISPCNT - case 0x04000000: return regs.control >> 0; - case 0x04000001: return regs.control >> 8; + case 0x0400'0000: return regs.control >> 0; + case 0x0400'0001: return regs.control >> 8; //GRSWP - case 0x04000002: return regs.greenswap; - case 0x04000003: return 0u; + case 0x0400'0002: return regs.greenswap; + case 0x0400'0003: return 0u; //DISPSTAT - case 0x04000004: return regs.status >> 0; - case 0x04000005: return regs.status >> 8; + case 0x0400'0004: return regs.status >> 0; + case 0x0400'0005: return regs.status >> 8; //VCOUNT - case 0x04000006: return regs.vcounter >> 0; - case 0x04000007: return regs.vcounter >> 8; + case 0x0400'0006: return regs.vcounter >> 0; + case 0x0400'0007: return regs.vcounter >> 8; //BG0CNT,BG1CNT,BG2CNT,BG3CNT - case 0x04000008: case 0x04000009: - case 0x0400000a: case 0x0400000b: - case 0x0400000c: case 0x0400000d: - case 0x0400000e: case 0x0400000f: { + case 0x0400'0008: case 0x0400'0009: + case 0x0400'000a: case 0x0400'000b: + case 0x0400'000c: case 0x0400'000d: + case 0x0400'000e: case 0x0400'000f: { auto& bg = regs.bg[(addr >> 1) & 3]; unsigned shift = (addr & 1) * 8; return bg.control >> shift; } //WININ - case 0x04000048: return regs.windowflags[In0]; - case 0x04000049: return regs.windowflags[In1]; - case 0x0400004a: return regs.windowflags[Out]; - case 0x0400004b: return regs.windowflags[Obj]; + case 0x0400'0048: return regs.windowflags[In0]; + case 0x0400'0049: return regs.windowflags[In1]; + case 0x0400'004a: return regs.windowflags[Out]; + case 0x0400'004b: return regs.windowflags[Obj]; //BLTCNT - case 0x04000050: return regs.blend.control >> 0; - case 0x04000051: return regs.blend.control >> 8; + case 0x0400'0050: return regs.blend.control >> 0; + case 0x0400'0051: return regs.blend.control >> 8; //BLDALPHA - case 0x04000052: return regs.blend.eva; - case 0x04000053: return regs.blend.evb; + case 0x0400'0052: return regs.blend.eva; + case 0x0400'0053: return regs.blend.evb; //BLDY is write-only @@ -52,28 +52,28 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { switch(addr) { //DISPCNT - case 0x04000000: regs.control = (regs.control & 0xff00) | (byte << 0); return; - case 0x04000001: regs.control = (regs.control & 0x00ff) | (byte << 8); return; + case 0x0400'0000: regs.control = (regs.control & 0xff00) | (byte << 0); return; + case 0x0400'0001: regs.control = (regs.control & 0x00ff) | (byte << 8); return; //GRSWP - case 0x04000002: regs.greenswap = byte >> 0; return; - case 0x04000003: return; + case 0x0400'0002: regs.greenswap = byte >> 0; return; + case 0x0400'0003: return; //DISPSTAT - case 0x04000004: + case 0x0400'0004: regs.status.irqvblank = byte >> 3; regs.status.irqhblank = byte >> 4; regs.status.irqvcoincidence = byte >> 5; return; - case 0x04000005: + case 0x0400'0005: regs.status.vcompare = byte; return; //BG0CNT,BG1CNT,BG2CNT,BG3CNT - case 0x04000008: case 0x04000009: - case 0x0400000a: case 0x0400000b: - case 0x0400000c: case 0x0400000d: - case 0x0400000e: case 0x0400000f: { + case 0x0400'0008: case 0x0400'0009: + case 0x0400'000a: case 0x0400'000b: + case 0x0400'000c: case 0x0400'000d: + case 0x0400'000e: case 0x0400'000f: { auto& bg = regs.bg[(addr >> 1) & 3]; unsigned shift = (addr & 1) * 8; if(addr == 0x04000009 || addr == 0x0400000b) byte &= 0xdf; //clear affine wrap for BG0,1 @@ -82,10 +82,10 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG0HOFS,BG1HOFS,BG2BOFS,BG3HOFS - case 0x04000010: case 0x04000011: - case 0x04000014: case 0x04000015: - case 0x04000018: case 0x04000019: - case 0x0400001c: case 0x0400001d: { + case 0x0400'0010: case 0x0400'0011: + case 0x0400'0014: case 0x0400'0015: + case 0x0400'0018: case 0x0400'0019: + case 0x0400'001c: case 0x0400'001d: { auto& bg = regs.bg[(addr >> 2) & 3]; unsigned shift = (addr & 1) * 8; bg.hoffset = (bg.hoffset & ~(255 << shift)) | (byte << shift); @@ -93,10 +93,10 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG0VOFS,BG1VOFS,BG2VOFS,BG3VOFS - case 0x04000012: case 0x04000013: - case 0x04000016: case 0x04000017: - case 0x0400001a: case 0x0400001b: - case 0x0400001e: case 0x0400001f: { + case 0x0400'0012: case 0x0400'0013: + case 0x0400'0016: case 0x0400'0017: + case 0x0400'001a: case 0x0400'001b: + case 0x0400'001e: case 0x0400'001f: { auto& bg = regs.bg[(addr >> 2) & 3]; unsigned shift = (addr & 1) * 8; bg.voffset = (bg.voffset & ~(255 << shift)) | (byte << shift); @@ -104,8 +104,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG2PA,BG3PA - case 0x04000020: case 0x04000021: - case 0x04000030: case 0x04000031: { + case 0x0400'0020: case 0x0400'0021: + case 0x0400'0030: case 0x0400'0031: { auto& bg = regs.bg[(addr >> 4) & 3]; unsigned shift = (addr & 1) * 8; bg.pa = (bg.pa & ~(255 << shift)) | (byte << shift); @@ -113,8 +113,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG2PB,BG3PB - case 0x04000022: case 0x04000023: - case 0x04000032: case 0x04000033: { + case 0x0400'0022: case 0x0400'0023: + case 0x0400'0032: case 0x0400'0033: { auto& bg = regs.bg[(addr >> 4) & 3]; unsigned shift = (addr & 1) * 8; bg.pb = (bg.pb & ~(255 << shift)) | (byte << shift); @@ -122,8 +122,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG2PC,BG3PC - case 0x04000024: case 0x04000025: - case 0x04000034: case 0x04000035: { + case 0x0400'0024: case 0x0400'0025: + case 0x0400'0034: case 0x0400'0035: { auto& bg = regs.bg[(addr >> 4) & 3]; unsigned shift = (addr & 1) * 8; bg.pc = (bg.pc & ~(255 << shift)) | (byte << shift); @@ -131,8 +131,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG2PD,BG3PD - case 0x04000026: case 0x04000027: - case 0x04000036: case 0x04000037: { + case 0x0400'0026: case 0x0400'0027: + case 0x0400'0036: case 0x0400'0037: { auto& bg = regs.bg[(addr >> 4) & 3]; unsigned shift = (addr & 1) * 8; bg.pd = (bg.pd & ~(255 << shift)) | (byte << shift); @@ -140,8 +140,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG2X_L,BG2X_H,BG3X_L,BG3X_H - case 0x04000028: case 0x04000029: case 0x0400002a: case 0x0400002b: - case 0x04000038: case 0x04000039: case 0x0400003a: case 0x0400003b: { + case 0x0400'0028: case 0x0400'0029: case 0x0400'002a: case 0x0400'002b: + case 0x0400'0038: case 0x0400'0039: case 0x0400'003a: case 0x0400'003b: { auto& bg = regs.bg[(addr >> 4) & 3]; unsigned shift = (addr & 3) * 8; bg.lx = bg.x = (bg.x & ~(255 << shift)) | (byte << shift); @@ -149,8 +149,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //BG2Y_L,BG2Y_H,BG3Y_L,BG3Y_H - case 0x0400002c: case 0x0400002d: case 0x0400002e: case 0x0400002f: - case 0x0400003c: case 0x0400003d: case 0x0400003e: case 0x0400003f: { + case 0x0400'002c: case 0x0400'002d: case 0x0400'002e: case 0x0400'002f: + case 0x0400'003c: case 0x0400'003d: case 0x0400'003e: case 0x0400'003f: { auto& bg = regs.bg[(addr >> 4) & 3]; unsigned shift = (addr & 3) * 8; bg.ly = bg.y = (bg.y & ~(255 << shift)) | (byte << shift); @@ -158,50 +158,50 @@ auto PPU::write(uint32 addr, uint8 byte) -> void { } //WIN0H - case 0x04000040: regs.window[0].x2 = byte; return; - case 0x04000041: regs.window[0].x1 = byte; return; + case 0x0400'0040: regs.window[0].x2 = byte; return; + case 0x0400'0041: regs.window[0].x1 = byte; return; //WIN1H - case 0x04000042: regs.window[1].x2 = byte; return; - case 0x04000043: regs.window[1].x1 = byte; return; + case 0x0400'0042: regs.window[1].x2 = byte; return; + case 0x0400'0043: regs.window[1].x1 = byte; return; //WIN0V - case 0x04000044: regs.window[0].y2 = byte; return; - case 0x04000045: regs.window[0].y1 = byte; return; + case 0x0400'0044: regs.window[0].y2 = byte; return; + case 0x0400'0045: regs.window[0].y1 = byte; return; //WIN1V - case 0x04000046: regs.window[1].y2 = byte; return; - case 0x04000047: regs.window[1].y1 = byte; return; + case 0x0400'0046: regs.window[1].y2 = byte; return; + case 0x0400'0047: regs.window[1].y1 = byte; return; //WININ - case 0x04000048: regs.windowflags[In0] = byte; return; - case 0x04000049: regs.windowflags[In1] = byte; return; + case 0x0400'0048: regs.windowflags[In0] = byte; return; + case 0x0400'0049: regs.windowflags[In1] = byte; return; //WINOUT - case 0x0400004a: regs.windowflags[Out] = byte; return; - case 0x0400004b: regs.windowflags[Obj] = byte; return; + case 0x0400'004a: regs.windowflags[Out] = byte; return; + case 0x0400'004b: regs.windowflags[Obj] = byte; return; //MOSAIC - case 0x0400004c: + case 0x0400'004c: regs.mosaic.bghsize = byte >> 0; regs.mosaic.bgvsize = byte >> 4; return; - case 0x0400004d: + case 0x0400'004d: regs.mosaic.objhsize = byte >> 0; regs.mosaic.objvsize = byte >> 4; return; //BLDCNT - case 0x04000050: regs.blend.control = (regs.blend.control & 0xff00) | (byte << 0); return; - case 0x04000051: regs.blend.control = (regs.blend.control & 0x00ff) | (byte << 8); return; + case 0x0400'0050: regs.blend.control = (regs.blend.control & 0xff00) | (byte << 0); return; + case 0x0400'0051: regs.blend.control = (regs.blend.control & 0x00ff) | (byte << 8); return; //BLDALPHA - case 0x04000052: regs.blend.eva = byte & 0x1f; return; - case 0x04000053: regs.blend.evb = byte & 0x1f; return; + case 0x0400'0052: regs.blend.eva = byte & 0x1f; return; + case 0x0400'0053: regs.blend.evb = byte & 0x1f; return; //BLDY - case 0x04000054: regs.blend.evy = byte & 0x1f; return; - case 0x04000055: return; + case 0x0400'0054: regs.blend.evy = byte & 0x1f; return; + case 0x0400'0055: return; } } diff --git a/higan/gba/ppu/ppu.cpp b/higan/gba/ppu/ppu.cpp index 18e20048..d6ec98b8 100644 --- a/higan/gba/ppu/ppu.cpp +++ b/higan/gba/ppu/ppu.cpp @@ -113,12 +113,12 @@ auto PPU::scanline() -> void { } if(regs.vcounter == 160) { - if(regs.status.irqvblank) cpu.regs.irq.flag.vblank = 1; + if(regs.status.irqvblank) cpu.regs.irq.flag |= CPU::Interrupt::VBlank; cpu.dma_vblank(); } if(regs.status.irqvcoincidence) { - if(regs.status.vcoincidence) cpu.regs.irq.flag.vcoincidence = 1; + if(regs.status.vcoincidence) cpu.regs.irq.flag |= CPU::Interrupt::VCoincidence; } if(regs.vcounter < 160) { @@ -146,7 +146,7 @@ auto PPU::scanline() -> void { step(960); regs.status.hblank = 1; - if(regs.status.irqhblank) cpu.regs.irq.flag.hblank = 1; + if(regs.status.irqhblank) cpu.regs.irq.flag |= CPU::Interrupt::HBlank; if(regs.vcounter < 160) cpu.dma_hblank(); step(240); diff --git a/higan/processor/upd96050/upd96050.cpp b/higan/processor/upd96050/upd96050.cpp index c9f6e870..4dd237d8 100644 --- a/higan/processor/upd96050/upd96050.cpp +++ b/higan/processor/upd96050/upd96050.cpp @@ -11,15 +11,15 @@ namespace Processor { auto uPD96050::power() -> void { if(revision == Revision::uPD7725) { - regs.pc.bits(11); - regs.rp.bits(10); - regs.dp.bits( 8); + regs.pc.resize(11); + regs.rp.resize(10); + regs.dp.resize( 8); } if(revision == Revision::uPD96050) { - regs.pc.bits(14); - regs.rp.bits(11); - regs.dp.bits(11); + regs.pc.resize(14); + regs.rp.resize(11); + regs.dp.resize(11); } for(auto n : range(16)) regs.stack[n] = 0x0000; diff --git a/higan/processor/upd96050/upd96050.hpp b/higan/processor/upd96050/upd96050.hpp index 751eb538..afbfc84b 100644 --- a/higan/processor/upd96050/upd96050.hpp +++ b/higan/processor/upd96050/upd96050.hpp @@ -49,9 +49,9 @@ struct uPD96050 { struct Regs { uint16 stack[16]; //LIFO - varuint_t pc; //program counter - varuint_t rp; //ROM pointer - varuint_t dp; //data pointer + VariadicNatural pc; //program counter + VariadicNatural rp; //ROM pointer + VariadicNatural dp; //data pointer uint4 sp; //stack pointer int16 k; int16 l; diff --git a/higan/processor/v30mz/instructions-exec.cpp b/higan/processor/v30mz/instructions-exec.cpp index 83f20da9..07ab5732 100644 --- a/higan/processor/v30mz/instructions-exec.cpp +++ b/higan/processor/v30mz/instructions-exec.cpp @@ -179,7 +179,7 @@ auto V30MZ::opPopAll() { r.dx = pop(); r.cx = pop(); r.ax = pop(); - r.sp = sp; + //r.sp is not restored } //68 push imm16 diff --git a/higan/target-tomoko/tomoko.cpp b/higan/target-tomoko/tomoko.cpp index 9a8a08b6..ed3997cd 100644 --- a/higan/target-tomoko/tomoko.cpp +++ b/higan/target-tomoko/tomoko.cpp @@ -6,10 +6,10 @@ Emulator::Interface* emulator = nullptr; auto locate(string name) -> string { string location = {programpath(), name}; - if(file_system_object::exists(location)) return location; + if(inode::exists(location)) return location; location = {configpath(), "higan/", name}; - if(file_system_object::exists(location)) return location; + if(inode::exists(location)) return location; directory::create({localpath(), "higan/"}); return {localpath(), "higan/", name}; diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index 7a45cca7..8a1aca54 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -6,10 +6,10 @@ using namespace hiro; auto locate(string name) -> string { string location = {programpath(), name}; - if(file_system_object::exists(location)) return location; + if(inode::exists(location)) return location; location = {configpath(), "icarus/", name}; - if(file_system_object::exists(location)) return location; + if(inode::exists(location)) return location; directory::create({localpath(), "icarus/"}); return {localpath(), "icarus/", name}; diff --git a/nall/beat/archive.hpp b/nall/beat/archive.hpp index fab11225..65be3387 100644 --- a/nall/beat/archive.hpp +++ b/nall/beat/archive.hpp @@ -29,9 +29,9 @@ auto Archive::create(const string& beatname, const string& pathname, const strin for(auto& name : contents) { string location{pathname, name}; bool directory = name.endsWith("/"); - bool writable = file_system_object::writable(location); - bool executable = file_system_object::executable(location); - unsigned info = directory << 0 | writable << 1 | executable << 2 | (name.rtrim("/").size() - 1) << 3; + bool writable = inode::writable(location); + bool executable = inode::executable(location); + uint info = directory << 0 | writable << 1 | executable << 2 | (name.rtrim("/").size() - 1) << 3; beat.writevu(info); beat.writes(name); diff --git a/nall/directory.hpp b/nall/directory.hpp index 3246324f..34ced00b 100644 --- a/nall/directory.hpp +++ b/nall/directory.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include @@ -17,7 +17,7 @@ namespace nall { -struct directory : file_system_object { +struct directory : inode { static auto create(const string& pathname, unsigned permissions = 0755) -> bool; //recursive static auto remove(const string& pathname) -> bool; //recursive static auto exists(const string& pathname) -> bool; diff --git a/nall/file.hpp b/nall/file.hpp index b570d050..b4495aca 100644 --- a/nall/file.hpp +++ b/nall/file.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include @@ -11,7 +11,7 @@ namespace nall { -struct file : file_system_object, varint { +struct file : inode, varint { enum class mode : uint { read, write, modify, append, readwrite = modify, writeread = append }; enum class index : uint { absolute, relative }; diff --git a/nall/file-system-object.hpp b/nall/inode.hpp similarity index 92% rename from nall/file-system-object.hpp rename to nall/inode.hpp index a418cc6a..a5f9e907 100644 --- a/nall/file-system-object.hpp +++ b/nall/inode.hpp @@ -8,7 +8,7 @@ namespace nall { -struct file_system_object { +struct inode { enum class time : unsigned { access, modify }; static auto exists(const string& name) -> bool { @@ -70,8 +70,13 @@ struct file_system_object { //returns false if 'name' is a directory that is not empty static auto remove(const string& name) -> bool { + #if defined(PLATFORM_WINDOWS) + if(name.endsWith("/")) return _wrmdir(utf16_t(name)) == 0; + return _wunlink(utf16_t(name)) == 0; + #else if(name.endsWith("/")) return rmdir(name) == 0; return unlink(name) == 0; + #endif } }; diff --git a/nall/nall.hpp b/nall/nall.hpp index 8b425562..fe5ea45b 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -23,12 +23,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/nall/primitives.hpp b/nall/primitives.hpp index 7a20b0fa..f551aa54 100644 --- a/nall/primitives.hpp +++ b/nall/primitives.hpp @@ -212,3 +212,139 @@ template struct Real { }; } + +using boolean = nall::Boolean; + +using int1 = nall::Integer< 1>; +using int2 = nall::Integer< 2>; +using int3 = nall::Integer< 3>; +using int4 = nall::Integer< 4>; +using int5 = nall::Integer< 5>; +using int6 = nall::Integer< 6>; +using int7 = nall::Integer< 7>; +using int8 = nall::Integer< 8>; +using int9 = nall::Integer< 9>; +using int10 = nall::Integer<10>; +using int11 = nall::Integer<11>; +using int12 = nall::Integer<12>; +using int13 = nall::Integer<13>; +using int14 = nall::Integer<14>; +using int15 = nall::Integer<15>; +using int16 = nall::Integer<16>; +using int17 = nall::Integer<17>; +using int18 = nall::Integer<18>; +using int19 = nall::Integer<19>; +using int20 = nall::Integer<20>; +using int21 = nall::Integer<21>; +using int22 = nall::Integer<22>; +using int23 = nall::Integer<23>; +using int24 = nall::Integer<24>; +using int25 = nall::Integer<25>; +using int26 = nall::Integer<26>; +using int27 = nall::Integer<27>; +using int28 = nall::Integer<28>; +using int29 = nall::Integer<29>; +using int30 = nall::Integer<30>; +using int31 = nall::Integer<31>; +using int32 = nall::Integer<32>; +using int33 = nall::Integer<33>; +using int34 = nall::Integer<34>; +using int35 = nall::Integer<35>; +using int36 = nall::Integer<36>; +using int37 = nall::Integer<37>; +using int38 = nall::Integer<38>; +using int39 = nall::Integer<39>; +using int40 = nall::Integer<40>; +using int41 = nall::Integer<41>; +using int42 = nall::Integer<42>; +using int43 = nall::Integer<43>; +using int44 = nall::Integer<44>; +using int45 = nall::Integer<45>; +using int46 = nall::Integer<46>; +using int47 = nall::Integer<47>; +using int48 = nall::Integer<48>; +using int49 = nall::Integer<49>; +using int50 = nall::Integer<50>; +using int51 = nall::Integer<51>; +using int52 = nall::Integer<52>; +using int53 = nall::Integer<53>; +using int54 = nall::Integer<54>; +using int55 = nall::Integer<55>; +using int56 = nall::Integer<56>; +using int57 = nall::Integer<57>; +using int58 = nall::Integer<58>; +using int59 = nall::Integer<59>; +using int60 = nall::Integer<60>; +using int61 = nall::Integer<61>; +using int62 = nall::Integer<62>; +using int63 = nall::Integer<63>; +using int64 = nall::Integer<64>; + +using uint1 = nall::Natural< 1>; +using uint2 = nall::Natural< 2>; +using uint3 = nall::Natural< 3>; +using uint4 = nall::Natural< 4>; +using uint5 = nall::Natural< 5>; +using uint6 = nall::Natural< 6>; +using uint7 = nall::Natural< 7>; +using uint8 = nall::Natural< 8>; +using uint9 = nall::Natural< 9>; +using uint10 = nall::Natural<10>; +using uint11 = nall::Natural<11>; +using uint12 = nall::Natural<12>; +using uint13 = nall::Natural<13>; +using uint14 = nall::Natural<14>; +using uint15 = nall::Natural<15>; +using uint16 = nall::Natural<16>; +using uint17 = nall::Natural<17>; +using uint18 = nall::Natural<18>; +using uint19 = nall::Natural<19>; +using uint20 = nall::Natural<20>; +using uint21 = nall::Natural<21>; +using uint22 = nall::Natural<22>; +using uint23 = nall::Natural<23>; +using uint24 = nall::Natural<24>; +using uint25 = nall::Natural<25>; +using uint26 = nall::Natural<26>; +using uint27 = nall::Natural<27>; +using uint28 = nall::Natural<28>; +using uint29 = nall::Natural<29>; +using uint30 = nall::Natural<30>; +using uint31 = nall::Natural<31>; +using uint32 = nall::Natural<32>; +using uint33 = nall::Natural<33>; +using uint34 = nall::Natural<34>; +using uint35 = nall::Natural<35>; +using uint36 = nall::Natural<36>; +using uint37 = nall::Natural<37>; +using uint38 = nall::Natural<38>; +using uint39 = nall::Natural<39>; +using uint40 = nall::Natural<40>; +using uint41 = nall::Natural<41>; +using uint42 = nall::Natural<42>; +using uint43 = nall::Natural<43>; +using uint44 = nall::Natural<44>; +using uint45 = nall::Natural<45>; +using uint46 = nall::Natural<46>; +using uint47 = nall::Natural<47>; +using uint48 = nall::Natural<48>; +using uint49 = nall::Natural<49>; +using uint50 = nall::Natural<50>; +using uint51 = nall::Natural<51>; +using uint52 = nall::Natural<52>; +using uint53 = nall::Natural<53>; +using uint54 = nall::Natural<54>; +using uint55 = nall::Natural<55>; +using uint56 = nall::Natural<56>; +using uint57 = nall::Natural<57>; +using uint58 = nall::Natural<58>; +using uint59 = nall::Natural<59>; +using uint60 = nall::Natural<60>; +using uint61 = nall::Natural<61>; +using uint62 = nall::Natural<62>; +using uint63 = nall::Natural<63>; +using uint64 = nall::Natural<64>; + +using float32 = nall::Real<32>; +using float64 = nall::Real<64>; +using float80 = nall::Real<80>; diff --git a/nall/string/base.hpp b/nall/string/base.hpp index cdffb29d..e72c7026 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -51,6 +51,7 @@ inline auto suffixname(rstring self) -> string; inline auto activepath() -> string; inline auto realpath(rstring name) -> string; inline auto programpath() -> string; +inline auto rootpath() -> string; inline auto userpath() -> string; inline auto configpath() -> string; inline auto localpath() -> string; diff --git a/nall/string/path.hpp b/nall/string/path.hpp index 8672fe71..b5903d56 100644 --- a/nall/string/path.hpp +++ b/nall/string/path.hpp @@ -6,67 +6,67 @@ namespace nall { // (/parent/child.type/)name.type auto pathname(rstring self) -> string { const char* p = self.data() + self.size() - 1; - for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/') return slice(self, 0, offset + 1); } - return ""; + return ""; //no path found } // /parent/child.type/() // /parent/child.type/(name.type) auto filename(rstring self) -> string { const char* p = self.data() + self.size() - 1; - for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/') return slice(self, offset + 1); } - return ""; + return self; //no path found } // (/parent/)child.type/ // (/parent/child.type/)name.type auto dirname(rstring self) -> string { const char* p = self.data() + self.size() - 1, *last = p; - for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; if(*p == '/') return slice(self, 0, offset + 1); } - return self.data(); //this is the root directory + return rootpath(); //technically, directory is unknown; must return something } // /parent/(child.type/) // /parent/child.type/(name.type) auto basename(rstring self) -> string { const char* p = self.data() + self.size() - 1, *last = p; - for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; if(*p == '/') return slice(self, offset + 1); } - return ""; + return self; //no path found } // /parent/(child).type/ // /parent/child.type/(name).type auto prefixname(rstring self) -> string { const char* p = self.data() + self.size() - 1, *last = p; - for(signed offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) { + for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).rtrim("/"); if(*p == '.' && suffix == -1) { suffix = offset; continue; } if(offset == 0) return slice(self, offset, suffix).rtrim("/"); } - return ""; + return ""; //no prefix found } // /parent/child(.type)/ // /parent/child.type/name(.type) auto suffixname(rstring self) -> string { const char* p = self.data() + self.size() - 1, *last = p; - for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; if(*p == '/') break; if(*p == '.') return slice(self, offset).rtrim("/"); } - return ""; + return ""; //no suffix found } } diff --git a/nall/string/platform.hpp b/nall/string/platform.hpp index 89b59898..6241c100 100644 --- a/nall/string/platform.hpp +++ b/nall/string/platform.hpp @@ -36,6 +36,20 @@ auto programpath() -> string { #endif } +// / +// c:/ +auto rootpath() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + return result.slice(0, 3); + #else + return "/"; + #endif +} + // /home/username/ // c:/users/username/ auto userpath() -> string { diff --git a/nall/varint.hpp b/nall/varint.hpp index 912e4729..f684bf4c 100644 --- a/nall/varint.hpp +++ b/nall/varint.hpp @@ -48,165 +48,75 @@ struct varint { } }; -template struct varuint_t { - inline operator type_t() const { return data; } - inline auto operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; } - inline auto operator --(int) { type_t r = data; data = (data - 1) & mask; return r; } - inline auto operator ++() { return data = (data + 1) & mask; } - inline auto operator --() { return data = (data - 1) & mask; } - inline auto operator =(const type_t i) { return data = (i) & mask; } - inline auto operator |=(const type_t i) { return data = (data | i) & mask; } - inline auto operator ^=(const type_t i) { return data = (data ^ i) & mask; } - inline auto operator &=(const type_t i) { return data = (data & i) & mask; } - inline auto operator<<=(const type_t i) { return data = (data << i) & mask; } - inline auto operator>>=(const type_t i) { return data = (data >> i) & mask; } - inline auto operator +=(const type_t i) { return data = (data + i) & mask; } - inline auto operator -=(const type_t i) { return data = (data - i) & mask; } - inline auto operator *=(const type_t i) { return data = (data * i) & mask; } - inline auto operator /=(const type_t i) { return data = (data / i) & mask; } - inline auto operator %=(const type_t i) { return data = (data % i) & mask; } +struct VariadicNatural { + inline VariadicNatural() : mask(~0ull) { assign(0); } + template inline VariadicNatural(const T& value) : mask(~0ull) { assign(value); } - inline auto bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; } - inline varuint_t() : data(0ull), mask((type_t)~0ull) {} - inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {} + inline operator uint64_t() const { return data; } + template inline auto& operator=(const T& value) { return assign(value); } - auto serialize(serializer& s) { s(data); s(mask); } + inline auto operator++(int) { auto value = data; assign(data + 1); return value; } + inline auto operator--(int) { auto value = data; assign(data - 1); return value; } + + inline auto& operator++() { return assign(data + 1); } + inline auto& operator--() { return assign(data - 1); } + + inline auto& operator &=(const uint64_t value) { return assign(data & value); } + inline auto& operator |=(const uint64_t value) { return assign(data | value); } + inline auto& operator ^=(const uint64_t value) { return assign(data ^ value); } + inline auto& operator<<=(const uint64_t value) { return assign(data << value); } + inline auto& operator>>=(const uint64_t value) { return assign(data >> value); } + inline auto& operator +=(const uint64_t value) { return assign(data + value); } + inline auto& operator -=(const uint64_t value) { return assign(data - value); } + inline auto& operator *=(const uint64_t value) { return assign(data * value); } + inline auto& operator /=(const uint64_t value) { return assign(data / value); } + inline auto& operator %=(const uint64_t value) { return assign(data % value); } + + inline auto resize(uint bits) { + assert(bits <= 64); + mask = ~0ull >> (64 - bits); + data &= mask; + } + + inline auto serialize(serializer& s) { + s(data); + s(mask); + } + + struct Reference { + inline Reference(VariadicNatural& self, uint lo, uint hi) : self(self), Lo(lo), Hi(hi) {} + + inline operator uint64_t() const { + const uint64_t RangeBits = Hi - Lo + 1; + const uint64_t RangeMask = (((1ull << RangeBits) - 1) << Lo) & self.mask; + return (self & RangeMask) >> Lo; + } + + inline auto& operator=(const uint64_t value) { + const uint64_t RangeBits = Hi - Lo + 1; + const uint64_t RangeMask = (((1ull << RangeBits) - 1) << Lo) & self.mask; + self.data = (self.data & ~RangeMask) | ((value << Lo) & RangeMask); + return *this; + } + + private: + VariadicNatural& self; + const uint Lo; + const uint Hi; + }; + + inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; } + inline auto bit(uint index) -> Reference { return {*this, index, index}; } + inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; } private: - type_t data; - type_t mask; + auto assign(uint64_t value) -> VariadicNatural& { + data = value & mask; + return *this; + } + + uint64_t data; + uint64_t mask; }; } - -using boolean = nall::Boolean; - -using int1 = nall::Integer< 1>; -using int2 = nall::Integer< 2>; -using int3 = nall::Integer< 3>; -using int4 = nall::Integer< 4>; -using int5 = nall::Integer< 5>; -using int6 = nall::Integer< 6>; -using int7 = nall::Integer< 7>; -using int8 = nall::Integer< 8>; -using int9 = nall::Integer< 9>; -using int10 = nall::Integer<10>; -using int11 = nall::Integer<11>; -using int12 = nall::Integer<12>; -using int13 = nall::Integer<13>; -using int14 = nall::Integer<14>; -using int15 = nall::Integer<15>; -using int16 = nall::Integer<16>; -using int17 = nall::Integer<17>; -using int18 = nall::Integer<18>; -using int19 = nall::Integer<19>; -using int20 = nall::Integer<20>; -using int21 = nall::Integer<21>; -using int22 = nall::Integer<22>; -using int23 = nall::Integer<23>; -using int24 = nall::Integer<24>; -using int25 = nall::Integer<25>; -using int26 = nall::Integer<26>; -using int27 = nall::Integer<27>; -using int28 = nall::Integer<28>; -using int29 = nall::Integer<29>; -using int30 = nall::Integer<30>; -using int31 = nall::Integer<31>; -using int32 = nall::Integer<32>; -using int33 = nall::Integer<33>; -using int34 = nall::Integer<34>; -using int35 = nall::Integer<35>; -using int36 = nall::Integer<36>; -using int37 = nall::Integer<37>; -using int38 = nall::Integer<38>; -using int39 = nall::Integer<39>; -using int40 = nall::Integer<40>; -using int41 = nall::Integer<41>; -using int42 = nall::Integer<42>; -using int43 = nall::Integer<43>; -using int44 = nall::Integer<44>; -using int45 = nall::Integer<45>; -using int46 = nall::Integer<46>; -using int47 = nall::Integer<47>; -using int48 = nall::Integer<48>; -using int49 = nall::Integer<49>; -using int50 = nall::Integer<50>; -using int51 = nall::Integer<51>; -using int52 = nall::Integer<52>; -using int53 = nall::Integer<53>; -using int54 = nall::Integer<54>; -using int55 = nall::Integer<55>; -using int56 = nall::Integer<56>; -using int57 = nall::Integer<57>; -using int58 = nall::Integer<58>; -using int59 = nall::Integer<59>; -using int60 = nall::Integer<60>; -using int61 = nall::Integer<61>; -using int62 = nall::Integer<62>; -using int63 = nall::Integer<63>; -using int64 = nall::Integer<64>; - -using uint1 = nall::Natural< 1>; -using uint2 = nall::Natural< 2>; -using uint3 = nall::Natural< 3>; -using uint4 = nall::Natural< 4>; -using uint5 = nall::Natural< 5>; -using uint6 = nall::Natural< 6>; -using uint7 = nall::Natural< 7>; -using uint8 = nall::Natural< 8>; -using uint9 = nall::Natural< 9>; -using uint10 = nall::Natural<10>; -using uint11 = nall::Natural<11>; -using uint12 = nall::Natural<12>; -using uint13 = nall::Natural<13>; -using uint14 = nall::Natural<14>; -using uint15 = nall::Natural<15>; -using uint16 = nall::Natural<16>; -using uint17 = nall::Natural<17>; -using uint18 = nall::Natural<18>; -using uint19 = nall::Natural<19>; -using uint20 = nall::Natural<20>; -using uint21 = nall::Natural<21>; -using uint22 = nall::Natural<22>; -using uint23 = nall::Natural<23>; -using uint24 = nall::Natural<24>; -using uint25 = nall::Natural<25>; -using uint26 = nall::Natural<26>; -using uint27 = nall::Natural<27>; -using uint28 = nall::Natural<28>; -using uint29 = nall::Natural<29>; -using uint30 = nall::Natural<30>; -using uint31 = nall::Natural<31>; -using uint32 = nall::Natural<32>; -using uint33 = nall::Natural<33>; -using uint34 = nall::Natural<34>; -using uint35 = nall::Natural<35>; -using uint36 = nall::Natural<36>; -using uint37 = nall::Natural<37>; -using uint38 = nall::Natural<38>; -using uint39 = nall::Natural<39>; -using uint40 = nall::Natural<40>; -using uint41 = nall::Natural<41>; -using uint42 = nall::Natural<42>; -using uint43 = nall::Natural<43>; -using uint44 = nall::Natural<44>; -using uint45 = nall::Natural<45>; -using uint46 = nall::Natural<46>; -using uint47 = nall::Natural<47>; -using uint48 = nall::Natural<48>; -using uint49 = nall::Natural<49>; -using uint50 = nall::Natural<50>; -using uint51 = nall::Natural<51>; -using uint52 = nall::Natural<52>; -using uint53 = nall::Natural<53>; -using uint54 = nall::Natural<54>; -using uint55 = nall::Natural<55>; -using uint56 = nall::Natural<56>; -using uint57 = nall::Natural<57>; -using uint58 = nall::Natural<58>; -using uint59 = nall::Natural<59>; -using uint60 = nall::Natural<60>; -using uint61 = nall::Natural<61>; -using uint62 = nall::Natural<62>; -using uint63 = nall::Natural<63>; -using uint64 = nall::Natural<64>; diff --git a/nall/windows/utf8.hpp b/nall/windows/utf8.hpp index 04db9757..d2804eef 100644 --- a/nall/windows/utf8.hpp +++ b/nall/windows/utf8.hpp @@ -9,8 +9,11 @@ #define UNICODE #undef NOMINMAX #define NOMINMAX + +#define boolean WindowsBoolean #include #include +#undef boolean #undef interface #if !defined(PATH_MAX) diff --git a/ruby/audio/directsound.cpp b/ruby/audio/directsound.cpp index db49b751..f3fb978f 100644 --- a/ruby/audio/directsound.cpp +++ b/ruby/audio/directsound.cpp @@ -10,22 +10,22 @@ struct AudioDS : Audio { WAVEFORMATEX wfx; struct { - unsigned rings = 0; - unsigned latency = 0; + uint rings = 0; + uint latency = 0; uint32_t* buffer = nullptr; - unsigned bufferoffset = 0; + uint bufferoffset = 0; - unsigned readring = 0; - unsigned writering = 0; + uint readring = 0; + uint writering = 0; int distance = 0; } device; struct { HWND handle = nullptr; bool synchronize = false; - unsigned frequency = 22050; - unsigned latency = 120; + uint frequency = 22050; + uint latency = 120; } settings; auto cap(const string& name) -> bool { @@ -56,15 +56,15 @@ struct AudioDS : Audio { return true; } - if(name == Audio::Frequency && value.is()) { - settings.frequency = value.get(); + if(name == Audio::Frequency && value.is()) { + settings.frequency = value.get(); if(ds) init(); return true; } - if(name == Audio::Latency && value.is()) { + if(name == Audio::Latency && value.is()) { //latency settings below 40ms causes DirectSound to hang - settings.latency = max(40u, value.get()); + settings.latency = max(40u, value.get()); if(ds) init(); return true; } @@ -84,7 +84,7 @@ struct AudioDS : Audio { //wait until playback buffer has an empty ring to write new audio data to while(device.distance >= device.rings - 1) { dsb_b->GetCurrentPosition(&pos, 0); - unsigned activering = pos / (device.latency * 4); + uint activering = pos / (device.latency * 4); if(activering == device.readring) continue; //subtract number of played rings from ring distance counter @@ -138,17 +138,17 @@ struct AudioDS : Audio { device.buffer = new uint32_t[device.latency * device.rings]; device.bufferoffset = 0; - DirectSoundCreate(0, &ds, 0); + if(DirectSoundCreate(0, &ds, 0) != DS_OK) return term(), false; ds->SetCooperativeLevel((HWND)settings.handle, DSSCL_PRIORITY); - memset(&dsbd, 0, sizeof(dsbd)); + memory::fill(&dsbd, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwBufferBytes = 0; dsbd.lpwfxFormat = 0; ds->CreateSoundBuffer(&dsbd, &dsb_p, 0); - memset(&wfx, 0, sizeof(wfx)); + memory::fill(&wfx, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; wfx.nSamplesPerSec = settings.frequency; @@ -157,7 +157,7 @@ struct AudioDS : Audio { wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; dsb_p->SetFormat(&wfx); - memset(&dsbd, 0, sizeof(dsbd)); + memory::fill(&dsbd, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE; dsbd.dwBufferBytes = device.latency * device.rings * sizeof(uint32_t); @@ -174,11 +174,11 @@ struct AudioDS : Audio { auto term() -> void { if(device.buffer) { delete[] device.buffer; - device.buffer = 0; + device.buffer = nullptr; } - if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = 0; } - if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; } - if(ds) { ds->Release(); ds = 0; } + if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = nullptr; } + if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = nullptr; } + if(ds) { ds->Release(); ds = nullptr; } } };