diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 35471153..cb8a833e 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -6,7 +6,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "097.21"; + static const string Version = "097.22"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/v30mz/instructions-group.cpp b/higan/processor/v30mz/instructions-group.cpp index d4dfbed6..0fe5c5b7 100644 --- a/higan/processor/v30mz/instructions-group.cpp +++ b/higan/processor/v30mz/instructions-group.cpp @@ -53,7 +53,7 @@ auto V30MZ::opGroup3MemImm(Size size) { auto mem = getMem(size); switch(modrm.reg) { case 0: alAnd(size, mem, fetch(size)); break; - case 1: break; + case 1: debug("[V30MZ] GRP3.1"); break; case 2: wait(2); setMem(size, alNot(size, mem)); break; case 3: wait(2); setMem(size, alNeg(size, mem)); break; case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break; @@ -67,15 +67,47 @@ auto V30MZ::opGroup3MemImm(Size size) { //ff grp4 memw auto V30MZ::opGroup4MemImm(Size size) { modRM(); - auto mem = getMem(size); switch(modrm.reg) { - case 0: wait(2); setMem(size, alInc(size, mem)); break; - case 1: wait(2); setMem(size, alDec(size, mem)); break; - case 2: break; - case 3: break; - case 4: break; - case 5: break; - case 6: break; - case 7: break; + case 0: + wait(2); + setMem(size, alInc(size, getMem(size))); + break; + case 1: + wait(2); + setMem(size, alDec(size, getMem(size))); + break; + case 2: + if(size == Byte) { debug("[V30MZ] GRP4.2"); break; } + wait(5); + push(r.ip); + r.ip = getMem(Word); + break; + case 3: + if(size == Byte) { debug("[V30MZ] GRP4.3"); break; } + wait(11); + push(r.cs); + push(r.ip); + r.ip = getMem(Word, 0); + r.cs = getMem(Word, 2); + break; + case 4: + if(size == Byte) { debug("[V30MZ] GRP4.4"); break; } + wait(4); + r.ip = getMem(Word); + break; + case 5: + if(size == Byte) { debug("[V30MZ] GRP4.5"); break; } + wait(9); + r.ip = getMem(Word, 0); + r.cs = getMem(Word, 2); + break; + case 6: + if(size == Byte) { debug("[V30MZ] GRP4.6"); break; } + wait(1); + push(getMem(Word)); + break; + case 7: + debug("[V30MZ] GRP4.7"); + break; } } diff --git a/higan/processor/v30mz/instructions-string.cpp b/higan/processor/v30mz/instructions-string.cpp index 47112364..df785a08 100644 --- a/higan/processor/v30mz/instructions-string.cpp +++ b/higan/processor/v30mz/instructions-string.cpp @@ -65,6 +65,7 @@ auto V30MZ::opStoreString(Size size) { auto V30MZ::opLoadString(Size size) { wait(2); setAcc(size, read(size, segment(r.ds), r.si)); + r.si += r.f.d ? -size : size; if(prefix.repeat && --r.cx) { state.prefix = true; @@ -78,6 +79,7 @@ auto V30MZ::opScanString(Size size) { wait(3); auto x = getAcc(size); auto y = read(size, r.es, r.di); + r.di += r.f.d ? -size : size; alSub(size, x, y); if(prefix.repeat && prefix.repeat() == r.f.z && --r.cx) { diff --git a/higan/processor/v30mz/v30mz.cpp b/higan/processor/v30mz/v30mz.cpp index 47b38506..d5d8f74d 100644 --- a/higan/processor/v30mz/v30mz.cpp +++ b/higan/processor/v30mz/v30mz.cpp @@ -17,6 +17,10 @@ namespace Processor { #include "instructions-string.cpp" #include "disassembler.cpp" +auto V30MZ::debug(string text) -> void { + print(text, "\n"); +} + auto V30MZ::exec() -> void { state.poll = true; if(state.halt) return wait(1); diff --git a/higan/processor/v30mz/v30mz.hpp b/higan/processor/v30mz/v30mz.hpp index 5637a7f7..23694a70 100644 --- a/higan/processor/v30mz/v30mz.hpp +++ b/higan/processor/v30mz/v30mz.hpp @@ -14,6 +14,7 @@ struct V30MZ { virtual auto in(uint16 port) -> uint8 = 0; virtual auto out(uint16 port, uint8 data) -> void = 0; + auto debug(string text) -> void; auto exec() -> void; auto instruction() -> void; auto interrupt(uint8 vector) -> void; diff --git a/higan/sfc/expansion/superdisc/superdisc.cpp b/higan/sfc/expansion/superdisc/superdisc.cpp index 8d75c985..6a89bb92 100644 --- a/higan/sfc/expansion/superdisc/superdisc.cpp +++ b/higan/sfc/expansion/superdisc/superdisc.cpp @@ -4,6 +4,23 @@ namespace SuperFamicom { SuperDisc superdisc; +auto SuperDisc::Enter() -> void { + while(true) scheduler.synchronize(), superdisc.main(); +} + +auto SuperDisc::main() -> void { + if(r21e4 & 0x04) { + cpu.regs.irq = 1; + r21e1 = 0x81; + } else { + cpu.regs.irq = 0; + r21e1 = 0x00; + } + + step(1); + synchronizeCPU(); +} + auto SuperDisc::init() -> void { } @@ -16,18 +33,77 @@ auto SuperDisc::unload() -> void { } auto SuperDisc::power() -> void { + create(&SuperDisc::Enter, 75); } auto SuperDisc::reset() -> void { + r21e0 = 0x00; + r21e1 = 0x00; + r21e2 = 0x00; + r21e3 = 0x00; + r21e4 = 0x00; + r21e5 = 0x00; } auto SuperDisc::read(uint24 addr, uint8 data) -> uint8 { addr = 0x21e0 | (addr & 7); + + if(addr == 0x21e0) { + data = r21e0; + } + + if(addr == 0x21e1) { + data = r21e1; + } + + if(addr == 0x21e2) { + data = r21e2; + } + + if(addr == 0x21e3) { + if(r21e2 == 0x01) data = 0x10; + else data = 0x00; + r21e2++; + } + + if(addr == 0x21e4) { + data = r21e4; + } + + if(addr == 0x21e5) { + data = r21e5; + } + return data; } auto SuperDisc::write(uint24 addr, uint8 data) -> void { addr = 0x21e0 | (addr & 7); + + if(addr == 0x21e0) { + r21e0 = data; + } + + if(addr == 0x21e1) { + r21e1 = data; + } + + if(addr == 0x21e2) { + r21e2 = data; + } + + if(addr == 0x21e3) { + r21e2++; + r21e3 = data; + } + + if(addr == 0x21e4) { + r21e4 = data; + } + + if(addr == 0x21e5) { + r21e5 = data; + } } } diff --git a/higan/sfc/expansion/superdisc/superdisc.hpp b/higan/sfc/expansion/superdisc/superdisc.hpp index 928aedf7..2665fddb 100644 --- a/higan/sfc/expansion/superdisc/superdisc.hpp +++ b/higan/sfc/expansion/superdisc/superdisc.hpp @@ -1,4 +1,7 @@ -struct SuperDisc : Memory { +struct SuperDisc : Coprocessor, Memory { + static auto Enter() -> void; + auto main() -> void; + auto init() -> void; auto load() -> void; auto unload() -> void; @@ -9,6 +12,12 @@ struct SuperDisc : Memory { auto write(uint24 addr, uint8 data) -> void; private: + uint8 r21e0; + uint8 r21e1; + uint8 r21e2; + uint8 r21e3; + uint8 r21e4; + uint8 r21e5; }; extern SuperDisc superdisc; diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index b100df3d..a37f09ae 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -69,8 +69,8 @@ namespace SuperFamicom { #include #include #include - #include #include + #include #include #include #include diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 0021b312..452e1c82 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -209,6 +209,7 @@ auto System::reset() -> void { if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc); if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110); if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1); + if(expansionPort() == Device::ID::SuperDisc) cpu.coprocessors.append(&superdisc); scheduler.reset(); device.connect(0, (Device::ID)settings.controllerPort1); diff --git a/higan/ws/apu/apu.cpp b/higan/ws/apu/apu.cpp index 0e84a266..bc79c129 100644 --- a/higan/ws/apu/apu.cpp +++ b/higan/ws/apu/apu.cpp @@ -3,6 +3,7 @@ namespace WonderSwan { APU apu; +#include "io.cpp" auto APU::Enter() -> void { while(true) scheduler.synchronize(), apu.main(); @@ -20,6 +21,41 @@ auto APU::step(uint clocks) -> void { auto APU::power() -> void { create(APU::Enter, 3'072'000); + + for(uint n = 0x0080; n <= 0x0094; n++) iomap[n] = this; + + channel1.r.pitch = 0; + channel1.r.volumeLeft = 0; + channel1.r.volumeRight = 0; + channel1.r.enable = 0; + + channel2.r.pitch = 0; + channel2.r.volumeLeft = 0; + channel2.r.volumeRight = 0; + channel2.r.enable = 0; + channel2.r.voice = 0; + + channel3.r.pitch = 0; + channel3.r.volumeLeft = 0; + channel3.r.volumeRight = 0; + channel3.r.sweepValue = 0; + channel3.r.sweepTime = 0; + channel3.r.enable = 0; + channel3.r.sweep = 0; + + channel4.r.pitch = 0; + channel4.r.volumeLeft = 0; + channel4.r.volumeRight = 0; + channel4.r.noiseMode = 0; + channel4.r.enable = 0; + channel4.r.noise = 0; + + r.waveBase = 0; + r.speakerEnable = 0; + r.speakerShift = 0; + r.headphoneEnable = 0; + r.voiceEnableLeft = 0; + r.voiceEnableRight = 0; } } diff --git a/higan/ws/apu/apu.hpp b/higan/ws/apu/apu.hpp index 9837ca04..e737e6d3 100644 --- a/higan/ws/apu/apu.hpp +++ b/higan/ws/apu/apu.hpp @@ -1,8 +1,94 @@ -struct APU : Thread { +struct APU : Thread, IO { static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void; auto power() -> void; + + //io.cpp + auto portRead(uint16 addr) -> uint8; + auto portWrite(uint16 addr, uint8 data) -> void; + + struct Channel1 { + struct Registers { + //$0080-0081 SND_CH1_PITCH + uint11 pitch; + + //$0088 SND_CH1_VOL + uint4 volumeLeft; + uint4 volumeRight; + + //$0090 SND_CTRL + uint1 enable; + } r; + } channel1; + + struct Channel2 { + struct Registers { + //$0082-0083 SND_CH2_PITCH + uint11 pitch; + + //$0089 SND_CH2_VOL + uint4 volumeLeft; + uint4 volumeRight; + + //$0090 SND_CTRL + uint1 enable; + uint1 voice; + } r; + } channel2; + + struct Channel3 { + struct Registers { + //$0084-0085 SND_CH3_PITCH + uint11 pitch; + + //$008a SND_CH3_VOL + uint4 volumeLeft; + uint4 volumeRight; + + //$008c SND_SWEEP_VALUE + uint8 sweepValue; + + //$008d SND_SWEEP_TIME + uint5 sweepTime; + + //$0090 SND_CTRL + uint1 enable; + uint1 sweep; + } r; + } channel3; + + struct Channel4 { + struct Registers { + //$0086-0087 SND_CH4_PITCH + uint11 pitch; + + //$008b SND_CH4_VOL + uint4 volumeLeft; + uint4 volumeRight; + + //$008e SND_NOISE + uint5 noiseMode; + + //$0090 SND_CTRL + uint1 enable; + uint1 noise; + } r; + } channel4; + + struct Registers { + //$008f SND_WAVE_BASE + uint8 waveBase; + + //$0091 SND_OUTPUT + uint1 speakerEnable; + uint2 speakerShift; + uint1 headphoneEnable; + + //$0092 SND_VOICE_CTRL + uint2 voiceEnableLeft; + uint2 voiceEnableRight; + } r; }; extern APU apu; diff --git a/higan/ws/apu/io.cpp b/higan/ws/apu/io.cpp new file mode 100644 index 00000000..9f1a82ae --- /dev/null +++ b/higan/ws/apu/io.cpp @@ -0,0 +1,181 @@ +auto APU::portRead(uint16 addr) -> uint8 { + //SND_CH1_PITCH + if(addr == 0x0080) return channel1.r.pitch.bits(0, 7); + if(addr == 0x0081) return channel1.r.pitch.bits(8,11); + + //SND_CH2_PITCH + if(addr == 0x0082) return channel2.r.pitch.bits(0, 7); + if(addr == 0x0083) return channel2.r.pitch.bits(8,11); + + //SND_CH3_PITCH + if(addr == 0x0084) return channel3.r.pitch.bits(0, 7); + if(addr == 0x0085) return channel3.r.pitch.bits(8,11); + + //SND_CH4_PITCH + if(addr == 0x0086) return channel4.r.pitch.bits(0, 7); + if(addr == 0x0087) return channel4.r.pitch.bits(8,11); + + //SND_CH1_VOL + if(addr == 0x0088) return ( + channel1.r.volumeRight << 0 + | channel1.r.volumeLeft << 4 + ); + + //SND_CH2_VOL + if(addr == 0x0089) return ( + channel2.r.volumeRight << 0 + | channel2.r.volumeLeft << 4 + ); + + //SND_CH3_VOL + if(addr == 0x008a) return ( + channel3.r.volumeRight << 0 + | channel3.r.volumeLeft << 4 + ); + + //SND_CH4_VOL + if(addr == 0x008b) return ( + channel4.r.volumeRight << 0 + | channel4.r.volumeLeft << 4 + ); + + //SND_SWEEP_VALUE + if(addr == 0x008c) return channel3.r.sweepValue; + + //SND_SWEEP_TIME + if(addr == 0x008d) return channel3.r.sweepTime; + + //SND_NOISE + if(addr == 0x008e) return channel4.r.noiseMode; + + //SND_WAVE_BASE + if(addr == 0x008f) return r.waveBase; + + //SND_CTRL + if(addr == 0x0090) return ( + channel1.r.enable << 0 + | channel2.r.enable << 1 + | channel3.r.enable << 2 + | channel4.r.enable << 3 + | channel2.r.voice << 5 + | channel3.r.sweep << 6 + | channel4.r.noise << 7 + ); + + //SND_OUTPUT + if(addr == 0x0091) return ( + r.speakerEnable << 0 + | r.speakerShift << 1 + | r.headphoneEnable << 3 + | 1 << 7 //headphone connected + ); + + //SND_RANDOM + if(addr == 0x0092) return rand() & 0xff; + if(addr == 0x0093) return rand() & 0x7f; + + //SND_VOICE_CTRL + if(addr == 0x0094) return ( + r.voiceEnableRight << 0 + | r.voiceEnableLeft << 2 + ); + + return 0x00; +} + +auto APU::portWrite(uint16 addr, uint8 data) -> void { + //SND_CH1_PITCH + if(addr == 0x0080) { channel1.r.pitch.bits(0, 7) = data.bits(0,7); return; } + if(addr == 0x0081) { channel1.r.pitch.bits(8,11) = data.bits(0,3); return; } + + //SND_CH2_PITCH + if(addr == 0x0082) { channel2.r.pitch.bits(0, 7) = data.bits(0,7); return; } + if(addr == 0x0083) { channel2.r.pitch.bits(8,11) = data.bits(0,3); return; } + + //SND_CH3_PITCH + if(addr == 0x0084) { channel3.r.pitch.bits(0, 7) = data.bits(0,7); return; } + if(addr == 0x0085) { channel3.r.pitch.bits(8,11) = data.bits(0,3); return; } + + //SND_CH4_PITCH + if(addr == 0x0086) { channel4.r.pitch.bits(0, 7) = data.bits(0,7); return; } + if(addr == 0x0087) { channel4.r.pitch.bits(8,11) = data.bits(0,3); return; } + + //SND_CH1_VOL + if(addr == 0x0088) { + channel1.r.volumeRight = data.bits(0,3); + channel1.r.volumeLeft = data.bits(4,7); + return; + } + + //SND_CH2_VOL + if(addr == 0x0089) { + channel2.r.volumeRight = data.bits(0,3); + channel2.r.volumeLeft = data.bits(4,7); + return; + } + + //SND_CH3_VOL + if(addr == 0x008a) { + channel3.r.volumeRight = data.bits(0,3); + channel3.r.volumeLeft = data.bits(4,7); + return; + } + + //SND_CH4_VOL + if(addr == 0x008b) { + channel4.r.volumeRight = data.bits(0,3); + channel4.r.volumeLeft = data.bits(4,7); + return; + } + + //SND_SWEEP_VALUE + if(addr == 0x008c) { + channel3.r.sweepValue = data; + return; + } + + //SND_SWEEP_TIME + if(addr == 0x008d) { + channel3.r.sweepTime = data.bits(0,4); + return; + } + + //SND_NOISE + if(addr == 0x008e) { + channel4.r.noiseMode = data.bits(0,4); + return; + } + + //SND_WAVE_BASE + if(addr == 0x008f) { + r.waveBase = data; + return; + } + + //SND_CTRL + if(addr == 0x0090) { + channel1.r.enable = data.bit(0); + channel2.r.enable = data.bit(1); + channel3.r.enable = data.bit(2); + channel4.r.enable = data.bit(3); + channel2.r.voice = data.bit(5); + channel3.r.sweep = data.bit(6); + channel4.r.noise = data.bit(7); + return; + } + + //SND_OUTPUT + if(addr == 0x0091) { + r.speakerEnable = data.bit (0); + r.speakerShift = data.bits(1,2); + r.headphoneEnable = data.bit (3); + return; + } + + //SND_VOICE_CTRL + if(addr == 0x0094) { + r.voiceEnableRight = data.bits(0,1); + r.voiceEnableLeft = data.bits(2,3); + return; + } +} diff --git a/higan/ws/cpu/cpu.cpp b/higan/ws/cpu/cpu.cpp index 2afe126b..5f5c00d7 100644 --- a/higan/ws/cpu/cpu.cpp +++ b/higan/ws/cpu/cpu.cpp @@ -3,7 +3,6 @@ namespace WonderSwan { CPU cpu; -#include "memory.cpp" #include "io.cpp" #include "interrupt.cpp" #include "dma.cpp" @@ -61,14 +60,17 @@ auto CPU::power() -> void { iomap[0x0062] = this; } - r.dmaSource = 0x00000; - r.dmaTarget = 0x0000; - r.dmaLength = 0x0000; - r.dmaEnable = false; + r.dmaSource = 0; + r.dmaTarget = 0; + r.dmaLength = 0; + r.dmaEnable = 0; r.dmaMode = 0; - r.interruptBase = 0x00; - r.interruptEnable = 0x00; - r.interruptStatus = 0x00; + r.interruptBase = 0; + r.interruptEnable = 0; + r.interruptStatus = 0; + r.ypadEnable = 0; + r.xpadEnable = 0; + r.buttonEnable = 0; } } diff --git a/higan/ws/cpu/cpu.hpp b/higan/ws/cpu/cpu.hpp index c57b5581..92f13f35 100644 --- a/higan/ws/cpu/cpu.hpp +++ b/higan/ws/cpu/cpu.hpp @@ -22,10 +22,6 @@ struct CPU : Processor::V30MZ, Thread, IO { auto power() -> void; - //memory.cpp - auto ramRead(uint16 addr) -> uint8; - auto ramWrite(uint16 addr, uint8 data) -> void; - //io.cpp auto keypadRead() -> uint4; auto portRead(uint16 addr) -> uint8 override; diff --git a/higan/ws/cpu/memory.cpp b/higan/ws/cpu/memory.cpp deleted file mode 100644 index a7583d87..00000000 --- a/higan/ws/cpu/memory.cpp +++ /dev/null @@ -1,9 +0,0 @@ -auto CPU::ramRead(uint16 addr) -> uint8 { - if(WS() && addr >= 0x4000) return 0x90; - return iram[addr]; -} - -auto CPU::ramWrite(uint16 addr, uint8 data) -> void { - if(WS() && addr >= 0x4000) return; - iram[addr] = data; -} diff --git a/higan/ws/interface/interface.cpp b/higan/ws/interface/interface.cpp index 0b5b8a0f..2cbfed77 100644 --- a/higan/ws/interface/interface.cpp +++ b/higan/ws/interface/interface.cpp @@ -92,11 +92,11 @@ auto Interface::group(uint id) -> uint { case ID::ROM: case ID::RAM: case ID::EEPROM: - switch(system.revision()) { - case System::Revision::WonderSwan: + switch(system.model()) { + case System::Model::WonderSwan: return ID::WonderSwan; - case System::Revision::WonderSwanColor: - case System::Revision::SwanCrystal: + case System::Model::WonderSwanColor: + case System::Model::SwanCrystal: return ID::WonderSwanColor; } } @@ -104,8 +104,8 @@ auto Interface::group(uint id) -> uint { } auto Interface::load(uint id) -> void { - if(id == ID::WonderSwan) system.load(System::Revision::WonderSwan); - if(id == ID::WonderSwanColor) system.load(System::Revision::WonderSwanColor); + if(id == ID::WonderSwan) system.load(System::Model::WonderSwan); + if(id == ID::WonderSwanColor) system.load(System::Model::WonderSwanColor); } auto Interface::save() -> void { diff --git a/higan/ws/memory/memory.cpp b/higan/ws/memory/memory.cpp index d0004501..acb11ab2 100644 --- a/higan/ws/memory/memory.cpp +++ b/higan/ws/memory/memory.cpp @@ -2,8 +2,8 @@ namespace WonderSwan { -uint8 iram[64 * 1024]; IO* iomap[64 * 1024] = {nullptr}; +InternalRAM iram; Bus bus; auto IO::power() -> void { @@ -20,15 +20,32 @@ auto IO::portWrite(uint16 addr, uint8 data) -> void { //print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n"); } +auto InternalRAM::power() -> void { + for(auto& byte : memory) byte = 0x00; +} + +auto InternalRAM::read(uint16 addr, uint size) -> uint32 { + if(size == Long) return read(addr + 0, Word) << 0 | read(addr + 2, Word) << 16; + if(size == Word) return read(addr + 0, Byte) << 0 | read(addr + 1, Byte) << 8; + + if(addr >= 0x4000 && !system.r.depth) return 0x90; + return memory[addr]; +} + +auto InternalRAM::write(uint16 addr, uint8 data) -> void { + if(addr >= 0x4000 && !system.r.depth) return; + memory[addr] = data; +} + auto Bus::read(uint20 addr) -> uint8 { - if(addr.bits(16,19) == 0) return cpu.ramRead(addr); + if(addr.bits(16,19) == 0) return iram.read(addr); if(addr.bits(16,19) == 1) return cartridge.ramRead(addr); if(addr.bits(16,19) >= 2) return cartridge.romRead(addr); unreachable; } auto Bus::write(uint20 addr, uint8 data) -> void { - if(addr.bits(16,19) == 0) return cpu.ramWrite(addr, data); + if(addr.bits(16,19) == 0) return iram.write(addr, data); if(addr.bits(16,19) == 1) return cartridge.ramWrite(addr, data); if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data); } diff --git a/higan/ws/memory/memory.hpp b/higan/ws/memory/memory.hpp index f64fd98f..bc16ce87 100644 --- a/higan/ws/memory/memory.hpp +++ b/higan/ws/memory/memory.hpp @@ -5,11 +5,21 @@ struct IO { virtual auto portWrite(uint16 addr, uint8 data) -> void; }; +struct InternalRAM { + auto power() -> void; + + auto read(uint16 addr, uint size = Byte) -> uint32; + auto write(uint16 addr, uint8 data) -> void; + +private: + uint8 memory[65536]; +}; + struct Bus { auto read(uint20 addr) -> uint8; auto write(uint20 addr, uint8 data) -> void; }; -extern uint8 iram[64 * 1024]; extern IO* iomap[64 * 1024]; +extern InternalRAM iram; extern Bus bus; diff --git a/higan/ws/ppu/io.cpp b/higan/ws/ppu/io.cpp index 5be47943..f12fba81 100644 --- a/higan/ws/ppu/io.cpp +++ b/higan/ws/ppu/io.cpp @@ -12,7 +12,7 @@ auto PPU::portRead(uint16 addr) -> uint8 { } //BACK_COLOR - if(addr == 0x0001) return r.backColorPalette << 4 | r.backColorIndex << 0; + if(addr == 0x0001) return r.backColor; //LINE_CUR if(addr == 0x0002) return status.vclk; @@ -105,16 +105,6 @@ auto PPU::portRead(uint16 addr) -> uint8 { ); } - //DISP_MODE - if(addr == 0x0060) { - return ( - r.bpp << 7 - | r.color << 6 - | r.format << 5 - | r.u0060 << 0 - ); - } - return 0x00; } @@ -133,11 +123,9 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void { //BACK_COLOR if(addr == 0x0001) { if(WS()) { - r.backColorPalette = 0; - r.backColorIndex = data.bits(2,0); + r.backColor = data.bits(0,2); } else { - r.backColorPalette = data.bits(7,4); - r.backColorIndex = data.bits(3,0); + r.backColor = data.bits(0,7); } return; } @@ -296,13 +284,4 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void { r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0); return; } - - //DISP_MODE - if(addr == 0x0060) { - r.bpp = data.bit(7); - r.color = data.bit(6); - r.format = data.bit(5); - r.u0060 = data & 0b1011; - return; - } } diff --git a/higan/ws/ppu/ppu.cpp b/higan/ws/ppu/ppu.cpp index 267a8b3d..7dff785e 100644 --- a/higan/ws/ppu/ppu.cpp +++ b/higan/ws/ppu/ppu.cpp @@ -4,7 +4,8 @@ namespace WonderSwan { PPU ppu; #include "io.cpp" -#include "render.cpp" +#include "render-mono.cpp" +#include "render-color.cpp" #include "video.cpp" auto PPU::Enter() -> void { @@ -14,10 +15,17 @@ auto PPU::Enter() -> void { auto PPU::main() -> void { if(status.vclk < 144) { for(uint x = 0; x < 224; x++) { - renderBack(); - renderScreenOne(); - renderScreenTwo(); - renderSprite(); + if(!system.color()) { + renderMonoBack(); + renderMonoScreenOne(); + renderMonoScreenTwo(); + renderMonoSprite(); + } else { + renderColorBack(); + renderColorScreenOne(); + renderColorScreenTwo(); + renderColorSprite(); + } output[status.vclk * 224 + status.hclk] = pixel.color; step(1); } @@ -60,14 +68,48 @@ auto PPU::power() -> void { for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this; for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this; - iomap[0x0060] = this; for(auto& n : output) n = 0; status.vclk = 0; status.hclk = 0; + r.screenTwoWindowEnable = 0; + r.screenTwoWindowInvert = 0; + r.spriteWindowEnable = 0; + r.spriteEnable = 0; + r.screenTwoEnable = 0; + r.screenOneEnable = 0; + r.backColor = 0; r.lineCompare = 0xff; + r.spriteBase = 0; + r.spriteFirst = 0; + r.spriteCount = 0; + r.screenTwoMapBase = 0; + r.screenOneMapBase = 0; + r.screenTwoWindowX0 = 0; + r.screenTwoWindowY0 = 0; + r.screenTwoWindowX1 = 0; + r.screenTwoWindowY1 = 0; + r.spriteWindowX0 = 0; + r.spriteWindowY0 = 0; + r.spriteWindowX1 = 0; + r.spriteWindowY1 = 0; + r.scrollOneX = 0; + r.scrollOneY = 0; + r.scrollTwoX = 0; + r.scrollTwoY = 0; + r.control = 0; + r.iconAux3 = 0; + r.iconAux2 = 0; + r.iconAux1 = 0; + r.iconHorizontal = 0; + r.iconVertical = 0; + r.iconSleep = 0; + r.vtotal = 158; + r.vblank = 155; + for(auto& color : r.pool) color = 0; + for(auto& p : r.palette) for(auto& color : p.color) color = 0; video.power(); } diff --git a/higan/ws/ppu/ppu.hpp b/higan/ws/ppu/ppu.hpp index bd2517f5..fd468301 100644 --- a/higan/ws/ppu/ppu.hpp +++ b/higan/ws/ppu/ppu.hpp @@ -12,11 +12,19 @@ struct PPU : Thread, IO { auto portRead(uint16 addr) -> uint8 override; auto portWrite(uint16 addr, uint8 data) -> void override; - //render.cpp - auto renderBack() -> void; - auto renderScreenOne() -> void; - auto renderScreenTwo() -> void; - auto renderSprite() -> void; + //render-mono.cpp + auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2; + auto renderMonoBack() -> void; + auto renderMonoScreenOne() -> void; + auto renderMonoScreenTwo() -> void; + auto renderMonoSprite() -> void; + + //render-color.cpp + auto renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4; + auto renderColorBack() -> void; + auto renderColorScreenOne() -> void; + auto renderColorScreenTwo() -> void; + auto renderColorSprite() -> void; //state uint12 output[224 * 144]; @@ -34,16 +42,15 @@ struct PPU : Thread, IO { struct Registers { //$0000 DISP_CTRL - bool screenTwoWindowEnable; - bool screenTwoWindowInvert; - bool spriteWindowEnable; - bool spriteEnable; - bool screenTwoEnable; - bool screenOneEnable; + uint1 screenTwoWindowEnable; + uint1 screenTwoWindowInvert; + uint1 spriteWindowEnable; + uint1 spriteEnable; + uint1 screenTwoEnable; + uint1 screenOneEnable; //$0001 BACK_COLOR - uint4 backColorIndex; - uint4 backColorPalette; + uint8 backColor; //$0003 LINE_CMP uint8 lineCompare; @@ -101,12 +108,12 @@ struct PPU : Thread, IO { uint8 control; //$0015 LCD_ICON - bool iconAux3; - bool iconAux2; - bool iconAux1; - bool iconHorizontal; - bool iconVertical; - bool iconSleep; + uint1 iconAux3; + uint1 iconAux2; + uint1 iconAux1; + uint1 iconHorizontal; + uint1 iconVertical; + uint1 iconSleep; //$0016 LCD_VTOTAL uint8 vtotal; @@ -121,12 +128,6 @@ struct PPU : Thread, IO { struct Palette { uint3 color[4]; } palette[16]; - - //$0060 DISP_MODE - bool bpp; - bool color; - bool format; - uint5 u0060; //unknown purpose } r; }; diff --git a/higan/ws/ppu/render-color.cpp b/higan/ws/ppu/render-color.cpp new file mode 100644 index 00000000..dc85725d --- /dev/null +++ b/higan/ws/ppu/render-color.cpp @@ -0,0 +1,104 @@ +auto PPU::renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4 { + uint4 color; + + if(system.planar()) { + uint32 data = iram.read(offset + (y << 2), Long); + color |= data.bit( 7 - x) << 0; + color |= data.bit(15 - x) << 1; + color |= data.bit(23 - x) << 2; + color |= data.bit(31 - x) << 3; + } + + if(system.packed()) { + uint8 data = iram.read(offset + (y << 2) + (x >> 1)); + color = data >> (4 - (x.bit(0) << 2)); + } + + return color; +} + +auto PPU::renderColorBack() -> void { + uint12 color = iram.read(0xfe00 + (r.backColor << 1), Word); + pixel = {Pixel::Source::Back, color}; +} + +auto PPU::renderColorScreenOne() -> void { + if(!r.screenOneEnable) return; + + uint8 scrollY = status.vclk + r.scrollOneY; + uint8 scrollX = status.hclk + r.scrollOneX; + + uint16 tilemapOffset = r.screenOneMapBase << 11; + tilemapOffset += (scrollY >> 3) << 6; + tilemapOffset += (scrollX >> 3) << 1; + + uint16 tile = iram.read(tilemapOffset, Word); + uint16 tileOffset = 0x4000 + (tile.bit(13) << 14) + (tile.bits(0,8) << 5); + uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); + uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX); + if(tileColor == 0) return; + + uint12 color = iram.read(0xfe00 + (tile.bits(9, 12) << 5) + (tileColor << 1), Word); + pixel = {Pixel::Source::ScreenOne, color}; +} + +auto PPU::renderColorScreenTwo() -> void { + if(!r.screenTwoEnable) return; + + bool windowInside = status.vclk >= r.screenTwoWindowY0 && status.vclk <= r.screenTwoWindowY1 + && status.hclk >= r.screenTwoWindowX0 && status.hclk <= r.screenTwoWindowX1; + windowInside ^= r.screenTwoWindowInvert; + if(r.screenTwoWindowEnable && !windowInside) return; + + uint8 scrollY = status.vclk + r.scrollTwoY; + uint8 scrollX = status.hclk + r.scrollTwoX; + + uint16 tilemapOffset = r.screenTwoMapBase << 11; + tilemapOffset += (scrollY >> 3) << 6; + tilemapOffset += (scrollX >> 3) << 1; + + uint16 tile = iram.read(tilemapOffset, Word); + uint16 tileOffset = 0x4000 + (tile.bit(13) << 14) + (tile.bits(0,8) << 5); + uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); + uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX); + if(tileColor == 0) return; + + uint12 color = iram.read(0xfe00 + (tile.bits(9,12) << 5) + (tileColor << 1), Word); + pixel = {Pixel::Source::ScreenTwo, color}; +} + +auto PPU::renderColorSprite() -> void { + if(!r.spriteEnable) return; + + bool windowInside = status.vclk >= r.spriteWindowY0 && status.vclk <= r.spriteWindowY1 + && status.hclk >= r.spriteWindowX0 && status.hclk <= r.spriteWindowX1; + uint16 spriteBase = r.spriteBase << 9; + + uint7 spriteIndex = r.spriteFirst; + uint8 spriteCount = min(128, (uint)r.spriteCount); + while(spriteCount--) { + uint32 sprite = iram.read(spriteBase + (spriteIndex++ << 2), Long); + if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue; + + uint8 spriteY = sprite.bits(16,23); + uint8 spriteX = sprite.bits(24,31); + + if(status.vclk < spriteY) continue; + if(status.vclk > (uint8)(spriteY + 7)) continue; + if(status.hclk < spriteX) continue; + if(status.hclk > (uint8)(spriteX + 7)) continue; + + uint16 tileOffset = 0x4000 + (sprite.bits(0,8) << 5); + uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0); + uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0); + uint4 tileColor = renderColorFetch(tileOffset, tileY, tileX); + if(tileColor == 0) continue; + if(!sprite.bit(13) && pixel.source == Pixel::Source::ScreenTwo) continue; + + uint12 color = iram.read(0xff00 + (sprite.bits(9,11) << 5) + (tileColor << 1), Word); + pixel = {Pixel::Source::Sprite, color}; + return; + } +} diff --git a/higan/ws/ppu/render.cpp b/higan/ws/ppu/render-mono.cpp similarity index 57% rename from higan/ws/ppu/render.cpp rename to higan/ws/ppu/render-mono.cpp index b694fe74..6fdb94c5 100644 --- a/higan/ws/ppu/render.cpp +++ b/higan/ws/ppu/render-mono.cpp @@ -1,47 +1,52 @@ -auto PPU::renderBack() -> void { - uint4 poolColor = 15 - r.pool[r.backColorIndex]; +auto PPU::renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2 { + uint2 color; + + if(system.planar()) { + uint16 data = iram.read(offset + (y << 1), Word); + color |= data.bit( 7 - x) << 0; + color |= data.bit(15 - x) << 1; + } + + if(system.packed()) { + uint8 data = iram.read(offset + (y << 1) + (x >> 2)); + color = data >> (6 - (x.bits(0,1) << 1)); + } + + return color; +} + +auto PPU::renderMonoBack() -> void { + uint4 poolColor = 15 - r.pool[r.backColor.bits(0,2)]; pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8}; } -auto PPU::renderScreenOne() -> void { +auto PPU::renderMonoScreenOne() -> void { if(!r.screenOneEnable) return; - uint8 scrollX = status.hclk + r.scrollOneX; uint8 scrollY = status.vclk + r.scrollOneY; + uint8 scrollX = status.hclk + r.scrollOneX; uint14 tilemapOffset = r.screenOneMapBase << 11; tilemapOffset += (scrollY >> 3) << 6; tilemapOffset += (scrollX >> 3) << 1; - uint16 tile; - tile.byte(0) = iram[tilemapOffset++]; - tile.byte(1) = iram[tilemapOffset++]; - - uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint16 tile = iram.read(tilemapOffset, Word); + uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4); uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); - - uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1); - uint8 d0 = iram[tileOffset++]; - uint8 d1 = iram[tileOffset++]; - - uint8 tileMask = 0x80 >> tileX; - uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0); + uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX); + if(tile.bit(11) && tileColor == 0) return; uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor]; uint4 poolColor = 15 - r.pool[paletteColor]; - pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8}; } -auto PPU::renderScreenTwo() -> void { +auto PPU::renderMonoScreenTwo() -> void { if(!r.screenTwoEnable) return; - bool windowInside = ( - status.hclk >= r.screenTwoWindowX0 - && status.hclk <= r.screenTwoWindowX1 - && status.vclk >= r.screenTwoWindowY0 - && status.vclk <= r.screenTwoWindowY1 - ); + bool windowInside = status.vclk >= r.screenTwoWindowY0 && status.vclk <= r.screenTwoWindowY1 + && status.hclk >= r.screenTwoWindowX0 && status.hclk <= r.screenTwoWindowX1; windowInside ^= r.screenTwoWindowInvert; if(r.screenTwoWindowEnable && !windowInside) return; @@ -52,74 +57,48 @@ auto PPU::renderScreenTwo() -> void { tilemapOffset += (scrollY >> 3) << 6; tilemapOffset += (scrollX >> 3) << 1; - uint16 tile; - tile.byte(0) = iram[tilemapOffset++]; - tile.byte(1) = iram[tilemapOffset++]; - - uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint16 tile = iram.read(tilemapOffset, Word); + uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4); uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); - - uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1); - uint8 d0 = iram[tileOffset++]; - uint8 d1 = iram[tileOffset++]; - - uint8 tileMask = 0x80 >> tileX; - uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0); - + uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX); if(tile.bit(11) && tileColor == 0) return; + uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor]; uint4 poolColor = 15 - r.pool[paletteColor]; - pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8}; } -auto PPU::renderSprite() -> void { +auto PPU::renderMonoSprite() -> void { if(!r.spriteEnable) return; - bool windowInside = ( - status.hclk >= r.spriteWindowX0 - && status.hclk <= r.spriteWindowX1 - && status.vclk >= r.spriteWindowY0 - && status.vclk <= r.spriteWindowY1 - ); - + bool windowInside = status.vclk >= r.spriteWindowY0 && status.vclk <= r.spriteWindowY1 + && status.hclk >= r.spriteWindowX0 && status.hclk <= r.spriteWindowX1; uint14 spriteBase = r.spriteBase << 9; uint7 spriteIndex = r.spriteFirst; uint8 spriteCount = min(128, (uint)r.spriteCount); while(spriteCount--) { - uint32 sprite; - sprite.byte(0) = iram[spriteBase + (spriteIndex << 2) + 0]; - sprite.byte(1) = iram[spriteBase + (spriteIndex << 2) + 1]; - sprite.byte(2) = iram[spriteBase + (spriteIndex << 2) + 2]; - sprite.byte(3) = iram[spriteBase + (spriteIndex << 2) + 3]; - spriteIndex++; - + uint32 sprite = iram.read(spriteBase + (spriteIndex++ << 2), Long); if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue; uint8 spriteY = sprite.bits(16,23); uint8 spriteX = sprite.bits(24,31); - if(status.hclk < spriteX) continue; - if(status.hclk > (uint8)(spriteX + 7)) continue; if(status.vclk < spriteY) continue; if(status.vclk > (uint8)(spriteY + 7)) continue; + if(status.hclk < spriteX) continue; + if(status.hclk > (uint8)(spriteX + 7)) continue; - uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0); + uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4); uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0); - - uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4) + (tileY << 1); - uint8 d0 = iram[tileOffset++]; - uint8 d1 = iram[tileOffset++]; - - uint8 tileMask = 0x80 >> tileX; - uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0); - + uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0); + uint2 tileColor = renderMonoFetch(tileOffset, tileY, tileX); if(sprite.bit(11) && tileColor == 0) continue; if(!sprite.bit(13) && pixel.source == Pixel::Source::ScreenTwo) continue; + uint3 paletteColor = r.palette[8 + sprite.bits(9,11)].color[tileColor]; uint4 poolColor = 15 - r.pool[paletteColor]; - pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8}; return; } diff --git a/higan/ws/ppu/video.cpp b/higan/ws/ppu/video.cpp index e0c7e7be..37930792 100644 --- a/higan/ws/ppu/video.cpp +++ b/higan/ws/ppu/video.cpp @@ -28,8 +28,8 @@ auto Video::refresh() -> void { auto source = ppu.output + y * 224; for(uint x = 0; x < 224; x++) { auto color = paletteStandard[*source++]; - //*(output() + y * 224 + x) = color; - *(output() + (223 - x) * 224 + 40 + y) = color; + *(output() + (y + 40) * 224 + x) = color; + //*(output() + (223 - x) * 224 + 40 + y) = color; } } diff --git a/higan/ws/system/io.cpp b/higan/ws/system/io.cpp index a7010750..d1aaadd2 100644 --- a/higan/ws/system/io.cpp +++ b/higan/ws/system/io.cpp @@ -1,4 +1,12 @@ auto System::portRead(uint16 addr) -> uint8 { + //DISP_MODE + if(addr == 0x0060) return ( + r.unknown << 0 + | r.format << 5 + | r.color << 6 + | r.depth << 7 + ); + //IEEP_DATA if(addr == 0x00ba) return eeprom.read(EEPROM::DataLo); if(addr == 0x00bb) return eeprom.read(EEPROM::DataHi); @@ -12,6 +20,15 @@ auto System::portRead(uint16 addr) -> uint8 { } auto System::portWrite(uint16 addr, uint8 data) -> void { + //DISP_MODE + if(addr == 0x0060) { + r.unknown = data.bits(0,4) & 0b01011; + r.format = data.bit (5); + r.color = data.bit (6); + r.depth = data.bit (7); + return; + } + //IEEP_DATA if(addr == 0x00ba) return eeprom.write(EEPROM::DataLo, data); if(addr == 0x00bb) return eeprom.write(EEPROM::DataHi, data); diff --git a/higan/ws/system/system.cpp b/higan/ws/system/system.cpp index 84194c73..39944765 100644 --- a/higan/ws/system/system.cpp +++ b/higan/ws/system/system.cpp @@ -6,7 +6,10 @@ System system; #include "io.cpp" auto System::loaded() const -> bool { return _loaded; } -auto System::revision() const -> Revision { return _revision; } +auto System::model() const -> Model { return _model; } +auto System::color() const -> bool { return r.color; } +auto System::planar() const -> bool { return r.format == 0; } +auto System::packed() const -> bool { return r.format == 1; } auto System::init() -> void { } @@ -14,8 +17,8 @@ auto System::init() -> void { auto System::term() -> void { } -auto System::load(Revision revision) -> void { - _revision = revision; +auto System::load(Model model) -> void { + _model = model; interface->loadRequest(ID::SystemManifest, "manifest.bml", true); auto document = BML::unserialize(information.manifest); @@ -45,6 +48,7 @@ auto System::unload() -> void { auto System::power() -> void { IO::power(); + iram.power(); eeprom.power(); cpu.power(); ppu.power(); @@ -52,7 +56,13 @@ auto System::power() -> void { cartridge.power(); scheduler.power(); + iomap[0x0060] = this; for(uint n = 0x00ba; n <= 0x00be; n++) iomap[n] = this; + + r.depth = 0; + r.color = 0; + r.format = 0; + r.unknown = 0; } auto System::run() -> void { diff --git a/higan/ws/system/system.hpp b/higan/ws/system/system.hpp index fb5c9b31..0eb47137 100644 --- a/higan/ws/system/system.hpp +++ b/higan/ws/system/system.hpp @@ -5,18 +5,21 @@ enum class Keypad : uint { }; struct System : IO { - enum class Revision : uint { + enum class Model : uint { WonderSwan, //SW-001 (ASWAN) WonderSwanColor, //WSC-001 (SPHINX) SwanCrystal, //SCT-001 (SPHINX2) }; auto loaded() const -> bool; - auto revision() const -> Revision; + auto model() const -> Model; + auto color() const -> bool; + auto planar() const -> bool; + auto packed() const -> bool; auto init() -> void; auto term() -> void; - auto load(Revision) -> void; + auto load(Model) -> void; auto unload() -> void; auto power() -> void; auto run() -> void; @@ -30,9 +33,17 @@ struct System : IO { EEPROM eeprom; + struct Registers { + //$0060 DISP_MODE + uint1 depth; + uint1 color; + uint1 format; + uint5 unknown; + } r; + privileged: bool _loaded = false; - Revision _revision = Revision::WonderSwan; + Model _model = Model::WonderSwan; }; extern System system; diff --git a/higan/ws/ws.hpp b/higan/ws/ws.hpp index 166536a5..d8e1f8d5 100644 --- a/higan/ws/ws.hpp +++ b/higan/ws/ws.hpp @@ -42,6 +42,8 @@ namespace WonderSwan { int64 clock = 0; }; + enum : uint { Byte = 1, Word = 2, Long = 4 }; + #include #include #include @@ -51,9 +53,9 @@ namespace WonderSwan { #include #include - inline auto WS() { return system.revision() == System::Revision::WonderSwan; } - inline auto WSC() { return system.revision() == System::Revision::WonderSwanColor; } - inline auto SC() { return system.revision() == System::Revision::SwanCrystal; } + inline auto WS() { return system.model() == System::Model::WonderSwan; } + inline auto WSC() { return system.model() == System::Model::WonderSwanColor; } + inline auto SC() { return system.model() == System::Model::SwanCrystal; } } #include