From 29be18ce0c1337f75f5fe86ebf236df9c633ab50 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 23 Feb 2016 22:08:44 +1100 Subject: [PATCH] Update to v097r17 release. byuu says: Changelog: - ruby: if DirectSoundCreate fails (no sound device present), return false from init instead of crashing - nall: improved edge case return values for (basename,pathname,dirname,...) - nall: renamed file_system_object class to inode - nall: varuint_t replaced with VariadicNatural; which contains .bit,.bits,.byte ala Natural/Integer - nall: fixed boolean compilation error on Windows - WS: popa should not restore SP - GBA: rewrote the CPU/APU cores to use the .bit,.bits functions; removed registers.cpp from each Note that the GBA changes are extremely major. This is about five hours worth of extremely delicate work. Any slight errors could break emulation in extremely bad ways. Let's hold off on extensive testing until the next WIP, after I do the same to the PPU. So far ... endrift's SOUNDCNT_X I/O test is failing, although that code didn't change, so clearly I messed up SOUNDCNT_H somehow ... To compile on Windows: 1. change nall/string/platform.hpp line 47 to return slice(result, 0, 3); 2. change ruby/video.wgl.cpp line 72 to auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { 3. add this line to the very top of hiro/windows/header.cpp: #define boolean FuckYouMicrosoft --- higan/emulator/emulator.hpp | 2 +- higan/gba/apu/apu.cpp | 4 +- higan/gba/apu/mmio.cpp | 237 +++++---- higan/gba/apu/registers.cpp | 12 - higan/gba/apu/registers.hpp | 4 - higan/gba/cpu/cpu.cpp | 61 ++- higan/gba/cpu/cpu.hpp | 19 + higan/gba/cpu/dma.cpp | 4 +- higan/gba/cpu/mmio.cpp | 538 ++++++++++++-------- higan/gba/cpu/registers.cpp | 244 --------- higan/gba/cpu/registers.hpp | 219 +++----- higan/gba/cpu/serialization.cpp | 19 +- higan/gba/cpu/timer.cpp | 2 +- higan/gba/player/player.cpp | 25 +- higan/gba/player/player.hpp | 2 +- higan/gba/ppu/mmio.cpp | 140 ++--- higan/gba/ppu/ppu.cpp | 6 +- higan/processor/upd96050/upd96050.cpp | 12 +- higan/processor/upd96050/upd96050.hpp | 6 +- higan/processor/v30mz/instructions-exec.cpp | 2 +- higan/target-tomoko/tomoko.cpp | 4 +- icarus/icarus.cpp | 4 +- nall/beat/archive.hpp | 6 +- nall/directory.hpp | 4 +- nall/file.hpp | 4 +- nall/{file-system-object.hpp => inode.hpp} | 7 +- nall/nall.hpp | 2 +- nall/primitives.hpp | 136 +++++ nall/string/base.hpp | 1 + nall/string/path.hpp | 24 +- nall/string/platform.hpp | 14 + nall/varint.hpp | 220 +++----- nall/windows/utf8.hpp | 3 + ruby/audio/directsound.cpp | 40 +- 34 files changed, 961 insertions(+), 1066 deletions(-) delete mode 100644 higan/gba/apu/registers.cpp delete mode 100644 higan/gba/cpu/registers.cpp rename nall/{file-system-object.hpp => inode.hpp} (92%) 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; } } };