From 3d3ac8c1db11d7566dacf128ebf30cc34628ee62 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 8 Mar 2016 22:34:00 +1100 Subject: [PATCH] Update to v097r22 release. byuu says: Changelog: - WS: fixed lods, scas instructions - WS: implemented missing GRP4 instructions - WS: fixed transparency for screen one - WSC: added color-mode PPU rendering - WS+WSC: added packed pixel mode support - WS+WSC: added dummy sound register reads/writes - SFC: added threading to SuperDisc (it's hanging for right now; need to clear IRQ on $21e2 writes) SuperDisc Timer and Sound Check were failing before due to not turning off IRQs on $21e4 clear, so I'm happy that's fixed now. Riviera starts now, and displays the first intro screen before crashing. Huge, huge amounts of corrupted graphics, though. This game's really making me work for it :( No color games seem fully playable yet, but a lot of monochrome and color games are now at least showing more intro screen graphics before dying. This build defaults to horizontal orientation, but I left the inputs bound to vertical orientation. Whoops. I still need to implement a screen flip key binding. --- higan/emulator/emulator.hpp | 2 +- higan/processor/v30mz/instructions-group.cpp | 52 ++++- higan/processor/v30mz/instructions-string.cpp | 2 + higan/processor/v30mz/v30mz.cpp | 4 + higan/processor/v30mz/v30mz.hpp | 1 + higan/sfc/expansion/superdisc/superdisc.cpp | 76 ++++++++ higan/sfc/expansion/superdisc/superdisc.hpp | 11 +- higan/sfc/sfc.hpp | 2 +- higan/sfc/system/system.cpp | 1 + higan/ws/apu/apu.cpp | 36 ++++ higan/ws/apu/apu.hpp | 88 ++++++++- higan/ws/apu/io.cpp | 181 ++++++++++++++++++ higan/ws/cpu/cpu.cpp | 18 +- higan/ws/cpu/cpu.hpp | 4 - higan/ws/cpu/memory.cpp | 9 - higan/ws/interface/interface.cpp | 12 +- higan/ws/memory/memory.cpp | 23 ++- higan/ws/memory/memory.hpp | 12 +- higan/ws/ppu/io.cpp | 27 +-- higan/ws/ppu/ppu.cpp | 54 +++++- higan/ws/ppu/ppu.hpp | 51 ++--- higan/ws/ppu/render-color.cpp | 104 ++++++++++ higan/ws/ppu/{render.cpp => render-mono.cpp} | 109 +++++------ higan/ws/ppu/video.cpp | 4 +- higan/ws/system/io.cpp | 17 ++ higan/ws/system/system.cpp | 16 +- higan/ws/system/system.hpp | 19 +- higan/ws/ws.hpp | 8 +- 28 files changed, 766 insertions(+), 177 deletions(-) create mode 100644 higan/ws/apu/io.cpp delete mode 100644 higan/ws/cpu/memory.cpp create mode 100644 higan/ws/ppu/render-color.cpp rename higan/ws/ppu/{render.cpp => render-mono.cpp} (57%) 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