diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index c143f4c1..6e403b74 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.30"; + static const string Version = "097.31"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/sfc/GNUmakefile b/higan/sfc/GNUmakefile index 4aa55e3e..ef037d72 100644 --- a/higan/sfc/GNUmakefile +++ b/higan/sfc/GNUmakefile @@ -3,7 +3,8 @@ processors += r65816 spc700 arm gsu hg51b upd96050 objects += sfc-interface sfc-system sfc-scheduler sfc-controller objects += sfc-cartridge sfc-cheat objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu -objects += sfc-satellaview sfc-superdisc sfc-eboot +objects += sfc-satellaview sfc-superdisc +objects += sfc-21fx objects += sfc-icd2 sfc-mcc sfc-nss sfc-event objects += sfc-sa1 sfc-superfx objects += sfc-armdsp sfc-hitachidsp sfc-necdsp @@ -48,7 +49,7 @@ obj/sfc-ppu.o: sfc/$(sfcppu)/ppu.cpp $(call rwildcard,sfc/$(sfcppu)/) obj/sfc-satellaview.o: sfc/expansion/satellaview/satellaview.cpp $(call rwildcard,sfc/expansion/satellaview/) obj/sfc-superdisc.o: sfc/expansion/superdisc/superdisc.cpp $(call rwildcard,sfc/expansion/superdisc/) -obj/sfc-eboot.o: sfc/expansion/eboot/eboot.cpp $(call rwildcard,sfc/expansion/eboot/) +obj/sfc-21fx.o: sfc/expansion/21fx/21fx.cpp $(call rwildcard,sfc/expansion/21fx/) obj/sfc-icd2.o: sfc/coprocessor/icd2/icd2.cpp $(call rwildcard,sfc/coprocessor/icd2/) obj/sfc-mcc.o: sfc/coprocessor/mcc/mcc.cpp $(call rwildcard,sfc/coprocessor/mcc/) diff --git a/higan/sfc/dsp/brr.cpp b/higan/sfc/dsp/brr.cpp index 71dd0901..710d10f3 100644 --- a/higan/sfc/dsp/brr.cpp +++ b/higan/sfc/dsp/brr.cpp @@ -1,15 +1,15 @@ auto DSP::brrDecode(Voice& v) -> void { //state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle - signed nybbles = (state._brrByte << 8) + smp.apuram[(uint16)(v.brrAddress + v.brrOffset + 1)]; + int nybbles = (state._brrByte << 8) + smp.apuram[(uint16)(v.brrAddress + v.brrOffset + 1)]; - const signed filter = (state._brrHeader >> 2) & 3; - const signed scale = (state._brrHeader >> 4); + const int filter = (state._brrHeader >> 2) & 3; + const int scale = (state._brrHeader >> 4); //decode four samples for(auto n : range(4)) { //bits 12-15 = current nybble; sign extend, then shift right to 4-bit precision //result: s = 4-bit sign-extended sample value - signed s = (int16)nybbles >> 12; + int s = (int16)nybbles >> 12; nybbles <<= 4; //slide nybble so that on next loop iteration, bits 12-15 = current nybble if(scale <= 12) { @@ -20,8 +20,8 @@ auto DSP::brrDecode(Voice& v) -> void { } //apply IIR filter (2 is the most commonly used) - const signed p1 = v.buffer[v.bufferOffset - 1]; - const signed p2 = v.buffer[v.bufferOffset - 2] >> 1; + const int p1 = v.buffer[v.bufferOffset - 1]; + const int p2 = v.buffer[v.bufferOffset - 2] >> 1; switch(filter) { case 0: diff --git a/higan/sfc/dsp/counter.cpp b/higan/sfc/dsp/counter.cpp index 42edcbe0..4a2a7537 100644 --- a/higan/sfc/dsp/counter.cpp +++ b/higan/sfc/dsp/counter.cpp @@ -42,7 +42,7 @@ inline auto DSP::counterTick() -> void { //return true if counter event should trigger -inline auto DSP::counterPoll(unsigned rate) -> bool { +inline auto DSP::counterPoll(uint rate) -> bool { if(rate == 0) return false; - return (((unsigned)state.counter + CounterOffset[rate]) % CounterRate[rate]) == 0; + return (((uint)state.counter + CounterOffset[rate]) % CounterRate[rate]) == 0; } diff --git a/higan/sfc/dsp/echo.cpp b/higan/sfc/dsp/echo.cpp index 51ce14ba..8630edfc 100644 --- a/higan/sfc/dsp/echo.cpp +++ b/higan/sfc/dsp/echo.cpp @@ -1,26 +1,26 @@ -auto DSP::calculateFIR(signed i, bool channel) -> signed { - signed s = state.echoHistory[channel][state.echoHistoryOffset + i + 1]; +auto DSP::calculateFIR(int i, bool channel) -> int { + int s = state.echoHistory[channel][state.echoHistoryOffset + i + 1]; return (s * (int8)REG(FIR + i * 0x10)) >> 6; } -auto DSP::echoOutput(bool channel) -> signed { - signed output = (int16)((state._mainOut[channel] * (int8)REG(MVOLL + channel * 0x10)) >> 7) +auto DSP::echoOutput(bool channel) -> int { + int output = (int16)((state._mainOut[channel] * (int8)REG(MVOLL + channel * 0x10)) >> 7) + (int16)((state._echoIn [channel] * (int8)REG(EVOLL + channel * 0x10)) >> 7); return sclamp<16>(output); } auto DSP::echoRead(bool channel) -> void { - unsigned addr = state._echoPointer + channel * 2; + uint addr = state._echoPointer + channel * 2; uint8 lo = smp.apuram[(uint16)(addr + 0)]; uint8 hi = smp.apuram[(uint16)(addr + 1)]; - signed s = (int16)((hi << 8) + lo); + int s = (int16)((hi << 8) + lo); state.echoHistory[channel].write(state.echoHistoryOffset, s >> 1); } auto DSP::echoWrite(bool channel) -> void { if(!(state._echoDisabled & 0x20)) { - unsigned addr = state._echoPointer + channel * 2; - signed s = state._echoOut[channel]; + uint addr = state._echoPointer + channel * 2; + int s = state._echoOut[channel]; smp.apuram[(uint16)(addr + 0)] = s; smp.apuram[(uint16)(addr + 1)] = s >> 8; } @@ -37,16 +37,16 @@ auto DSP::echo22() -> void { echoRead(0); //FIR - signed l = calculateFIR(0, 0); - signed r = calculateFIR(0, 1); + int l = calculateFIR(0, 0); + int r = calculateFIR(0, 1); state._echoIn[0] = l; state._echoIn[1] = r; } auto DSP::echo23() -> void { - signed l = calculateFIR(1, 0) + calculateFIR(2, 0); - signed r = calculateFIR(1, 1) + calculateFIR(2, 1); + int l = calculateFIR(1, 0) + calculateFIR(2, 0); + int r = calculateFIR(1, 1) + calculateFIR(2, 1); state._echoIn[0] += l; state._echoIn[1] += r; @@ -55,16 +55,16 @@ auto DSP::echo23() -> void { } auto DSP::echo24() -> void { - signed l = calculateFIR(3, 0) + calculateFIR(4, 0) + calculateFIR(5, 0); - signed r = calculateFIR(3, 1) + calculateFIR(4, 1) + calculateFIR(5, 1); + int l = calculateFIR(3, 0) + calculateFIR(4, 0) + calculateFIR(5, 0); + int r = calculateFIR(3, 1) + calculateFIR(4, 1) + calculateFIR(5, 1); state._echoIn[0] += l; state._echoIn[1] += r; } auto DSP::echo25() -> void { - signed l = state._echoIn[0] + calculateFIR(6, 0); - signed r = state._echoIn[1] + calculateFIR(6, 1); + int l = state._echoIn[0] + calculateFIR(6, 0); + int r = state._echoIn[1] + calculateFIR(6, 1); l = (int16)l; r = (int16)r; @@ -82,8 +82,8 @@ auto DSP::echo26() -> void { state._mainOut[0] = echoOutput(0); //echo feedback - signed l = state._echoOut[0] + (int16)((state._echoIn[0] * (int8)REG(EFB)) >> 7); - signed r = state._echoOut[1] + (int16)((state._echoIn[1] * (int8)REG(EFB)) >> 7); + int l = state._echoOut[0] + (int16)((state._echoIn[0] * (int8)REG(EFB)) >> 7); + int r = state._echoOut[1] + (int16)((state._echoIn[1] * (int8)REG(EFB)) >> 7); state._echoOut[0] = sclamp<16>(l) & ~1; state._echoOut[1] = sclamp<16>(r) & ~1; @@ -91,12 +91,12 @@ auto DSP::echo26() -> void { auto DSP::echo27() -> void { //output - signed outl = state._mainOut[0]; - signed outr = echoOutput(1); + int outl = state._mainOut[0]; + int outr = echoOutput(1); state._mainOut[0] = 0; state._mainOut[1] = 0; - //TODO: global muting isn't this simple + //todo: global muting isn't this simple //(turns DAC on and off or something, causing small ~37-sample pulse when first muted) if(REG(FLG) & 0x40) { outl = 0; diff --git a/higan/sfc/dsp/envelope.cpp b/higan/sfc/dsp/envelope.cpp index 81a10533..67f615ab 100644 --- a/higan/sfc/dsp/envelope.cpp +++ b/higan/sfc/dsp/envelope.cpp @@ -1,5 +1,5 @@ auto DSP::envelopeRun(Voice& v) -> void { - signed envelope = v.envelope; + int envelope = v.envelope; if(v.envelopeMode == EnvelopeRelease) { //60% envelope -= 0x8; @@ -8,8 +8,8 @@ auto DSP::envelopeRun(Voice& v) -> void { return; } - signed rate; - signed envelopeData = VREG(ADSR1); + int rate; + int envelopeData = VREG(ADSR1); if(state._adsr0 & 0x80) { //99% ADSR if(v.envelopeMode >= EnvelopeDecay) { //99% envelope--; @@ -24,7 +24,7 @@ auto DSP::envelopeRun(Voice& v) -> void { } } else { //GAIN envelopeData = VREG(GAIN); - signed mode = envelopeData >> 5; + int mode = envelopeData >> 5; if(mode < 4) { //direct envelope = envelopeData << 4; rate = 31; @@ -37,7 +37,7 @@ auto DSP::envelopeRun(Voice& v) -> void { envelope -= envelope >> 8; } else { //6, 7: linear increase envelope += 0x20; - if(mode > 6 && (unsigned)v.hiddenEnvelope >= 0x600) { + if(mode > 6 && (uint)v.hiddenEnvelope >= 0x600) { envelope += 0x8 - 0x20; //7: two-slope linear increase } } @@ -48,8 +48,8 @@ auto DSP::envelopeRun(Voice& v) -> void { if((envelope >> 8) == (envelopeData >> 5) && v.envelopeMode == EnvelopeDecay) v.envelopeMode = EnvelopeSustain; v.hiddenEnvelope = envelope; - //unsigned cast because linear decrease underflowing also triggers this - if((unsigned)envelope > 0x7ff) { + //uint cast because linear decrease underflowing also triggers this + if((uint)envelope > 0x7ff) { envelope = (envelope < 0 ? 0 : 0x7ff); if(v.envelopeMode == EnvelopeAttack) v.envelopeMode = EnvelopeDecay; } diff --git a/higan/sfc/dsp/gaussian.cpp b/higan/sfc/dsp/gaussian.cpp index 55f0a6a3..8bc0873c 100644 --- a/higan/sfc/dsp/gaussian.cpp +++ b/higan/sfc/dsp/gaussian.cpp @@ -33,14 +33,14 @@ const int16 DSP::GaussianTable[512] = { 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305, }; -auto DSP::gaussianInterpolate(const Voice& v) -> signed { +auto DSP::gaussianInterpolate(const Voice& v) -> int { //make pointers into gaussian table based on fractional position between samples - signed offset = (v.gaussianOffset >> 4) & 0xff; + int offset = (v.gaussianOffset >> 4) & 0xff; const int16* forward = GaussianTable + 255 - offset; const int16* reverse = GaussianTable + offset; //mirror left half of gaussian table offset = v.bufferOffset + (v.gaussianOffset >> 12); - signed output; + int output; output = (forward[ 0] * v.buffer[offset + 0]) >> 11; output += (forward[256] * v.buffer[offset + 1]) >> 11; output += (reverse[256] * v.buffer[offset + 2]) >> 11; diff --git a/higan/sfc/dsp/misc.cpp b/higan/sfc/dsp/misc.cpp index d96c00ec..31434815 100644 --- a/higan/sfc/dsp/misc.cpp +++ b/higan/sfc/dsp/misc.cpp @@ -25,7 +25,7 @@ auto DSP::misc30() -> void { //noise if(counterPoll(REG(FLG) & 0x1f)) { - signed feedback = (state.noise << 13) ^ (state.noise << 14); + int feedback = (state.noise << 13) ^ (state.noise << 14); state.noise = (feedback & 0x4000) ^ (state.noise >> 1); } } diff --git a/higan/sfc/dsp/modulo-array.hpp b/higan/sfc/dsp/modulo-array.hpp index c03de4dd..85e8b1b8 100644 --- a/higan/sfc/dsp/modulo-array.hpp +++ b/higan/sfc/dsp/modulo-array.hpp @@ -1,14 +1,14 @@ -template +template struct ModuloArray { - inline auto operator[](signed index) const -> T { + inline auto operator[](int index) const -> T { return buffer[size + index]; } - inline auto read(signed index) const -> T { + inline auto read(int index) const -> T { return buffer[size + index]; } - inline auto write(unsigned index, const T value) -> void { + inline auto write(uint index, const T value) -> void { buffer[index] = buffer[index + size] = buffer[index + size + size] = value; diff --git a/higan/sfc/dsp/voice.cpp b/higan/sfc/dsp/voice.cpp index 3dbe2cd4..baa9abdd 100644 --- a/higan/sfc/dsp/voice.cpp +++ b/higan/sfc/dsp/voice.cpp @@ -1,6 +1,6 @@ inline auto DSP::voiceOutput(Voice& v, bool channel) -> void { //apply left/right volume - signed amp = (state._output * (int8)VREG(VOLL + channel)) >> 7; + int amp = (state._output * (int8)VREG(VOLL + channel)) >> 7; //add to output total state._mainOut[channel] += amp; @@ -77,7 +77,7 @@ auto DSP::voice3c(Voice& v) -> void { } //gaussian interpolation - signed output = gaussianInterpolate(v); + int output = gaussianInterpolate(v); //noise if(state._non & v.vbit) { diff --git a/higan/sfc/expansion/21fx/21fx.cpp b/higan/sfc/expansion/21fx/21fx.cpp new file mode 100644 index 00000000..aed5f56e --- /dev/null +++ b/higan/sfc/expansion/21fx/21fx.cpp @@ -0,0 +1,143 @@ +#include + +namespace SuperFamicom { + +S21FX s21fx; + +auto S21FX::Enter() -> void { + while(true) scheduler.synchronize(), s21fx.main(); +} + +auto S21FX::main() -> void { + if(linkInit) linkInit( + {&S21FX::quit, this}, + {&S21FX::usleep, this}, + {&S21FX::readable, this}, + {&S21FX::writable, this}, + {&S21FX::read, this}, + {&S21FX::write, this} + ); + if(linkMain) linkMain({}); + while(true) step(10'000'000); +} + +auto S21FX::step(uint clocks) -> void { + clock += clocks * (uint64)cpu.frequency; + if(CPU::Threaded) { + if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.main(); + } +} + +auto S21FX::init() -> void { +} + +auto S21FX::load() -> void { + resetVector.byte(0) = bus.read(0xfffc, 0x00); + resetVector.byte(1) = bus.read(0xfffd, 0x00); + + for(auto& byte : ram) byte = 0xdb; //stp + ram[0] = 0x6c; //jmp ($fffc) + ram[1] = 0xfc; + ram[2] = 0xff; + + bus.map({&S21FX::read, &s21fx}, {&S21FX::write, &s21fx}, 0x00, 0x00, 0xfffc, 0xfffd); + bus.map({&S21FX::read, &s21fx}, {&S21FX::write, &s21fx}, 0x00, 0x3f, 0x2184, 0x21ff); + bus.map({&S21FX::read, &s21fx}, {&S21FX::write, &s21fx}, 0x80, 0xbf, 0x2184, 0x21ff); + + if(auto buffer = file::read({interface->path(ID::System), "21fx.rom"})) { + memory::copy(ram, sizeof(ram), buffer.data(), buffer.size()); + } + + string filename{interface->path(ID::SuperFamicom), "21fx.so"}; + if(link.openAbsolute(filename)) { + linkInit = link.sym("fx_init"); + linkMain = link.sym("fx_main"); + } +} + +auto S21FX::unload() -> void { + if(link.open()) link.close(); + linkInit.reset(); + linkMain.reset(); +} + +auto S21FX::power() -> void { +} + +auto S21FX::reset() -> void { + create(S21FX::Enter, 10'000'000); + booted = false; +} + +auto S21FX::read(uint24 addr, uint8 data) -> uint8 { + addr &= 0x40ffff; + + if(addr == 0xfffc) return booted ? resetVector.byte(0) : (uint8)0x84; + if(addr == 0xfffd) return booted ? resetVector.byte(1) : (booted = true, (uint8)0x21); + + if(addr >= 0x2184 && addr <= 0x21fd) return ram[addr - 0x2184]; + + if(addr == 0x21fe) return ( + (linkBuffer.size() > 0) << 7 //1 = readable + | (snesBuffer.size() < 65536) << 6 //1 = writable + | (link.open()) << 5 //1 = connected + ); + + if(addr == 0x21ff) { + if(linkBuffer.size() > 0) { + data = linkBuffer.takeFirst(); + } + } + + return data; +} + +auto S21FX::write(uint24 addr, uint8 data) -> void { + addr &= 0x40ffff; + + if(addr == 0x21ff) { + if(snesBuffer.size() < 65536) { + snesBuffer.append(data); + } + } +} + +auto S21FX::quit() -> bool { + step(1); + return false; +} + +auto S21FX::usleep(uint microseconds) -> void { + step(10 * microseconds); +} + +auto S21FX::readable() -> bool { + step(1); + return snesBuffer.size() > 0; +} + +auto S21FX::writable() -> bool { + step(1); + return linkBuffer.size() < 65536; +} + +//SNES -> Link +auto S21FX::read() -> uint8 { + step(1); + if(snesBuffer.size() > 0) { + return snesBuffer.takeFirst(); + } + return 0x00; +} + +//Link -> SNES +auto S21FX::write(uint8 data) -> void { + step(1); + if(linkBuffer.size() < 65536) { + linkBuffer.append(data); + } +} + +} diff --git a/higan/sfc/expansion/21fx/21fx.hpp b/higan/sfc/expansion/21fx/21fx.hpp new file mode 100644 index 00000000..a71308e9 --- /dev/null +++ b/higan/sfc/expansion/21fx/21fx.hpp @@ -0,0 +1,41 @@ +struct S21FX : Thread, Memory { + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + auto init() -> void; + auto load() -> void; + auto unload() -> void; + auto power() -> void; + auto reset() -> void; + + auto read(uint24 addr, uint8 data) -> uint8; + auto write(uint24 addr, uint8 data) -> void; + +private: + auto quit() -> bool; + auto usleep(uint) -> void; + auto readable() -> bool; + auto writable() -> bool; + auto read() -> uint8; + auto write(uint8) -> void; + + bool booted = false; + uint16 resetVector; + uint8 ram[122]; + + nall::library link; + function, //quit + function, //usleep + function, //readable + function, //writable + function, //read + function //write + )> linkInit; + function linkMain; + + vector snesBuffer; //SNES -> Link + vector linkBuffer; //Link -> SNES +}; + +extern S21FX s21fx; diff --git a/higan/sfc/expansion/eboot/eboot.cpp b/higan/sfc/expansion/eboot/eboot.cpp deleted file mode 100644 index 237d147b..00000000 --- a/higan/sfc/expansion/eboot/eboot.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -namespace SuperFamicom { - -eBoot eboot; - -auto eBoot::init() -> void { -} - -auto eBoot::load() -> void { - resetVector.byte(0) = bus.read(0xfffc, 0x00); - resetVector.byte(1) = bus.read(0xfffd, 0x00); - - for(auto& byte : ram) byte = 0xdb; //stp - ram[0] = 0x6c; //jmp ($fffc) - ram[1] = 0xfc; - ram[2] = 0xff; - - bus.map({&eBoot::read, &eboot}, {&eBoot::write, &eboot}, 0x00, 0x00, 0xfffc, 0xfffd); - bus.map({&eBoot::read, &eboot}, {&eBoot::write, &eboot}, 0x00, 0x3f, 0x2184, 0x21ff); - bus.map({&eBoot::read, &eboot}, {&eBoot::write, &eboot}, 0x80, 0xbf, 0x2184, 0x21ff); - - if(auto buffer = file::read({interface->path(ID::System), "eboot.rom"})) { - memory::copy(ram, sizeof(ram), buffer.data(), buffer.size()); - } -} - -auto eBoot::unload() -> void { -} - -auto eBoot::power() -> void { -} - -auto eBoot::reset() -> void { - booted = false; -} - -auto eBoot::read(uint24 addr, uint8 data) -> uint8 { - addr &= 0x40ffff; - if(addr == 0xfffc) return booted ? resetVector.byte(0) : (uint8)0x84; - if(addr == 0xfffd) return booted ? resetVector.byte(1) : (booted = true, (uint8)0x21); - if(addr >= 0x2184 && addr <= 0x21ff) return ram[addr - 0x2184]; - return data; -} - -auto eBoot::write(uint24 addr, uint8 data) -> void { -} - -} diff --git a/higan/sfc/expansion/eboot/eboot.hpp b/higan/sfc/expansion/eboot/eboot.hpp deleted file mode 100644 index c7254131..00000000 --- a/higan/sfc/expansion/eboot/eboot.hpp +++ /dev/null @@ -1,17 +0,0 @@ -struct eBoot : Memory { - auto init() -> void; - auto load() -> void; - auto unload() -> void; - auto power() -> void; - auto reset() -> void; - - auto read(uint24 addr, uint8 data) -> uint8; - auto write(uint24 addr, uint8 data) -> void; - -private: - bool booted = false; - uint16 resetVector; - uint8 ram[124]; -}; - -extern eBoot eboot; diff --git a/higan/sfc/expansion/expansion.hpp b/higan/sfc/expansion/expansion.hpp index f5bd1714..9f42ca4e 100644 --- a/higan/sfc/expansion/expansion.hpp +++ b/higan/sfc/expansion/expansion.hpp @@ -1,3 +1,3 @@ #include #include -#include +#include diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index bf1190f3..60d6039f 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -121,7 +121,7 @@ Interface::Interface() { this->device.append(device); } - { Device device{10, ID::ExpansionPort, "eBoot"}; + { Device device{10, ID::ExpansionPort, "21fx"}; this->device.append(device); } diff --git a/higan/sfc/system/device.hpp b/higan/sfc/system/device.hpp index ef69c8ab..b8289e3d 100644 --- a/higan/sfc/system/device.hpp +++ b/higan/sfc/system/device.hpp @@ -20,7 +20,7 @@ struct Device { //expansion port devices Satellaview, SuperDisc, - eBoot, + S21FX, }; Device(); diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 452e1c82..ccfc6cff 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -33,7 +33,7 @@ auto System::init() -> void { satellaview.init(); superdisc.init(); - eboot.init(); + s21fx.init(); icd2.init(); mcc.init(); @@ -83,7 +83,7 @@ auto System::load() -> void { if(expansionPort() == Device::ID::Satellaview) satellaview.load(); if(expansionPort() == Device::ID::SuperDisc) superdisc.load(); - if(expansionPort() == Device::ID::eBoot) eboot.load(); + if(expansionPort() == Device::ID::S21FX) s21fx.load(); if(cartridge.hasICD2()) icd2.load(); if(cartridge.hasMCC()) mcc.load(); @@ -112,7 +112,7 @@ auto System::unload() -> void { if(!loaded()) return; if(expansionPort() == Device::ID::Satellaview) satellaview.unload(); if(expansionPort() == Device::ID::SuperDisc) superdisc.unload(); - if(expansionPort() == Device::ID::eBoot) eboot.unload(); + if(expansionPort() == Device::ID::S21FX) s21fx.unload(); if(cartridge.hasICD2()) icd2.unload(); if(cartridge.hasMCC()) mcc.unload(); @@ -147,7 +147,7 @@ auto System::power() -> void { if(expansionPort() == Device::ID::Satellaview) satellaview.power(); if(expansionPort() == Device::ID::SuperDisc) superdisc.power(); - if(expansionPort() == Device::ID::eBoot) eboot.power(); + if(expansionPort() == Device::ID::S21FX) s21fx.power(); if(cartridge.hasICD2()) icd2.power(); if(cartridge.hasMCC()) mcc.power(); @@ -178,7 +178,7 @@ auto System::reset() -> void { if(expansionPort() == Device::ID::Satellaview) satellaview.reset(); if(expansionPort() == Device::ID::SuperDisc) superdisc.reset(); - if(expansionPort() == Device::ID::eBoot) eboot.reset(); + if(expansionPort() == Device::ID::S21FX) s21fx.reset(); if(cartridge.hasICD2()) icd2.reset(); if(cartridge.hasMCC()) mcc.reset(); @@ -210,6 +210,7 @@ auto System::reset() -> void { if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110); if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1); if(expansionPort() == Device::ID::SuperDisc) cpu.coprocessors.append(&superdisc); + if(expansionPort() == Device::ID::S21FX) cpu.coprocessors.append(&s21fx); scheduler.reset(); device.connect(0, (Device::ID)settings.controllerPort1); diff --git a/higan/ws/cpu/interrupt.cpp b/higan/ws/cpu/interrupt.cpp index f888452d..5b0c91b7 100644 --- a/higan/ws/cpu/interrupt.cpp +++ b/higan/ws/cpu/interrupt.cpp @@ -11,6 +11,7 @@ auto CPU::poll() -> void { } auto CPU::raise(Interrupt irq) -> void { + if(!r.interruptEnable.bit((uint)irq)) return; r.interruptStatus.bit((uint)irq) = 1; } diff --git a/higan/ws/cpu/io.cpp b/higan/ws/cpu/io.cpp index d9500b98..ee9a199a 100644 --- a/higan/ws/cpu/io.cpp +++ b/higan/ws/cpu/io.cpp @@ -50,18 +50,17 @@ auto CPU::portRead(uint16 addr) -> uint8 { if(addr == 0x00a0) { bool model = system.model() != Model::WonderSwan; return ( - 1 << 7 //1 = built-in self-test passed - | 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width + 1 << 0 //0 = BIOS mapped; 1 = cartridge mapped | model << 1 //0 = WonderSwan; 1 = WonderSwan Color or SwanCrystal - | 1 << 0 //0 = BIOS mapped; 1 = cartridge mapped + | 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width + | 1 << 7 //1 = built-in self-test passed ); } //INT_BASE - if(addr == 0x00b0) { - if(system.model() == Model::WonderSwan) return r.interruptBase | 3; - return r.interruptBase; - } + if(addr == 0x00b0) return ( + r.interruptBase | (system.model() == Model::WonderSwan ? 3 : 0) + ); //SER_DATA if(addr == 0x00b1) return r.serialData; @@ -92,42 +91,38 @@ auto CPU::portRead(uint16 addr) -> uint8 { auto CPU::portWrite(uint16 addr, uint8 data) -> void { //DMA_SRC - if(addr == 0x0040) { r.dmaSource.byte(0) = data & ~1; return; } - if(addr == 0x0041) { r.dmaSource.byte(1) = data; return; } - if(addr == 0x0042) { r.dmaSource.byte(2) = data; return; } + if(addr == 0x0040) r.dmaSource.byte(0) = data & ~1; + if(addr == 0x0041) r.dmaSource.byte(1) = data; + if(addr == 0x0042) r.dmaSource.byte(2) = data; //DMA_DST - if(addr == 0x0044) { r.dmaTarget.byte(0) = data & ~1; return; } - if(addr == 0x0045) { r.dmaTarget.byte(1) = data; return; } + if(addr == 0x0044) r.dmaTarget.byte(0) = data & ~1; + if(addr == 0x0045) r.dmaTarget.byte(1) = data; //DMA_LEN - if(addr == 0x0046) { r.dmaLength.byte(0) = data & ~1; return; } - if(addr == 0x0047) { r.dmaLength.byte(1) = data; return; } + if(addr == 0x0046) r.dmaLength.byte(0) = data & ~1; + if(addr == 0x0047) r.dmaLength.byte(1) = data; //DMA_CTRL if(addr == 0x0048) { - r.dmaEnable = data.bit(7); r.dmaMode = data.bit(0); + r.dmaEnable = data.bit(7); if(r.dmaEnable) dmaTransfer(); - return; } //WSC_SYSTEM if(addr == 0x0062) { //todo: d0 = 1 powers off system - return; } //HW_FLAGS if(addr == 0x00a0) { //todo: d2 (bus width) bit is writable; but ... it will do very bad things - return; } //INT_BASE if(addr == 0x00b0) { r.interruptBase = (system.model() == Model::WonderSwan) ? data & ~7 : data & ~1; - return; } //SER_DATA @@ -136,7 +131,7 @@ auto CPU::portWrite(uint16 addr, uint8 data) -> void { //INT_ENABLE if(addr == 0x00b2) { r.interruptEnable = data; - return; + r.interruptStatus &= ~r.interruptEnable; } //SER_STATUS @@ -156,6 +151,5 @@ auto CPU::portWrite(uint16 addr, uint8 data) -> void { if(addr == 0x00b6) { //acknowledge only edge-sensitive interrupts r.interruptStatus &= ~(data & 0b11110010); - return; } } diff --git a/higan/ws/ppu/latch.cpp b/higan/ws/ppu/latch.cpp index f75ee7c0..f47f48a0 100644 --- a/higan/ws/ppu/latch.cpp +++ b/higan/ws/ppu/latch.cpp @@ -28,25 +28,10 @@ auto PPU::latchRegisters() -> void { auto PPU::latchSprites() -> void { l.spriteCount = 0; if(!l.spriteEnable) return; - - uint offset = 0; - bool windowInside = s.vclk >= l.spriteWindowY0 && s.vclk <= l.spriteWindowY1; for(auto index : range(l.oamCount)) { uint32 attributes = l.oam[!s.field][index]; - - auto& sprite = l.sprite[l.spriteCount]; - sprite.x = attributes.bits(24,31); - if(sprite.x > 224 && sprite.x < 249) continue; - sprite.y = attributes.bits(16,23); - if((uint8)(s.vclk - sprite.y) > 7) continue; - sprite.vflip = attributes.bit(15); - sprite.hflip = attributes.bit(14); - sprite.priority = attributes.bit(13); - sprite.window = attributes.bit(12); - if(l.spriteWindowEnable && !sprite.window && !windowInside) continue; - sprite.palette = 8 + attributes.bits(9,11); - sprite.tile = attributes.bits(0,8); - + if((uint8)(s.vclk - attributes.bits(16,23)) > 7) continue; + l.sprite[l.spriteCount] = attributes; if(++l.spriteCount >= 32) break; } } diff --git a/higan/ws/ppu/ppu.hpp b/higan/ws/ppu/ppu.hpp index f8c2bd47..1c7f311b 100644 --- a/higan/ws/ppu/ppu.hpp +++ b/higan/ws/ppu/ppu.hpp @@ -36,17 +36,6 @@ struct PPU : Thread, IO { uint12 color; }; - struct Sprite { - uint8 x; - uint8 y; - uint1 vflip; - uint1 hflip; - uint1 priority; - uint1 window; - uint4 palette; //latchSprites() always sets bit3 - uint9 tile; - }; - uint12 output[224 * 144]; struct State { @@ -84,7 +73,7 @@ struct PPU : Thread, IO { uint8 spriteWindowY1; //latchSprites() - Sprite sprite[32]; + uint32 sprite[32]; uint spriteCount; //latchOAM() diff --git a/higan/ws/ppu/render.cpp b/higan/ws/ppu/render.cpp index 977ec3e9..782bcc51 100644 --- a/higan/ws/ppu/render.cpp +++ b/higan/ws/ppu/render.cpp @@ -96,19 +96,20 @@ auto PPU::renderScreenTwo() -> void { } auto PPU::renderSprite() -> void { - bool windowInside = s.hclk >= l.spriteWindowX0 && s.hclk <= l.spriteWindowY0; + bool windowInside = s.vclk >= l.spriteWindowY0 && s.vclk <= l.spriteWindowY1 + && s.hclk >= l.spriteWindowX0 && s.hclk <= l.spriteWindowX1; for(auto index : range(l.spriteCount)) { - auto& sprite = l.sprite[index]; - if(l.spriteWindowEnable && !sprite.window && !windowInside) continue; - if((uint8)(s.hclk - sprite.x) > 7) continue; + auto sprite = l.sprite[index]; + if(l.spriteWindowEnable && sprite.bit(12) == windowInside) continue; + if((uint8)(s.hclk - sprite.bits(24,31)) > 7) continue; - uint3 tileY = (s.vclk - sprite.y) ^ sprite.vflip * 7; - uint3 tileX = (s.hclk - sprite.x) ^ sprite.hflip * 7; - uint4 tileColor = renderFetch(sprite.tile, tileY, tileX); - if(renderTransparent(sprite.palette.bit(2), tileColor)) continue; - if(!sprite.priority && s.pixel.source == Pixel::Source::ScreenTwo) continue; + uint3 tileY = (s.vclk - sprite.bits(16,23)) ^ sprite.bit(15) * 7; + uint3 tileX = (s.hclk - sprite.bits(24,31)) ^ sprite.bit(14) * 7; + uint4 tileColor = renderFetch(sprite.bits(0,8), tileY, tileX); + if(renderTransparent(sprite.bit(11), tileColor)) continue; + if(!sprite.bit(13) && s.pixel.source == Pixel::Source::ScreenTwo) continue; - s.pixel = {Pixel::Source::Sprite, renderPalette(sprite.palette, tileColor)}; + s.pixel = {Pixel::Source::Sprite, renderPalette(8 + sprite.bits(9,11), tileColor)}; break; } } diff --git a/higan/ws/ppu/serialization.cpp b/higan/ws/ppu/serialization.cpp index 33ea78c0..e0f682c3 100644 --- a/higan/ws/ppu/serialization.cpp +++ b/higan/ws/ppu/serialization.cpp @@ -29,21 +29,10 @@ auto PPU::serialize(serializer& s) -> void { s.integer(l.spriteWindowX1); s.integer(l.spriteWindowY1); - for(uint n : range(32)) { - s.integer(l.sprite[n].x); - s.integer(l.sprite[n].y); - s.integer(l.sprite[n].vflip); - s.integer(l.sprite[n].hflip); - s.integer(l.sprite[n].priority); - s.integer(l.sprite[n].window); - s.integer(l.sprite[n].palette); - s.integer(l.sprite[n].tile); - } + s.array(l.sprite); s.integer(l.spriteCount); - for(uint n : range(2)) { - s.array(l.oam[n]); - } + for(uint n : range(2)) s.array(l.oam[n]); s.integer(l.oamCount); s.integer(r.screenOneEnable); @@ -83,9 +72,7 @@ auto PPU::serialize(serializer& s) -> void { s.integer(r.vtotal); s.integer(r.vblank); s.array(r.pool); - for(uint n : range(16)) { - s.array(r.palette[n].color); - } + for(uint n : range(16)) s.array(r.palette[n].color); s.integer(r.htimerEnable); s.integer(r.htimerRepeat); s.integer(r.vtimerEnable);