From a7f7985581f7a32851d50d569fe6fab160b3b50b Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 17 Mar 2016 22:28:15 +1100 Subject: [PATCH] Update to v097r26 release. byuu says: Changelog: - WS: fixed 8-bit sign-extended imul (fixes Star Hearts completely, Final Fantasy world map) - WS: fixed rcl/rcr carry shifting (fixes Crazy Climber, others) - WS: added sound DMA emulation (Star Hearts rain sound for one example) - WS: added OAM caching, but it's forced every line for now because otherwise there are too many sprite glitches - WS: use headphoneEnable bit instead of speakerEnable bit (fixes muted audio in games) - WS: various code cleanups (I/O mapping, audio channel naming, etc) The hypervoice channel doesn't sound all that great just yet. But I'm not sure how it's supposed to sound. I need a better example of some more complex music. What's left are some unknown register status bits (especially in the sound area), keypad interrupts, RTC emulation, CPU prefetch emulation. And then it's all just bugs. Lots and lots of bugs that need to be fixed. EDIT: oops, bad typo in the code. ws/ppu/ppu.cpp line 20: change range(256) to range(224). Also, delete the r.speed stuff from channel5.cpp to make the rain sound a lot better in Star Hearts. Apparently that's outdated and not what the bits really do. --- higan/emulator/emulator.hpp | 2 +- higan/processor/v30mz/algorithms.cpp | 4 +- higan/processor/v30mz/instructions-alu.cpp | 2 +- higan/processor/v30mz/v30mz.cpp | 2 +- .../profile/WonderSwan Color.sys/manifest.bml | 2 +- higan/profile/WonderSwan.sys/manifest.bml | 2 +- higan/ws/apu/apu.cpp | 114 +++++---- higan/ws/apu/apu.hpp | 120 +++++++--- higan/ws/apu/channel.cpp | 8 - higan/ws/apu/channel0.cpp | 11 - higan/ws/apu/channel1.cpp | 11 +- higan/ws/apu/channel2.cpp | 18 +- higan/ws/apu/channel3.cpp | 27 +-- higan/ws/apu/channel4.cpp | 28 ++- higan/ws/apu/channel5.cpp | 17 ++ higan/ws/apu/dma.cpp | 29 +++ higan/ws/apu/io.cpp | 225 ++++++++++-------- higan/ws/cartridge/cartridge.cpp | 2 +- higan/ws/cpu/cpu.cpp | 20 +- higan/ws/memory/memory.cpp | 32 +-- higan/ws/memory/memory.hpp | 16 +- higan/ws/ppu/ppu.cpp | 12 +- higan/ws/ppu/ppu.hpp | 4 + higan/ws/ppu/render-color.cpp | 13 +- higan/ws/ppu/render-mono.cpp | 20 +- higan/ws/ppu/render-sprite.cpp | 9 +- higan/ws/system/system.cpp | 6 +- 27 files changed, 444 insertions(+), 312 deletions(-) delete mode 100644 higan/ws/apu/channel.cpp delete mode 100644 higan/ws/apu/channel0.cpp create mode 100644 higan/ws/apu/channel5.cpp create mode 100644 higan/ws/apu/dma.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 260b391e..1718d867 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.25"; + static const string Version = "097.26"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/v30mz/algorithms.cpp b/higan/processor/v30mz/algorithms.cpp index a75eae95..4165dc98 100644 --- a/higan/processor/v30mz/algorithms.cpp +++ b/higan/processor/v30mz/algorithms.cpp @@ -119,7 +119,7 @@ auto V30MZ::alRcl(Size size, uint16 x, uint5 y) -> uint16 { uint16 result = x; for(uint n = 0; n < y; n++) { bool carry = result & sign; - result = (result << 1) | carry; + result = (result << 1) | r.f.c; r.f.c = carry; } r.f.v = (x ^ result) & sign; @@ -130,7 +130,7 @@ auto V30MZ::alRcr(Size size, uint16 x, uint5 y) -> uint16 { uint16 result = x; for(uint n = 0; n < y; n++) { bool carry = result & 1; - result = (carry ? sign : 0) | (result >> 1); + result = (r.f.c ? sign : 0) | (result >> 1); r.f.c = carry; } r.f.v = (x ^ result) & sign; diff --git a/higan/processor/v30mz/instructions-alu.cpp b/higan/processor/v30mz/instructions-alu.cpp index 1ed3255b..89334dbe 100644 --- a/higan/processor/v30mz/instructions-alu.cpp +++ b/higan/processor/v30mz/instructions-alu.cpp @@ -134,7 +134,7 @@ auto V30MZ::opTestMemReg(Size size) { auto V30MZ::opMultiplySignedRegMemImm(Size size) { wait(2); modRM(); - setReg(size, alMuli(size, getMem(size), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte))); + setReg(Word, alMuli(Word, getMem(Word), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte))); } //40 inc ax diff --git a/higan/processor/v30mz/v30mz.cpp b/higan/processor/v30mz/v30mz.cpp index 11bf214a..e1efd74b 100644 --- a/higan/processor/v30mz/v30mz.cpp +++ b/higan/processor/v30mz/v30mz.cpp @@ -18,7 +18,7 @@ namespace Processor { #include "disassembler.cpp" auto V30MZ::debug(string text) -> void { - print(text, "\n"); +//print(text, "\n"); } auto V30MZ::power() -> void { diff --git a/higan/profile/WonderSwan Color.sys/manifest.bml b/higan/profile/WonderSwan Color.sys/manifest.bml index 22c9faea..3422d5f1 100644 --- a/higan/profile/WonderSwan Color.sys/manifest.bml +++ b/higan/profile/WonderSwan Color.sys/manifest.bml @@ -1,2 +1,2 @@ system name:WonderSwan Color - eeprom name=internal.rom size=2048 + eeprom name=internal.ram size=2048 diff --git a/higan/profile/WonderSwan.sys/manifest.bml b/higan/profile/WonderSwan.sys/manifest.bml index 9c778cc0..26aa0503 100644 --- a/higan/profile/WonderSwan.sys/manifest.bml +++ b/higan/profile/WonderSwan.sys/manifest.bml @@ -1,2 +1,2 @@ system name:WonderSwan - eeprom name=internal.rom size=128 + eeprom name=internal.ram size=128 diff --git a/higan/ws/apu/apu.cpp b/higan/ws/apu/apu.cpp index c4a1801e..6e135616 100644 --- a/higan/ws/apu/apu.cpp +++ b/higan/ws/apu/apu.cpp @@ -4,56 +4,54 @@ namespace WonderSwan { APU apu; #include "io.cpp" -#include "channel.cpp" -#include "channel0.cpp" +#include "dma.cpp" #include "channel1.cpp" #include "channel2.cpp" #include "channel3.cpp" #include "channel4.cpp" +#include "channel5.cpp" auto APU::Enter() -> void { while(true) scheduler.synchronize(), apu.main(); } auto APU::main() -> void { - channel0.run(); + dma.run(); channel1.run(); channel2.run(); channel3.run(); - - if(s.clock.bits(0,12) == 0) { - channel2.sweep(); - } - - if(s.clock.bits(0,6) == 0) { - channel4.run(); - dacRun(); - } - + channel4.run(); + channel5.run(); + if(s.clock.bits(0,12) == 0) channel3.sweep(); + if(s.clock.bits(0, 6) == 0) dacRun(); s.clock++; step(1); } +auto APU::sample(uint channel, uint5 index) -> uint4 { + uint8 data = iram.read((r.waveBase << 6) + (--channel << 4) + (index >> 1)); + if(index.bit(0) == 0) return data.bits(0,3); + if(index.bit(0) == 1) return data.bits(4,7); +} + auto APU::dacRun() -> void { int left = 0; - if(channel0.r.enable) left += channel0.o.left; if(channel1.r.enable) left += channel1.o.left; if(channel2.r.enable) left += channel2.o.left; if(channel3.r.enable) left += channel3.o.left; - left = (left >> r.speakerShift) << 5; if(channel4.r.enable) left += channel4.o.left; - left = sclamp<16>(left << 3); + if(channel5.r.enable) left += (int11)channel5.o.left >> 3; + left = sclamp<16>(left << 5); int right = 0; - if(channel0.r.enable) right += channel0.o.right; if(channel1.r.enable) right += channel1.o.right; if(channel2.r.enable) right += channel2.o.right; if(channel3.r.enable) right += channel3.o.right; - right = (right >> r.speakerShift) << 5; if(channel4.r.enable) right += channel4.o.right; - right = sclamp<16>(right << 3); + if(channel5.r.enable) right += (int11)channel5.o.right >> 3; + right = sclamp<16>(right << 5); - if(!r.speakerEnable) { + if(!r.headphoneEnable) { left = 0; right = 0; } @@ -69,8 +67,11 @@ auto APU::step(uint clocks) -> void { auto APU::power() -> void { create(APU::Enter, 3'072'000); - for(uint n = 0x006a; n <= 0x006b; n++) iomap[n] = this; - for(uint n = 0x0080; n <= 0x0094; n++) iomap[n] = this; + bus.map(this, 0x004a, 0x004c); + bus.map(this, 0x004e, 0x0050); + bus.map(this, 0x0052); + bus.map(this, 0x006a, 0x006b); + bus.map(this, 0x0080, 0x0095); s.clock = 0; r.waveBase = 0; @@ -78,14 +79,17 @@ auto APU::power() -> void { r.speakerShift = 0; r.headphoneEnable = 0; - channel0.o.left = 0; - channel0.o.right = 0; - channel0.s.period = 0; - channel0.s.sampleOffset = 0; - channel0.r.pitch = 0; - channel0.r.volumeLeft = 0; - channel0.r.volumeRight = 0; - channel0.r.enable = 0; + dma.s.clock = 0; + dma.s.source = 0; + dma.s.length = 0; + dma.r.source = 0; + dma.r.length = 0; + dma.r.rate = 0; + dma.r.unknown = 0; + dma.r.loop = 0; + dma.r.target = 0; + dma.r.direction = 0; + dma.r.enable = 0; channel1.o.left = 0; channel1.o.right = 0; @@ -95,48 +99,58 @@ auto APU::power() -> void { channel1.r.volumeLeft = 0; channel1.r.volumeRight = 0; channel1.r.enable = 0; - channel1.r.voice = 0; - channel1.r.voiceEnableLeft = 0; - channel1.r.voiceEnableRight = 0; channel2.o.left = 0; channel2.o.right = 0; channel2.s.period = 0; channel2.s.sampleOffset = 0; - channel2.s.sweepCounter = 0; channel2.r.pitch = 0; channel2.r.volumeLeft = 0; channel2.r.volumeRight = 0; - channel2.r.sweepValue = 0; - channel2.r.sweepTime = 0; channel2.r.enable = 0; - channel2.r.sweep = 0; + channel2.r.voice = 0; + channel2.r.voiceEnableLeft = 0; + channel2.r.voiceEnableRight = 0; channel3.o.left = 0; channel3.o.right = 0; channel3.s.period = 0; channel3.s.sampleOffset = 0; - channel3.s.noiseOutput = 0; - channel3.s.noiseLFSR = 0; + channel3.s.sweepCounter = 0; channel3.r.pitch = 0; channel3.r.volumeLeft = 0; channel3.r.volumeRight = 0; - channel3.r.noiseMode = 0; - channel3.r.noiseReset = 0; - channel3.r.noiseUpdate = 0; + channel3.r.sweepValue = 0; + channel3.r.sweepTime = 0; channel3.r.enable = 0; - channel3.r.noise = 0; + channel3.r.sweep = 0; channel4.o.left = 0; channel4.o.right = 0; - channel4.s.data = 0; - channel4.r.volume = 0; - channel4.r.scale = 0; - channel4.r.speed = 0; + channel4.s.period = 0; + channel4.s.sampleOffset = 0; + channel4.s.noiseOutput = 0; + channel4.s.noiseLFSR = 0; + channel4.r.pitch = 0; + channel4.r.volumeLeft = 0; + channel4.r.volumeRight = 0; + channel4.r.noiseMode = 0; + channel4.r.noiseReset = 0; + channel4.r.noiseUpdate = 0; channel4.r.enable = 0; - channel4.r.unknown = 0; - channel4.r.leftEnable = 0; - channel4.r.rightEnable = 0; + channel4.r.noise = 0; + + channel5.o.left = 0; + channel5.o.right = 0; + channel5.s.clock = 0; + channel5.s.data = 0; + channel5.r.volume = 0; + channel5.r.scale = 0; + channel5.r.speed = 0; + channel5.r.enable = 0; + channel5.r.unknown = 0; + channel5.r.leftEnable = 0; + channel5.r.rightEnable = 0; } } diff --git a/higan/ws/apu/apu.hpp b/higan/ws/apu/apu.hpp index 641fbe04..db124068 100644 --- a/higan/ws/apu/apu.hpp +++ b/higan/ws/apu/apu.hpp @@ -1,6 +1,7 @@ struct APU : Thread, IO { static auto Enter() -> void; auto main() -> void; + auto sample(uint channel, uint5 index) -> uint4; auto dacRun() -> void; auto step(uint clocks) -> void; auto power() -> void; @@ -13,7 +14,47 @@ struct APU : Thread, IO { uint13 clock; } s; + struct DMA { + auto run() -> void; + + struct State { + uint clock; + uint20 source; + uint20 length; + } s; + + struct Registers { + //$004a-$004c SDMA_SRC + uint20 source; + + //$004e-$0050 SDMA_LEN + uint20 length; + + //$0052 SDMA_CTRL + uint2 rate; + uint1 unknown; + uint1 loop; + uint1 target; + uint1 direction; + uint1 enable; + } r; + } dma; + struct Registers { + //$004a-$004c SDMA_SRC + uint20 dmaSource; + + //$004e-$0050 SDMA_LEN + uint20 dmaLength; + + //$0052 SDMA_CTRL + uint2 dmaRate; + uint1 dmaUnknown; + uint1 dmaLoop; + uint1 dmaTarget; + uint1 dmaDirection; + uint1 dmaEnable; + //$008f SND_WAVE_BASE uint8 waveBase; @@ -23,21 +64,13 @@ struct APU : Thread, IO { uint1 headphoneEnable; } r; - struct Channel { - Channel(uint id); - auto sample(uint5 index) -> uint4; - - const uint id; + struct Channel1 { + auto run() -> void; struct Output { - int16 left; - int16 right; + uint8 left; + uint8 right; } o; - }; - - struct Channel0 : Channel { - Channel0(); - auto run() -> void; struct State { uint11 period; @@ -45,32 +78,36 @@ struct APU : Thread, IO { } s; struct Registers { - //$0080-0081 SND_CH0_PITCH + //$0080-0081 SND_CH1_PITCH uint11 pitch; - //$0088 SND_CH0_VOL + //$0088 SND_CH1_VOL uint4 volumeLeft; uint4 volumeRight; //$0090 SND_CTRL uint1 enable; } r; - } channel0; + } channel1; - struct Channel1 : Channel { - Channel1(); + struct Channel2 { auto run() -> void; + struct Output { + uint8 left; + uint8 right; + } o; + struct State { uint11 period; uint5 sampleOffset; } s; struct Registers { - //$0082-0083 SND_CH1_PITCH + //$0082-0083 SND_CH2_PITCH uint11 pitch; - //$0089 SND_CH1_VOL + //$0089 SND_CH2_VOL uint4 volumeLeft; uint4 volumeRight; @@ -78,17 +115,21 @@ struct APU : Thread, IO { uint1 enable; uint1 voice; - //$0092 SND_VOICE_CTRL + //$0094 SND_VOICE_CTRL uint2 voiceEnableLeft; uint2 voiceEnableRight; } r; - } channel1; + } channel2; - struct Channel2 : Channel { - Channel2(); + struct Channel3 { auto sweep() -> void; auto run() -> void; + struct Output { + uint8 left; + uint8 right; + } o; + struct State { uint11 period; uint5 sampleOffset; @@ -97,10 +138,10 @@ struct APU : Thread, IO { } s; struct Registers { - //$0084-0085 SND_CH2_PITCH + //$0084-0085 SND_CH3_PITCH uint11 pitch; - //$008a SND_CH2_VOL + //$008a SND_CH3_VOL uint4 volumeLeft; uint4 volumeRight; @@ -114,13 +155,17 @@ struct APU : Thread, IO { uint1 enable; uint1 sweep; } r; - } channel2; + } channel3; - struct Channel3 : Channel { - Channel3(); + struct Channel4 { auto noiseSample() -> uint4; auto run() -> void; + struct Output { + uint8 left; + uint8 right; + } o; + struct State { uint11 period; uint5 sampleOffset; @@ -130,10 +175,10 @@ struct APU : Thread, IO { } s; struct Registers { - //$0086-0087 SND_CH3_PITCH + //$0086-0087 SND_CH4_PITCH uint11 pitch; - //$008b SND_CH3_VOL + //$008b SND_CH4_VOL uint4 volumeLeft; uint4 volumeRight; @@ -146,14 +191,19 @@ struct APU : Thread, IO { uint1 enable; uint1 noise; } r; - } channel3; + } channel4; - struct Channel4 : Channel { - Channel4(); + struct Channel5 { auto run() -> void; + struct Output { + uint11 left; + uint11 right; + } o; + struct State { - int8 data; + uint clock; + uint8 data; } s; struct Registers { @@ -168,7 +218,7 @@ struct APU : Thread, IO { uint1 leftEnable; uint1 rightEnable; } r; - } channel4; + } channel5; }; extern APU apu; diff --git a/higan/ws/apu/channel.cpp b/higan/ws/apu/channel.cpp deleted file mode 100644 index c0218fdc..00000000 --- a/higan/ws/apu/channel.cpp +++ /dev/null @@ -1,8 +0,0 @@ -APU::Channel::Channel(uint id) : id(id) { -} - -auto APU::Channel::sample(uint5 index) -> uint4 { - auto data = iram.read((apu.r.waveBase << 6) + (id << 4) + (index >> 1)); - if(index.bit(0) == 0) return data.bits(0,3); - if(index.bit(0) == 1) return data.bits(4,7); -} diff --git a/higan/ws/apu/channel0.cpp b/higan/ws/apu/channel0.cpp deleted file mode 100644 index 548c1425..00000000 --- a/higan/ws/apu/channel0.cpp +++ /dev/null @@ -1,11 +0,0 @@ -APU::Channel0::Channel0() : Channel(0) { -} - -auto APU::Channel0::run() -> void { - if(--s.period == r.pitch) { - s.period = 0; - auto output = sample(s.sampleOffset++); - o.left = output * r.volumeLeft; - o.right = output * r.volumeRight; - } -} diff --git a/higan/ws/apu/channel1.cpp b/higan/ws/apu/channel1.cpp index 7c70a887..18c10201 100644 --- a/higan/ws/apu/channel1.cpp +++ b/higan/ws/apu/channel1.cpp @@ -1,14 +1,7 @@ -APU::Channel1::Channel1() : Channel(1) { -} - auto APU::Channel1::run() -> void { - if(r.voice) { - uint8 volume = r.volumeLeft << 4 | r.volumeRight << 0; - o.left = r.voiceEnableLeft ? volume : (uint8)0x80; - o.right = r.voiceEnableRight ? volume : (uint8)0x80; - } else if(--s.period == r.pitch) { + if(--s.period == r.pitch) { s.period = 0; - auto output = sample(s.sampleOffset++); + auto output = apu.sample(1, s.sampleOffset++); o.left = output * r.volumeLeft; o.right = output * r.volumeRight; } diff --git a/higan/ws/apu/channel2.cpp b/higan/ws/apu/channel2.cpp index ec7110dd..42cf8fc0 100644 --- a/higan/ws/apu/channel2.cpp +++ b/higan/ws/apu/channel2.cpp @@ -1,17 +1,11 @@ -APU::Channel2::Channel2() : Channel(2) { -} - -auto APU::Channel2::sweep() -> void { - if(r.sweep && --s.sweepCounter < 0) { - s.sweepCounter = r.sweepTime; - r.pitch += r.sweepTime; - } -} - auto APU::Channel2::run() -> void { - if(--s.period == r.pitch) { + if(r.voice) { + uint8 volume = r.volumeLeft << 4 | r.volumeRight << 0; + o.left = r.voiceEnableLeft ? volume : (uint8)0; + o.right = r.voiceEnableRight ? volume : (uint8)0; + } else if(--s.period == r.pitch) { s.period = 0; - auto output = sample(s.sampleOffset++); + auto output = apu.sample(2, s.sampleOffset++); o.left = output * r.volumeLeft; o.right = output * r.volumeRight; } diff --git a/higan/ws/apu/channel3.cpp b/higan/ws/apu/channel3.cpp index d628fad4..2ee6211a 100644 --- a/higan/ws/apu/channel3.cpp +++ b/higan/ws/apu/channel3.cpp @@ -1,30 +1,15 @@ -APU::Channel3::Channel3() : Channel(3) { -} - -auto APU::Channel3::noiseSample() -> uint4 { - return s.noiseOutput ? 0xf : 0x0; +auto APU::Channel3::sweep() -> void { + if(r.sweep && --s.sweepCounter < 0) { + s.sweepCounter = r.sweepTime; + r.pitch += r.sweepTime; + } } auto APU::Channel3::run() -> void { if(--s.period == r.pitch) { s.period = 0; - - auto output = r.noise ? noiseSample() : sample(s.sampleOffset++); + auto output = apu.sample(3, s.sampleOffset++); o.left = output * r.volumeLeft; o.right = output * r.volumeRight; - - if(r.noiseReset) { - r.noiseReset = 0; - s.noiseLFSR = 0; - s.noiseOutput = 0; - } - - if(r.noiseUpdate) { - static const int taps[8] = {14, 10, 13, 4, 8, 6, 9, 11}; - auto tap = taps[r.noiseMode]; - - s.noiseOutput = (1 ^ (s.noiseLFSR >> 7) ^ (s.noiseLFSR >> tap)) & 1; - s.noiseLFSR = s.noiseLFSR << 1 | s.noiseOutput; - } } } diff --git a/higan/ws/apu/channel4.cpp b/higan/ws/apu/channel4.cpp index 30366416..c71da08d 100644 --- a/higan/ws/apu/channel4.cpp +++ b/higan/ws/apu/channel4.cpp @@ -1,11 +1,27 @@ -APU::Channel4::Channel4() : Channel(4) { +auto APU::Channel4::noiseSample() -> uint4 { + return s.noiseOutput ? 0xf : 0x0; } auto APU::Channel4::run() -> void { - int16 sample = s.data << 8; - if(r.scale != 3) sample >>= r.volume; - if(r.scale == 1) sample |= 0x70000 >> r.volume; + if(--s.period == r.pitch) { + s.period = 0; - o.left = r.leftEnable ? sample : (int16)0; - o.right = r.rightEnable ? sample : (int16)0; + auto output = r.noise ? noiseSample() : apu.sample(4, s.sampleOffset++); + o.left = output * r.volumeLeft; + o.right = output * r.volumeRight; + + if(r.noiseReset) { + r.noiseReset = 0; + s.noiseLFSR = 0; + s.noiseOutput = 0; + } + + if(r.noiseUpdate) { + static const int taps[8] = {14, 10, 13, 4, 8, 6, 9, 11}; + auto tap = taps[r.noiseMode]; + + s.noiseOutput = (1 ^ (s.noiseLFSR >> 7) ^ (s.noiseLFSR >> tap)) & 1; + s.noiseLFSR = s.noiseLFSR << 1 | s.noiseOutput; + } + } } diff --git a/higan/ws/apu/channel5.cpp b/higan/ws/apu/channel5.cpp new file mode 100644 index 00000000..50cf2009 --- /dev/null +++ b/higan/ws/apu/channel5.cpp @@ -0,0 +1,17 @@ +auto APU::Channel5::run() -> void { + if(r.speed <= 5 && s.clock++ < 1536) return; //2000hz + if(r.speed == 6 && s.clock++ < 2048) return; //1500hz + if(r.speed == 7 && s.clock++ < 3072) return; //1000hz + s.clock = 0; + + uint11 output = s.data; + switch(r.scale) { + case 0: output <<= 3 - r.volume; break; + case 1: output <<= 3 - r.volume; output |= -0x100 << (3 - r.volume); break; + case 2: output <<= 3 - r.volume; break; + case 3: output <<= r.volume; break; + } + + o.left = r.leftEnable ? output : (uint11)0; + o.right = r.rightEnable ? output : (uint11)0; +} diff --git a/higan/ws/apu/dma.cpp b/higan/ws/apu/dma.cpp new file mode 100644 index 00000000..c33c1c80 --- /dev/null +++ b/higan/ws/apu/dma.cpp @@ -0,0 +1,29 @@ +auto APU::DMA::run() -> void { + if(!r.enable) return; + + if(r.rate == 0 && ++s.clock < 768) return; // 4000hz + if(r.rate == 1 && ++s.clock < 512) return; // 6000hz + if(r.rate == 2 && ++s.clock < 256) return; //12000hz + if(r.rate == 3 && ++s.clock < 128) return; //24000hz + s.clock = 0; + + uint8 data = bus.read(s.source); + if(r.direction == 0) s.source++; + if(r.direction == 1) s.source--; + + if(r.target == 0) { + apu.channel2.r.volumeRight = data.bits(0,3); + apu.channel2.r.volumeLeft = data.bits(4,7); + } else { + apu.channel5.s.data = data; + } + + if(--s.length) return; + + if(r.loop) { + s.source = r.source; + s.length = r.length; + } else { + r.enable = false; + } +} diff --git a/higan/ws/apu/io.cpp b/higan/ws/apu/io.cpp index 14b3ea0d..2ce2890e 100644 --- a/higan/ws/apu/io.cpp +++ b/higan/ws/apu/io.cpp @@ -1,70 +1,90 @@ auto APU::portRead(uint16 addr) -> uint8 { + //SDMA_SRC + if(addr == 0x004a) return dma.s.source.bits( 0, 7); + if(addr == 0x004b) return dma.s.source.bits( 8,15); + if(addr == 0x004c) return dma.s.source.bits(16,19); + + //SDMA_LEN + if(addr == 0x004e) return dma.s.length.bits( 0, 7); + if(addr == 0x004f) return dma.s.length.bits( 8,15); + if(addr == 0x0050) return dma.s.length.bits(16,19); + + //SDMA_CTRL + if(addr == 0x0052) return ( + dma.r.rate << 0 + | dma.r.unknown << 2 + | dma.r.loop << 3 + | dma.r.target << 4 + | dma.r.direction << 6 + | dma.r.enable << 7 + ); + //SND_HYPER_CTRL if(addr == 0x006a) return ( - channel4.r.volume << 0 - | channel4.r.scale << 2 - | channel4.r.speed << 4 - | channel4.r.enable << 7 + channel5.r.volume << 0 + | channel5.r.scale << 2 + | channel5.r.speed << 4 + | channel5.r.enable << 7 ); //SND_HYPER_CHAN_CTRL if(addr == 0x006b) return ( - channel4.r.unknown << 0 - | channel4.r.leftEnable << 5 - | channel4.r.rightEnable << 6 + channel5.r.unknown << 0 + | channel5.r.leftEnable << 5 + | channel5.r.rightEnable << 6 ); - //SND_CH0_PITCH - if(addr == 0x0080) return channel0.r.pitch.bits(0, 7); - if(addr == 0x0081) return channel0.r.pitch.bits(8,11); - //SND_CH1_PITCH - if(addr == 0x0082) return channel1.r.pitch.bits(0, 7); - if(addr == 0x0083) return channel1.r.pitch.bits(8,11); + 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 == 0x0084) return channel2.r.pitch.bits(0, 7); - if(addr == 0x0085) return channel2.r.pitch.bits(8,11); + 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 == 0x0086) return channel3.r.pitch.bits(0, 7); - if(addr == 0x0087) return channel3.r.pitch.bits(8,11); + if(addr == 0x0084) return channel3.r.pitch.bits(0, 7); + if(addr == 0x0085) return channel3.r.pitch.bits(8,11); - //SND_CH0_VOL - if(addr == 0x0088) return ( - channel0.r.volumeRight << 0 - | channel0.r.volumeLeft << 4 - ); + //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 == 0x0089) return ( + if(addr == 0x0088) return ( channel1.r.volumeRight << 0 | channel1.r.volumeLeft << 4 ); //SND_CH2_VOL - if(addr == 0x008a) return ( + if(addr == 0x0089) return ( channel2.r.volumeRight << 0 | channel2.r.volumeLeft << 4 ); //SND_CH3_VOL - if(addr == 0x008b) return ( + 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 channel2.r.sweepValue; + if(addr == 0x008c) return channel3.r.sweepValue; //SND_SWEEP_TIME - if(addr == 0x008d) return channel2.r.sweepTime; + if(addr == 0x008d) return channel3.r.sweepTime; //SND_NOISE //(noiseReset [bit 3] always reads as zero) if(addr == 0x008e) return ( - channel3.r.noiseMode << 0 - | channel3.r.noiseUpdate << 4 + channel4.r.noiseMode << 0 + | channel4.r.noiseUpdate << 4 ); //SND_WAVE_BASE @@ -72,13 +92,13 @@ auto APU::portRead(uint16 addr) -> uint8 { //SND_CTRL if(addr == 0x0090) return ( - channel0.r.enable << 0 - | channel1.r.enable << 1 - | channel2.r.enable << 2 - | channel3.r.enable << 3 - | channel1.r.voice << 5 - | channel2.r.sweep << 6 - | channel3.r.noise << 7 + 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 @@ -90,114 +110,127 @@ auto APU::portRead(uint16 addr) -> uint8 { ); //SND_RANDOM - if(addr == 0x0092) return channel3.s.noiseLFSR.bits(0, 7); - if(addr == 0x0093) return channel3.s.noiseLFSR.bits(8,14); + if(addr == 0x0092) return channel4.s.noiseLFSR.bits(0, 7); + if(addr == 0x0093) return channel4.s.noiseLFSR.bits(8,14); //SND_VOICE_CTRL if(addr == 0x0094) return ( - channel1.r.voiceEnableRight << 0 - | channel1.r.voiceEnableLeft << 2 + channel2.r.voiceEnableRight << 0 + | channel2.r.voiceEnableLeft << 2 ); + //SND_HYPERVOICE + if(addr == 0x0095) return channel5.s.data; + return 0x00; } auto APU::portWrite(uint16 addr, uint8 data) -> void { + //SDMA_SRC + if(addr == 0x004a) dma.r.source.bits( 0, 7) = data.bits(0,7); + if(addr == 0x004b) dma.r.source.bits( 8,15) = data.bits(0,7); + if(addr == 0x004c) dma.r.source.bits(16,19) = data.bits(0,3); + + //SDMA_LEN + if(addr == 0x004e) dma.r.length.bits( 0, 7) = data.bits(0,7); + if(addr == 0x004f) dma.r.length.bits( 8,15) = data.bits(0,7); + if(addr == 0x0050) dma.r.length.bits(16,19) = data.bits(0,3); + + //SDMA_CTRL + if(addr == 0x0052) { + bool trigger = !dma.r.enable && data.bit(7); + dma.r.rate = data.bits(0,1); + dma.r.unknown = data.bit (2); + dma.r.loop = data.bit (3); + dma.r.target = data.bit (4); + dma.r.direction = data.bit (6); + dma.r.enable = data.bit (7); + if(trigger) { + dma.s.source = dma.r.source; + dma.s.length = dma.r.length; + } + } + //SND_HYPER_CTRL if(addr == 0x006a) { - channel4.r.volume = data.bits(0,1); - channel4.r.scale = data.bits(2,3); - channel4.r.speed = data.bits(4,6); - channel4.r.enable = data.bit (7); + channel5.r.volume = data.bits(0,1); + channel5.r.scale = data.bits(2,3); + channel5.r.speed = data.bits(4,6); + channel5.r.enable = data.bit (7); } //SND_HYPER_CHAN_CTRL if(addr == 0x006b) { - channel4.r.unknown = data.bits(0,3); - channel4.r.leftEnable = data.bit (5); - channel4.r.rightEnable = data.bit (6); + channel5.r.unknown = data.bits(0,3); + channel5.r.leftEnable = data.bit (5); + channel5.r.rightEnable = data.bit (6); } - //SND_CH0_PITCH - if(addr == 0x0080) { channel0.r.pitch.bits(0, 7) = data.bits(0,7); return; } - if(addr == 0x0081) { channel0.r.pitch.bits(8,11) = data.bits(0,3); return; } - //SND_CH1_PITCH - if(addr == 0x0082) { channel1.r.pitch.bits(0, 7) = data.bits(0,7); return; } - if(addr == 0x0083) { channel1.r.pitch.bits(8,11) = data.bits(0,3); return; } + if(addr == 0x0080) channel1.r.pitch.bits(0, 7) = data.bits(0,7); + if(addr == 0x0081) channel1.r.pitch.bits(8,11) = data.bits(0,3); //SND_CH2_PITCH - if(addr == 0x0084) { channel2.r.pitch.bits(0, 7) = data.bits(0,7); return; } - if(addr == 0x0085) { channel2.r.pitch.bits(8,11) = data.bits(0,3); return; } + if(addr == 0x0082) channel2.r.pitch.bits(0, 7) = data.bits(0,7); + if(addr == 0x0083) channel2.r.pitch.bits(8,11) = data.bits(0,3); //SND_CH3_PITCH - if(addr == 0x0086) { channel3.r.pitch.bits(0, 7) = data.bits(0,7); return; } - if(addr == 0x0087) { channel3.r.pitch.bits(8,11) = data.bits(0,3); return; } + if(addr == 0x0084) channel3.r.pitch.bits(0, 7) = data.bits(0,7); + if(addr == 0x0085) channel3.r.pitch.bits(8,11) = data.bits(0,3); - //SND_CH0_VOL - if(addr == 0x0088) { - channel0.r.volumeRight = data.bits(0,3); - channel0.r.volumeLeft = data.bits(4,7); - return; - } + //SND_CH4_PITCH + if(addr == 0x0086) channel4.r.pitch.bits(0, 7) = data.bits(0,7); + if(addr == 0x0087) channel4.r.pitch.bits(8,11) = data.bits(0,3); //SND_CH1_VOL - if(addr == 0x0089) { + if(addr == 0x0088) { channel1.r.volumeRight = data.bits(0,3); channel1.r.volumeLeft = data.bits(4,7); - return; } //SND_CH2_VOL - if(addr == 0x008a) { + if(addr == 0x0089) { channel2.r.volumeRight = data.bits(0,3); channel2.r.volumeLeft = data.bits(4,7); - return; } //SND_CH3_VOL - if(addr == 0x008b) { + 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); } //SND_SWEEP_VALUE - if(addr == 0x008c) { - channel2.r.sweepValue = data; - return; - } + if(addr == 0x008c) channel3.r.sweepValue = data; //SND_SWEEP_TIME - if(addr == 0x008d) { - channel2.r.sweepTime = data.bits(0,4); - return; - } + if(addr == 0x008d) channel3.r.sweepTime = data.bits(0,4); //SND_NOISE if(addr == 0x008e) { - channel3.r.noiseMode = data.bits(0,2); - channel3.r.noiseReset = data.bit (3); - channel3.r.noiseUpdate = data.bit (4); - return; + channel4.r.noiseMode = data.bits(0,2); + channel4.r.noiseReset = data.bit (3); + channel4.r.noiseUpdate = data.bit (4); } //SND_WAVE_BASE - if(addr == 0x008f) { - r.waveBase = data; - return; - } + if(addr == 0x008f) r.waveBase = data; //SND_CTRL if(addr == 0x0090) { - channel0.r.enable = data.bit(0); - channel1.r.enable = data.bit(1); - channel2.r.enable = data.bit(2); - channel3.r.enable = data.bit(3); - channel1.r.voice = data.bit(5); - channel2.r.sweep = data.bit(6); - channel3.r.noise = data.bit(7); - return; + 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); } //SND_OUTPUT @@ -205,13 +238,11 @@ auto APU::portWrite(uint16 addr, uint8 data) -> void { r.speakerEnable = data.bit (0); r.speakerShift = data.bits(1,2); r.headphoneEnable = data.bit (3); - return; } //SND_VOICE_CTRL if(addr == 0x0094) { - channel1.r.voiceEnableRight = data.bits(0,1); - channel1.r.voiceEnableLeft = data.bits(2,3); - return; + channel2.r.voiceEnableRight = data.bits(0,1); + channel2.r.voiceEnableLeft = data.bits(2,3); } } diff --git a/higan/ws/cartridge/cartridge.cpp b/higan/ws/cartridge/cartridge.cpp index ba6815a3..6be7d5dd 100644 --- a/higan/ws/cartridge/cartridge.cpp +++ b/higan/ws/cartridge/cartridge.cpp @@ -60,7 +60,7 @@ auto Cartridge::unload() -> void { auto Cartridge::power() -> void { eeprom.power(); - for(uint n = 0x00c0; n <= 0x00c8; n++) iomap[n] = this; + bus.map(this, 0x00c0, 0x00c8); r.bank_rom0 = 0xff; r.bank_rom1 = 0xff; diff --git a/higan/ws/cpu/cpu.cpp b/higan/ws/cpu/cpu.cpp index ec1045e2..7b90308a 100644 --- a/higan/ws/cpu/cpu.cpp +++ b/higan/ws/cpu/cpu.cpp @@ -37,27 +37,27 @@ auto CPU::write(uint20 addr, uint8 data) -> void { } auto CPU::in(uint16 port) -> uint8 { - return iomap[port]->portRead(port); + return bus.portRead(port); } auto CPU::out(uint16 port, uint8 data) -> void { - return iomap[port]->portWrite(port, data); + return bus.portWrite(port, data); } auto CPU::power() -> void { V30MZ::power(); create(CPU::Enter, 3'072'000); - iomap[0x00a0] = this; - iomap[0x00b0] = this; - iomap[0x00b2] = this; - iomap[0x00b4] = this; - iomap[0x00b5] = this; - iomap[0x00b6] = this; + bus.map(this, 0x00a0); + bus.map(this, 0x00b0); + bus.map(this, 0x00b2); + bus.map(this, 0x00b4); + bus.map(this, 0x00b5); + bus.map(this, 0x00b6); if(system.model() != Model::WonderSwan) { - for(uint p = 0x0040; p <= 0x0049; p++) iomap[p] = this; - iomap[0x0062] = this; + bus.map(this, 0x0040, 0x0049); + bus.map(this, 0x0062); } r.dmaSource = 0; diff --git a/higan/ws/memory/memory.cpp b/higan/ws/memory/memory.cpp index acb11ab2..1fed6c9b 100644 --- a/higan/ws/memory/memory.cpp +++ b/higan/ws/memory/memory.cpp @@ -2,24 +2,9 @@ namespace WonderSwan { -IO* iomap[64 * 1024] = {nullptr}; InternalRAM iram; Bus bus; -auto IO::power() -> void { - static IO unmapped; - for(auto& n : iomap) n = &unmapped; -} - -auto IO::portRead(uint16 addr) -> uint8 { -//print("[", hex(addr, 4L), "]: port unmapped\n"); - return 0x00; -} - -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; } @@ -37,6 +22,10 @@ auto InternalRAM::write(uint16 addr, uint8 data) -> void { memory[addr] = data; } +auto Bus::power() -> void { + for(auto& io : port) io = nullptr; +} + auto Bus::read(uint20 addr) -> uint8 { if(addr.bits(16,19) == 0) return iram.read(addr); if(addr.bits(16,19) == 1) return cartridge.ramRead(addr); @@ -50,4 +39,17 @@ auto Bus::write(uint20 addr, uint8 data) -> void { if(addr.bits(16,19) >= 2) return cartridge.romWrite(addr, data); } +auto Bus::map(IO* io, uint16_t lo, maybe hi) -> void { + for(uint addr = lo; addr <= (hi ? hi() : lo); addr++) port[addr] = io; +} + +auto Bus::portRead(uint16 addr) -> uint8 { + if(auto io = port[addr]) return io->portRead(addr); + return 0x00; +} + +auto Bus::portWrite(uint16 addr, uint8 data) -> void { + if(auto io = port[addr]) return io->portWrite(addr, data); +} + } diff --git a/higan/ws/memory/memory.hpp b/higan/ws/memory/memory.hpp index bc16ce87..c6997679 100644 --- a/higan/ws/memory/memory.hpp +++ b/higan/ws/memory/memory.hpp @@ -1,8 +1,6 @@ struct IO { - static auto power() -> void; - - virtual auto portRead(uint16 addr) -> uint8; - virtual auto portWrite(uint16 addr, uint8 data) -> void; + virtual auto portRead(uint16 addr) -> uint8 = 0; + virtual auto portWrite(uint16 addr, uint8 data) -> void = 0; }; struct InternalRAM { @@ -16,10 +14,18 @@ private: }; struct Bus { + auto power() -> void; + auto read(uint20 addr) -> uint8; auto write(uint20 addr, uint8 data) -> void; + + auto map(IO* io, uint16_t lo, maybe hi = nothing) -> void; + auto portRead(uint16 addr) -> uint8; + auto portWrite(uint16 addr, uint8 data) -> void; + +private: + IO* port[64 * 1024] = {nullptr}; }; -extern IO* iomap[64 * 1024]; extern InternalRAM iram; extern Bus bus; diff --git a/higan/ws/ppu/ppu.cpp b/higan/ws/ppu/ppu.cpp index 995d0a74..c5490bd3 100644 --- a/higan/ws/ppu/ppu.cpp +++ b/higan/ws/ppu/ppu.cpp @@ -15,8 +15,9 @@ auto PPU::Enter() -> void { auto PPU::main() -> void { if(status.vclk < 144) { + renderSpriteFetch(); renderSpriteDecode(); - for(uint x = 0; x < 224; x++) { + for(auto x : range(256)) { if(!system.color()) { renderMonoBack(); renderMonoScreenOne(); @@ -86,12 +87,13 @@ auto PPU::step(uint clocks) -> void { auto PPU::power() -> void { create(PPU::Enter, 3'072'000); - for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this; - for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this; - iomap[0x00a2] = this; - for(uint n = 0x00a4; n <= 0x00ab; n++) iomap[n] = this; + bus.map(this, 0x0000, 0x0017); + bus.map(this, 0x001c, 0x003f); + bus.map(this, 0x00a2); + bus.map(this, 0x00a4, 0x00ab); for(auto& n : output) n = 0; + for(auto& n : oam) n = 0; status.vclk = 0; status.hclk = 0; diff --git a/higan/ws/ppu/ppu.hpp b/higan/ws/ppu/ppu.hpp index b63cb23e..58baab0d 100644 --- a/higan/ws/ppu/ppu.hpp +++ b/higan/ws/ppu/ppu.hpp @@ -13,10 +13,12 @@ struct PPU : Thread, IO { auto portWrite(uint16 addr, uint8 data) -> void override; //render-sprite.cpp + auto renderSpriteFetch() -> void; auto renderSpriteDecode() -> void; //render-mono.cpp auto renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2; + auto renderMonoPalette(uint4 palette, uint2 index) -> uint12; auto renderMonoBack() -> void; auto renderMonoScreenOne() -> void; auto renderMonoScreenTwo() -> void; @@ -24,6 +26,7 @@ struct PPU : Thread, IO { //render-color.cpp auto renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4; + auto renderColorPalette(uint4 palette, uint4 index) -> uint12; auto renderColorBack() -> void; auto renderColorScreenOne() -> void; auto renderColorScreenTwo() -> void; @@ -31,6 +34,7 @@ struct PPU : Thread, IO { //state uint12 output[224 * 144]; + uint32 oam[128]; struct Status { uint vclk; diff --git a/higan/ws/ppu/render-color.cpp b/higan/ws/ppu/render-color.cpp index 76212836..fae8b517 100644 --- a/higan/ws/ppu/render-color.cpp +++ b/higan/ws/ppu/render-color.cpp @@ -17,6 +17,10 @@ auto PPU::renderColorFetch(uint16 offset, uint3 y, uint3 x) -> uint4 { return color; } +auto PPU::renderColorPalette(uint4 palette, uint4 index) -> uint12 { + return iram.read(0xfe00 + (palette << 5) + (index << 1), Word); +} + auto PPU::renderColorBack() -> void { uint12 color = iram.read(0xfe00 + (r.backColor << 1), Word); pixel = {Pixel::Source::Back, color}; @@ -39,8 +43,7 @@ auto PPU::renderColorScreenOne() -> void { 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}; + pixel = {Pixel::Source::ScreenOne, renderColorPalette(tile.bits(9, 12), tileColor)}; } auto PPU::renderColorScreenTwo() -> void { @@ -65,8 +68,7 @@ auto PPU::renderColorScreenTwo() -> void { 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}; + pixel = {Pixel::Source::ScreenTwo, renderColorPalette(tile.bits(9, 12), tileColor)}; } auto PPU::renderColorSprite() -> void { @@ -85,8 +87,7 @@ auto PPU::renderColorSprite() -> void { if(tileColor == 0) continue; if(!sprite.priority && pixel.source == Pixel::Source::ScreenTwo) continue; - uint12 color = iram.read(0xfe00 + (sprite.palette << 5) + (tileColor << 1), Word); - pixel = {Pixel::Source::Sprite, color}; + pixel = {Pixel::Source::Sprite, renderColorPalette(sprite.palette, tileColor)}; break; } } diff --git a/higan/ws/ppu/render-mono.cpp b/higan/ws/ppu/render-mono.cpp index f5955852..497319a1 100644 --- a/higan/ws/ppu/render-mono.cpp +++ b/higan/ws/ppu/render-mono.cpp @@ -15,6 +15,12 @@ auto PPU::renderMonoFetch(uint14 offset, uint3 y, uint3 x) -> uint2 { return color; } +auto PPU::renderMonoPalette(uint4 palette, uint2 index) -> uint12 { + uint3 paletteColor = r.palette[palette].color[index]; + uint4 poolColor = 15 - r.pool[paletteColor]; + return poolColor << 0 | poolColor << 4 | poolColor << 8; +} + auto PPU::renderMonoBack() -> void { uint4 poolColor = 15 - r.pool[r.backColor.bits(0,2)]; pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8}; @@ -37,9 +43,7 @@ auto PPU::renderMonoScreenOne() -> void { 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}; + pixel = {Pixel::Source::ScreenOne, renderMonoPalette(tile.bits(9,12), tileColor)}; } auto PPU::renderMonoScreenTwo() -> void { @@ -50,8 +54,8 @@ auto PPU::renderMonoScreenTwo() -> void { windowInside ^= r.screenTwoWindowInvert; if(r.screenTwoWindowEnable && !windowInside) return; - uint8 scrollX = status.hclk + r.scrollTwoX; uint8 scrollY = status.vclk + r.scrollTwoY; + uint8 scrollX = status.hclk + r.scrollTwoX; uint14 tilemapOffset = r.screenTwoMapBase.bits(0,2) << 11; tilemapOffset += (scrollY >> 3) << 6; @@ -64,9 +68,7 @@ auto PPU::renderMonoScreenTwo() -> void { 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}; + pixel = {Pixel::Source::ScreenTwo, renderMonoPalette(tile.bits(9,12), tileColor)}; } auto PPU::renderMonoSprite() -> void { @@ -85,9 +87,7 @@ auto PPU::renderMonoSprite() -> void { if(sprite.palette.bit(2) && tileColor == 0) continue; if(!sprite.priority && pixel.source == Pixel::Source::ScreenTwo) continue; - uint3 paletteColor = r.palette[sprite.palette].color[tileColor]; - uint4 poolColor = 15 - r.pool[paletteColor]; - pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8}; + pixel = {Pixel::Source::Sprite, renderMonoPalette(sprite.palette, tileColor)}; break; } } diff --git a/higan/ws/ppu/render-sprite.cpp b/higan/ws/ppu/render-sprite.cpp index 5c20c333..f255bbcc 100644 --- a/higan/ws/ppu/render-sprite.cpp +++ b/higan/ws/ppu/render-sprite.cpp @@ -1,3 +1,10 @@ +auto PPU::renderSpriteFetch() -> void { + uint16 spriteBase = r.spriteBase.bits(0, 4 + system.depth()) << 9; + for(auto spriteIndex : range(128)) { + oam[spriteIndex] = iram.read(spriteBase + (spriteIndex << 2), Long); + } +} + auto PPU::renderSpriteDecode() -> void { sprites.reset(); sprites.reserve(32); @@ -9,7 +16,7 @@ auto PPU::renderSpriteDecode() -> void { uint7 spriteIndex = r.spriteFirst; uint8 spriteCount = min(128, (uint)r.spriteCount); while(spriteCount--) { - uint32 attributes = iram.read(spriteBase + (spriteIndex++ << 2), Long); + uint32 attributes = oam[spriteIndex++]; Sprite sprite; sprite.x = attributes.bits(24,31); diff --git a/higan/ws/system/system.cpp b/higan/ws/system/system.cpp index f86a303b..dabfe54d 100644 --- a/higan/ws/system/system.cpp +++ b/higan/ws/system/system.cpp @@ -50,7 +50,7 @@ auto System::unload() -> void { } auto System::power() -> void { - IO::power(); + bus.power(); iram.power(); eeprom.power(); cpu.power(); @@ -59,8 +59,8 @@ auto System::power() -> void { cartridge.power(); scheduler.power(); - iomap[0x0060] = this; - for(uint n = 0x00ba; n <= 0x00be; n++) iomap[n] = this; + bus.map(this, 0x0060); + bus.map(this, 0x00ba, 0x00be); r.depth = 0; r.color = 0;