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 {
static const string Name = "higan";
static const string Version = "097.16";
static const string Version = "097.17";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

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

View File

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

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 {
uint10 level;
uint2 amplitude;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const SoundBias&) -> SoundBias& = delete;
} bias;
uint clock;

View File

@ -2,7 +2,6 @@
namespace GameBoyAdvance {
#include "registers.cpp"
#include "prefetch.cpp"
#include "bus.cpp"
#include "mmio.cpp"
@ -16,21 +15,21 @@ CPU::CPU() {
iwram = new uint8[ 32 * 1024];
ewram = new uint8[256 * 1024];
regs.dma[0].source.bits(27); regs.dma[0].run.source.bits(27);
regs.dma[0].target.bits(27); regs.dma[0].run.target.bits(27);
regs.dma[0].length.bits(14); regs.dma[0].run.length.bits(14);
regs.dma[0].source.resize(27); regs.dma[0].run.source.resize(27);
regs.dma[0].target.resize(27); regs.dma[0].run.target.resize(27);
regs.dma[0].length.resize(14); regs.dma[0].run.length.resize(14);
regs.dma[1].source.bits(28); regs.dma[1].run.source.bits(28);
regs.dma[1].target.bits(27); regs.dma[1].run.target.bits(27);
regs.dma[1].length.bits(14); regs.dma[1].run.length.bits(14);
regs.dma[1].source.resize(28); regs.dma[1].run.source.resize(28);
regs.dma[1].target.resize(27); regs.dma[1].run.target.resize(27);
regs.dma[1].length.resize(14); regs.dma[1].run.length.resize(14);
regs.dma[2].source.bits(28); regs.dma[2].run.source.bits(28);
regs.dma[2].target.bits(27); regs.dma[2].run.target.bits(27);
regs.dma[2].length.bits(14); regs.dma[2].run.length.bits(14);
regs.dma[2].source.resize(28); regs.dma[2].run.source.resize(28);
regs.dma[2].target.resize(27); regs.dma[2].run.target.resize(27);
regs.dma[2].length.resize(14); regs.dma[2].run.length.resize(14);
regs.dma[3].source.bits(28); regs.dma[3].run.source.bits(28);
regs.dma[3].target.bits(28); regs.dma[3].run.target.bits(28);
regs.dma[3].length.bits(16); regs.dma[3].run.length.bits(16);
regs.dma[3].source.resize(28); regs.dma[3].run.source.resize(28);
regs.dma[3].target.resize(28); regs.dma[3].run.target.resize(28);
regs.dma[3].length.resize(16); regs.dma[3].run.length.resize(16);
}
CPU::~CPU() {
@ -56,7 +55,7 @@ auto CPU::main() -> void {
processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag);
if(regs.mode == Registers::Mode::Stop) {
if((regs.irq.enable.keypad & regs.irq.flag.keypad) == 0) {
if(!(regs.irq.enable & regs.irq.flag & Interrupt::Keypad)) {
sync_step(16); //STOP does not advance timers
} else {
regs.mode = Registers::Mode::Normal;
@ -67,7 +66,7 @@ auto CPU::main() -> void {
dma_run();
if(regs.mode == Registers::Mode::Halt) {
if((regs.irq.enable & regs.irq.flag) == 0) {
if(!(regs.irq.enable & regs.irq.flag)) {
step(16);
} else {
regs.mode = Registers::Mode::Normal;
@ -101,7 +100,7 @@ auto CPU::keypad_run() -> void {
if(regs.keypad.control.condition == 0) test |= input;
if(regs.keypad.control.condition == 1) test &= input;
}
if(test) regs.irq.flag.keypad = true;
if(test) regs.irq.flag |= Interrupt::Keypad;
}
auto CPU::power() -> void {
@ -116,7 +115,14 @@ auto CPU::power() -> void {
dma.target = 0;
dma.length = 0;
dma.data = 0;
dma.control = 0;
dma.control.targetmode = 0;
dma.control.sourcemode = 0;
dma.control.repeat = 0;
dma.control.size = 0;
dma.control.drq = 0;
dma.control.timingmode = 0;
dma.control.irq = 0;
dma.control.enable = 0;
dma.pending = 0;
dma.run.target = 0;
dma.run.source = 0;
@ -126,17 +132,30 @@ auto CPU::power() -> void {
timer.period = 0;
timer.reload = 0;
timer.pending = false;
timer.control = 0;
timer.control.frequency = 0;
timer.control.cascade = 0;
timer.control.irq = 0;
timer.control.enable = 0;
}
regs.keypad.control = 0;
for(auto& flag : regs.keypad.control.flag) flag = 0;
regs.keypad.control.enable = 0;
regs.keypad.control.condition = 0;
regs.ime = 0;
regs.irq.enable = 0;
regs.irq.flag = 0;
regs.wait.control = 0;
for(auto& nwait : regs.wait.control.nwait) nwait = 0;
for(auto& swait : regs.wait.control.swait) swait = 0;
regs.wait.control.phi = 0;
regs.wait.control.prefetch = 0;
regs.wait.control.gametype = 0;
regs.postboot = 0;
regs.mode = Registers::Mode::Normal;
regs.clock = 0;
regs.memory.control = 0x0d00'0020;
regs.memory.control.disable = 0;
regs.memory.control.unknown1 = 0;
regs.memory.control.ewram = 1;
regs.memory.control.ewramwait = 13;
regs.memory.control.unknown2 = 0;
pending.dma.vblank = 0;
pending.dma.hblank = 0;

View File

@ -2,6 +2,25 @@ struct CPU : Processor::ARM, Thread, MMIO {
using ARM::read;
using ARM::write;
struct Interrupt {
enum : uint {
VBlank = 0x0001,
HBlank = 0x0002,
VCoincidence = 0x0004,
Timer0 = 0x0008,
Timer1 = 0x0010,
Timer2 = 0x0020,
Timer3 = 0x0040,
Serial = 0x0080,
DMA0 = 0x0100,
DMA1 = 0x0200,
DMA2 = 0x0400,
DMA3 = 0x0800,
Keypad = 0x1000,
Cartridge = 0x2000,
};
};
#include "registers.hpp"
#include "prefetch.hpp"
#include "state.hpp"

View File

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

View File

@ -1,321 +1,415 @@
auto CPU::read(uint32 addr) -> uint8 {
uint8 result = 0;
auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; };
auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; };
switch(addr) {
//DMA0CNT_H
//DMA1CNT_H
//DMA2CNT_H
//DMA3CNT_H
case 0x040000ba: case 0x040000bb:
case 0x040000c6: case 0x040000c7:
case 0x040000d2: case 0x040000d3:
case 0x040000de: case 0x040000df: {
auto& dma = regs.dma[(addr - 0x040000ba) / 12];
unsigned shift = (addr & 1) * 8;
return dma.control >> shift;
}
//DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H
case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de: return (
dma().control.targetmode << 5
| dma().control.sourcemode.bit(0) << 7
);
case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: return (
dma().control.sourcemode.bit(1) << 0
| dma().control.repeat << 1
| dma().control.size << 2
| dma().control.drq << 3
| dma().control.timingmode << 4
| dma().control.irq << 6
| dma().control.enable << 7
);
//TM0CNT_L
//TM1CNT_L
//TM2CNT_L
//TM3CNT_L
case 0x04000100: case 0x04000101:
case 0x04000104: case 0x04000105:
case 0x04000108: case 0x04000109:
case 0x0400010c: case 0x0400010d: {
auto& timer = regs.timer[(addr >> 2) & 3];
unsigned shift = (addr & 1) * 8;
return timer.period >> shift;
}
//TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L
case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: return timer().period.byte(0);
case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: return timer().period.byte(1);
//TIM0CNT_H
case 0x04000102: case 0x04000103:
case 0x04000106: case 0x04000107:
case 0x0400010a: case 0x0400010b:
case 0x0400010e: case 0x0400010f: {
auto& timer = regs.timer[(addr >> 2) & 3];
unsigned shift = (addr & 1) * 8;
return timer.control >> shift;
}
//TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H
case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: return (
timer().control.frequency << 0
| timer().control.cascade << 2
| timer().control.irq << 6
| timer().control.enable << 7
);
case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: return 0;
//SIOMULTI0 (SIODATA32_L)
//SIOMULTI1 (SIODATA32_H)
//SIOMULTI2
//SIOMULTI3
case 0x04000120: case 0x04000121:
case 0x04000122: case 0x04000123:
case 0x04000124: case 0x04000125:
case 0x04000126: case 0x04000127: {
if(auto data = player.read()) return data() >> ((addr & 3) << 3);
unsigned shift = (addr & 1) * 8;
auto& data = regs.serial.data[(addr >> 1) & 3];
return data >> shift;
//SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3
case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126: {
if(auto data = player.read()) return data().byte(addr.bits(0,1));
return regs.serial.data[addr.bits(1,2)].byte(0);
}
case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127: {
if(auto data = player.read()) return data().byte(addr.bits(0,1));
return regs.serial.data[addr.bits(1,2)].byte(1);
}
//SIOCNT
case 0x04000128: return regs.serial.control >> 0;
case 0x04000129: return regs.serial.control >> 8;
case 0x0400'0128: return (
regs.serial.control.shiftclockselect << 0
| regs.serial.control.shiftclockfrequency << 1
| regs.serial.control.transferenablereceive << 2
| regs.serial.control.transferenablesend << 3
| regs.serial.control.startbit << 7
);
case 0x0400'0129: return (
regs.serial.control.transferlength << 4
| regs.serial.control.irqenable << 6
);
//SIOMLT_SEND (SIODATA8)
case 0x0400012a: return regs.serial.data8;
case 0x0400012b: return 0u;
case 0x0400'012a: return regs.serial.data8;
case 0x0400'012b: return 0;
//KEYINPUT
case 0x04000130:
case 0x04000130: {
if(auto result = player.keyinput()) return result() >> 0;
for(unsigned n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, n) << n;
uint8 result = 0;
for(uint n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, n) << n;
if((result & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously
if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously
return result ^ 0xff;
case 0x04000131:
}
case 0x04000131: {
if(auto result = player.keyinput()) return result() >> 8;
uint8 result = 0;
result |= interface->inputPoll(0, 0, 8) << 0;
result |= interface->inputPoll(0, 0, 9) << 1;
return result ^ 0x03;
}
//KEYCNT
case 0x04000132: return regs.keypad.control >> 0;
case 0x04000133: return regs.keypad.control >> 8;
case 0x0400'0132: return (
regs.keypad.control.flag[0] << 0
| regs.keypad.control.flag[1] << 1
| regs.keypad.control.flag[2] << 2
| regs.keypad.control.flag[3] << 3
| regs.keypad.control.flag[4] << 4
| regs.keypad.control.flag[5] << 5
| regs.keypad.control.flag[6] << 6
| regs.keypad.control.flag[7] << 7
);
case 0x0400'0133: return (
regs.keypad.control.flag[8] << 0
| regs.keypad.control.flag[9] << 1
| regs.keypad.control.enable << 6
| regs.keypad.control.condition << 7
);
//RCNT
case 0x04000134: return regs.joybus.settings >> 0;
case 0x04000135: return regs.joybus.settings >> 8;
case 0x0400'0134: return (
regs.joybus.settings.sc << 0
| regs.joybus.settings.sd << 1
| regs.joybus.settings.si << 2
| regs.joybus.settings.so << 3
| regs.joybus.settings.scmode << 4
| regs.joybus.settings.sdmode << 5
| regs.joybus.settings.simode << 6
| regs.joybus.settings.somode << 7
);
case 0x0400'0135: return (
regs.joybus.settings.irqenable << 0
| regs.joybus.settings.mode << 6
);
//JOYCNT
case 0x04000140: return regs.joybus.control >> 0;
case 0x04000141: return regs.joybus.control >> 8;
case 0x0400'0140: return (
regs.joybus.control.resetsignal << 0
| regs.joybus.control.receivecomplete << 1
| regs.joybus.control.sendcomplete << 2
| regs.joybus.control.irqenable << 6
);
case 0x0400'0141: return 0;
case 0x0400'0142: return 0;
case 0x0400'0143: return 0;
//JOY_RECV_L
//JOY_RECV_H
case 0x04000150: return regs.joybus.receive >> 0;
case 0x04000151: return regs.joybus.receive >> 8;
case 0x04000152: return regs.joybus.receive >> 16;
case 0x04000153: return regs.joybus.receive >> 24;
//JOY_RECV_L, JOY_RECV_H
case 0x0400'0150: return regs.joybus.receive.byte(0);
case 0x0400'0151: return regs.joybus.receive.byte(1);
case 0x0400'0152: return regs.joybus.receive.byte(2);
case 0x0400'0153: return regs.joybus.receive.byte(3);
//JOY_TRANS_L
//JOY_TRANS_H
case 0x04000154: return regs.joybus.transmit >> 0;
case 0x04000155: return regs.joybus.transmit >> 8;
case 0x04000156: return regs.joybus.transmit >> 16;
case 0x04000157: return regs.joybus.transmit >> 24;
//JOY_TRANS_L, JOY_TRANS_H
case 0x0400'0154: return regs.joybus.transmit.byte(0);
case 0x0400'0155: return regs.joybus.transmit.byte(1);
case 0x0400'0156: return regs.joybus.transmit.byte(2);
case 0x0400'0157: return regs.joybus.transmit.byte(3);
//JOYSTAT
case 0x04000158: return regs.joybus.status >> 0;
case 0x04000159: return regs.joybus.status >> 8;
case 0x0400'0158: return (
regs.joybus.status.receiveflag << 1
| regs.joybus.status.sendflag << 3
| regs.joybus.status.generalflag << 4
);
case 0x0400'0159: return 0;
case 0x0400'015a: return 0;
case 0x0400'015b: return 0;
//IE
case 0x04000200: return regs.irq.enable >> 0;
case 0x04000201: return regs.irq.enable >> 8;
case 0x0400'0200: return regs.irq.enable.byte(0);
case 0x0400'0201: return regs.irq.enable.byte(1);
//IF
case 0x04000202: return regs.irq.flag >> 0;
case 0x04000203: return regs.irq.flag >> 8;
case 0x0400'0202: return regs.irq.flag.byte(0);
case 0x0400'0203: return regs.irq.flag.byte(1);
//WAITCNT
case 0x04000204: return regs.wait.control >> 0;
case 0x04000205: return regs.wait.control >> 8;
case 0x0400'0204: return (
regs.wait.control.nwait[3] << 0
| regs.wait.control.nwait[0] << 2
| regs.wait.control.swait[0] << 4
| regs.wait.control.nwait[1] << 5
| regs.wait.control.swait[1] << 7
);
case 0x0400'0205: return (
regs.wait.control.nwait[2] << 0
| regs.wait.control.swait[2] << 2
| regs.wait.control.phi << 3
| regs.wait.control.prefetch << 6
| regs.wait.control.gametype << 7
);
//IME
case 0x04000208: return regs.ime;
case 0x04000209: return 0u;
case 0x0400'0208: return regs.ime;
case 0x0400'0209: return 0;
//POSTFLG + HALTCNT
case 0x04000300: return regs.postboot;
case 0x04000301: return 0u;
case 0x0400'0300: return regs.postboot;
case 0x0400'0301: return 0;
//MEMCNT_L
case 0x04000800: return regs.memory.control >> 0;
case 0x04000801: return regs.memory.control >> 8;
case 0x0400'0800: return (
regs.memory.control.disable << 0
| regs.memory.control.unknown1 << 1
| regs.memory.control.ewram << 5
);
case 0x0400'0801: return 0;
//MEMCNT_H
case 0x04000802: return regs.memory.control >> 16;
case 0x04000803: return regs.memory.control >> 24;
case 0x0400'0802: return 0;
case 0x0400'0803: return (
regs.memory.control.ewramwait << 0
| regs.memory.control.unknown2 << 4
);
}
return 0u;
return 0;
}
auto CPU::write(uint32 addr, uint8 byte) -> void {
auto CPU::write(uint32 addr, uint8 data) -> void {
auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; };
auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; };
switch(addr) {
//DMA0SAD
//DMA1SAD
//DMA2SAD
//DMA3SAD
case 0x040000b0: case 0x040000b1: case 0x040000b2: case 0x040000b3:
case 0x040000bc: case 0x040000bd: case 0x040000be: case 0x040000bf:
case 0x040000c8: case 0x040000c9: case 0x040000ca: case 0x040000cb:
case 0x040000d4: case 0x040000d5: case 0x040000d6: case 0x040000d7: {
auto& dma = regs.dma[(addr - 0x040000b0) / 12];
unsigned shift = (addr & 3) * 8;
dma.source = (dma.source & ~(255 << shift)) | (byte << shift);
return;
}
//DMA0SAD, DMA1SAD, DMA2SAD, DMA3SAD
case 0x0400'00b0: case 0x0400'00bc: case 0x0400'00c8: case 0x0400'00d4: dma().source.byte(0) = data; return;
case 0x0400'00b1: case 0x0400'00bd: case 0x0400'00c9: case 0x0400'00d5: dma().source.byte(1) = data; return;
case 0x0400'00b2: case 0x0400'00be: case 0x0400'00ca: case 0x0400'00d6: dma().source.byte(2) = data; return;
case 0x0400'00b3: case 0x0400'00bf: case 0x0400'00cb: case 0x0400'00d7: dma().source.byte(3) = data; return;
//DMA0DAD
//DMA1DAD
//DMA2DAD
//DMA3DAD
case 0x040000b4: case 0x040000b5: case 0x040000b6: case 0x040000b7:
case 0x040000c0: case 0x040000c1: case 0x040000c2: case 0x040000c3:
case 0x040000cc: case 0x040000cd: case 0x040000ce: case 0x040000cf:
case 0x040000d8: case 0x040000d9: case 0x040000da: case 0x040000db: {
auto& dma = regs.dma[(addr - 0x040000b4) / 12];
unsigned shift = (addr & 3) * 8;
dma.target = (dma.target & ~(255 << shift)) | (byte << shift);
return;
}
//DMA0DAD, DMA1DAD, DMA2DAD, DMA3DAD
case 0x0400'00b4: case 0x0400'00c0: case 0x0400'00cc: case 0x0400'00d8: dma().target.byte(0) = data; return;
case 0x0400'00b5: case 0x0400'00c1: case 0x0400'00cd: case 0x0400'00d9: dma().target.byte(1) = data; return;
case 0x0400'00b6: case 0x0400'00c2: case 0x0400'00ce: case 0x0400'00da: dma().target.byte(2) = data; return;
case 0x0400'00b7: case 0x0400'00c3: case 0x0400'00cf: case 0x0400'00db: dma().target.byte(3) = data; return;
//DMA0CNT_L
//DMA1CNT_L
//DMA2CNT_L
//DMA3CNT_L
case 0x040000b8: case 0x040000b9:
case 0x040000c4: case 0x040000c5:
case 0x040000d0: case 0x040000d1:
case 0x040000dc: case 0x040000dd: {
auto& dma = regs.dma[(addr - 0x040000b8) / 12];
unsigned shift = (addr & 1) * 8;
dma.length = (dma.length & ~(255 << shift)) | (byte << shift);
return;
}
//DMA0CNT_L, DMA1CNT_L, DMA2CNT_L, DMA3CNT_L
case 0x0400'00b8: case 0x0400'00c4: case 0x0400'00d0: case 0x0400'00dc: dma().length.byte(0) = data; return;
case 0x0400'00b9: case 0x0400'00c5: case 0x0400'00d1: case 0x0400'00dd: dma().length.byte(1) = data; return;
//DMA0CNT_H
//DMA1CNT_H
//DMA2CNT_H
//DMA3CNT_H
case 0x040000ba: case 0x040000bb:
case 0x040000c6: case 0x040000c7:
case 0x040000d2: case 0x040000d3:
case 0x040000de: case 0x040000df: {
if(addr == 0x040000bb || addr == 0x040000c7 || addr == 0x040000d3) byte &= 0xf7; //gamepak DRQ valid for DMA3 only
auto& dma = regs.dma[(addr - 0x040000ba) / 12];
unsigned shift = (addr & 1) * 8;
bool enable = dma.control.enable;
dma.control = (dma.control & ~(255 << shift)) | (byte << shift);
if(enable == 0 && dma.control.enable) {
if(dma.control.timingmode == 0) dma.pending = true; //immediate transfer mode
dma.run.target = dma.target;
dma.run.source = dma.source;
dma.run.length = dma.length;
} else if(dma.control.enable == 0) {
dma.pending = false;
//DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H
case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de:
dma().control.targetmode = data.bits(5,6);
dma().control.sourcemode.bit(0) = data.bit (7);
return;
case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: {
bool enable = dma().control.enable;
if(addr != 0x0400'00df) data.bit(3) = 0; //gamepad DRQ valid for DMA3 only
dma().control.sourcemode.bit(1) = data.bit (0);
dma().control.repeat = data.bit (1);
dma().control.size = data.bit (2);
dma().control.drq = data.bit (3);
dma().control.timingmode = data.bits(4,5);
dma().control.irq = data.bit (6);
dma().control.enable = data.bit (7);
if(!enable && dma().control.enable) { //0->1 transition
if(dma().control.timingmode == 0) dma().pending = true; //immediate transfer mode
dma().run.target = dma().target;
dma().run.source = dma().source;
dma().run.length = dma().length;
} else if(!dma().control.enable) {
dma().pending = false;
}
return;
}
//TM0CNT_L
//TM1CNT_L
//TM2CNT_L
//TM3CNT_L
case 0x04000100: case 0x04000101:
case 0x04000104: case 0x04000105:
case 0x04000108: case 0x04000109:
case 0x0400010c: case 0x0400010d: {
auto& timer = regs.timer[(addr >> 2) & 3];
unsigned shift = (addr & 1) * 8;
timer.reload = (timer.reload & ~(255 << shift)) | (byte << shift);
return;
}
//TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L
case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: timer().reload.byte(0) = data; return;
case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: timer().reload.byte(1) = data; return;
//TM0CNT_H
//TM1CNT_H
//TM2CNT_H
//TM3CNT_H
case 0x04000102:
case 0x04000106:
case 0x0400010a:
case 0x0400010e: {
auto& timer = regs.timer[(addr >> 2) & 3];
bool enable = timer.control.enable;
timer.control = byte;
if(enable == 0 && timer.control.enable == 1) {
timer.pending = true;
//TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H
case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: {
bool enable = timer().control.enable;
timer().control.frequency = data.bits(0,1);
timer().control.cascade = data.bit (2);
timer().control.irq = data.bit (6);
timer().control.enable = data.bit (7);
if(!enable && timer().control.enable) { //0->1 transition
timer().pending = true;
}
return;
}
//SIOMULTI0 (SIODATA32_L)
//SIOMULTI1 (SIODATA32_H)
//SIOMULTI2
//SIOMULTI3
case 0x04000120: case 0x04000121:
case 0x04000122: case 0x04000123:
case 0x04000124: case 0x04000125:
case 0x04000126: case 0x04000127: {
player.write(byte, addr & 3);
auto& data = regs.serial.data[(addr >> 1) & 3];
unsigned shift = (addr & 1) * 8;
data = (data & ~(255 << shift)) | (byte << shift);
case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f:
return;
//SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3
case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126:
player.write(addr.bits(0,1), data);
regs.serial.data[addr.bits(1,2)].byte(0) = data;
return;
case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127:
player.write(addr.bits(0,1), data);
regs.serial.data[addr.bits(1,2)].byte(1) = data;
return;
}
//SIOCNT
case 0x04000128: regs.serial.control = (regs.serial.control & 0xff00) | (byte << 0); return;
case 0x04000129: regs.serial.control = (regs.serial.control & 0x00ff) | (byte << 8); return;
case 0x0400'0128:
regs.serial.control.shiftclockselect = data.bit(0);
regs.serial.control.shiftclockfrequency = data.bit(1);
regs.serial.control.transferenablereceive = data.bit(2);
regs.serial.control.transferenablesend = data.bit(3);
regs.serial.control.startbit = data.bit(7);
return;
case 0x0400'0129:
regs.serial.control.transferlength = data.bit(4);
regs.serial.control.irqenable = data.bit(6);
return;
//SIOMLT_SEND (SIODATA8)
case 0x0400012a: regs.serial.data8 = byte; return;
case 0x0400012b: return;
case 0x0400'012a: regs.serial.data8 = data; return;
case 0x0400'012b: return;
//KEYCNT
case 0x04000132: regs.keypad.control = (regs.keypad.control & 0xff00) | (byte << 0); return;
case 0x04000133: regs.keypad.control = (regs.keypad.control & 0x00ff) | (byte << 8); return;
case 0x0400'0132:
regs.keypad.control.flag[0] = data.bit(0);
regs.keypad.control.flag[1] = data.bit(1);
regs.keypad.control.flag[2] = data.bit(2);
regs.keypad.control.flag[3] = data.bit(3);
regs.keypad.control.flag[4] = data.bit(4);
regs.keypad.control.flag[5] = data.bit(5);
regs.keypad.control.flag[6] = data.bit(6);
regs.keypad.control.flag[7] = data.bit(7);
return;
case 0x0400'0133:
regs.keypad.control.flag[8] = data.bit(0);
regs.keypad.control.flag[9] = data.bit(1);
regs.keypad.control.enable = data.bit(6);
regs.keypad.control.condition = data.bit(7);
return;
//RCNT
case 0x04000134: regs.joybus.settings = (regs.joybus.settings & 0xff00) | (byte << 0); return;
case 0x04000135: regs.joybus.settings = (regs.joybus.settings & 0x00ff) | (byte << 8); return;
case 0x0400'0134:
regs.joybus.settings.sc = data.bit(0);
regs.joybus.settings.sd = data.bit(1);
regs.joybus.settings.si = data.bit(2);
regs.joybus.settings.so = data.bit(3);
regs.joybus.settings.scmode = data.bit(4);
regs.joybus.settings.sdmode = data.bit(5);
regs.joybus.settings.simode = data.bit(6);
regs.joybus.settings.somode = data.bit(7);
return;
case 0x0400'0135:
regs.joybus.settings.irqenable = data.bit (0);
regs.joybus.settings.mode = data.bits(6,7);
return;
//JOYCNT
case 0x04000140: regs.joybus.control = (regs.joybus.control & 0xff00) | (byte << 0); return;
case 0x04000141: regs.joybus.control = (regs.joybus.control & 0x00ff) | (byte << 8); return;
case 0x0400'0140:
regs.joybus.control.resetsignal = data.bit(0);
regs.joybus.control.receivecomplete = data.bit(1);
regs.joybus.control.sendcomplete = data.bit(2);
regs.joybus.control.irqenable = data.bit(6);
return;
case 0x0400'0141: return;
case 0x0400'0142: return;
case 0x0400'0143: return;
//JOY_RECV_L
//JOY_RECV_H
case 0x04000150: regs.joybus.receive = (regs.joybus.receive & 0xffffff00) | (byte << 0); return;
case 0x04000151: regs.joybus.receive = (regs.joybus.receive & 0xffff00ff) | (byte << 8); return;
case 0x04000152: regs.joybus.receive = (regs.joybus.receive & 0xff00ffff) | (byte << 16); return;
case 0x04000153: regs.joybus.receive = (regs.joybus.receive & 0x00ffffff) | (byte << 24); return;
case 0x0400'0150: regs.joybus.receive.byte(0) = data; return;
case 0x0400'0151: regs.joybus.receive.byte(1) = data; return;
case 0x0400'0152: regs.joybus.receive.byte(2) = data; return;
case 0x0400'0153: regs.joybus.receive.byte(3) = data; return;
//JOY_TRANS_L
//JOY_TRANS_H
case 0x04000154: regs.joybus.transmit = (regs.joybus.transmit & 0xffffff00) | (byte << 0); return;
case 0x04000155: regs.joybus.transmit = (regs.joybus.transmit & 0xffff00ff) | (byte << 8); return;
case 0x04000156: regs.joybus.transmit = (regs.joybus.transmit & 0xff00ffff) | (byte << 16); return;
case 0x04000157: regs.joybus.transmit = (regs.joybus.transmit & 0x00ffffff) | (byte << 24); return;
case 0x0400'0154: regs.joybus.transmit.byte(0) = data; return;
case 0x0400'0155: regs.joybus.transmit.byte(1) = data; return;
case 0x0400'0156: regs.joybus.transmit.byte(2) = data; return;
case 0x0400'0157: regs.joybus.transmit.byte(3) = data; return;
//JOYSTAT
case 0x04000158: regs.joybus.status = (regs.joybus.status & 0xff00) | (byte << 0); return;
case 0x04000159: regs.joybus.status = (regs.joybus.status & 0x00ff) | (byte << 8); return;
case 0x0400'0158:
regs.joybus.status.receiveflag = data.bit (1);
regs.joybus.status.sendflag = data.bit (3);
regs.joybus.status.generalflag = data.bits(4,5);
return;
case 0x0400'0159: return;
//IE
case 0x04000200: regs.irq.enable = (regs.irq.enable & 0xff00) | (byte << 0); return;
case 0x04000201: regs.irq.enable = (regs.irq.enable & 0x00ff) | (byte << 8); return;
case 0x0400'0200: regs.irq.enable.byte(0) = data; return;
case 0x0400'0201: regs.irq.enable.byte(1) = data; return;
//IF
case 0x04000202: regs.irq.flag = regs.irq.flag & ~(byte << 0); return;
case 0x04000203: regs.irq.flag = regs.irq.flag & ~(byte << 8); return;
case 0x0400'0202: regs.irq.flag.byte(0) = regs.irq.flag.byte(0) & ~data; return;
case 0x0400'0203: regs.irq.flag.byte(1) = regs.irq.flag.byte(1) & ~data; return;
//WAITCNT
case 0x04000204: regs.wait.control = (regs.wait.control & 0xff00) | ((byte & 0xff) << 0); return;
case 0x04000205: regs.wait.control = (regs.wait.control & 0x00ff) | ((byte & 0x7f) << 8); return;
case 0x0400'0204:
regs.wait.control.swait[3] = data.bit (0); //todo: is this correct?
regs.wait.control.nwait[3] = data.bits(0,1);
regs.wait.control.nwait[0] = data.bits(2,3);
regs.wait.control.swait[0] = data.bit (4);
regs.wait.control.nwait[1] = data.bits(5,6);
regs.wait.control.swait[1] = data.bit (7);
return;
case 0x0400'0205:
regs.wait.control.nwait[2] = data.bits(0,1);
regs.wait.control.swait[2] = data.bit (2);
regs.wait.control.phi = data.bit (3);
regs.wait.control.prefetch = data.bit (6);
regs.wait.control.gametype = data.bit (7);
return;
//IME
case 0x04000208: regs.ime = byte >> 0; return;
case 0x04000209: return;
case 0x0400'0208: regs.ime = data.bit(0); return;
case 0x0400'0209: return;
//POSTFLG, HALTCNT
case 0x04000300: regs.postboot |= byte >> 0; return;
case 0x04000301: regs.mode = byte & 0x80 ? Registers::Mode::Stop : Registers::Mode::Halt; return;
case 0x0400'0300:
if(data.bit(0)) regs.postboot = 1;
return;
case 0x0400'0301:
regs.mode = data.bit(7) ? Registers::Mode::Stop : Registers::Mode::Halt;
return;
//MEMCNT_L
//MEMCNT_H
case 0x04000800: regs.memory.control = (regs.memory.control & 0xffffff00) | (byte << 0); return;
case 0x04000801: regs.memory.control = (regs.memory.control & 0xffff00ff) | (byte << 8); return;
case 0x04000802: regs.memory.control = (regs.memory.control & 0xff00ffff) | (byte << 16); return;
case 0x04000803: regs.memory.control = (regs.memory.control & 0x00ffffff) | (byte << 24); return;
case 0x0400'0800:
regs.memory.control.disable = data.bit (0);
regs.memory.control.unknown1 = data.bits(1,3);
regs.memory.control.ewram = data.bit (5);
return;
case 0x0400'0801: return;
case 0x0400'0802: return;
case 0x0400'0803:
regs.memory.control.ewramwait = data.bits(0,3);
regs.memory.control.unknown2 = data.bits(4,7);
return;
}
}

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 DMAControl {
uint2 targetmode;
uint2 sourcemode;
uint1 repeat;
uint1 size;
uint1 drq;
uint2 timingmode;
uint1 irq;
uint1 enable;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const DMAControl&) -> DMAControl& = delete;
};
struct DMA {
varuint_t<uint> source;
varuint_t<uint> target;
varuint_t<uint> length;
VariadicNatural source;
VariadicNatural target;
VariadicNatural length;
uint32 data;
DMAControl control;
struct Control {
uint2 targetmode;
uint2 sourcemode;
uint1 repeat;
uint1 size;
uint1 drq;
uint2 timingmode;
uint1 irq;
uint1 enable;
} control;
//internal
bool pending;
struct Run {
varuint_t<uint> target;
varuint_t<uint> source;
varuint_t<uint> length;
VariadicNatural target;
VariadicNatural source;
VariadicNatural length;
} run;
} dma[4];
struct TimerControl {
uint2 frequency;
uint1 cascade;
uint1 irq;
uint1 enable;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const TimerControl&) -> TimerControl& = delete;
};
struct Timer {
uint16 period;
uint16 reload;
bool pending;
TimerControl control;
struct Control {
uint2 frequency;
uint1 cascade;
uint1 irq;
uint1 enable;
} control;
} timer[4];
struct SerialControl {
uint1 shiftclockselect;
uint1 shiftclockfrequency;
uint1 transferenablereceive;
uint1 transferenablesend;
uint1 startbit;
uint1 transferlength;
uint1 irqenable;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const SerialControl&) -> SerialControl& = delete;
};
struct Serial {
uint16 data[4];
SerialControl control;
struct Control {
uint1 shiftclockselect;
uint1 shiftclockfrequency;
uint1 transferenablereceive;
uint1 transferenablesend;
uint1 startbit;
uint1 transferlength;
uint1 irqenable;
} control;
uint8 data8;
} serial;
struct KeypadControl {
uint1 flag[10];
uint1 enable;
uint1 condition;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const KeypadControl&) -> KeypadControl& = delete;
};
struct Keypad {
KeypadControl control;
struct Control {
uint1 flag[10];
uint1 enable;
uint1 condition;
} control;
} keypad;
struct JoybusSettings {
uint1 sc;
uint1 sd;
uint1 si;
uint1 so;
uint1 scmode;
uint1 sdmode;
uint1 simode;
uint1 somode;
uint1 irqenable;
uint2 mode;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const JoybusSettings&) -> JoybusSettings& = delete;
};
struct JoybusControl {
uint1 resetsignal;
uint1 receivecomplete;
uint1 sendcomplete;
uint1 irqenable;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const JoybusControl&) -> JoybusControl& = delete;
};
struct JoybusStatus {
uint1 receiveflag;
uint1 sendflag;
uint2 generalflag;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const JoybusStatus&) -> JoybusStatus& = delete;
};
struct Joybus {
JoybusSettings settings;
JoybusControl control;
struct Settings {
uint1 sc;
uint1 sd;
uint1 si;
uint1 so;
uint1 scmode;
uint1 sdmode;
uint1 simode;
uint1 somode;
uint1 irqenable;
uint2 mode;
} settings;
struct Control {
uint1 resetsignal;
uint1 receivecomplete;
uint1 sendcomplete;
uint1 irqenable;
} control;
uint32 receive;
uint32 transmit;
JoybusStatus status;
struct Status {
uint1 receiveflag;
uint1 sendflag;
uint2 generalflag;
} status;
} joybus;
uint1 ime;
struct Interrupt {
uint1 vblank;
uint1 hblank;
uint1 vcoincidence;
uint1 timer[4];
uint1 serial;
uint1 dma[4];
uint1 keypad;
uint1 cartridge;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const Interrupt&) -> Interrupt& = delete;
};
struct IRQ {
Interrupt enable;
Interrupt flag;
uint16 enable;
uint16 flag;
} irq;
struct WaitControl {
uint2 nwait[4];
uint1 swait[4];
uint2 phi;
uint1 prefetch;
uint1 gametype;
operator uint16_t() const;
auto operator=(uint16 source) -> uint16;
auto operator=(const WaitControl&) -> WaitControl& = delete;
};
struct Wait {
WaitControl control;
struct Control {
uint2 nwait[4];
uint1 swait[4];
uint2 phi;
uint1 prefetch;
uint1 gametype;
} control;
} wait;
struct MemoryControl {
uint1 disable;
uint3 unknown1;
uint1 ewram;
uint4 ewramwait;
uint4 unknown2;
operator uint32_t() const;
auto operator=(uint32 source) -> uint32;
auto operator=(const MemoryControl&) -> MemoryControl& = delete;
};
struct Memory {
MemoryControl control;
struct Control {
uint1 disable;
uint3 unknown1;
uint1 ewram;
uint4 ewramwait;
uint4 unknown2;
} control;
} memory;
uint1 postboot;

View File

@ -72,23 +72,8 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(regs.ime);
s.integer(regs.irq.enable.vblank);
s.integer(regs.irq.enable.hblank);
s.integer(regs.irq.enable.vcoincidence);
for(auto& flag : regs.irq.enable.timer) s.integer(flag);
s.integer(regs.irq.enable.serial);
for(auto& flag : regs.irq.enable.dma) s.integer(flag);
s.integer(regs.irq.enable.keypad);
s.integer(regs.irq.enable.cartridge);
s.integer(regs.irq.flag.vblank);
s.integer(regs.irq.flag.hblank);
s.integer(regs.irq.flag.vcoincidence);
for(auto& flag : regs.irq.flag.timer) s.integer(flag);
s.integer(regs.irq.flag.serial);
for(auto& flag : regs.irq.flag.dma) s.integer(flag);
s.integer(regs.irq.flag.keypad);
s.integer(regs.irq.flag.cartridge);
s.integer(regs.irq.enable);
s.integer(regs.irq.flag);
for(auto& flag : regs.wait.control.nwait) s.integer(flag);
for(auto& flag : regs.wait.control.swait) s.integer(flag);

View File

@ -28,7 +28,7 @@ auto CPU::timer_increment(uint n) -> void {
if(++timer.period == 0) {
timer.period = timer.reload;
if(timer.control.irq) regs.irq.flag.timer[n] = 1;
if(timer.control.irq) regs.irq.flag |= Interrupt::Timer0 << n;
if(apu.fifo[0].timer == n) timer_fifo_run(0);
if(apu.fifo[1].timer == n) timer_fifo_run(1);

View File

@ -31,7 +31,26 @@ auto Player::frame() -> void {
if(!status.enable) return;
if(cpu.regs.joybus.settings == 0x0000 && cpu.regs.serial.control == 0x5088) {
//todo: verify which settings are actually required
//values were taken from observing GBP-compatible games
if(!cpu.regs.joybus.settings.sc
&& !cpu.regs.joybus.settings.sd
&& !cpu.regs.joybus.settings.si
&& !cpu.regs.joybus.settings.so
&& !cpu.regs.joybus.settings.scmode
&& !cpu.regs.joybus.settings.sdmode
&& !cpu.regs.joybus.settings.simode
&& !cpu.regs.joybus.settings.somode
&& !cpu.regs.joybus.settings.irqenable
&& !cpu.regs.joybus.settings.mode
&& !cpu.regs.serial.control.shiftclockselect
&& !cpu.regs.serial.control.shiftclockfrequency
&& !cpu.regs.serial.control.transferenablereceive
&& cpu.regs.serial.control.transferenablesend
&& cpu.regs.serial.control.startbit
&& cpu.regs.serial.control.transferlength
&& cpu.regs.serial.control.irqenable
) {
status.packet = (status.packet + 1) % 17;
switch(status.packet) {
case 0: status.send = 0x0000494e; break;
@ -52,7 +71,7 @@ auto Player::frame() -> void {
case 15: status.send = 0x30000003; break;
case 16: status.send = 0x30000003; break;
}
cpu.regs.irq.flag.serial = true;
cpu.regs.irq.flag |= CPU::Interrupt::Serial;
}
}
@ -72,7 +91,7 @@ auto Player::read() -> maybe<uint32> {
return nothing;
}
auto Player::write(uint8 byte, uint2 addr) -> void {
auto Player::write(uint2 addr, uint8 byte) -> void {
if(!status.enable) return;
uint shift = addr << 3;

View File

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

View File

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

View File

@ -113,12 +113,12 @@ auto PPU::scanline() -> void {
}
if(regs.vcounter == 160) {
if(regs.status.irqvblank) cpu.regs.irq.flag.vblank = 1;
if(regs.status.irqvblank) cpu.regs.irq.flag |= CPU::Interrupt::VBlank;
cpu.dma_vblank();
}
if(regs.status.irqvcoincidence) {
if(regs.status.vcoincidence) cpu.regs.irq.flag.vcoincidence = 1;
if(regs.status.vcoincidence) cpu.regs.irq.flag |= CPU::Interrupt::VCoincidence;
}
if(regs.vcounter < 160) {
@ -146,7 +146,7 @@ auto PPU::scanline() -> void {
step(960);
regs.status.hblank = 1;
if(regs.status.irqhblank) cpu.regs.irq.flag.hblank = 1;
if(regs.status.irqhblank) cpu.regs.irq.flag |= CPU::Interrupt::HBlank;
if(regs.vcounter < 160) cpu.dma_hblank();
step(240);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -23,12 +23,12 @@
#include <nall/dl.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/file-system-object.hpp>
#include <nall/filemap.hpp>
#include <nall/function.hpp>
#include <nall/hashset.hpp>
#include <nall/hid.hpp>
#include <nall/image.hpp>
#include <nall/inode.hpp>
#include <nall/interpolation.hpp>
#include <nall/intrinsics.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 realpath(rstring name) -> string;
inline auto programpath() -> string;
inline auto rootpath() -> string;
inline auto userpath() -> string;
inline auto configpath() -> string;
inline auto localpath() -> string;

View File

@ -6,67 +6,67 @@ namespace nall {
// (/parent/child.type/)name.type
auto pathname(rstring self) -> string {
const char* p = self.data() + self.size() - 1;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/') return slice(self, 0, offset + 1);
}
return "";
return ""; //no path found
}
// /parent/child.type/()
// /parent/child.type/(name.type)
auto filename(rstring self) -> string {
const char* p = self.data() + self.size() - 1;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/') return slice(self, offset + 1);
}
return "";
return self; //no path found
}
// (/parent/)child.type/
// (/parent/child.type/)name.type
auto dirname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
if(*p == '/') return slice(self, 0, offset + 1);
}
return self.data(); //this is the root directory
return rootpath(); //technically, directory is unknown; must return something
}
// /parent/(child.type/)
// /parent/child.type/(name.type)
auto basename(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
if(*p == '/') return slice(self, offset + 1);
}
return "";
return self; //no path found
}
// /parent/(child).type/
// /parent/child.type/(name).type
auto prefixname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) {
for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).rtrim("/");
if(*p == '.' && suffix == -1) { suffix = offset; continue; }
if(offset == 0) return slice(self, offset, suffix).rtrim("/");
}
return "";
return ""; //no prefix found
}
// /parent/child(.type)/
// /parent/child.type/name(.type)
auto suffixname(rstring self) -> string {
const char* p = self.data() + self.size() - 1, *last = p;
for(signed offset = self.size() - 1; offset >= 0; offset--, p--) {
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
if(*p == '/' && p == last) continue;
if(*p == '/') break;
if(*p == '.') return slice(self, offset).rtrim("/");
}
return "";
return ""; //no suffix found
}
}

View File

@ -36,6 +36,20 @@ auto programpath() -> string {
#endif
}
// /
// c:/
auto rootpath() -> string {
#if defined(PLATFORM_WINDOWS)
wchar_t path[PATH_MAX] = L"";
SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path);
string result = (const char*)utf8_t(path);
result.transform("\\", "/");
return result.slice(0, 3);
#else
return "/";
#endif
}
// /home/username/
// c:/users/username/
auto userpath() -> string {

View File

@ -48,165 +48,75 @@ struct varint {
}
};
template<typename type_t> struct varuint_t {
inline operator type_t() const { return data; }
inline auto operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; }
inline auto operator --(int) { type_t r = data; data = (data - 1) & mask; return r; }
inline auto operator ++() { return data = (data + 1) & mask; }
inline auto operator --() { return data = (data - 1) & mask; }
inline auto operator =(const type_t i) { return data = (i) & mask; }
inline auto operator |=(const type_t i) { return data = (data | i) & mask; }
inline auto operator ^=(const type_t i) { return data = (data ^ i) & mask; }
inline auto operator &=(const type_t i) { return data = (data & i) & mask; }
inline auto operator<<=(const type_t i) { return data = (data << i) & mask; }
inline auto operator>>=(const type_t i) { return data = (data >> i) & mask; }
inline auto operator +=(const type_t i) { return data = (data + i) & mask; }
inline auto operator -=(const type_t i) { return data = (data - i) & mask; }
inline auto operator *=(const type_t i) { return data = (data * i) & mask; }
inline auto operator /=(const type_t i) { return data = (data / i) & mask; }
inline auto operator %=(const type_t i) { return data = (data % i) & mask; }
struct VariadicNatural {
inline VariadicNatural() : mask(~0ull) { assign(0); }
template<typename T> inline VariadicNatural(const T& value) : mask(~0ull) { assign(value); }
inline auto bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; }
inline varuint_t() : data(0ull), mask((type_t)~0ull) {}
inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {}
inline operator uint64_t() const { return data; }
template<typename T> inline auto& operator=(const T& value) { return assign(value); }
auto serialize(serializer& s) { s(data); s(mask); }
inline auto operator++(int) { auto value = data; assign(data + 1); return value; }
inline auto operator--(int) { auto value = data; assign(data - 1); return value; }
inline auto& operator++() { return assign(data + 1); }
inline auto& operator--() { return assign(data - 1); }
inline auto& operator &=(const uint64_t value) { return assign(data & value); }
inline auto& operator |=(const uint64_t value) { return assign(data | value); }
inline auto& operator ^=(const uint64_t value) { return assign(data ^ value); }
inline auto& operator<<=(const uint64_t value) { return assign(data << value); }
inline auto& operator>>=(const uint64_t value) { return assign(data >> value); }
inline auto& operator +=(const uint64_t value) { return assign(data + value); }
inline auto& operator -=(const uint64_t value) { return assign(data - value); }
inline auto& operator *=(const uint64_t value) { return assign(data * value); }
inline auto& operator /=(const uint64_t value) { return assign(data / value); }
inline auto& operator %=(const uint64_t value) { return assign(data % value); }
inline auto resize(uint bits) {
assert(bits <= 64);
mask = ~0ull >> (64 - bits);
data &= mask;
}
inline auto serialize(serializer& s) {
s(data);
s(mask);
}
struct Reference {
inline Reference(VariadicNatural& self, uint lo, uint hi) : self(self), Lo(lo), Hi(hi) {}
inline operator uint64_t() const {
const uint64_t RangeBits = Hi - Lo + 1;
const uint64_t RangeMask = (((1ull << RangeBits) - 1) << Lo) & self.mask;
return (self & RangeMask) >> Lo;
}
inline auto& operator=(const uint64_t value) {
const uint64_t RangeBits = Hi - Lo + 1;
const uint64_t RangeMask = (((1ull << RangeBits) - 1) << Lo) & self.mask;
self.data = (self.data & ~RangeMask) | ((value << Lo) & RangeMask);
return *this;
}
private:
VariadicNatural& self;
const uint Lo;
const uint Hi;
};
inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; }
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
private:
type_t data;
type_t mask;
auto assign(uint64_t value) -> VariadicNatural& {
data = value & mask;
return *this;
}
uint64_t data;
uint64_t mask;
};
}
using boolean = nall::Boolean;
using int1 = nall::Integer< 1>;
using int2 = nall::Integer< 2>;
using int3 = nall::Integer< 3>;
using int4 = nall::Integer< 4>;
using int5 = nall::Integer< 5>;
using int6 = nall::Integer< 6>;
using int7 = nall::Integer< 7>;
using int8 = nall::Integer< 8>;
using int9 = nall::Integer< 9>;
using int10 = nall::Integer<10>;
using int11 = nall::Integer<11>;
using int12 = nall::Integer<12>;
using int13 = nall::Integer<13>;
using int14 = nall::Integer<14>;
using int15 = nall::Integer<15>;
using int16 = nall::Integer<16>;
using int17 = nall::Integer<17>;
using int18 = nall::Integer<18>;
using int19 = nall::Integer<19>;
using int20 = nall::Integer<20>;
using int21 = nall::Integer<21>;
using int22 = nall::Integer<22>;
using int23 = nall::Integer<23>;
using int24 = nall::Integer<24>;
using int25 = nall::Integer<25>;
using int26 = nall::Integer<26>;
using int27 = nall::Integer<27>;
using int28 = nall::Integer<28>;
using int29 = nall::Integer<29>;
using int30 = nall::Integer<30>;
using int31 = nall::Integer<31>;
using int32 = nall::Integer<32>;
using int33 = nall::Integer<33>;
using int34 = nall::Integer<34>;
using int35 = nall::Integer<35>;
using int36 = nall::Integer<36>;
using int37 = nall::Integer<37>;
using int38 = nall::Integer<38>;
using int39 = nall::Integer<39>;
using int40 = nall::Integer<40>;
using int41 = nall::Integer<41>;
using int42 = nall::Integer<42>;
using int43 = nall::Integer<43>;
using int44 = nall::Integer<44>;
using int45 = nall::Integer<45>;
using int46 = nall::Integer<46>;
using int47 = nall::Integer<47>;
using int48 = nall::Integer<48>;
using int49 = nall::Integer<49>;
using int50 = nall::Integer<50>;
using int51 = nall::Integer<51>;
using int52 = nall::Integer<52>;
using int53 = nall::Integer<53>;
using int54 = nall::Integer<54>;
using int55 = nall::Integer<55>;
using int56 = nall::Integer<56>;
using int57 = nall::Integer<57>;
using int58 = nall::Integer<58>;
using int59 = nall::Integer<59>;
using int60 = nall::Integer<60>;
using int61 = nall::Integer<61>;
using int62 = nall::Integer<62>;
using int63 = nall::Integer<63>;
using int64 = nall::Integer<64>;
using uint1 = nall::Natural< 1>;
using uint2 = nall::Natural< 2>;
using uint3 = nall::Natural< 3>;
using uint4 = nall::Natural< 4>;
using uint5 = nall::Natural< 5>;
using uint6 = nall::Natural< 6>;
using uint7 = nall::Natural< 7>;
using uint8 = nall::Natural< 8>;
using uint9 = nall::Natural< 9>;
using uint10 = nall::Natural<10>;
using uint11 = nall::Natural<11>;
using uint12 = nall::Natural<12>;
using uint13 = nall::Natural<13>;
using uint14 = nall::Natural<14>;
using uint15 = nall::Natural<15>;
using uint16 = nall::Natural<16>;
using uint17 = nall::Natural<17>;
using uint18 = nall::Natural<18>;
using uint19 = nall::Natural<19>;
using uint20 = nall::Natural<20>;
using uint21 = nall::Natural<21>;
using uint22 = nall::Natural<22>;
using uint23 = nall::Natural<23>;
using uint24 = nall::Natural<24>;
using uint25 = nall::Natural<25>;
using uint26 = nall::Natural<26>;
using uint27 = nall::Natural<27>;
using uint28 = nall::Natural<28>;
using uint29 = nall::Natural<29>;
using uint30 = nall::Natural<30>;
using uint31 = nall::Natural<31>;
using uint32 = nall::Natural<32>;
using uint33 = nall::Natural<33>;
using uint34 = nall::Natural<34>;
using uint35 = nall::Natural<35>;
using uint36 = nall::Natural<36>;
using uint37 = nall::Natural<37>;
using uint38 = nall::Natural<38>;
using uint39 = nall::Natural<39>;
using uint40 = nall::Natural<40>;
using uint41 = nall::Natural<41>;
using uint42 = nall::Natural<42>;
using uint43 = nall::Natural<43>;
using uint44 = nall::Natural<44>;
using uint45 = nall::Natural<45>;
using uint46 = nall::Natural<46>;
using uint47 = nall::Natural<47>;
using uint48 = nall::Natural<48>;
using uint49 = nall::Natural<49>;
using uint50 = nall::Natural<50>;
using uint51 = nall::Natural<51>;
using uint52 = nall::Natural<52>;
using uint53 = nall::Natural<53>;
using uint54 = nall::Natural<54>;
using uint55 = nall::Natural<55>;
using uint56 = nall::Natural<56>;
using uint57 = nall::Natural<57>;
using uint58 = nall::Natural<58>;
using uint59 = nall::Natural<59>;
using uint60 = nall::Natural<60>;
using uint61 = nall::Natural<61>;
using uint62 = nall::Natural<62>;
using uint63 = nall::Natural<63>;
using uint64 = nall::Natural<64>;

View File

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

View File

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