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
This commit is contained in:
Tim Allen 2016-02-23 22:08:44 +11:00
parent 810cbdafb4
commit 29be18ce0c
34 changed files with 961 additions and 1066 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; 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 Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -2,7 +2,6 @@
namespace GameBoyAdvance { namespace GameBoyAdvance {
#include "registers.cpp"
#include "mmio.cpp" #include "mmio.cpp"
#include "square.cpp" #include "square.cpp"
#include "square1.cpp" #include "square1.cpp"
@ -84,7 +83,8 @@ auto APU::power() -> void {
fifo[0].power(); fifo[0].power();
fifo[1].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; for(uint n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this;
} }

View File

@ -2,215 +2,234 @@ auto APU::read(uint32 addr) -> uint8 {
switch(addr) { switch(addr) {
//NR10 //NR10
case 0x04000060: return square1.read(0); case 0x0400'0060: return square1.read(0);
case 0x04000061: return 0u; case 0x0400'0061: return 0;
//NR11 + NR12 //NR11 + NR12
case 0x04000062: return square1.read(1); case 0x0400'0062: return square1.read(1);
case 0x04000063: return square1.read(2); case 0x0400'0063: return square1.read(2);
//NR13 + NR14 //NR13 + NR14
case 0x04000064: return square1.read(3); case 0x0400'0064: return square1.read(3);
case 0x04000065: return square1.read(4); case 0x0400'0065: return square1.read(4);
//NR21 + NR22 //NR21 + NR22
case 0x04000068: return square2.read(1); case 0x0400'0068: return square2.read(1);
case 0x04000069: return square2.read(2); case 0x0400'0069: return square2.read(2);
//NR23 + NR24 //NR23 + NR24
case 0x0400006c: return square2.read(3); case 0x0400'006c: return square2.read(3);
case 0x0400006d: return square2.read(4); case 0x0400'006d: return square2.read(4);
//NR30 //NR30
case 0x04000070: return wave.read(0); case 0x0400'0070: return wave.read(0);
case 0x04000071: return 0u; case 0x0400'0071: return 0;
//NR31 + NR32 //NR31 + NR32
case 0x04000072: return wave.read(1); case 0x0400'0072: return wave.read(1);
case 0x04000073: return wave.read(2); case 0x0400'0073: return wave.read(2);
//NR33 + NR34 //NR33 + NR34
case 0x04000074: return wave.read(3); case 0x0400'0074: return wave.read(3);
case 0x04000075: return wave.read(4); case 0x0400'0075: return wave.read(4);
//NR41 + NR42 //NR41 + NR42
case 0x04000078: return noise.read(1); case 0x0400'0078: return noise.read(1);
case 0x04000079: return noise.read(2); case 0x0400'0079: return noise.read(2);
//NR43 + NR44 //NR43 + NR44
case 0x0400007c: return noise.read(3); case 0x0400'007c: return noise.read(3);
case 0x0400007d: return noise.read(4); case 0x0400'007d: return noise.read(4);
//NR50 + NR51 //NR50 + NR51
case 0x04000080: return sequencer.read(0); case 0x0400'0080: return sequencer.read(0);
case 0x04000081: return sequencer.read(1); case 0x0400'0081: return sequencer.read(1);
//SOUND_CNT_H //SOUND_CNT_H
case 0x04000082: case 0x0400'0082: return (
return (fifo[1].volume << 3) | (fifo[0].volume << 2) | (sequencer.volume << 0); sequencer.volume << 0
case 0x04000083: | fifo[0].volume << 2
return (fifo[1].timer << 6) | (fifo[1].lenable << 5) | (fifo[1].renable << 4) | fifo[1].volume << 3
| (fifo[0].timer << 2) | (fifo[0].lenable << 1) | (fifo[0].renable << 0); );
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 //NR52
case 0x04000084: return sequencer.read(2); case 0x0400'0084: return sequencer.read(2);
case 0x04000085: return 0u; case 0x0400'0085: return 0;
//SOUNDBIAS //SOUNDBIAS
case 0x04000088: return regs.bias >> 0; case 0x0400'0088: return (
case 0x04000089: return regs.bias >> 8; regs.bias.level.bits(0,7)
);
case 0x0400'0089: return (
regs.bias.level.bits(8,9)
| regs.bias.amplitude << 6
);
//WAVE_RAM0_L //WAVE_RAM0_L
case 0x04000090: return wave.readram( 0); case 0x0400'0090: return wave.readram( 0);
case 0x04000091: return wave.readram( 1); case 0x0400'0091: return wave.readram( 1);
//WAVE_RAM0_H //WAVE_RAM0_H
case 0x04000092: return wave.readram( 2); case 0x0400'0092: return wave.readram( 2);
case 0x04000093: return wave.readram( 3); case 0x0400'0093: return wave.readram( 3);
//WAVE_RAM1_L //WAVE_RAM1_L
case 0x04000094: return wave.readram( 4); case 0x0400'0094: return wave.readram( 4);
case 0x04000095: return wave.readram( 5); case 0x0400'0095: return wave.readram( 5);
//WAVE_RAM1_H //WAVE_RAM1_H
case 0x04000096: return wave.readram( 6); case 0x0400'0096: return wave.readram( 6);
case 0x04000097: return wave.readram( 7); case 0x0400'0097: return wave.readram( 7);
//WAVE_RAM2_L //WAVE_RAM2_L
case 0x04000098: return wave.readram( 8); case 0x0400'0098: return wave.readram( 8);
case 0x04000099: return wave.readram( 9); case 0x0400'0099: return wave.readram( 9);
//WAVE_RAM2_H //WAVE_RAM2_H
case 0x0400009a: return wave.readram(10); case 0x0400'009a: return wave.readram(10);
case 0x0400009b: return wave.readram(11); case 0x0400'009b: return wave.readram(11);
//WAVE_RAM3_L //WAVE_RAM3_L
case 0x0400009c: return wave.readram(12); case 0x0400'009c: return wave.readram(12);
case 0x0400009d: return wave.readram(13); case 0x0400'009d: return wave.readram(13);
//WAVE_RAM3_H //WAVE_RAM3_H
case 0x0400009e: return wave.readram(14); case 0x0400'009e: return wave.readram(14);
case 0x0400009f: return wave.readram(15); case 0x0400'009f: return wave.readram(15);
} }
return 0u; return 0u;
} }
auto APU::write(uint32 addr, uint8 byte) -> void { auto APU::write(uint32 addr, uint8 data) -> void {
switch(addr) { switch(addr) {
//NR10 //NR10
case 0x04000060: return square1.write(0, byte); case 0x0400'0060: return square1.write(0, data);
case 0x04000061: return; case 0x0400'0061: return;
//NR11 + NR12 //NR11 + NR12
case 0x04000062: return square1.write(1, byte); case 0x0400'0062: return square1.write(1, data);
case 0x04000063: return square1.write(2, byte); case 0x0400'0063: return square1.write(2, data);
//NR13 + NR14 //NR13 + NR14
case 0x04000064: return square1.write(3, byte); case 0x0400'0064: return square1.write(3, data);
case 0x04000065: return square1.write(4, byte); case 0x0400'0065: return square1.write(4, data);
//NR21 + NR22 //NR21 + NR22
case 0x04000068: return square2.write(1, byte); case 0x0400'0068: return square2.write(1, data);
case 0x04000069: return square2.write(2, byte); case 0x0400'0069: return square2.write(2, data);
//NR23 + NR24 //NR23 + NR24
case 0x0400006c: return square2.write(3, byte); case 0x0400'006c: return square2.write(3, data);
case 0x0400006d: return square2.write(4, byte); case 0x0400'006d: return square2.write(4, data);
//NR30 //NR30
case 0x04000070: return wave.write(0, byte); case 0x0400'0070: return wave.write(0, data);
case 0x04000071: return; case 0x0400'0071: return;
//NR31 + NR32 //NR31 + NR32
case 0x04000072: return wave.write(1, byte); case 0x0400'0072: return wave.write(1, data);
case 0x04000073: return wave.write(2, byte); case 0x0400'0073: return wave.write(2, data);
//NR33 + NR34 //NR33 + NR34
case 0x04000074: return wave.write(3, byte); case 0x0400'0074: return wave.write(3, data);
case 0x04000075: return wave.write(4, byte); case 0x0400'0075: return wave.write(4, data);
//NR41 + NR42 //NR41 + NR42
case 0x04000078: return noise.write(1, byte); case 0x0400'0078: return noise.write(1, data);
case 0x04000079: return noise.write(2, byte); case 0x0400'0079: return noise.write(2, data);
//NR43 + NR44 //NR43 + NR44
case 0x0400007c: return noise.write(3, byte); case 0x0400'007c: return noise.write(3, data);
case 0x0400007d: return noise.write(4, byte); case 0x0400'007d: return noise.write(4, data);
//NR50 + NR51 //NR50 + NR51
case 0x04000080: return sequencer.write(0, byte); case 0x0400'0080: return sequencer.write(0, data);
case 0x04000081: return sequencer.write(1, byte); case 0x0400'0081: return sequencer.write(1, data);
//SOUND_CNT_H //SOUND_CNT_H
case 0x04000082: case 0x0400'0082:
sequencer.volume = byte >> 0; sequencer.volume = data.bits(0,1);
fifo[0].volume = byte >> 2; fifo[0].volume = data.bit (2);
fifo[1].volume = byte >> 3; fifo[1].volume = data.bit (3);
return; return;
case 0x04000083: case 0x0400'0083:
fifo[0].renable = byte >> 0; fifo[0].renable = data.bit(0);
fifo[0].lenable = byte >> 1; fifo[0].lenable = data.bit(1);
fifo[0].timer = byte >> 2; fifo[0].timer = data.bit(2);
if(byte & 1 << 3) fifo[0].reset(); if(data.bit(3)) fifo[0].reset();
fifo[1].renable = byte >> 4; fifo[1].renable = data.bit(4);
fifo[1].lenable = byte >> 5; fifo[1].lenable = data.bit(5);
fifo[1].timer = byte >> 6; fifo[1].timer = data.bit(6);
if(byte & 1 << 7) fifo[1].reset(); if(data.bit(7)) fifo[1].reset();
return; return;
//NR52 //NR52
case 0x04000084: return sequencer.write(2, byte); case 0x0400'0084: return sequencer.write(2, data);
case 0x04000085: return; case 0x0400'0085: return;
//SOUNDBIAS //SOUNDBIAS
case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return; case 0x0400'0088:
case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return; 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 //WAVE_RAM0_L
case 0x04000090: return wave.writeram( 0, byte); case 0x0400'0090: return wave.writeram( 0, data);
case 0x04000091: return wave.writeram( 1, byte); case 0x0400'0091: return wave.writeram( 1, data);
//WAVE_RAM0_H //WAVE_RAM0_H
case 0x04000092: return wave.writeram( 2, byte); case 0x0400'0092: return wave.writeram( 2, data);
case 0x04000093: return wave.writeram( 3, byte); case 0x0400'0093: return wave.writeram( 3, data);
//WAVE_RAM1_L //WAVE_RAM1_L
case 0x04000094: return wave.writeram( 4, byte); case 0x0400'0094: return wave.writeram( 4, data);
case 0x04000095: return wave.writeram( 5, byte); case 0x0400'0095: return wave.writeram( 5, data);
//WAVE_RAM1_H //WAVE_RAM1_H
case 0x04000096: return wave.writeram( 6, byte); case 0x0400'0096: return wave.writeram( 6, data);
case 0x04000097: return wave.writeram( 7, byte); case 0x0400'0097: return wave.writeram( 7, data);
//WAVE_RAM2_L //WAVE_RAM2_L
case 0x04000098: return wave.writeram( 8, byte); case 0x0400'0098: return wave.writeram( 8, data);
case 0x04000099: return wave.writeram( 9, byte); case 0x0400'0099: return wave.writeram( 9, data);
//WAVE_RAM2_H //WAVE_RAM2_H
case 0x0400009a: return wave.writeram(10, byte); case 0x0400'009a: return wave.writeram(10, data);
case 0x0400009b: return wave.writeram(11, byte); case 0x0400'009b: return wave.writeram(11, data);
//WAVE_RAM3_L //WAVE_RAM3_L
case 0x0400009c: return wave.writeram(12, byte); case 0x0400'009c: return wave.writeram(12, data);
case 0x0400009d: return wave.writeram(13, byte); case 0x0400'009d: return wave.writeram(13, data);
//WAVE_RAM3_H //WAVE_RAM3_H
case 0x0400009e: return wave.writeram(14, byte); case 0x0400'009e: return wave.writeram(14, data);
case 0x0400009f: return wave.writeram(15, byte); case 0x0400'009f: return wave.writeram(15, data);
//FIFO_A_L //FIFO_A_L
//FIFO_A_H //FIFO_A_H
case 0x040000a0: case 0x040000a1: case 0x0400'00a0: case 0x0400'00a1:
case 0x040000a2: case 0x040000a3: case 0x0400'00a2: case 0x0400'00a3:
return fifo[0].write(byte); return fifo[0].write(data);
//FIFO_B_L //FIFO_B_L
//FIFO_B_H //FIFO_B_H
case 0x040000a4: case 0x040000a5: case 0x0400'00a4: case 0x0400'00a5:
case 0x040000a6: case 0x040000a7: case 0x0400'00a6: case 0x0400'00a7:
return fifo[1].write(byte); return fifo[1].write(data);
} }
} }

View File

@ -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();
}

View File

@ -2,10 +2,6 @@ struct Registers {
struct SoundBias { struct SoundBias {
uint10 level; uint10 level;
uint2 amplitude; uint2 amplitude;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const SoundBias&) -> SoundBias& = delete;
} bias; } bias;
uint clock; uint clock;

View File

@ -2,7 +2,6 @@
namespace GameBoyAdvance { namespace GameBoyAdvance {
#include "registers.cpp"
#include "prefetch.cpp" #include "prefetch.cpp"
#include "bus.cpp" #include "bus.cpp"
#include "mmio.cpp" #include "mmio.cpp"
@ -16,21 +15,21 @@ CPU::CPU() {
iwram = new uint8[ 32 * 1024]; iwram = new uint8[ 32 * 1024];
ewram = new uint8[256 * 1024]; ewram = new uint8[256 * 1024];
regs.dma[0].source.bits(27); regs.dma[0].run.source.bits(27); regs.dma[0].source.resize(27); regs.dma[0].run.source.resize(27);
regs.dma[0].target.bits(27); regs.dma[0].run.target.bits(27); regs.dma[0].target.resize(27); regs.dma[0].run.target.resize(27);
regs.dma[0].length.bits(14); regs.dma[0].run.length.bits(14); 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].source.resize(28); regs.dma[1].run.source.resize(28);
regs.dma[1].target.bits(27); regs.dma[1].run.target.bits(27); regs.dma[1].target.resize(27); regs.dma[1].run.target.resize(27);
regs.dma[1].length.bits(14); regs.dma[1].run.length.bits(14); 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].source.resize(28); regs.dma[2].run.source.resize(28);
regs.dma[2].target.bits(27); regs.dma[2].run.target.bits(27); regs.dma[2].target.resize(27); regs.dma[2].run.target.resize(27);
regs.dma[2].length.bits(14); regs.dma[2].run.length.bits(14); 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].source.resize(28); regs.dma[3].run.source.resize(28);
regs.dma[3].target.bits(28); regs.dma[3].run.target.bits(28); regs.dma[3].target.resize(28); regs.dma[3].run.target.resize(28);
regs.dma[3].length.bits(16); regs.dma[3].run.length.bits(16); regs.dma[3].length.resize(16); regs.dma[3].run.length.resize(16);
} }
CPU::~CPU() { CPU::~CPU() {
@ -56,7 +55,7 @@ auto CPU::main() -> void {
processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag); processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag);
if(regs.mode == Registers::Mode::Stop) { 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 sync_step(16); //STOP does not advance timers
} else { } else {
regs.mode = Registers::Mode::Normal; regs.mode = Registers::Mode::Normal;
@ -67,7 +66,7 @@ auto CPU::main() -> void {
dma_run(); dma_run();
if(regs.mode == Registers::Mode::Halt) { if(regs.mode == Registers::Mode::Halt) {
if((regs.irq.enable & regs.irq.flag) == 0) { if(!(regs.irq.enable & regs.irq.flag)) {
step(16); step(16);
} else { } else {
regs.mode = Registers::Mode::Normal; 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 == 0) test |= input;
if(regs.keypad.control.condition == 1) 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 { auto CPU::power() -> void {
@ -116,7 +115,14 @@ auto CPU::power() -> void {
dma.target = 0; dma.target = 0;
dma.length = 0; dma.length = 0;
dma.data = 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.pending = 0;
dma.run.target = 0; dma.run.target = 0;
dma.run.source = 0; dma.run.source = 0;
@ -126,17 +132,30 @@ auto CPU::power() -> void {
timer.period = 0; timer.period = 0;
timer.reload = 0; timer.reload = 0;
timer.pending = false; 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.ime = 0;
regs.irq.enable = 0; regs.irq.enable = 0;
regs.irq.flag = 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.postboot = 0;
regs.mode = Registers::Mode::Normal; regs.mode = Registers::Mode::Normal;
regs.clock = 0; 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.vblank = 0;
pending.dma.hblank = 0; pending.dma.hblank = 0;

View File

@ -2,6 +2,25 @@ struct CPU : Processor::ARM, Thread, MMIO {
using ARM::read; using ARM::read;
using ARM::write; 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 "registers.hpp"
#include "prefetch.hpp" #include "prefetch.hpp"
#include "state.hpp" #include "state.hpp"

View File

@ -7,8 +7,8 @@ auto CPU::dma_run() -> void {
auto& dma = regs.dma[n]; auto& dma = regs.dma[n];
if(dma.pending) { if(dma.pending) {
dma_exec(dma); dma_exec(dma);
if(dma.control.irq) regs.irq.flag.dma[n] = 1; if(dma.control.irq) regs.irq.flag |= Interrupt::DMA0 << n;
if(dma.control.drq && n == 3) regs.irq.flag.cartridge = 1; if(dma.control.drq && n == 3) regs.irq.flag |= Interrupt::Cartridge;
transferred = true; transferred = true;
break; break;
} }

View File

@ -1,321 +1,415 @@
auto CPU::read(uint32 addr) -> uint8 { 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) { switch(addr) {
//DMA0CNT_H //DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H
//DMA1CNT_H case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de: return (
//DMA2CNT_H dma().control.targetmode << 5
//DMA3CNT_H | dma().control.sourcemode.bit(0) << 7
case 0x040000ba: case 0x040000bb: );
case 0x040000c6: case 0x040000c7: case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: return (
case 0x040000d2: case 0x040000d3: dma().control.sourcemode.bit(1) << 0
case 0x040000de: case 0x040000df: { | dma().control.repeat << 1
auto& dma = regs.dma[(addr - 0x040000ba) / 12]; | dma().control.size << 2
unsigned shift = (addr & 1) * 8; | dma().control.drq << 3
return dma.control >> shift; | dma().control.timingmode << 4
} | dma().control.irq << 6
| dma().control.enable << 7
);
//TM0CNT_L //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L
//TM1CNT_L case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: return timer().period.byte(0);
//TM2CNT_L case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: return timer().period.byte(1);
//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;
}
//TIM0CNT_H //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H
case 0x04000102: case 0x04000103: case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: return (
case 0x04000106: case 0x04000107: timer().control.frequency << 0
case 0x0400010a: case 0x0400010b: | timer().control.cascade << 2
case 0x0400010e: case 0x0400010f: { | timer().control.irq << 6
auto& timer = regs.timer[(addr >> 2) & 3]; | timer().control.enable << 7
unsigned shift = (addr & 1) * 8; );
return timer.control >> shift; case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: return 0;
}
//SIOMULTI0 (SIODATA32_L) //SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3
//SIOMULTI1 (SIODATA32_H) case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126: {
//SIOMULTI2 if(auto data = player.read()) return data().byte(addr.bits(0,1));
//SIOMULTI3 return regs.serial.data[addr.bits(1,2)].byte(0);
case 0x04000120: case 0x04000121: }
case 0x04000122: case 0x04000123: case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127: {
case 0x04000124: case 0x04000125: if(auto data = player.read()) return data().byte(addr.bits(0,1));
case 0x04000126: case 0x04000127: { return regs.serial.data[addr.bits(1,2)].byte(1);
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;
} }
//SIOCNT //SIOCNT
case 0x04000128: return regs.serial.control >> 0; case 0x0400'0128: return (
case 0x04000129: return regs.serial.control >> 8; 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) //SIOMLT_SEND (SIODATA8)
case 0x0400012a: return regs.serial.data8; case 0x0400'012a: return regs.serial.data8;
case 0x0400012b: return 0u; case 0x0400'012b: return 0;
//KEYINPUT //KEYINPUT
case 0x04000130: case 0x04000130: {
if(auto result = player.keyinput()) return result() >> 0; 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 & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously
if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously
return result ^ 0xff; return result ^ 0xff;
case 0x04000131: }
case 0x04000131: {
if(auto result = player.keyinput()) return result() >> 8; if(auto result = player.keyinput()) return result() >> 8;
uint8 result = 0;
result |= interface->inputPoll(0, 0, 8) << 0; result |= interface->inputPoll(0, 0, 8) << 0;
result |= interface->inputPoll(0, 0, 9) << 1; result |= interface->inputPoll(0, 0, 9) << 1;
return result ^ 0x03; return result ^ 0x03;
}
//KEYCNT //KEYCNT
case 0x04000132: return regs.keypad.control >> 0; case 0x0400'0132: return (
case 0x04000133: return regs.keypad.control >> 8; 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 //RCNT
case 0x04000134: return regs.joybus.settings >> 0; case 0x0400'0134: return (
case 0x04000135: return regs.joybus.settings >> 8; 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 //JOYCNT
case 0x04000140: return regs.joybus.control >> 0; case 0x0400'0140: return (
case 0x04000141: return regs.joybus.control >> 8; 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_L, JOY_RECV_H
//JOY_RECV_H case 0x0400'0150: return regs.joybus.receive.byte(0);
case 0x04000150: return regs.joybus.receive >> 0; case 0x0400'0151: return regs.joybus.receive.byte(1);
case 0x04000151: return regs.joybus.receive >> 8; case 0x0400'0152: return regs.joybus.receive.byte(2);
case 0x04000152: return regs.joybus.receive >> 16; case 0x0400'0153: return regs.joybus.receive.byte(3);
case 0x04000153: return regs.joybus.receive >> 24;
//JOY_TRANS_L //JOY_TRANS_L, JOY_TRANS_H
//JOY_TRANS_H case 0x0400'0154: return regs.joybus.transmit.byte(0);
case 0x04000154: return regs.joybus.transmit >> 0; case 0x0400'0155: return regs.joybus.transmit.byte(1);
case 0x04000155: return regs.joybus.transmit >> 8; case 0x0400'0156: return regs.joybus.transmit.byte(2);
case 0x04000156: return regs.joybus.transmit >> 16; case 0x0400'0157: return regs.joybus.transmit.byte(3);
case 0x04000157: return regs.joybus.transmit >> 24;
//JOYSTAT //JOYSTAT
case 0x04000158: return regs.joybus.status >> 0; case 0x0400'0158: return (
case 0x04000159: return regs.joybus.status >> 8; 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 //IE
case 0x04000200: return regs.irq.enable >> 0; case 0x0400'0200: return regs.irq.enable.byte(0);
case 0x04000201: return regs.irq.enable >> 8; case 0x0400'0201: return regs.irq.enable.byte(1);
//IF //IF
case 0x04000202: return regs.irq.flag >> 0; case 0x0400'0202: return regs.irq.flag.byte(0);
case 0x04000203: return regs.irq.flag >> 8; case 0x0400'0203: return regs.irq.flag.byte(1);
//WAITCNT //WAITCNT
case 0x04000204: return regs.wait.control >> 0; case 0x0400'0204: return (
case 0x04000205: return regs.wait.control >> 8; 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 //IME
case 0x04000208: return regs.ime; case 0x0400'0208: return regs.ime;
case 0x04000209: return 0u; case 0x0400'0209: return 0;
//POSTFLG + HALTCNT //POSTFLG + HALTCNT
case 0x04000300: return regs.postboot; case 0x0400'0300: return regs.postboot;
case 0x04000301: return 0u; case 0x0400'0301: return 0;
//MEMCNT_L //MEMCNT_L
case 0x04000800: return regs.memory.control >> 0; case 0x0400'0800: return (
case 0x04000801: return regs.memory.control >> 8; regs.memory.control.disable << 0
| regs.memory.control.unknown1 << 1
| regs.memory.control.ewram << 5
);
case 0x0400'0801: return 0;
//MEMCNT_H //MEMCNT_H
case 0x04000802: return regs.memory.control >> 16; case 0x0400'0802: return 0;
case 0x04000803: return regs.memory.control >> 24; 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) { switch(addr) {
//DMA0SAD //DMA0SAD, DMA1SAD, DMA2SAD, DMA3SAD
//DMA1SAD case 0x0400'00b0: case 0x0400'00bc: case 0x0400'00c8: case 0x0400'00d4: dma().source.byte(0) = data; return;
//DMA2SAD case 0x0400'00b1: case 0x0400'00bd: case 0x0400'00c9: case 0x0400'00d5: dma().source.byte(1) = data; return;
//DMA3SAD case 0x0400'00b2: case 0x0400'00be: case 0x0400'00ca: case 0x0400'00d6: dma().source.byte(2) = data; return;
case 0x040000b0: case 0x040000b1: case 0x040000b2: case 0x040000b3: case 0x0400'00b3: case 0x0400'00bf: case 0x0400'00cb: case 0x0400'00d7: dma().source.byte(3) = data; return;
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;
}
//DMA0DAD //DMA0DAD, DMA1DAD, DMA2DAD, DMA3DAD
//DMA1DAD case 0x0400'00b4: case 0x0400'00c0: case 0x0400'00cc: case 0x0400'00d8: dma().target.byte(0) = data; return;
//DMA2DAD case 0x0400'00b5: case 0x0400'00c1: case 0x0400'00cd: case 0x0400'00d9: dma().target.byte(1) = data; return;
//DMA3DAD case 0x0400'00b6: case 0x0400'00c2: case 0x0400'00ce: case 0x0400'00da: dma().target.byte(2) = data; return;
case 0x040000b4: case 0x040000b5: case 0x040000b6: case 0x040000b7: case 0x0400'00b7: case 0x0400'00c3: case 0x0400'00cf: case 0x0400'00db: dma().target.byte(3) = data; return;
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;
}
//DMA0CNT_L //DMA0CNT_L, DMA1CNT_L, DMA2CNT_L, DMA3CNT_L
//DMA1CNT_L case 0x0400'00b8: case 0x0400'00c4: case 0x0400'00d0: case 0x0400'00dc: dma().length.byte(0) = data; return;
//DMA2CNT_L case 0x0400'00b9: case 0x0400'00c5: case 0x0400'00d1: case 0x0400'00dd: dma().length.byte(1) = data; return;
//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_H //DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H
//DMA1CNT_H case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de:
//DMA2CNT_H dma().control.targetmode = data.bits(5,6);
//DMA3CNT_H dma().control.sourcemode.bit(0) = data.bit (7);
case 0x040000ba: case 0x040000bb: return;
case 0x040000c6: case 0x040000c7: case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: {
case 0x040000d2: case 0x040000d3: bool enable = dma().control.enable;
case 0x040000de: case 0x040000df: { if(addr != 0x0400'00df) data.bit(3) = 0; //gamepad DRQ valid for DMA3 only
if(addr == 0x040000bb || addr == 0x040000c7 || addr == 0x040000d3) byte &= 0xf7; //gamepak DRQ valid for DMA3 only
auto& dma = regs.dma[(addr - 0x040000ba) / 12]; dma().control.sourcemode.bit(1) = data.bit (0);
unsigned shift = (addr & 1) * 8; dma().control.repeat = data.bit (1);
bool enable = dma.control.enable; dma().control.size = data.bit (2);
dma.control = (dma.control & ~(255 << shift)) | (byte << shift); dma().control.drq = data.bit (3);
if(enable == 0 && dma.control.enable) { dma().control.timingmode = data.bits(4,5);
if(dma.control.timingmode == 0) dma.pending = true; //immediate transfer mode dma().control.irq = data.bit (6);
dma.run.target = dma.target; dma().control.enable = data.bit (7);
dma.run.source = dma.source;
dma.run.length = dma.length; if(!enable && dma().control.enable) { //0->1 transition
} else if(dma.control.enable == 0) { if(dma().control.timingmode == 0) dma().pending = true; //immediate transfer mode
dma.pending = false; dma().run.target = dma().target;
dma().run.source = dma().source;
dma().run.length = dma().length;
} else if(!dma().control.enable) {
dma().pending = false;
} }
return; return;
} }
//TM0CNT_L //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L
//TM1CNT_L case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: timer().reload.byte(0) = data; return;
//TM2CNT_L case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: timer().reload.byte(1) = data; return;
//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_H //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H
//TM1CNT_H case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: {
//TM2CNT_H bool enable = timer().control.enable;
//TM3CNT_H
case 0x04000102: timer().control.frequency = data.bits(0,1);
case 0x04000106: timer().control.cascade = data.bit (2);
case 0x0400010a: timer().control.irq = data.bit (6);
case 0x0400010e: { timer().control.enable = data.bit (7);
auto& timer = regs.timer[(addr >> 2) & 3];
bool enable = timer.control.enable; if(!enable && timer().control.enable) { //0->1 transition
timer.control = byte; timer().pending = true;
if(enable == 0 && timer.control.enable == 1) {
timer.pending = true;
} }
return; return;
} }
case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f:
//SIOMULTI0 (SIODATA32_L) return;
//SIOMULTI1 (SIODATA32_H)
//SIOMULTI2 //SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3
//SIOMULTI3 case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126:
case 0x04000120: case 0x04000121: player.write(addr.bits(0,1), data);
case 0x04000122: case 0x04000123: regs.serial.data[addr.bits(1,2)].byte(0) = data;
case 0x04000124: case 0x04000125: return;
case 0x04000126: case 0x04000127: { case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127:
player.write(byte, addr & 3); player.write(addr.bits(0,1), data);
auto& data = regs.serial.data[(addr >> 1) & 3]; regs.serial.data[addr.bits(1,2)].byte(1) = data;
unsigned shift = (addr & 1) * 8;
data = (data & ~(255 << shift)) | (byte << shift);
return; return;
}
//SIOCNT //SIOCNT
case 0x04000128: regs.serial.control = (regs.serial.control & 0xff00) | (byte << 0); return; case 0x0400'0128:
case 0x04000129: regs.serial.control = (regs.serial.control & 0x00ff) | (byte << 8); return; 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) //SIOMLT_SEND (SIODATA8)
case 0x0400012a: regs.serial.data8 = byte; return; case 0x0400'012a: regs.serial.data8 = data; return;
case 0x0400012b: return; case 0x0400'012b: return;
//KEYCNT //KEYCNT
case 0x04000132: regs.keypad.control = (regs.keypad.control & 0xff00) | (byte << 0); return; case 0x0400'0132:
case 0x04000133: regs.keypad.control = (regs.keypad.control & 0x00ff) | (byte << 8); return; 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 //RCNT
case 0x04000134: regs.joybus.settings = (regs.joybus.settings & 0xff00) | (byte << 0); return; case 0x0400'0134:
case 0x04000135: regs.joybus.settings = (regs.joybus.settings & 0x00ff) | (byte << 8); return; 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 //JOYCNT
case 0x04000140: regs.joybus.control = (regs.joybus.control & 0xff00) | (byte << 0); return; case 0x0400'0140:
case 0x04000141: regs.joybus.control = (regs.joybus.control & 0x00ff) | (byte << 8); return; 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_L
//JOY_RECV_H //JOY_RECV_H
case 0x04000150: regs.joybus.receive = (regs.joybus.receive & 0xffffff00) | (byte << 0); return; case 0x0400'0150: regs.joybus.receive.byte(0) = data; return;
case 0x04000151: regs.joybus.receive = (regs.joybus.receive & 0xffff00ff) | (byte << 8); return; case 0x0400'0151: regs.joybus.receive.byte(1) = data; return;
case 0x04000152: regs.joybus.receive = (regs.joybus.receive & 0xff00ffff) | (byte << 16); return; case 0x0400'0152: regs.joybus.receive.byte(2) = data; return;
case 0x04000153: regs.joybus.receive = (regs.joybus.receive & 0x00ffffff) | (byte << 24); return; case 0x0400'0153: regs.joybus.receive.byte(3) = data; return;
//JOY_TRANS_L //JOY_TRANS_L
//JOY_TRANS_H //JOY_TRANS_H
case 0x04000154: regs.joybus.transmit = (regs.joybus.transmit & 0xffffff00) | (byte << 0); return; case 0x0400'0154: regs.joybus.transmit.byte(0) = data; return;
case 0x04000155: regs.joybus.transmit = (regs.joybus.transmit & 0xffff00ff) | (byte << 8); return; case 0x0400'0155: regs.joybus.transmit.byte(1) = data; return;
case 0x04000156: regs.joybus.transmit = (regs.joybus.transmit & 0xff00ffff) | (byte << 16); return; case 0x0400'0156: regs.joybus.transmit.byte(2) = data; return;
case 0x04000157: regs.joybus.transmit = (regs.joybus.transmit & 0x00ffffff) | (byte << 24); return; case 0x0400'0157: regs.joybus.transmit.byte(3) = data; return;
//JOYSTAT //JOYSTAT
case 0x04000158: regs.joybus.status = (regs.joybus.status & 0xff00) | (byte << 0); return; case 0x0400'0158:
case 0x04000159: regs.joybus.status = (regs.joybus.status & 0x00ff) | (byte << 8); return; 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 //IE
case 0x04000200: regs.irq.enable = (regs.irq.enable & 0xff00) | (byte << 0); return; case 0x0400'0200: regs.irq.enable.byte(0) = data; return;
case 0x04000201: regs.irq.enable = (regs.irq.enable & 0x00ff) | (byte << 8); return; case 0x0400'0201: regs.irq.enable.byte(1) = data; return;
//IF //IF
case 0x04000202: regs.irq.flag = regs.irq.flag & ~(byte << 0); return; case 0x0400'0202: regs.irq.flag.byte(0) = regs.irq.flag.byte(0) & ~data; return;
case 0x04000203: regs.irq.flag = regs.irq.flag & ~(byte << 8); return; case 0x0400'0203: regs.irq.flag.byte(1) = regs.irq.flag.byte(1) & ~data; return;
//WAITCNT //WAITCNT
case 0x04000204: regs.wait.control = (regs.wait.control & 0xff00) | ((byte & 0xff) << 0); return; case 0x0400'0204:
case 0x04000205: regs.wait.control = (regs.wait.control & 0x00ff) | ((byte & 0x7f) << 8); return; 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 //IME
case 0x04000208: regs.ime = byte >> 0; return; case 0x0400'0208: regs.ime = data.bit(0); return;
case 0x04000209: return; case 0x0400'0209: return;
//POSTFLG, HALTCNT //POSTFLG, HALTCNT
case 0x04000300: regs.postboot |= byte >> 0; return; case 0x0400'0300:
case 0x04000301: regs.mode = byte & 0x80 ? Registers::Mode::Stop : Registers::Mode::Halt; return; 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_L
//MEMCNT_H //MEMCNT_H
case 0x04000800: regs.memory.control = (regs.memory.control & 0xffffff00) | (byte << 0); return; case 0x0400'0800:
case 0x04000801: regs.memory.control = (regs.memory.control & 0xffff00ff) | (byte << 8); return; regs.memory.control.disable = data.bit (0);
case 0x04000802: regs.memory.control = (regs.memory.control & 0xff00ffff) | (byte << 16); return; regs.memory.control.unknown1 = data.bits(1,3);
case 0x04000803: regs.memory.control = (regs.memory.control & 0x00ffffff) | (byte << 24); return; 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;
} }
} }

View File

@ -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();
}

View File

@ -1,185 +1,116 @@
struct Registers { 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 { struct DMA {
varuint_t<uint> source; VariadicNatural source;
varuint_t<uint> target; VariadicNatural target;
varuint_t<uint> length; VariadicNatural length;
uint32 data; uint32 data;
DMAControl control; struct Control {
uint2 targetmode;
uint2 sourcemode;
uint1 repeat;
uint1 size;
uint1 drq;
uint2 timingmode;
uint1 irq;
uint1 enable;
} control;
//internal //internal
bool pending; bool pending;
struct Run { struct Run {
varuint_t<uint> target; VariadicNatural target;
varuint_t<uint> source; VariadicNatural source;
varuint_t<uint> length; VariadicNatural length;
} run; } run;
} dma[4]; } 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 { struct Timer {
uint16 period; uint16 period;
uint16 reload; uint16 reload;
bool pending; bool pending;
TimerControl control; struct Control {
uint2 frequency;
uint1 cascade;
uint1 irq;
uint1 enable;
} control;
} timer[4]; } 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 { struct Serial {
uint16 data[4]; uint16 data[4];
SerialControl control; struct Control {
uint1 shiftclockselect;
uint1 shiftclockfrequency;
uint1 transferenablereceive;
uint1 transferenablesend;
uint1 startbit;
uint1 transferlength;
uint1 irqenable;
} control;
uint8 data8; uint8 data8;
} serial; } 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 { struct Keypad {
KeypadControl control; struct Control {
uint1 flag[10];
uint1 enable;
uint1 condition;
} control;
} keypad; } 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 { struct Joybus {
JoybusSettings settings; struct Settings {
JoybusControl control; 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 receive;
uint32 transmit; uint32 transmit;
JoybusStatus status; struct Status {
uint1 receiveflag;
uint1 sendflag;
uint2 generalflag;
} status;
} joybus; } joybus;
uint1 ime; 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 { struct IRQ {
Interrupt enable; uint16 enable;
Interrupt flag; uint16 flag;
} irq; } 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 { struct Wait {
WaitControl control; struct Control {
uint2 nwait[4];
uint1 swait[4];
uint2 phi;
uint1 prefetch;
uint1 gametype;
} control;
} wait; } 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 { struct Memory {
MemoryControl control; struct Control {
uint1 disable;
uint3 unknown1;
uint1 ewram;
uint4 ewramwait;
uint4 unknown2;
} control;
} memory; } memory;
uint1 postboot; uint1 postboot;

View File

@ -72,23 +72,8 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(regs.ime); s.integer(regs.ime);
s.integer(regs.irq.enable.vblank); s.integer(regs.irq.enable);
s.integer(regs.irq.enable.hblank); s.integer(regs.irq.flag);
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);
for(auto& flag : regs.wait.control.nwait) s.integer(flag); for(auto& flag : regs.wait.control.nwait) s.integer(flag);
for(auto& flag : regs.wait.control.swait) s.integer(flag); for(auto& flag : regs.wait.control.swait) s.integer(flag);

View File

@ -28,7 +28,7 @@ auto CPU::timer_increment(uint n) -> void {
if(++timer.period == 0) { if(++timer.period == 0) {
timer.period = timer.reload; 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[0].timer == n) timer_fifo_run(0);
if(apu.fifo[1].timer == n) timer_fifo_run(1); if(apu.fifo[1].timer == n) timer_fifo_run(1);

View File

@ -31,7 +31,26 @@ auto Player::frame() -> void {
if(!status.enable) return; 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; status.packet = (status.packet + 1) % 17;
switch(status.packet) { switch(status.packet) {
case 0: status.send = 0x0000494e; break; case 0: status.send = 0x0000494e; break;
@ -52,7 +71,7 @@ auto Player::frame() -> void {
case 15: status.send = 0x30000003; break; case 15: status.send = 0x30000003; break;
case 16: 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<uint32> {
return nothing; return nothing;
} }
auto Player::write(uint8 byte, uint2 addr) -> void { auto Player::write(uint2 addr, uint8 byte) -> void {
if(!status.enable) return; if(!status.enable) return;
uint shift = addr << 3; uint shift = addr << 3;

View File

@ -16,7 +16,7 @@ struct Player {
auto keyinput() -> maybe<uint16>; auto keyinput() -> maybe<uint16>;
auto read() -> maybe<uint32>; auto read() -> maybe<uint32>;
auto write(uint8 byte, uint2 addr) -> void; auto write(uint2 addr, uint8 byte) -> void;
auto serialize(serializer& s) -> void; auto serialize(serializer& s) -> void;
}; };

View File

@ -2,44 +2,44 @@ auto PPU::read(uint32 addr) -> uint8 {
switch(addr) { switch(addr) {
//DISPCNT //DISPCNT
case 0x04000000: return regs.control >> 0; case 0x0400'0000: return regs.control >> 0;
case 0x04000001: return regs.control >> 8; case 0x0400'0001: return regs.control >> 8;
//GRSWP //GRSWP
case 0x04000002: return regs.greenswap; case 0x0400'0002: return regs.greenswap;
case 0x04000003: return 0u; case 0x0400'0003: return 0u;
//DISPSTAT //DISPSTAT
case 0x04000004: return regs.status >> 0; case 0x0400'0004: return regs.status >> 0;
case 0x04000005: return regs.status >> 8; case 0x0400'0005: return regs.status >> 8;
//VCOUNT //VCOUNT
case 0x04000006: return regs.vcounter >> 0; case 0x0400'0006: return regs.vcounter >> 0;
case 0x04000007: return regs.vcounter >> 8; case 0x0400'0007: return regs.vcounter >> 8;
//BG0CNT,BG1CNT,BG2CNT,BG3CNT //BG0CNT,BG1CNT,BG2CNT,BG3CNT
case 0x04000008: case 0x04000009: case 0x0400'0008: case 0x0400'0009:
case 0x0400000a: case 0x0400000b: case 0x0400'000a: case 0x0400'000b:
case 0x0400000c: case 0x0400000d: case 0x0400'000c: case 0x0400'000d:
case 0x0400000e: case 0x0400000f: { case 0x0400'000e: case 0x0400'000f: {
auto& bg = regs.bg[(addr >> 1) & 3]; auto& bg = regs.bg[(addr >> 1) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
return bg.control >> shift; return bg.control >> shift;
} }
//WININ //WININ
case 0x04000048: return regs.windowflags[In0]; case 0x0400'0048: return regs.windowflags[In0];
case 0x04000049: return regs.windowflags[In1]; case 0x0400'0049: return regs.windowflags[In1];
case 0x0400004a: return regs.windowflags[Out]; case 0x0400'004a: return regs.windowflags[Out];
case 0x0400004b: return regs.windowflags[Obj]; case 0x0400'004b: return regs.windowflags[Obj];
//BLTCNT //BLTCNT
case 0x04000050: return regs.blend.control >> 0; case 0x0400'0050: return regs.blend.control >> 0;
case 0x04000051: return regs.blend.control >> 8; case 0x0400'0051: return regs.blend.control >> 8;
//BLDALPHA //BLDALPHA
case 0x04000052: return regs.blend.eva; case 0x0400'0052: return regs.blend.eva;
case 0x04000053: return regs.blend.evb; case 0x0400'0053: return regs.blend.evb;
//BLDY is write-only //BLDY is write-only
@ -52,28 +52,28 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
switch(addr) { switch(addr) {
//DISPCNT //DISPCNT
case 0x04000000: regs.control = (regs.control & 0xff00) | (byte << 0); return; case 0x0400'0000: regs.control = (regs.control & 0xff00) | (byte << 0); return;
case 0x04000001: regs.control = (regs.control & 0x00ff) | (byte << 8); return; case 0x0400'0001: regs.control = (regs.control & 0x00ff) | (byte << 8); return;
//GRSWP //GRSWP
case 0x04000002: regs.greenswap = byte >> 0; return; case 0x0400'0002: regs.greenswap = byte >> 0; return;
case 0x04000003: return; case 0x0400'0003: return;
//DISPSTAT //DISPSTAT
case 0x04000004: case 0x0400'0004:
regs.status.irqvblank = byte >> 3; regs.status.irqvblank = byte >> 3;
regs.status.irqhblank = byte >> 4; regs.status.irqhblank = byte >> 4;
regs.status.irqvcoincidence = byte >> 5; regs.status.irqvcoincidence = byte >> 5;
return; return;
case 0x04000005: case 0x0400'0005:
regs.status.vcompare = byte; regs.status.vcompare = byte;
return; return;
//BG0CNT,BG1CNT,BG2CNT,BG3CNT //BG0CNT,BG1CNT,BG2CNT,BG3CNT
case 0x04000008: case 0x04000009: case 0x0400'0008: case 0x0400'0009:
case 0x0400000a: case 0x0400000b: case 0x0400'000a: case 0x0400'000b:
case 0x0400000c: case 0x0400000d: case 0x0400'000c: case 0x0400'000d:
case 0x0400000e: case 0x0400000f: { case 0x0400'000e: case 0x0400'000f: {
auto& bg = regs.bg[(addr >> 1) & 3]; auto& bg = regs.bg[(addr >> 1) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
if(addr == 0x04000009 || addr == 0x0400000b) byte &= 0xdf; //clear affine wrap for BG0,1 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 //BG0HOFS,BG1HOFS,BG2BOFS,BG3HOFS
case 0x04000010: case 0x04000011: case 0x0400'0010: case 0x0400'0011:
case 0x04000014: case 0x04000015: case 0x0400'0014: case 0x0400'0015:
case 0x04000018: case 0x04000019: case 0x0400'0018: case 0x0400'0019:
case 0x0400001c: case 0x0400001d: { case 0x0400'001c: case 0x0400'001d: {
auto& bg = regs.bg[(addr >> 2) & 3]; auto& bg = regs.bg[(addr >> 2) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
bg.hoffset = (bg.hoffset & ~(255 << shift)) | (byte << shift); bg.hoffset = (bg.hoffset & ~(255 << shift)) | (byte << shift);
@ -93,10 +93,10 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
} }
//BG0VOFS,BG1VOFS,BG2VOFS,BG3VOFS //BG0VOFS,BG1VOFS,BG2VOFS,BG3VOFS
case 0x04000012: case 0x04000013: case 0x0400'0012: case 0x0400'0013:
case 0x04000016: case 0x04000017: case 0x0400'0016: case 0x0400'0017:
case 0x0400001a: case 0x0400001b: case 0x0400'001a: case 0x0400'001b:
case 0x0400001e: case 0x0400001f: { case 0x0400'001e: case 0x0400'001f: {
auto& bg = regs.bg[(addr >> 2) & 3]; auto& bg = regs.bg[(addr >> 2) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
bg.voffset = (bg.voffset & ~(255 << shift)) | (byte << shift); bg.voffset = (bg.voffset & ~(255 << shift)) | (byte << shift);
@ -104,8 +104,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
} }
//BG2PA,BG3PA //BG2PA,BG3PA
case 0x04000020: case 0x04000021: case 0x0400'0020: case 0x0400'0021:
case 0x04000030: case 0x04000031: { case 0x0400'0030: case 0x0400'0031: {
auto& bg = regs.bg[(addr >> 4) & 3]; auto& bg = regs.bg[(addr >> 4) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
bg.pa = (bg.pa & ~(255 << shift)) | (byte << shift); bg.pa = (bg.pa & ~(255 << shift)) | (byte << shift);
@ -113,8 +113,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
} }
//BG2PB,BG3PB //BG2PB,BG3PB
case 0x04000022: case 0x04000023: case 0x0400'0022: case 0x0400'0023:
case 0x04000032: case 0x04000033: { case 0x0400'0032: case 0x0400'0033: {
auto& bg = regs.bg[(addr >> 4) & 3]; auto& bg = regs.bg[(addr >> 4) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
bg.pb = (bg.pb & ~(255 << shift)) | (byte << shift); bg.pb = (bg.pb & ~(255 << shift)) | (byte << shift);
@ -122,8 +122,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
} }
//BG2PC,BG3PC //BG2PC,BG3PC
case 0x04000024: case 0x04000025: case 0x0400'0024: case 0x0400'0025:
case 0x04000034: case 0x04000035: { case 0x0400'0034: case 0x0400'0035: {
auto& bg = regs.bg[(addr >> 4) & 3]; auto& bg = regs.bg[(addr >> 4) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
bg.pc = (bg.pc & ~(255 << shift)) | (byte << shift); bg.pc = (bg.pc & ~(255 << shift)) | (byte << shift);
@ -131,8 +131,8 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
} }
//BG2PD,BG3PD //BG2PD,BG3PD
case 0x04000026: case 0x04000027: case 0x0400'0026: case 0x0400'0027:
case 0x04000036: case 0x04000037: { case 0x0400'0036: case 0x0400'0037: {
auto& bg = regs.bg[(addr >> 4) & 3]; auto& bg = regs.bg[(addr >> 4) & 3];
unsigned shift = (addr & 1) * 8; unsigned shift = (addr & 1) * 8;
bg.pd = (bg.pd & ~(255 << shift)) | (byte << shift); 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 //BG2X_L,BG2X_H,BG3X_L,BG3X_H
case 0x04000028: case 0x04000029: case 0x0400002a: case 0x0400002b: case 0x0400'0028: case 0x0400'0029: case 0x0400'002a: case 0x0400'002b:
case 0x04000038: case 0x04000039: case 0x0400003a: case 0x0400003b: { case 0x0400'0038: case 0x0400'0039: case 0x0400'003a: case 0x0400'003b: {
auto& bg = regs.bg[(addr >> 4) & 3]; auto& bg = regs.bg[(addr >> 4) & 3];
unsigned shift = (addr & 3) * 8; unsigned shift = (addr & 3) * 8;
bg.lx = bg.x = (bg.x & ~(255 << shift)) | (byte << shift); 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 //BG2Y_L,BG2Y_H,BG3Y_L,BG3Y_H
case 0x0400002c: case 0x0400002d: case 0x0400002e: case 0x0400002f: case 0x0400'002c: case 0x0400'002d: case 0x0400'002e: case 0x0400'002f:
case 0x0400003c: case 0x0400003d: case 0x0400003e: case 0x0400003f: { case 0x0400'003c: case 0x0400'003d: case 0x0400'003e: case 0x0400'003f: {
auto& bg = regs.bg[(addr >> 4) & 3]; auto& bg = regs.bg[(addr >> 4) & 3];
unsigned shift = (addr & 3) * 8; unsigned shift = (addr & 3) * 8;
bg.ly = bg.y = (bg.y & ~(255 << shift)) | (byte << shift); bg.ly = bg.y = (bg.y & ~(255 << shift)) | (byte << shift);
@ -158,50 +158,50 @@ auto PPU::write(uint32 addr, uint8 byte) -> void {
} }
//WIN0H //WIN0H
case 0x04000040: regs.window[0].x2 = byte; return; case 0x0400'0040: regs.window[0].x2 = byte; return;
case 0x04000041: regs.window[0].x1 = byte; return; case 0x0400'0041: regs.window[0].x1 = byte; return;
//WIN1H //WIN1H
case 0x04000042: regs.window[1].x2 = byte; return; case 0x0400'0042: regs.window[1].x2 = byte; return;
case 0x04000043: regs.window[1].x1 = byte; return; case 0x0400'0043: regs.window[1].x1 = byte; return;
//WIN0V //WIN0V
case 0x04000044: regs.window[0].y2 = byte; return; case 0x0400'0044: regs.window[0].y2 = byte; return;
case 0x04000045: regs.window[0].y1 = byte; return; case 0x0400'0045: regs.window[0].y1 = byte; return;
//WIN1V //WIN1V
case 0x04000046: regs.window[1].y2 = byte; return; case 0x0400'0046: regs.window[1].y2 = byte; return;
case 0x04000047: regs.window[1].y1 = byte; return; case 0x0400'0047: regs.window[1].y1 = byte; return;
//WININ //WININ
case 0x04000048: regs.windowflags[In0] = byte; return; case 0x0400'0048: regs.windowflags[In0] = byte; return;
case 0x04000049: regs.windowflags[In1] = byte; return; case 0x0400'0049: regs.windowflags[In1] = byte; return;
//WINOUT //WINOUT
case 0x0400004a: regs.windowflags[Out] = byte; return; case 0x0400'004a: regs.windowflags[Out] = byte; return;
case 0x0400004b: regs.windowflags[Obj] = byte; return; case 0x0400'004b: regs.windowflags[Obj] = byte; return;
//MOSAIC //MOSAIC
case 0x0400004c: case 0x0400'004c:
regs.mosaic.bghsize = byte >> 0; regs.mosaic.bghsize = byte >> 0;
regs.mosaic.bgvsize = byte >> 4; regs.mosaic.bgvsize = byte >> 4;
return; return;
case 0x0400004d: case 0x0400'004d:
regs.mosaic.objhsize = byte >> 0; regs.mosaic.objhsize = byte >> 0;
regs.mosaic.objvsize = byte >> 4; regs.mosaic.objvsize = byte >> 4;
return; return;
//BLDCNT //BLDCNT
case 0x04000050: regs.blend.control = (regs.blend.control & 0xff00) | (byte << 0); return; case 0x0400'0050: regs.blend.control = (regs.blend.control & 0xff00) | (byte << 0); return;
case 0x04000051: regs.blend.control = (regs.blend.control & 0x00ff) | (byte << 8); return; case 0x0400'0051: regs.blend.control = (regs.blend.control & 0x00ff) | (byte << 8); return;
//BLDALPHA //BLDALPHA
case 0x04000052: regs.blend.eva = byte & 0x1f; return; case 0x0400'0052: regs.blend.eva = byte & 0x1f; return;
case 0x04000053: regs.blend.evb = byte & 0x1f; return; case 0x0400'0053: regs.blend.evb = byte & 0x1f; return;
//BLDY //BLDY
case 0x04000054: regs.blend.evy = byte & 0x1f; return; case 0x0400'0054: regs.blend.evy = byte & 0x1f; return;
case 0x04000055: return; case 0x0400'0055: return;
} }
} }

View File

@ -113,12 +113,12 @@ auto PPU::scanline() -> void {
} }
if(regs.vcounter == 160) { 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(); cpu.dma_vblank();
} }
if(regs.status.irqvcoincidence) { 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) { if(regs.vcounter < 160) {
@ -146,7 +146,7 @@ auto PPU::scanline() -> void {
step(960); step(960);
regs.status.hblank = 1; 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(); if(regs.vcounter < 160) cpu.dma_hblank();
step(240); step(240);

View File

@ -11,15 +11,15 @@ namespace Processor {
auto uPD96050::power() -> void { auto uPD96050::power() -> void {
if(revision == Revision::uPD7725) { if(revision == Revision::uPD7725) {
regs.pc.bits(11); regs.pc.resize(11);
regs.rp.bits(10); regs.rp.resize(10);
regs.dp.bits( 8); regs.dp.resize( 8);
} }
if(revision == Revision::uPD96050) { if(revision == Revision::uPD96050) {
regs.pc.bits(14); regs.pc.resize(14);
regs.rp.bits(11); regs.rp.resize(11);
regs.dp.bits(11); regs.dp.resize(11);
} }
for(auto n : range(16)) regs.stack[n] = 0x0000; for(auto n : range(16)) regs.stack[n] = 0x0000;

View File

@ -49,9 +49,9 @@ struct uPD96050 {
struct Regs { struct Regs {
uint16 stack[16]; //LIFO uint16 stack[16]; //LIFO
varuint_t<uint> pc; //program counter VariadicNatural pc; //program counter
varuint_t<uint> rp; //ROM pointer VariadicNatural rp; //ROM pointer
varuint_t<uint> dp; //data pointer VariadicNatural dp; //data pointer
uint4 sp; //stack pointer uint4 sp; //stack pointer
int16 k; int16 k;
int16 l; int16 l;

View File

@ -179,7 +179,7 @@ auto V30MZ::opPopAll() {
r.dx = pop(); r.dx = pop();
r.cx = pop(); r.cx = pop();
r.ax = pop(); r.ax = pop();
r.sp = sp; //r.sp is not restored
} }
//68 push imm16 //68 push imm16

View File

@ -6,10 +6,10 @@ Emulator::Interface* emulator = nullptr;
auto locate(string name) -> string { auto locate(string name) -> string {
string location = {programpath(), name}; string location = {programpath(), name};
if(file_system_object::exists(location)) return location; if(inode::exists(location)) return location;
location = {configpath(), "higan/", name}; location = {configpath(), "higan/", name};
if(file_system_object::exists(location)) return location; if(inode::exists(location)) return location;
directory::create({localpath(), "higan/"}); directory::create({localpath(), "higan/"});
return {localpath(), "higan/", name}; return {localpath(), "higan/", name};

View File

@ -6,10 +6,10 @@ using namespace hiro;
auto locate(string name) -> string { auto locate(string name) -> string {
string location = {programpath(), name}; string location = {programpath(), name};
if(file_system_object::exists(location)) return location; if(inode::exists(location)) return location;
location = {configpath(), "icarus/", name}; location = {configpath(), "icarus/", name};
if(file_system_object::exists(location)) return location; if(inode::exists(location)) return location;
directory::create({localpath(), "icarus/"}); directory::create({localpath(), "icarus/"});
return {localpath(), "icarus/", name}; return {localpath(), "icarus/", name};

View File

@ -29,9 +29,9 @@ auto Archive::create(const string& beatname, const string& pathname, const strin
for(auto& name : contents) { for(auto& name : contents) {
string location{pathname, name}; string location{pathname, name};
bool directory = name.endsWith("/"); bool directory = name.endsWith("/");
bool writable = file_system_object::writable(location); bool writable = inode::writable(location);
bool executable = file_system_object::executable(location); bool executable = inode::executable(location);
unsigned info = directory << 0 | writable << 1 | executable << 2 | (name.rtrim("/").size() - 1) << 3; uint info = directory << 0 | writable << 1 | executable << 2 | (name.rtrim("/").size() - 1) << 3;
beat.writevu(info); beat.writevu(info);
beat.writes(name); beat.writes(name);

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <nall/file.hpp> #include <nall/file.hpp>
#include <nall/file-system-object.hpp> #include <nall/inode.hpp>
#include <nall/intrinsics.hpp> #include <nall/intrinsics.hpp>
#include <nall/sort.hpp> #include <nall/sort.hpp>
#include <nall/string.hpp> #include <nall/string.hpp>
@ -17,7 +17,7 @@
namespace nall { namespace nall {
struct directory : file_system_object { struct directory : inode {
static auto create(const string& pathname, unsigned permissions = 0755) -> bool; //recursive static auto create(const string& pathname, unsigned permissions = 0755) -> bool; //recursive
static auto remove(const string& pathname) -> bool; //recursive static auto remove(const string& pathname) -> bool; //recursive
static auto exists(const string& pathname) -> bool; static auto exists(const string& pathname) -> bool;

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <nall/platform.hpp> #include <nall/platform.hpp>
#include <nall/file-system-object.hpp> #include <nall/inode.hpp>
#include <nall/stdint.hpp> #include <nall/stdint.hpp>
#include <nall/string.hpp> #include <nall/string.hpp>
#include <nall/utility.hpp> #include <nall/utility.hpp>
@ -11,7 +11,7 @@
namespace nall { 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 mode : uint { read, write, modify, append, readwrite = modify, writeread = append };
enum class index : uint { absolute, relative }; enum class index : uint { absolute, relative };

View File

@ -8,7 +8,7 @@
namespace nall { namespace nall {
struct file_system_object { struct inode {
enum class time : unsigned { access, modify }; enum class time : unsigned { access, modify };
static auto exists(const string& name) -> bool { 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 //returns false if 'name' is a directory that is not empty
static auto remove(const string& name) -> bool { 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; if(name.endsWith("/")) return rmdir(name) == 0;
return unlink(name) == 0; return unlink(name) == 0;
#endif
} }
}; };

View File

@ -23,12 +23,12 @@
#include <nall/dl.hpp> #include <nall/dl.hpp>
#include <nall/endian.hpp> #include <nall/endian.hpp>
#include <nall/file.hpp> #include <nall/file.hpp>
#include <nall/file-system-object.hpp>
#include <nall/filemap.hpp> #include <nall/filemap.hpp>
#include <nall/function.hpp> #include <nall/function.hpp>
#include <nall/hashset.hpp> #include <nall/hashset.hpp>
#include <nall/hid.hpp> #include <nall/hid.hpp>
#include <nall/image.hpp> #include <nall/image.hpp>
#include <nall/inode.hpp>
#include <nall/interpolation.hpp> #include <nall/interpolation.hpp>
#include <nall/intrinsics.hpp> #include <nall/intrinsics.hpp>
#include <nall/map.hpp> #include <nall/map.hpp>

View File

@ -212,3 +212,139 @@ template<uint Bits> 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>;

View File

@ -51,6 +51,7 @@ inline auto suffixname(rstring self) -> string;
inline auto activepath() -> string; inline auto activepath() -> string;
inline auto realpath(rstring name) -> string; inline auto realpath(rstring name) -> string;
inline auto programpath() -> string; inline auto programpath() -> string;
inline auto rootpath() -> string;
inline auto userpath() -> string; inline auto userpath() -> string;
inline auto configpath() -> string; inline auto configpath() -> string;
inline auto localpath() -> string; inline auto localpath() -> string;

View File

@ -6,67 +6,67 @@ namespace nall {
// (/parent/child.type/)name.type // (/parent/child.type/)name.type
auto pathname(rstring self) -> string { auto pathname(rstring self) -> string {
const char* p = self.data() + self.size() - 1; 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); if(*p == '/') return slice(self, 0, offset + 1);
} }
return ""; return ""; //no path found
} }
// /parent/child.type/() // /parent/child.type/()
// /parent/child.type/(name.type) // /parent/child.type/(name.type)
auto filename(rstring self) -> string { auto filename(rstring self) -> string {
const char* p = self.data() + self.size() - 1; 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); if(*p == '/') return slice(self, offset + 1);
} }
return ""; return self; //no path found
} }
// (/parent/)child.type/ // (/parent/)child.type/
// (/parent/child.type/)name.type // (/parent/child.type/)name.type
auto dirname(rstring self) -> string { auto dirname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p; 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 == '/' && p == last) continue;
if(*p == '/') return slice(self, 0, offset + 1); 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/)
// /parent/child.type/(name.type) // /parent/child.type/(name.type)
auto basename(rstring self) -> string { auto basename(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p; 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 == '/' && p == last) continue;
if(*p == '/') return slice(self, offset + 1); if(*p == '/') return slice(self, offset + 1);
} }
return ""; return self; //no path found
} }
// /parent/(child).type/ // /parent/(child).type/
// /parent/child.type/(name).type // /parent/child.type/(name).type
auto prefixname(rstring self) -> string { auto prefixname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p; 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 == '/' && p == last) continue;
if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).rtrim("/"); if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).rtrim("/");
if(*p == '.' && suffix == -1) { suffix = offset; continue; } if(*p == '.' && suffix == -1) { suffix = offset; continue; }
if(offset == 0) return slice(self, offset, suffix).rtrim("/"); if(offset == 0) return slice(self, offset, suffix).rtrim("/");
} }
return ""; return ""; //no prefix found
} }
// /parent/child(.type)/ // /parent/child(.type)/
// /parent/child.type/name(.type) // /parent/child.type/name(.type)
auto suffixname(rstring self) -> string { auto suffixname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p; 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 == '/' && p == last) continue;
if(*p == '/') break; if(*p == '/') break;
if(*p == '.') return slice(self, offset).rtrim("/"); if(*p == '.') return slice(self, offset).rtrim("/");
} }
return ""; return ""; //no suffix found
} }
} }

View File

@ -36,6 +36,20 @@ auto programpath() -> string {
#endif #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/ // /home/username/
// c:/users/username/ // c:/users/username/
auto userpath() -> string { auto userpath() -> string {

View File

@ -48,165 +48,75 @@ struct varint {
} }
}; };
template<typename type_t> struct varuint_t { struct VariadicNatural {
inline operator type_t() const { return data; } inline VariadicNatural() : mask(~0ull) { assign(0); }
inline auto operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; } template<typename T> inline VariadicNatural(const T& value) : mask(~0ull) { assign(value); }
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; }
inline auto bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; } inline operator uint64_t() const { return data; }
inline varuint_t() : data(0ull), mask((type_t)~0ull) {} template<typename T> inline auto& operator=(const T& value) { return assign(value); }
inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {}
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: private:
type_t data; auto assign(uint64_t value) -> VariadicNatural& {
type_t mask; 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>;

View File

@ -9,8 +9,11 @@
#define UNICODE #define UNICODE
#undef NOMINMAX #undef NOMINMAX
#define NOMINMAX #define NOMINMAX
#define boolean WindowsBoolean
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#undef boolean
#undef interface #undef interface
#if !defined(PATH_MAX) #if !defined(PATH_MAX)

View File

@ -10,22 +10,22 @@ struct AudioDS : Audio {
WAVEFORMATEX wfx; WAVEFORMATEX wfx;
struct { struct {
unsigned rings = 0; uint rings = 0;
unsigned latency = 0; uint latency = 0;
uint32_t* buffer = nullptr; uint32_t* buffer = nullptr;
unsigned bufferoffset = 0; uint bufferoffset = 0;
unsigned readring = 0; uint readring = 0;
unsigned writering = 0; uint writering = 0;
int distance = 0; int distance = 0;
} device; } device;
struct { struct {
HWND handle = nullptr; HWND handle = nullptr;
bool synchronize = false; bool synchronize = false;
unsigned frequency = 22050; uint frequency = 22050;
unsigned latency = 120; uint latency = 120;
} settings; } settings;
auto cap(const string& name) -> bool { auto cap(const string& name) -> bool {
@ -56,15 +56,15 @@ struct AudioDS : Audio {
return true; return true;
} }
if(name == Audio::Frequency && value.is<unsigned>()) { if(name == Audio::Frequency && value.is<uint>()) {
settings.frequency = value.get<unsigned>(); settings.frequency = value.get<uint>();
if(ds) init(); if(ds) init();
return true; return true;
} }
if(name == Audio::Latency && value.is<unsigned>()) { if(name == Audio::Latency && value.is<uint>()) {
//latency settings below 40ms causes DirectSound to hang //latency settings below 40ms causes DirectSound to hang
settings.latency = max(40u, value.get<unsigned>()); settings.latency = max(40u, value.get<uint>());
if(ds) init(); if(ds) init();
return true; return true;
} }
@ -84,7 +84,7 @@ struct AudioDS : Audio {
//wait until playback buffer has an empty ring to write new audio data to //wait until playback buffer has an empty ring to write new audio data to
while(device.distance >= device.rings - 1) { while(device.distance >= device.rings - 1) {
dsb_b->GetCurrentPosition(&pos, 0); dsb_b->GetCurrentPosition(&pos, 0);
unsigned activering = pos / (device.latency * 4); uint activering = pos / (device.latency * 4);
if(activering == device.readring) continue; if(activering == device.readring) continue;
//subtract number of played rings from ring distance counter //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.buffer = new uint32_t[device.latency * device.rings];
device.bufferoffset = 0; device.bufferoffset = 0;
DirectSoundCreate(0, &ds, 0); if(DirectSoundCreate(0, &ds, 0) != DS_OK) return term(), false;
ds->SetCooperativeLevel((HWND)settings.handle, DSSCL_PRIORITY); ds->SetCooperativeLevel((HWND)settings.handle, DSSCL_PRIORITY);
memset(&dsbd, 0, sizeof(dsbd)); memory::fill(&dsbd, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd); dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0; dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = 0; dsbd.lpwfxFormat = 0;
ds->CreateSoundBuffer(&dsbd, &dsb_p, 0); ds->CreateSoundBuffer(&dsbd, &dsb_p, 0);
memset(&wfx, 0, sizeof(wfx)); memory::fill(&wfx, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2; wfx.nChannels = 2;
wfx.nSamplesPerSec = settings.frequency; wfx.nSamplesPerSec = settings.frequency;
@ -157,7 +157,7 @@ struct AudioDS : Audio {
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
dsb_p->SetFormat(&wfx); dsb_p->SetFormat(&wfx);
memset(&dsbd, 0, sizeof(dsbd)); memory::fill(&dsbd, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd); dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE; dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
dsbd.dwBufferBytes = device.latency * device.rings * sizeof(uint32_t); dsbd.dwBufferBytes = device.latency * device.rings * sizeof(uint32_t);
@ -174,11 +174,11 @@ struct AudioDS : Audio {
auto term() -> void { auto term() -> void {
if(device.buffer) { if(device.buffer) {
delete[] 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_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = nullptr; }
if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; } if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = nullptr; }
if(ds) { ds->Release(); ds = 0; } if(ds) { ds->Release(); ds = nullptr; }
} }
}; };