diff --git a/higan/GNUmakefile b/higan/GNUmakefile index 020c149c..f1d549e8 100644 --- a/higan/GNUmakefile +++ b/higan/GNUmakefile @@ -5,7 +5,7 @@ target := tomoko # console := true flags += -I. -I.. -O3 -objects := libco emulator audio video +objects := libco audio video # profile-guided optimization mode # pgo := instrument @@ -54,7 +54,6 @@ compile = \ all: build; obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/) -obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator/) obj/audio.o: audio/audio.cpp $(call rwildcard,audio/) obj/video.o: video/video.cpp $(call rwildcard,video/) diff --git a/higan/audio/audio.cpp b/higan/audio/audio.cpp index d0c691fb..d0a0cd92 100644 --- a/higan/audio/audio.cpp +++ b/higan/audio/audio.cpp @@ -1,5 +1,93 @@ #include -namespace { +namespace Emulator { + +Audio audio; + +Stream::Stream(double inputFrequency, double outputFrequency, double volume, double balance) { + dsp.setChannels(2); + dsp.setPrecision(16); + dsp.setFrequency(inputFrequency); + dsp.setResampler(DSP::ResampleEngine::Sinc); + dsp.setResamplerFrequency(outputFrequency); + dsp.setVolume(volume); + dsp.setBalance(balance); +} + +auto Stream::sample(int16 left, int16 right) -> void { + int samples[] = {left, right}; + dsp.sample(samples); + audio.poll(); +} + +// + +auto Audio::reset() -> void { + streams.reset(); + setReverbDelay(reverbDelay); +} + +auto Audio::setInterface(Interface* interface) -> void { + this->interface = interface; +} + +auto Audio::setFrequency(double frequency) -> void { + this->frequency = frequency; + for(auto& stream : streams) stream->dsp.setResamplerFrequency(frequency); +} + +auto Audio::setVolume(double volume) -> void { + this->volume = volume; + for(auto& stream : streams) stream->dsp.setVolume(volume); +} + +auto Audio::setBalance(double balance) -> void { + this->balance = balance; + for(auto& stream : streams) stream->dsp.setBalance(balance); +} + +auto Audio::setReverbDelay(uint reverbDelay) -> void { + this->reverbDelay = reverbDelay; + reverbLeft.resize(frequency * reverbDelay / 1000.0); + reverbRight.resize(frequency * reverbDelay / 1000.0); + memory::fill(reverbLeft.data(), reverbLeft.size() * sizeof(int16)); + memory::fill(reverbRight.data(), reverbRight.size() * sizeof(int16)); +} + +auto Audio::setReverbLevel(double reverbLevel) -> void { + this->reverbLevel = reverbLevel; +} + +auto Audio::createStream(double frequency) -> shared_pointer { + shared_pointer stream = new Stream{frequency, this->frequency, volume, balance}; + streams.append(stream); + return stream; +} + +//audio mixer +auto Audio::poll() -> void { + while(true) { + for(auto& stream : streams) { + if(!stream->dsp.pending()) return; + } + + int left = 0, right = 0; + for(auto& stream : streams) { + int samples[2]; + stream->dsp.read(samples); + left += samples[0]; + right += samples[1]; + } + + if(reverbDelay) { + reverbLeft.append(left); + reverbRight.append(right); + left += reverbLeft.takeFirst() * reverbLevel; + right += reverbRight.takeFirst() * reverbLevel; + } + + interface->audioSample(sclamp<16>(left), sclamp<16>(right)); + } +} } diff --git a/higan/audio/audio.hpp b/higan/audio/audio.hpp index bb73278b..1915bb2c 100644 --- a/higan/audio/audio.hpp +++ b/higan/audio/audio.hpp @@ -2,6 +2,48 @@ #include "core.hpp" -namespace { +namespace Emulator { + +struct Interface; + +struct Stream { + Stream(double inputFrequency, double outputFrequency, double volume, double balance); + auto sample(int16 left, int16 right) -> void; + +private: + nall::DSP dsp; + + friend class Audio; +}; + +struct Audio { + auto reset() -> void; + auto setInterface(Interface*) -> void; + + auto setFrequency(double frequency) -> void; + auto setVolume(double volume) -> void; + auto setBalance(double balance) -> void; + auto setReverbDelay(uint milliseconds) -> void; + auto setReverbLevel(double level) -> void; + + auto createStream(double frequency) -> shared_pointer; + + auto poll() -> void; + +private: + Interface* interface = nullptr; + vector> streams; + double frequency = 0.0; + double volume = 1.0; + double balance = 0.0; + uint reverbDelay = 0; //0 = disabled + double reverbLevel = 0.0; + vector reverbLeft; + vector reverbRight; + + friend class Stream; +}; + +extern Audio audio; } diff --git a/higan/emulator/emulator.cpp b/higan/emulator/emulator.cpp deleted file mode 100644 index 321bbad7..00000000 --- a/higan/emulator/emulator.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include - -namespace Emulator { - -auto Interface::videoColor(uint16 r, uint16 g, uint16 b) -> uint32 { - double saturation = 1.0; - double gamma = 1.0; - double luminance = 1.0; - - if(saturation != 1.0) { - uint16 grayscale = uclamp<16>((r + g + b) / 3); - double inverse = max(0.0, 1.0 - saturation); - r = uclamp<16>(r * saturation + grayscale * inverse); - g = uclamp<16>(g * saturation + grayscale * inverse); - b = uclamp<16>(b * saturation + grayscale * inverse); - } - - if(gamma != 1.0) { - double reciprocal = 1.0 / 32767.0; - r = r > 32767 ? r : uint16(32767 * pow(r * reciprocal, gamma)); - g = g > 32767 ? g : uint16(32767 * pow(g * reciprocal, gamma)); - b = b > 32767 ? b : uint16(32767 * pow(b * reciprocal, gamma)); - } - - if(luminance != 1.0) { - r = uclamp<16>(r * luminance); - g = uclamp<16>(g * luminance); - b = uclamp<16>(b * luminance); - } - - return 255 << 24 | (r >> 8) << 16 | (g >> 8) << 8 | (b >> 8) << 0; -} - -} diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 35517608..60b77028 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -8,7 +8,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "098.05"; + static const string Version = "098.06"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index 11ea0417..0ec6f1e9 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -75,7 +75,13 @@ struct Interface { //information virtual auto manifest() -> string = 0; virtual auto title() -> string = 0; + + //video information virtual auto videoFrequency() -> double = 0; + virtual auto videoColors() -> uint32 { return 1 << 19; } + virtual auto videoColor(uint32 color) -> uint64 { return 0; } + + //audio information virtual auto audioFrequency() -> double = 0; //media interface diff --git a/higan/fc/apu/apu.cpp b/higan/fc/apu/apu.cpp index 39d4e9be..e9418f23 100644 --- a/higan/fc/apu/apu.cpp +++ b/higan/fc/apu/apu.cpp @@ -57,7 +57,7 @@ auto APU::main() -> void { //output = filter.run_lopass(output); output = sclamp<16>(output); - interface->audioSample(output, output); + stream->sample(output, output); tick(); } @@ -89,6 +89,7 @@ auto APU::power() -> void { auto APU::reset() -> void { create(APU::Enter, 21'477'272); + stream = Emulator::audio.createStream(21'477'272.0 / 12.0); pulse[0].reset(); pulse[1].reset(); diff --git a/higan/fc/apu/apu.hpp b/higan/fc/apu/apu.hpp index 1e3824b8..e5f71162 100644 --- a/higan/fc/apu/apu.hpp +++ b/higan/fc/apu/apu.hpp @@ -1,4 +1,6 @@ struct APU : Thread { + shared_pointer stream; + APU(); static auto Enter() -> void; diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp index 77cdf803..20d5a570 100644 --- a/higan/fc/fc.hpp +++ b/higan/fc/fc.hpp @@ -22,7 +22,7 @@ namespace Famicom { auto create(auto (*entrypoint)() -> void, uint frequency) -> void { if(thread) co_delete(thread); - thread = co_create(262'144 * sizeof(void*), entrypoint); + thread = co_create(65'536 * sizeof(void*), entrypoint); this->frequency = frequency; clock = 0; } diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp index b9950858..4e6193eb 100644 --- a/higan/fc/interface/interface.cpp +++ b/higan/fc/interface/interface.cpp @@ -58,6 +58,61 @@ auto Interface::videoFrequency() -> double { return 21477272.0 / (262.0 * 1364.0 - 4.0); } +auto Interface::videoColors() -> uint32 { + return 1 << 9; +} + +auto Interface::videoColor(uint32 n) -> uint64 { + double saturation = 2.0; + double hue = 0.0; + double contrast = 1.0; + double brightness = 1.0; + double gamma = settings.colorEmulation ? 1.8 : 2.2; + + int color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1; + + static const double black = 0.518, white = 1.962, attenuation = 0.746; + static const double levels[8] = { + 0.350, 0.518, 0.962, 1.550, + 1.094, 1.506, 1.962, 1.962, + }; + + double lo_and_hi[2] = { + levels[level + 4 * (color == 0x0)], + levels[level + 4 * (color < 0xd)], + }; + + double y = 0.0, i = 0.0, q = 0.0; + auto wave = [](int p, int color) { return (color + p + 8) % 12 < 6; }; + for(int p : range(12)) { + double spot = lo_and_hi[wave(p, color)]; + + if(((n & 0x040) && wave(p, 12)) + || ((n & 0x080) && wave(p, 4)) + || ((n & 0x100) && wave(p, 8)) + ) spot *= attenuation; + + double v = (spot - black) / (white - black); + + v = (v - 0.5) * contrast + 0.5; + v *= brightness / 12.0; + + y += v; + i += v * std::cos((3.141592653 / 6.0) * (p + hue)); + q += v * std::sin((3.141592653 / 6.0) * (p + hue)); + } + + i *= saturation; + q *= saturation; + + auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); }; + uint64 r = uclamp<16>(65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q)); + uint64 g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q)); + uint64 b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q)); + + return r << 32 | g << 16 | b << 0; +} + auto Interface::audioFrequency() -> double { return 21477272.0 / 12.0; } diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp index 580355f2..f561216a 100644 --- a/higan/fc/interface/interface.hpp +++ b/higan/fc/interface/interface.hpp @@ -28,6 +28,8 @@ struct Interface : Emulator::Interface { auto manifest() -> string; auto title() -> string; auto videoFrequency() -> double; + auto videoColors() -> uint32; + auto videoColor(uint32 color) -> uint64; auto audioFrequency() -> double; auto loaded() -> bool; diff --git a/higan/fc/ppu/ppu.cpp b/higan/fc/ppu/ppu.cpp index 26c4ed71..afadf92b 100644 --- a/higan/fc/ppu/ppu.cpp +++ b/higan/fc/ppu/ppu.cpp @@ -42,10 +42,13 @@ auto PPU::scanline() -> void { auto PPU::frame() -> void { status.field ^= 1; - Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240); scheduler.exit(Scheduler::Event::Frame); } +auto PPU::refresh() -> void { + Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240); +} + auto PPU::power() -> void { } diff --git a/higan/fc/ppu/ppu.hpp b/higan/fc/ppu/ppu.hpp index 85b8f0dd..bfd0aba7 100644 --- a/higan/fc/ppu/ppu.hpp +++ b/higan/fc/ppu/ppu.hpp @@ -5,6 +5,7 @@ struct PPU : Thread { auto scanline() -> void; auto frame() -> void; + auto refresh() -> void; auto power() -> void; auto reset() -> void; diff --git a/higan/fc/scheduler/scheduler.cpp b/higan/fc/scheduler/scheduler.cpp index 47aae012..d8797956 100644 --- a/higan/fc/scheduler/scheduler.cpp +++ b/higan/fc/scheduler/scheduler.cpp @@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event { mode = mode_; host = co_active(); co_switch(resume); + if(event == Event::Frame) ppu.refresh(); return event; } diff --git a/higan/fc/system/system.cpp b/higan/fc/system/system.cpp index fb6e4ed5..f19a61ce 100644 --- a/higan/fc/system/system.cpp +++ b/higan/fc/system/system.cpp @@ -24,7 +24,6 @@ auto System::load() -> void { auto document = BML::unserialize(information.manifest); cartridge.load(); serializeInit(); - configureVideo(); _loaded = true; } @@ -44,6 +43,14 @@ auto System::power() -> void { } auto System::reset() -> void { + Emulator::video.reset(); + Emulator::video.setInterface(interface); + configureVideoPalette(); + configureVideoEffects(); + + Emulator::audio.reset(); + Emulator::audio.setInterface(interface); + cartridge.reset(); cpu.reset(); apu.reset(); diff --git a/higan/fc/system/system.hpp b/higan/fc/system/system.hpp index ae210293..4d1a1d94 100644 --- a/higan/fc/system/system.hpp +++ b/higan/fc/system/system.hpp @@ -13,8 +13,8 @@ struct System { auto term() -> void; //video.cpp - auto configureVideo() -> void; auto configureVideoPalette() -> void; + auto configureVideoEffects() -> void; //serialization.cpp auto serialize() -> serializer; diff --git a/higan/fc/system/video.cpp b/higan/fc/system/video.cpp index a7ba6922..66d09298 100644 --- a/higan/fc/system/video.cpp +++ b/higan/fc/system/video.cpp @@ -1,57 +1,6 @@ -auto System::configureVideo() -> void { - Emulator::video.reset(); - Emulator::video.setInterface(interface); - configureVideoPalette(); -} - auto System::configureVideoPalette() -> void { - auto generateColor = [](uint n, double saturation, double hue, double contrast, double brightness, double gamma) -> uint64 { - int color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1; - - static const double black = 0.518, white = 1.962, attenuation = 0.746; - static const double levels[8] = { - 0.350, 0.518, 0.962, 1.550, - 1.094, 1.506, 1.962, 1.962, - }; - - double lo_and_hi[2] = { - levels[level + 4 * (color == 0x0)], - levels[level + 4 * (color < 0xd)], - }; - - double y = 0.0, i = 0.0, q = 0.0; - auto wave = [](int p, int color) { return (color + p + 8) % 12 < 6; }; - for(int p : range(12)) { - double spot = lo_and_hi[wave(p, color)]; - - if(((n & 0x040) && wave(p, 12)) - || ((n & 0x080) && wave(p, 4)) - || ((n & 0x100) && wave(p, 8)) - ) spot *= attenuation; - - double v = (spot - black) / (white - black); - - v = (v - 0.5) * contrast + 0.5; - v *= brightness / 12.0; - - y += v; - i += v * std::cos((3.141592653 / 6.0) * (p + hue)); - q += v * std::sin((3.141592653 / 6.0) * (p + hue)); - } - - i *= saturation; - q *= saturation; - - auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); }; - uint64 r = uclamp<16>(65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q)); - uint64 g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q)); - uint64 b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q)); - - return r << 32 | g << 16 | b << 0; - }; - - Emulator::video.setPalette(1 << 9, [&](uint32 color) -> uint64 { - auto gamma = settings.colorEmulation ? 1.8 : 2.2; - return generateColor(color, 2.0, 0.0, 1.0, 1.0, gamma); - }); + Emulator::video.setPalette(); +} + +auto System::configureVideoEffects() -> void { } diff --git a/higan/gb/apu/apu.cpp b/higan/gb/apu/apu.cpp index 9a1a629d..4c2f598c 100644 --- a/higan/gb/apu/apu.cpp +++ b/higan/gb/apu/apu.cpp @@ -25,7 +25,11 @@ auto APU::main() -> void { hipass(sequencer.left, sequencer.leftBias); hipass(sequencer.right, sequencer.rightBias); - interface->audioSample(sequencer.left, sequencer.right); + if(!system.sgb()) { + stream->sample(sequencer.left, sequencer.right); + } else { + interface->audioSample(sequencer.left, sequencer.right); + } if(cycle == 0) { //512hz if(phase == 0 || phase == 2 || phase == 4 || phase == 6) { //256hz @@ -58,6 +62,7 @@ auto APU::hipass(int16& sample, int64& bias) -> void { auto APU::power() -> void { create(Enter, 2 * 1024 * 1024); + if(!system.sgb()) stream = Emulator::audio.createStream(2 * 1024 * 1024); for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this; square1.power(); diff --git a/higan/gb/apu/apu.hpp b/higan/gb/apu/apu.hpp index e008d649..a198e3d7 100644 --- a/higan/gb/apu/apu.hpp +++ b/higan/gb/apu/apu.hpp @@ -1,4 +1,6 @@ struct APU : Thread, MMIO { + shared_pointer stream; + static auto Enter() -> void; auto main() -> void; auto hipass(int16& sample, int64& bias) -> void; diff --git a/higan/gb/cartridge/cartridge.cpp b/higan/gb/cartridge/cartridge.cpp index ab0e3116..39e544f2 100644 --- a/higan/gb/cartridge/cartridge.cpp +++ b/higan/gb/cartridge/cartridge.cpp @@ -4,6 +4,7 @@ namespace GameBoy { #include "mbc0/mbc0.cpp" #include "mbc1/mbc1.cpp" +#include "mbc1m/mbc1m.cpp" #include "mbc2/mbc2.cpp" #include "mbc3/mbc3.cpp" #include "mbc5/mbc5.cpp" @@ -40,6 +41,7 @@ auto Cartridge::load(System::Revision revision) -> void { auto mapperid = document["board/mapper"].text(); if(mapperid == "none" ) information.mapper = Mapper::MBC0; if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1; + if(mapperid == "MBC1M") information.mapper = Mapper::MBC1M; if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2; if(mapperid == "MBC3" ) information.mapper = Mapper::MBC3; if(mapperid == "MBC5" ) information.mapper = Mapper::MBC5; @@ -70,6 +72,7 @@ auto Cartridge::load(System::Revision revision) -> void { switch(information.mapper) { default: case Mapper::MBC0: mapper = &mbc0; break; case Mapper::MBC1: mapper = &mbc1; break; + case Mapper::MBC1M: mapper = &mbc1m; break; case Mapper::MBC2: mapper = &mbc2; break; case Mapper::MBC3: mapper = &mbc3; break; case Mapper::MBC5: mapper = &mbc5; break; @@ -139,6 +142,7 @@ auto Cartridge::power() -> void { mbc0.power(); mbc1.power(); + mbc1m.power(); mbc2.power(); mbc3.power(); mbc5.power(); diff --git a/higan/gb/cartridge/cartridge.hpp b/higan/gb/cartridge/cartridge.hpp index ab13d649..1d8e5f97 100644 --- a/higan/gb/cartridge/cartridge.hpp +++ b/higan/gb/cartridge/cartridge.hpp @@ -16,6 +16,7 @@ struct Cartridge : MMIO, property { #include "mbc0/mbc0.hpp" #include "mbc1/mbc1.hpp" + #include "mbc1m/mbc1m.hpp" #include "mbc2/mbc2.hpp" #include "mbc3/mbc3.hpp" #include "mbc5/mbc5.hpp" @@ -26,6 +27,7 @@ struct Cartridge : MMIO, property { enum Mapper : uint { MBC0, MBC1, + MBC1M, MBC2, MBC3, MBC5, diff --git a/higan/gb/cartridge/mbc1m/mbc1m.cpp b/higan/gb/cartridge/mbc1m/mbc1m.cpp new file mode 100644 index 00000000..efd3cfe6 --- /dev/null +++ b/higan/gb/cartridge/mbc1m/mbc1m.cpp @@ -0,0 +1,26 @@ +auto Cartridge::MBC1M::mmio_read(uint16 addr) -> uint8 { + if((addr & 0xc000) == 0x0000) { //$0000-3fff + return cartridge.rom_read((romHi << 4) * 0x4000 + addr.bits(0,13)); + } + + if((addr & 0xc000) == 0x4000) { //$4000-7fff + return cartridge.rom_read((romHi << 4 | romLo) * 0x4000 + addr.bits(0,13)); + } + + return 0xff; +} + +auto Cartridge::MBC1M::mmio_write(uint16 addr, uint8 data) -> void { + if((addr & 0xe000) == 0x2000) { //$2000-3fff + romLo = data.bits(0,3); + } + + if((addr & 0xe000) == 0x4000) { //$4000-5fff + romHi = data.bits(0,1); + } +} + +auto Cartridge::MBC1M::power() -> void { + romHi = 0; + romLo = 1; +} diff --git a/higan/gb/cartridge/mbc1m/mbc1m.hpp b/higan/gb/cartridge/mbc1m/mbc1m.hpp new file mode 100644 index 00000000..16d173a1 --- /dev/null +++ b/higan/gb/cartridge/mbc1m/mbc1m.hpp @@ -0,0 +1,8 @@ +struct MBC1M : MMIO { + auto mmio_read(uint16 addr) -> uint8; + auto mmio_write(uint16 addr, uint8 data) -> void; + auto power() -> void; + + uint4 romLo; + uint2 romHi; +} mbc1m; diff --git a/higan/gb/cartridge/serialization.cpp b/higan/gb/cartridge/serialization.cpp index a2465182..55181431 100644 --- a/higan/gb/cartridge/serialization.cpp +++ b/higan/gb/cartridge/serialization.cpp @@ -7,6 +7,9 @@ auto Cartridge::serialize(serializer& s) -> void { s.integer(mbc1.ram_select); s.integer(mbc1.mode_select); + s.integer(mbc1m.romLo); + s.integer(mbc1m.romHi); + s.integer(mbc2.ram_enable); s.integer(mbc2.rom_select); diff --git a/higan/gb/gb.hpp b/higan/gb/gb.hpp index 8b8e5bf9..0338cba6 100644 --- a/higan/gb/gb.hpp +++ b/higan/gb/gb.hpp @@ -22,7 +22,7 @@ namespace GameBoy { auto create(auto (*entrypoint)() -> void, uint frequency) -> void { if(thread) co_delete(thread); - thread = co_create(262'144 * sizeof(void*), entrypoint); + thread = co_create(65'536 * sizeof(void*), entrypoint); this->frequency = frequency; clock = 0; } diff --git a/higan/gb/interface/interface.cpp b/higan/gb/interface/interface.cpp index fec86c66..735a3d57 100644 --- a/higan/gb/interface/interface.cpp +++ b/higan/gb/interface/interface.cpp @@ -52,6 +52,67 @@ auto Interface::videoFrequency() -> double { return 4194304.0 / (154.0 * 456.0); } +auto Interface::videoColors() -> uint32 { + return !system.cgb() ? 1 << 2 : 1 << 15; +} + +auto Interface::videoColor(uint32 color) -> uint64 { + if(!system.cgb()) { + if(!settings.colorEmulation) { + uint64 L = image::normalize(3 - color, 2, 16); + return L << 32 | L << 16 | L << 0; + } else { + #define DMG_PALETTE_GREEN + //#define DMG_PALETTE_YELLOW + //#define DMG_PALETTE_WHITE + + const uint16 monochrome[4][3] = { + #if defined(DMG_PALETTE_GREEN) + {0xaeae, 0xd9d9, 0x2727}, + {0x5858, 0xa0a0, 0x2828}, + {0x2020, 0x6262, 0x2929}, + {0x1a1a, 0x4545, 0x2a2a}, + #elif defined(DMG_PALETTE_YELLOW) + {0xffff, 0xf7f7, 0x7b7b}, + {0xb5b5, 0xaeae, 0x4a4a}, + {0x6b6b, 0x6969, 0x3131}, + {0x2121, 0x2020, 0x1010}, + #elif defined(DMG_PALETTE_WHITE) + {0xffff, 0xffff, 0xffff}, + {0xaaaa, 0xaaaa, 0xaaaa}, + {0x5555, 0x5555, 0x5555}, + {0x0000, 0x0000, 0x0000}, + #endif + }; + + uint64 R = monochrome[color][0]; + uint64 G = monochrome[color][1]; + uint64 B = monochrome[color][2]; + + return R << 32 | G << 16 | B << 0; + } + } else { + uint r = color.bits( 0, 4); + uint g = color.bits( 5, 9); + uint b = color.bits(10,14); + + uint64_t R = image::normalize(r, 5, 16); + uint64_t G = image::normalize(g, 5, 16); + uint64_t B = image::normalize(b, 5, 16); + + if(settings.colorEmulation) { + R = (r * 26 + g * 4 + b * 2); + G = ( g * 24 + b * 8); + B = (r * 6 + g * 4 + b * 22); + R = image::normalize(min(960, R), 10, 16); + G = image::normalize(min(960, G), 10, 16); + B = image::normalize(min(960, B), 10, 16); + } + + return R << 32 | G << 16 | B << 0; + } +} + auto Interface::audioFrequency() -> double { return 4194304.0 / 2.0; } diff --git a/higan/gb/interface/interface.hpp b/higan/gb/interface/interface.hpp index 55723826..c0c6cc84 100644 --- a/higan/gb/interface/interface.hpp +++ b/higan/gb/interface/interface.hpp @@ -30,6 +30,8 @@ struct Interface : Emulator::Interface { auto manifest() -> string; auto title() -> string; auto videoFrequency() -> double; + auto videoColors() -> uint32; + auto videoColor(uint32 color) -> uint64; auto audioFrequency() -> double; auto loaded() -> bool; diff --git a/higan/gb/ppu/ppu.cpp b/higan/gb/ppu/ppu.cpp index 1f0472fb..a30336ca 100644 --- a/higan/gb/ppu/ppu.cpp +++ b/higan/gb/ppu/ppu.cpp @@ -60,11 +60,14 @@ auto PPU::main() -> void { if(++status.ly == 154) { status.ly = 0; - if(!system.sgb()) Emulator::video.refresh(screen, 160 * sizeof(uint32), 160, 144); scheduler.exit(Scheduler::Event::Frame); } } +auto PPU::refresh() -> void { + if(!system.sgb()) Emulator::video.refresh(screen, 160 * sizeof(uint32), 160, 144); +} + auto PPU::add_clocks(uint clocks) -> void { while(clocks--) { if(status.dma_active) { diff --git a/higan/gb/ppu/ppu.hpp b/higan/gb/ppu/ppu.hpp index 5d82381b..f75eb042 100644 --- a/higan/gb/ppu/ppu.hpp +++ b/higan/gb/ppu/ppu.hpp @@ -1,6 +1,7 @@ struct PPU : Thread, MMIO { static auto Enter() -> void; auto main() -> void; + auto refresh() -> void; auto add_clocks(uint clocks) -> void; auto hflip(uint data) const -> uint; diff --git a/higan/gb/scheduler/scheduler.cpp b/higan/gb/scheduler/scheduler.cpp index aa6ce192..a1c88b2f 100644 --- a/higan/gb/scheduler/scheduler.cpp +++ b/higan/gb/scheduler/scheduler.cpp @@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event { mode = mode_; host = co_active(); co_switch(resume); + if(event == Event::Frame) ppu.refresh(); return event; } diff --git a/higan/gb/system/system.cpp b/higan/gb/system/system.cpp index 747bd8b7..485e103d 100644 --- a/higan/gb/system/system.cpp +++ b/higan/gb/system/system.cpp @@ -50,7 +50,6 @@ auto System::load(Revision revision) -> void { cartridge.load(revision); serializeInit(); - configureVideo(); _loaded = true; } @@ -61,6 +60,16 @@ auto System::unload() -> void { } auto System::power() -> void { + if(!system.sgb()) { + Emulator::video.reset(); + Emulator::video.setInterface(interface); + configureVideoPalette(); + configureVideoEffects(); + + Emulator::audio.reset(); + Emulator::audio.setInterface(interface); + } + bus.power(); cartridge.power(); cpu.power(); diff --git a/higan/gb/system/system.hpp b/higan/gb/system/system.hpp index b4d84d13..3acff4a9 100644 --- a/higan/gb/system/system.hpp +++ b/higan/gb/system/system.hpp @@ -30,7 +30,6 @@ struct System { auto power() -> void; //video.cpp - auto configureVideo() -> void; auto configureVideoPalette() -> void; auto configureVideoEffects() -> void; diff --git a/higan/gb/system/video.cpp b/higan/gb/system/video.cpp index 5c615110..6f27f6c8 100644 --- a/higan/gb/system/video.cpp +++ b/higan/gb/system/video.cpp @@ -1,75 +1,9 @@ -auto System::configureVideo() -> void { - if(sgb()) return; - - Emulator::video.reset(); - Emulator::video.setInterface(interface); - configureVideoPalette(); - configureVideoEffects(); -} - auto System::configureVideoPalette() -> void { if(sgb()) return; - - if(dmg()) Emulator::video.setPalette(1 << 2, [&](uint32 color) -> uint64 { - if(!settings.colorEmulation) { - uint64 L = image::normalize(3 - color, 2, 16); - return L << 32 | L << 16 | L << 0; - } else { - #define DMG_PALETTE_GREEN - //#define DMG_PALETTE_YELLOW - //#define DMG_PALETTE_WHITE - - const uint16 monochrome[4][3] = { - #if defined(DMG_PALETTE_GREEN) - {0xaeae, 0xd9d9, 0x2727}, - {0x5858, 0xa0a0, 0x2828}, - {0x2020, 0x6262, 0x2929}, - {0x1a1a, 0x4545, 0x2a2a}, - #elif defined(DMG_PALETTE_YELLOW) - {0xffff, 0xf7f7, 0x7b7b}, - {0xb5b5, 0xaeae, 0x4a4a}, - {0x6b6b, 0x6969, 0x3131}, - {0x2121, 0x2020, 0x1010}, - #elif defined(DMG_PALETTE_WHITE) - {0xffff, 0xffff, 0xffff}, - {0xaaaa, 0xaaaa, 0xaaaa}, - {0x5555, 0x5555, 0x5555}, - {0x0000, 0x0000, 0x0000}, - #endif - }; - - uint64 R = monochrome[color][0]; - uint64 G = monochrome[color][1]; - uint64 B = monochrome[color][2]; - - return R << 32 | G << 16 | B << 0; - } - }); - - if(cgb()) Emulator::video.setPalette(1 << 15, [&](uint32 color) -> uint64 { - uint r = color.bits( 0, 4); - uint g = color.bits( 5, 9); - uint b = color.bits(10,14); - - uint64_t R = image::normalize(r, 5, 16); - uint64_t G = image::normalize(g, 5, 16); - uint64_t B = image::normalize(b, 5, 16); - - if(settings.colorEmulation) { - R = (r * 26 + g * 4 + b * 2); - G = ( g * 24 + b * 8); - B = (r * 6 + g * 4 + b * 22); - R = image::normalize(min(960, R), 10, 16); - G = image::normalize(min(960, G), 10, 16); - B = image::normalize(min(960, B), 10, 16); - } - - return R << 32 | G << 16 | B << 0; - }); + Emulator::video.setPalette(); } auto System::configureVideoEffects() -> void { if(sgb()) return; - Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation); } diff --git a/higan/gba/apu/apu.cpp b/higan/gba/apu/apu.cpp index e03f223f..0ed9a7ac 100644 --- a/higan/gba/apu/apu.cpp +++ b/higan/gba/apu/apu.cpp @@ -63,7 +63,7 @@ auto APU::main() -> void { if(regs.bias.amplitude == 3) lsample &= ~15, rsample &= ~15; if(cpu.regs.mode == CPU::Registers::Mode::Stop) lsample = 0, rsample = 0; - interface->audioSample(sclamp<16>(lsample << 6), sclamp<16>(rsample << 6)); //should be <<5, use <<6 for added volume + stream->sample(sclamp<16>(lsample << 6), sclamp<16>(rsample << 6)); //should be <<5; use <<6 for added volume step(512); } @@ -74,6 +74,7 @@ auto APU::step(uint clocks) -> void { auto APU::power() -> void { create(APU::Enter, 16'777'216); + stream = Emulator::audio.createStream(16'777'216.0 / 512.0); square1.power(); square2.power(); diff --git a/higan/gba/apu/apu.hpp b/higan/gba/apu/apu.hpp index c78333f8..a043a1e4 100644 --- a/higan/gba/apu/apu.hpp +++ b/higan/gba/apu/apu.hpp @@ -1,4 +1,6 @@ struct APU : Thread, MMIO { + shared_pointer stream; + #include "registers.hpp" static auto Enter() -> void; diff --git a/higan/gba/cpu/bus.cpp b/higan/gba/cpu/bus.cpp index c79f01c5..2ffe24ef 100644 --- a/higan/gba/cpu/bus.cpp +++ b/higan/gba/cpu/bus.cpp @@ -1,10 +1,10 @@ -auto CPU::bus_idle() -> void { +auto CPU::busIdle() -> void { prefetch_step(1); } -auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 { - unsigned wait = bus_wait(mode, addr); - unsigned word = pipeline.fetch.instruction; +auto CPU::busRead(uint mode, uint32 addr) -> uint32 { + uint wait = busWait(mode, addr); + uint word = pipeline.fetch.instruction; if(addr >= 0x1000'0000) { prefetch_step(wait); @@ -35,8 +35,8 @@ auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 { return word; } -auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void { - unsigned wait = bus_wait(mode, addr); +auto CPU::busWrite(uint mode, uint32 addr, uint32 word) -> void { + uint wait = busWait(mode, addr); if(addr >= 0x1000'0000) { prefetch_step(wait); @@ -57,7 +57,7 @@ auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void { } } -auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned { +auto CPU::busWait(uint mode, uint32 addr) -> uint { if(addr >= 0x1000'0000) return 1; //unmapped if(addr < 0x0200'0000) return 1; if(addr < 0x0300'0000) return (16 - regs.memory.control.ewramwait) * (mode & Word ? 2 : 1); @@ -65,9 +65,9 @@ auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned { if(addr < 0x0700'0000) return mode & Word ? 2 : 1; if(addr < 0x0800'0000) return 1; - static unsigned timings[] = {5, 4, 3, 9}; - unsigned n = timings[regs.wait.control.nwait[addr >> 25 & 3]]; - unsigned s = regs.wait.control.swait[addr >> 25 & 3]; + static uint timings[] = {5, 4, 3, 9}; + uint n = timings[regs.wait.control.nwait[addr >> 25 & 3]]; + uint s = regs.wait.control.swait[addr >> 25 & 3]; switch(addr & 0x0e00'0000) { case 0x0800'0000: s = s ? 2 : 3; break; @@ -79,7 +79,7 @@ auto CPU::bus_wait(unsigned mode, uint32 addr) -> unsigned { bool sequential = (mode & Sequential); if((addr & 0x1fffe) == 0) sequential = false; //N cycle on 16-bit ROM crossing 128KB page boundary (RAM S==N) - unsigned clocks = sequential ? s : n; + uint clocks = sequential ? s : n; if(mode & Word) clocks += s; //16-bit bus requires two transfers for words return clocks; } diff --git a/higan/gba/cpu/cpu.hpp b/higan/gba/cpu/cpu.hpp index 89129e8c..db535ab3 100644 --- a/higan/gba/cpu/cpu.hpp +++ b/higan/gba/cpu/cpu.hpp @@ -39,10 +39,10 @@ struct CPU : Processor::ARM, Thread, MMIO { auto power() -> void; //bus.cpp - auto bus_idle() -> void override; - auto bus_read(uint mode, uint32 addr) -> uint32 override; - auto bus_write(uint mode, uint32 addr, uint32 word) -> void override; - auto bus_wait(uint mode, uint32 addr) -> uint; + auto busIdle() -> void override; + auto busRead(uint mode, uint32 addr) -> uint32 override; + auto busWrite(uint mode, uint32 addr, uint32 word) -> void override; + auto busWait(uint mode, uint32 addr) -> uint; //mmio.cpp auto read(uint32 addr) -> uint8; diff --git a/higan/gba/cpu/dma.cpp b/higan/gba/cpu/dma.cpp index a9a7a3af..8740de42 100644 --- a/higan/gba/cpu/dma.cpp +++ b/higan/gba/cpu/dma.cpp @@ -39,7 +39,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void { uint32 addr = dma.run.source; if(mode & Word) addr &= ~3; if(mode & Half) addr &= ~1; - dma.data = bus_read(mode, addr); + dma.data = busRead(mode, addr); } if(dma.run.target < 0x0200'0000) { @@ -48,7 +48,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void { uint32 addr = dma.run.target; if(mode & Word) addr &= ~3; if(mode & Half) addr &= ~1; - bus_write(mode, addr, dma.data); + busWrite(mode, addr, dma.data); } switch(dma.control.sourcemode) { diff --git a/higan/gba/cpu/prefetch.cpp b/higan/gba/cpu/prefetch.cpp index c829542f..ccc7d2ca 100644 --- a/higan/gba/cpu/prefetch.cpp +++ b/higan/gba/cpu/prefetch.cpp @@ -3,7 +3,7 @@ auto CPU::prefetch_sync(uint32 addr) -> void { prefetch.addr = addr; prefetch.load = addr; - prefetch.wait = bus_wait(Half | Nonsequential, prefetch.load); + prefetch.wait = busWait(Half | Nonsequential, prefetch.load); } auto CPU::prefetch_step(uint clocks) -> void { @@ -14,7 +14,7 @@ auto CPU::prefetch_step(uint clocks) -> void { if(--prefetch.wait) continue; prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load); prefetch.load += 2; - prefetch.wait = bus_wait(Half | Sequential, prefetch.load); + prefetch.wait = busWait(Half | Sequential, prefetch.load); } } @@ -22,14 +22,14 @@ auto CPU::prefetch_wait() -> void { if(!regs.wait.control.prefetch || active.dma || prefetch.full()) return; prefetch_step(prefetch.wait); - prefetch.wait = bus_wait(Half | Nonsequential, prefetch.load); + prefetch.wait = busWait(Half | Nonsequential, prefetch.load); } auto CPU::prefetch_read() -> uint16 { if(prefetch.empty()) prefetch_step(prefetch.wait); else prefetch_step(1); - if(prefetch.full()) prefetch.wait = bus_wait(Half | Sequential, prefetch.load); + if(prefetch.full()) prefetch.wait = busWait(Half | Sequential, prefetch.load); uint16 half = prefetch.slot[prefetch.addr >> 1 & 7]; prefetch.addr += 2; diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp index 18a2055b..4d2a68a4 100644 --- a/higan/gba/gba.hpp +++ b/higan/gba/gba.hpp @@ -34,7 +34,7 @@ namespace GameBoyAdvance { auto create(auto (*entrypoint)() -> void, uint frequency) -> void { if(thread) co_delete(thread); - thread = co_create(262'144 * sizeof(void*), entrypoint); + thread = co_create(65'536 * sizeof(void*), entrypoint); this->frequency = frequency; clock = 0; } diff --git a/higan/gba/interface/interface.cpp b/higan/gba/interface/interface.cpp index 5cd665fc..688332e4 100644 --- a/higan/gba/interface/interface.cpp +++ b/higan/gba/interface/interface.cpp @@ -52,6 +52,32 @@ auto Interface::videoFrequency() -> double { return 16777216.0 / (228.0 * 1232.0); } +auto Interface::videoColors() -> uint32 { + return 1 << 15; +} + +auto Interface::videoColor(uint32 color) -> uint64 { + uint R = color.bits( 0, 4); + uint G = color.bits( 5, 9); + uint B = color.bits(10,14); + + uint64 r = image::normalize(R, 5, 16); + uint64 g = image::normalize(G, 5, 16); + uint64 b = image::normalize(B, 5, 16); + + if(settings.colorEmulation) { + double lcdGamma = 4.0, outGamma = 2.2; + double lb = pow(B / 31.0, lcdGamma); + double lg = pow(G / 31.0, lcdGamma); + double lr = pow(R / 31.0, lcdGamma); + r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); + g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); + b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); + } + + return r << 32 | g << 16 | b << 0; +} + auto Interface::audioFrequency() -> double { return 16777216.0 / 512.0; } diff --git a/higan/gba/interface/interface.hpp b/higan/gba/interface/interface.hpp index c677b3c4..38a1e64e 100644 --- a/higan/gba/interface/interface.hpp +++ b/higan/gba/interface/interface.hpp @@ -28,6 +28,8 @@ struct Interface : Emulator::Interface { auto manifest() -> string; auto title() -> string; auto videoFrequency() -> double; + auto videoColors() -> uint32; + auto videoColor(uint32 color) -> uint64; auto audioFrequency() -> double; auto loaded() -> bool; diff --git a/higan/gba/ppu/ppu.cpp b/higan/gba/ppu/ppu.cpp index abbdccec..35190bd2 100644 --- a/higan/gba/ppu/ppu.cpp +++ b/higan/gba/ppu/ppu.cpp @@ -178,8 +178,11 @@ auto PPU::scanline() -> void { auto PPU::frame() -> void { player.frame(); - Emulator::video.refresh(output, 240 * sizeof(uint32), 240, 160); scheduler.exit(Scheduler::Event::Frame); } +auto PPU::refresh() -> void { + Emulator::video.refresh(output, 240 * sizeof(uint32), 240, 160); +} + } diff --git a/higan/gba/ppu/ppu.hpp b/higan/gba/ppu/ppu.hpp index 6e3061ab..4216f987 100644 --- a/higan/gba/ppu/ppu.hpp +++ b/higan/gba/ppu/ppu.hpp @@ -12,6 +12,7 @@ struct PPU : Thread, MMIO { auto power() -> void; auto scanline() -> void; auto frame() -> void; + auto refresh() -> void; auto read(uint32 addr) -> uint8; auto write(uint32 addr, uint8 byte) -> void; diff --git a/higan/gba/scheduler/scheduler.cpp b/higan/gba/scheduler/scheduler.cpp index 30bbf8c9..40c4d075 100644 --- a/higan/gba/scheduler/scheduler.cpp +++ b/higan/gba/scheduler/scheduler.cpp @@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event { mode = mode_; host = co_active(); co_switch(resume); + if(event == Event::Frame) ppu.refresh(); return event; } diff --git a/higan/gba/system/system.cpp b/higan/gba/system/system.cpp index 1d69dba4..9e8432fa 100644 --- a/higan/gba/system/system.cpp +++ b/higan/gba/system/system.cpp @@ -17,6 +17,14 @@ auto System::term() -> void { } auto System::power() -> void { + Emulator::video.reset(); + Emulator::video.setInterface(interface); + configureVideoPalette(); + configureVideoEffects(); + + Emulator::audio.reset(); + Emulator::audio.setInterface(interface); + bus.power(); player.power(); cpu.power(); @@ -36,7 +44,6 @@ auto System::load() -> void { cartridge.load(); serializeInit(); - configureVideo(); _loaded = true; } diff --git a/higan/gba/system/system.hpp b/higan/gba/system/system.hpp index 44eed38f..3cb319a7 100644 --- a/higan/gba/system/system.hpp +++ b/higan/gba/system/system.hpp @@ -26,7 +26,6 @@ struct System { auto runToSave() -> void; //video.cpp - auto configureVideo() -> void; auto configureVideoPalette() -> void; auto configureVideoEffects() -> void; diff --git a/higan/gba/system/video.cpp b/higan/gba/system/video.cpp index f775054a..f77e7ae9 100644 --- a/higan/gba/system/video.cpp +++ b/higan/gba/system/video.cpp @@ -1,32 +1,5 @@ -auto System::configureVideo() -> void { - Emulator::video.reset(); - Emulator::video.setInterface(interface); - configureVideoPalette(); - configureVideoEffects(); -} - auto System::configureVideoPalette() -> void { - Emulator::video.setPalette(1 << 15, [&](uint32 color) -> uint64 { - uint R = color.bits( 0, 4); - uint G = color.bits( 5, 9); - uint B = color.bits(10,14); - - uint64 r = image::normalize(R, 5, 16); - uint64 g = image::normalize(G, 5, 16); - uint64 b = image::normalize(B, 5, 16); - - if(settings.colorEmulation) { - double lcdGamma = 4.0, outGamma = 2.2; - double lb = pow(B / 31.0, lcdGamma); - double lg = pow(G / 31.0, lcdGamma); - double lr = pow(R / 31.0, lcdGamma); - r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); - g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); - b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); - } - - return r << 32 | g << 16 | b << 0; - }); + Emulator::video.setPalette(); } auto System::configureVideoEffects() -> void { diff --git a/higan/processor/arm/arm.cpp b/higan/processor/arm/arm.cpp index 6c3090da..601b6b84 100644 --- a/higan/processor/arm/arm.cpp +++ b/higan/processor/arm/arm.cpp @@ -31,16 +31,16 @@ auto ARM::exec() -> void { auto ARM::idle() -> void { pipeline.nonsequential = true; - return bus_idle(); + return busIdle(); } auto ARM::read(unsigned mode, uint32 addr) -> uint32 { - return bus_read(mode, addr); + return busRead(mode, addr); } auto ARM::load(unsigned mode, uint32 addr) -> uint32 { pipeline.nonsequential = true; - uint32 word = bus_read(Load | mode, addr); + uint32 word = busRead(Load | mode, addr); if(mode & Half) { addr &= 1; @@ -64,7 +64,7 @@ auto ARM::load(unsigned mode, uint32 addr) -> uint32 { auto ARM::write(unsigned mode, uint32 addr, uint32 word) -> void { pipeline.nonsequential = true; - return bus_write(mode, addr, word); + return busWrite(mode, addr, word); } auto ARM::store(unsigned mode, uint32 addr, uint32 word) -> void { @@ -73,7 +73,7 @@ auto ARM::store(unsigned mode, uint32 addr, uint32 word) -> void { if(mode & Half) { word &= 0xffff; word |= word << 16; } if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; } - return bus_write(Store | mode, addr, word); + return busWrite(Store | mode, addr, word); } auto ARM::vector(uint32 addr, Processor::Mode mode) -> void { diff --git a/higan/processor/arm/arm.hpp b/higan/processor/arm/arm.hpp index bea10663..608cf8f5 100644 --- a/higan/processor/arm/arm.hpp +++ b/higan/processor/arm/arm.hpp @@ -25,9 +25,9 @@ struct ARM { #include "disassembler.hpp" virtual auto step(unsigned clocks) -> void = 0; - virtual auto bus_idle() -> void = 0; - virtual auto bus_read(unsigned mode, uint32 addr) -> uint32 = 0; - virtual auto bus_write(unsigned mode, uint32 addr, uint32 word) -> void = 0; + virtual auto busIdle() -> void = 0; + virtual auto busRead(unsigned mode, uint32 addr) -> uint32 = 0; + virtual auto busWrite(unsigned mode, uint32 addr, uint32 word) -> void = 0; //arm.cpp auto power() -> void; diff --git a/higan/processor/hg51b/hg51b.cpp b/higan/processor/hg51b/hg51b.cpp index 7fc40baa..15038909 100644 --- a/higan/processor/hg51b/hg51b.cpp +++ b/higan/processor/hg51b/hg51b.cpp @@ -10,8 +10,8 @@ namespace Processor { auto HG51B::exec(uint24 addr) -> void { if(regs.halt) return; addr = addr + regs.pc * 2; - opcode = bus_read(addr++) << 0; - opcode |= bus_read(addr++) << 8; + opcode = read(addr++) << 0; + opcode |= read(addr++) << 8; regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff); instruction(); } diff --git a/higan/processor/hg51b/hg51b.hpp b/higan/processor/hg51b/hg51b.hpp index 3bf2150d..b7118878 100644 --- a/higan/processor/hg51b/hg51b.hpp +++ b/higan/processor/hg51b/hg51b.hpp @@ -1,13 +1,13 @@ -//Hitachi HG51B169 (HG51BS family/derivative?) - #pragma once +//Hitachi HG51B169 (HG51BS family/derivative?) + namespace Processor { struct HG51B { auto exec(uint24 addr) -> void; - virtual auto bus_read(uint24 addr) -> uint8 = 0; - virtual auto bus_write(uint24 addr, uint8 data) -> void = 0; + virtual auto read(uint24 addr) -> uint8 = 0; + virtual auto write(uint24 addr, uint8 data) -> void = 0; auto power() -> void; auto serialize(serializer&) -> void; @@ -25,8 +25,8 @@ protected: auto instruction() -> void; //registers.cpp - auto reg_read(uint8 addr) const -> uint24; - auto reg_write(uint8 addr, uint24 data) -> void; + auto regRead(uint8 addr) const -> uint24; + auto regWrite(uint8 addr, uint24 data) -> void; struct Registers { bool halt; diff --git a/higan/processor/hg51b/instructions.cpp b/higan/processor/hg51b/instructions.cpp index dc215f82..96ae8cc5 100644 --- a/higan/processor/hg51b/instructions.cpp +++ b/higan/processor/hg51b/instructions.cpp @@ -34,7 +34,7 @@ auto HG51B::sa() -> uint { //Register-or-Immediate: most opcodes can load from a register or immediate auto HG51B::ri() -> uint { if(opcode & 0x0400) return opcode & 0xff; - return reg_read(opcode & 0xff); + return regRead(opcode & 0xff); } //New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes) @@ -115,7 +115,7 @@ auto HG51B::instruction() -> void { else if((opcode & 0xffff) == 0x4000) { //0100 0000 0000 0000 //rdbus - regs.busdata = bus_read(regs.busaddr++); + regs.busdata = read(regs.busaddr++); } else if((opcode & 0xf800) == 0x4800) { @@ -306,7 +306,7 @@ auto HG51B::instruction() -> void { else if((opcode & 0xff00) == 0xe000) { //1110 0000 .... .... //st r,a - reg_write(opcode & 0xff, regs.a); + regWrite(opcode & 0xff, regs.a); } else if((opcode & 0xfb00) == 0xe800) { @@ -333,10 +333,10 @@ auto HG51B::instruction() -> void { else if((opcode & 0xff00) == 0xf000) { //1111 0000 .... .... //swap a,r - uint24 source = reg_read(opcode & 0xff); + uint24 source = regRead(opcode & 0xff); uint24 target = regs.a; regs.a = source; - reg_write(opcode & 0xff, target); + regWrite(opcode & 0xff, target); } else if((opcode & 0xffff) == 0xfc00) { diff --git a/higan/processor/hg51b/registers.cpp b/higan/processor/hg51b/registers.cpp index 82f9698e..4038efe5 100644 --- a/higan/processor/hg51b/registers.cpp +++ b/higan/processor/hg51b/registers.cpp @@ -1,4 +1,4 @@ -auto HG51B::reg_read(uint8 addr) const -> uint24 { +auto HG51B::regRead(uint8 addr) const -> uint24 { switch(addr) { case 0x00: return regs.a; case 0x01: return regs.acch; @@ -44,7 +44,7 @@ auto HG51B::reg_read(uint8 addr) const -> uint24 { return 0x000000; } -auto HG51B::reg_write(uint8 addr, uint24 data) -> void { +auto HG51B::regWrite(uint8 addr, uint24 data) -> void { switch(addr) { case 0x00: regs.a = data; return; case 0x01: regs.acch = data; return; diff --git a/higan/sfc/cartridge/markup.cpp b/higan/sfc/cartridge/markup.cpp index 7e28690b..28945113 100644 --- a/higan/sfc/cartridge/markup.cpp +++ b/higan/sfc/cartridge/markup.cpp @@ -98,7 +98,7 @@ auto Cartridge::parseMarkupMCC(Markup::Node root) -> void { for(auto node : root.find("map")) { if(node.text() == "mcu") { - parseMarkupMap(node, {&MCC::mcu_read, &mcc}, {&MCC::mcu_write, &mcc}); + parseMarkupMap(node, {&MCC::mcuRead, &mcc}, {&MCC::mcuWrite, &mcc}); } else { parseMarkupMap(node, {&MCC::read, &mcc}, {&MCC::write, &mcc}); } @@ -231,7 +231,7 @@ auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void { memory.append({ID::ArmDSPRAM, root["dram"]["name"].text()}); for(auto node : root.find("map")) { - parseMarkupMap(node, {&ArmDSP::mmio_read, &armdsp}, {&ArmDSP::mmio_write, &armdsp}); + parseMarkupMap(node, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp}); } } @@ -252,19 +252,19 @@ auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, uint roms) -> void { parseMarkupMemory(hitachidsp.ram, root["ram"], ID::HitachiDSPRAM, true); for(auto node : root.find("map")) { - parseMarkupMap(node, {&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp}); + parseMarkupMap(node, {&HitachiDSP::dspRead, &hitachidsp}, {&HitachiDSP::dspWrite, &hitachidsp}); } for(auto node : root["rom"].find("map")) { - parseMarkupMap(node, {&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp}); + parseMarkupMap(node, {&HitachiDSP::romRead, &hitachidsp}, {&HitachiDSP::romWrite, &hitachidsp}); } for(auto node : root["ram"].find("map")) { - parseMarkupMap(node, {&HitachiDSP::ram_read, &hitachidsp}, {&HitachiDSP::ram_write, &hitachidsp}); + parseMarkupMap(node, {&HitachiDSP::ramRead, &hitachidsp}, {&HitachiDSP::ramWrite, &hitachidsp}); } for(auto node : root["dram"].find("map")) { - parseMarkupMap(node, {&HitachiDSP::dram_read, &hitachidsp}, {&HitachiDSP::dram_write, &hitachidsp}); + parseMarkupMap(node, {&HitachiDSP::dramRead, &hitachidsp}, {&HitachiDSP::dramWrite, &hitachidsp}); } } @@ -380,6 +380,6 @@ auto Cartridge::parseMarkupMSU1(Markup::Node root) -> void { hasMSU1 = true; for(auto node : root.find("map")) { - parseMarkupMap(node, {&MSU1::mmioRead, &msu1}, {&MSU1::mmioWrite, &msu1}); + parseMarkupMap(node, {&MSU1::read, &msu1}, {&MSU1::write, &msu1}); } } diff --git a/higan/sfc/coprocessor/armdsp/armdsp.cpp b/higan/sfc/coprocessor/armdsp/armdsp.cpp index f6b328f6..4cdf6234 100644 --- a/higan/sfc/coprocessor/armdsp/armdsp.cpp +++ b/higan/sfc/coprocessor/armdsp/armdsp.cpp @@ -32,7 +32,7 @@ auto ArmDSP::boot() -> void { //reset sequence delay if(bridge.ready == false) { - step(65536); + step(65'536); bridge.ready = true; } } @@ -58,7 +58,7 @@ auto ArmDSP::step(uint clocks) -> void { //3800-3807 mirrored throughout //a0 ignored -auto ArmDSP::mmio_read(uint24 addr, uint8) -> uint8 { +auto ArmDSP::read(uint24 addr, uint8) -> uint8 { cpu.synchronizeCoprocessors(); uint8 data = 0x00; @@ -82,7 +82,7 @@ auto ArmDSP::mmio_read(uint24 addr, uint8) -> uint8 { return data; } -auto ArmDSP::mmio_write(uint24 addr, uint8 data) -> void { +auto ArmDSP::write(uint24 addr, uint8 data) -> void { cpu.synchronizeCoprocessors(); addr &= 0xff06; diff --git a/higan/sfc/coprocessor/armdsp/armdsp.hpp b/higan/sfc/coprocessor/armdsp/armdsp.hpp index 13390f9b..db373a87 100644 --- a/higan/sfc/coprocessor/armdsp/armdsp.hpp +++ b/higan/sfc/coprocessor/armdsp/armdsp.hpp @@ -11,12 +11,12 @@ struct ArmDSP : Processor::ARM, Cothread { auto main() -> void; auto step(uint clocks) -> void override; - auto bus_idle() -> void override; - auto bus_read(uint mode, uint32 addr) -> uint32 override; - auto bus_write(uint mode, uint32 addr, uint32 word) -> void override; + auto busIdle() -> void override; + auto busRead(uint mode, uint32 addr) -> uint32 override; + auto busWrite(uint mode, uint32 addr, uint32 word) -> void override; - auto mmio_read(uint24 addr, uint8 data) -> uint8; - auto mmio_write(uint24 addr, uint8 data) -> void; + auto read(uint24 addr, uint8 data) -> uint8; + auto write(uint24 addr, uint8 data) -> void; auto init() -> void; auto load() -> void; diff --git a/higan/sfc/coprocessor/armdsp/memory.cpp b/higan/sfc/coprocessor/armdsp/memory.cpp index c6d76a4b..05931a35 100644 --- a/higan/sfc/coprocessor/armdsp/memory.cpp +++ b/higan/sfc/coprocessor/armdsp/memory.cpp @@ -1,11 +1,11 @@ //note: timings are completely unverified //due to the ST018 chip design (on-die ROM), testing is nearly impossible -auto ArmDSP::bus_idle() -> void { +auto ArmDSP::busIdle() -> void { step(1); } -auto ArmDSP::bus_read(unsigned mode, uint32 addr) -> uint32 { +auto ArmDSP::busRead(uint mode, uint32 addr) -> uint32 { step(1); static auto memory = [&](const uint8* memory, uint mode, uint32 addr) -> uint32 { @@ -19,34 +19,34 @@ auto ArmDSP::bus_read(unsigned mode, uint32 addr) -> uint32 { } }; - switch(addr & 0xe0000000) { - case 0x00000000: return memory(programROM, mode, addr & 0x1ffff); - case 0x20000000: return pipeline.fetch.instruction; - case 0x40000000: break; - case 0x60000000: return 0x40404001; - case 0x80000000: return pipeline.fetch.instruction; - case 0xa0000000: return memory(dataROM, mode, addr & 0x7fff); - case 0xc0000000: return pipeline.fetch.instruction; - case 0xe0000000: return memory(programRAM, mode, addr & 0x3fff); + switch(addr & 0xe000'0000) { + case 0x0000'0000: return memory(programROM, mode, addr & 0x1ffff); + case 0x2000'0000: return pipeline.fetch.instruction; + case 0x4000'0000: break; + case 0x6000'0000: return 0x40404001; + case 0x8000'0000: return pipeline.fetch.instruction; + case 0xa000'0000: return memory(dataROM, mode, addr & 0x7fff); + case 0xc000'0000: return pipeline.fetch.instruction; + case 0xe000'0000: return memory(programRAM, mode, addr & 0x3fff); } - addr &= 0xe000003f; + addr &= 0xe000'003f; - if(addr == 0x40000010) { + if(addr == 0x4000'0010) { if(bridge.cputoarm.ready) { bridge.cputoarm.ready = false; return bridge.cputoarm.data; } } - if(addr == 0x40000020) { + if(addr == 0x4000'0020) { return bridge.status(); } return 0; } -auto ArmDSP::bus_write(uint mode, uint32 addr, uint32 word) -> void { +auto ArmDSP::busWrite(uint mode, uint32 addr, uint32 word) -> void { step(1); static auto memory = [](uint8* memory, uint mode, uint32 addr, uint32 word) { @@ -62,37 +62,30 @@ auto ArmDSP::bus_write(uint mode, uint32 addr, uint32 word) -> void { } }; - switch(addr & 0xe0000000) { - case 0x00000000: return; - case 0x20000000: return; - case 0x40000000: break; - case 0x60000000: return; - case 0x80000000: return; - case 0xa0000000: return; - case 0xc0000000: return; - case 0xe0000000: return memory(programRAM, mode, addr & 0x3fff, word); + switch(addr & 0xe000'0000) { + case 0x0000'0000: return; + case 0x2000'0000: return; + case 0x4000'0000: break; + case 0x6000'0000: return; + case 0x8000'0000: return; + case 0xa000'0000: return; + case 0xc000'0000: return; + case 0xe000'0000: return memory(programRAM, mode, addr & 0x3fff, word); } - addr &= 0xe000003f; - word &= 0x000000ff; + addr &= 0xe000'003f; + word &= 0x0000'00ff; - if(addr == 0x40000000) { + if(addr == 0x4000'0000) { bridge.armtocpu.ready = true; bridge.armtocpu.data = word; - return; } - if(addr == 0x40000010) { - bridge.signal = true; - return; - } + if(addr == 0x4000'0010) bridge.signal = true; - if(addr == 0x40000020) { bridge.timerlatch = (bridge.timerlatch & 0xffff00) | (word << 0); return; } - if(addr == 0x40000024) { bridge.timerlatch = (bridge.timerlatch & 0xff00ff) | (word << 8); return; } - if(addr == 0x40000028) { bridge.timerlatch = (bridge.timerlatch & 0x00ffff) | (word << 16); return; } + if(addr == 0x4000'0020) bridge.timerlatch.byte(0) = word; + if(addr == 0x4000'0024) bridge.timerlatch.byte(1) = word; + if(addr == 0x4000'0028) bridge.timerlatch.byte(2) = word; - if(addr == 0x4000002c) { - bridge.timer = bridge.timerlatch; - return; - } + if(addr == 0x4000'002c) bridge.timer = bridge.timerlatch; } diff --git a/higan/sfc/coprocessor/armdsp/registers.hpp b/higan/sfc/coprocessor/armdsp/registers.hpp index 813fdb47..c05a0975 100644 --- a/higan/sfc/coprocessor/armdsp/registers.hpp +++ b/higan/sfc/coprocessor/armdsp/registers.hpp @@ -12,6 +12,11 @@ struct Bridge { bool signal; auto status() const -> uint8 { - return (ready << 7) | (cputoarm.ready << 3) | (signal << 2) | (armtocpu.ready << 0); + return ( + armtocpu.ready << 0 + | signal << 2 + | cputoarm.ready << 3 + | ready << 7 + ); } } bridge; diff --git a/higan/sfc/coprocessor/epsonrtc/epsonrtc.cpp b/higan/sfc/coprocessor/epsonrtc/epsonrtc.cpp index 5445b48d..b3e353d3 100644 --- a/higan/sfc/coprocessor/epsonrtc/epsonrtc.cpp +++ b/higan/sfc/coprocessor/epsonrtc/epsonrtc.cpp @@ -15,7 +15,7 @@ auto EpsonRTC::main() -> void { if(wait) { if(--wait == 0) ready = 1; } clocks++; - if((clocks & ~0x00ff) == 0) round_seconds(); //125 microseconds + if((clocks & ~0x00ff) == 0) roundSeconds(); //125 microseconds if((clocks & ~0x3fff) == 0) duty(); //1/128th second if((clocks & ~0x7fff) == 0) irq(0); //1/64th second if(clocks == 0) { //1 second @@ -81,7 +81,7 @@ auto EpsonRTC::power() -> void { } auto EpsonRTC::reset() -> void { - create(EpsonRTC::Enter, 32768 * 64); + create(EpsonRTC::Enter, 32'768 * 64); clocks = 0; seconds = 0; @@ -150,7 +150,7 @@ auto EpsonRTC::read(uint24 addr, uint8 data) -> uint8 { if(state != State::Read) return 0; ready = 0; wait = 8; - return rtc_read(offset++); + return rtcRead(offset++); } if(addr == 2) { @@ -166,7 +166,7 @@ auto EpsonRTC::write(uint24 addr, uint8 data) -> void { if(addr == 0) { chipselect = data; - if(chipselect != 1) rtc_reset(); + if(chipselect != 1) rtcReset(); ready = 1; } @@ -192,7 +192,7 @@ auto EpsonRTC::write(uint24 addr, uint8 data) -> void { } else if(state == State::Write) { - rtc_write(offset++, data); + rtcWrite(offset++, data); ready = 0; wait = 8; mdr = data; diff --git a/higan/sfc/coprocessor/epsonrtc/epsonrtc.hpp b/higan/sfc/coprocessor/epsonrtc/epsonrtc.hpp index 3cd36a4f..0e0b9c71 100644 --- a/higan/sfc/coprocessor/epsonrtc/epsonrtc.hpp +++ b/higan/sfc/coprocessor/epsonrtc/epsonrtc.hpp @@ -67,9 +67,9 @@ struct EpsonRTC : Cothread { uint1 test; //memory.cpp - auto rtc_reset() -> void; - auto rtc_read(uint4 addr) -> uint4; - auto rtc_write(uint4 addr, uint4 data) -> void; + auto rtcReset() -> void; + auto rtcRead(uint4 addr) -> uint4; + auto rtcWrite(uint4 addr, uint4 data) -> void; auto load(const uint8* data) -> void; auto save(uint8* data) -> void; @@ -77,15 +77,15 @@ struct EpsonRTC : Cothread { //time.cpp auto irq(uint2 period) -> void; auto duty() -> void; - auto round_seconds() -> void; + auto roundSeconds() -> void; auto tick() -> void; - auto tick_second() -> void; - auto tick_minute() -> void; - auto tick_hour() -> void; - auto tick_day() -> void; - auto tick_month() -> void; - auto tick_year() -> void; + auto tickSecond() -> void; + auto tickMinute() -> void; + auto tickHour() -> void; + auto tickDay() -> void; + auto tickMonth() -> void; + auto tickYear() -> void; }; extern EpsonRTC epsonrtc; diff --git a/higan/sfc/coprocessor/epsonrtc/memory.cpp b/higan/sfc/coprocessor/epsonrtc/memory.cpp index be9da697..f3ab59ee 100644 --- a/higan/sfc/coprocessor/epsonrtc/memory.cpp +++ b/higan/sfc/coprocessor/epsonrtc/memory.cpp @@ -1,4 +1,4 @@ -auto EpsonRTC::rtc_reset() -> void { +auto EpsonRTC::rtcReset() -> void { state = State::Mode; offset = 0; @@ -7,7 +7,7 @@ auto EpsonRTC::rtc_reset() -> void { test = 0; } -auto EpsonRTC::rtc_read(uint4 addr) -> uint4 { +auto EpsonRTC::rtcRead(uint4 addr) -> uint4 { switch(addr) { default: case 0: return secondlo; case 1: return secondhi | batteryfailure << 3; @@ -32,7 +32,7 @@ auto EpsonRTC::rtc_read(uint4 addr) -> uint4 { } } -auto EpsonRTC::rtc_write(uint4 addr, uint4 data) -> void { +auto EpsonRTC::rtcWrite(uint4 addr, uint4 data) -> void { switch(addr) { case 0: secondlo = data; @@ -87,7 +87,7 @@ auto EpsonRTC::rtc_write(uint4 addr, uint4 data) -> void { if(held == 1 && hold == 0 && holdtick == 1) { //if a second has passed during hold, increment one second upon resuming holdtick = 0; - tick_second(); + tickSecond(); } } break; case 14: @@ -156,10 +156,10 @@ auto EpsonRTC::load(const uint8* data) -> void { } uint64 diff = (uint64)time(0) - timestamp; - while(diff >= 60 * 60 * 24) { tick_day(); diff -= 60 * 60 * 24; } - while(diff >= 60 * 60) { tick_hour(); diff -= 60 * 60; } - while(diff >= 60) { tick_minute(); diff -= 60; } - while(diff--) tick_second(); + while(diff >= 60 * 60 * 24) { tickDay(); diff -= 60 * 60 * 24; } + while(diff >= 60 * 60) { tickHour(); diff -= 60 * 60; } + while(diff >= 60) { tickMinute(); diff -= 60; } + while(diff--) tickSecond(); } auto EpsonRTC::save(uint8* data) -> void { diff --git a/higan/sfc/coprocessor/epsonrtc/time.cpp b/higan/sfc/coprocessor/epsonrtc/time.cpp index 2620627e..08c13a49 100644 --- a/higan/sfc/coprocessor/epsonrtc/time.cpp +++ b/higan/sfc/coprocessor/epsonrtc/time.cpp @@ -8,11 +8,11 @@ auto EpsonRTC::duty() -> void { if(irqduty) irqflag = 0; } -auto EpsonRTC::round_seconds() -> void { +auto EpsonRTC::roundSeconds() -> void { if(roundseconds == 0) return; roundseconds = 0; - if(secondhi >= 3) tick_minute(); + if(secondhi >= 3) tickMinute(); secondlo = 0; secondhi = 0; } @@ -26,13 +26,13 @@ auto EpsonRTC::tick() -> void { } resync = 1; - tick_second(); + tickSecond(); } //below code provides bit-perfect emulation of invalid BCD values on the RTC-4513 //code makes extensive use of variable-length integers (see epsonrtc.hpp for sizes) -auto EpsonRTC::tick_second() -> void { +auto EpsonRTC::tickSecond() -> void { if(secondlo <= 8 || secondlo == 12) { secondlo++; } else { @@ -41,12 +41,12 @@ auto EpsonRTC::tick_second() -> void { secondhi++; } else { secondhi = 0; - tick_minute(); + tickMinute(); } } } -auto EpsonRTC::tick_minute() -> void { +auto EpsonRTC::tickMinute() -> void { if(minutelo <= 8 || minutelo == 12) { minutelo++; } else { @@ -55,12 +55,12 @@ auto EpsonRTC::tick_minute() -> void { minutehi++; } else { minutehi = 0; - tick_hour(); + tickHour(); } } } -auto EpsonRTC::tick_hour() -> void { +auto EpsonRTC::tickHour() -> void { if(atime) { if(hourhi < 2) { if(hourlo <= 8 || hourlo == 12) { @@ -80,7 +80,7 @@ auto EpsonRTC::tick_hour() -> void { } else { hourlo = !(hourlo & 1); hourhi = 0; - tick_day(); + tickDay(); } } } else { @@ -99,12 +99,12 @@ auto EpsonRTC::tick_hour() -> void { hourlo = !(hourlo & 1); hourhi ^= 1; } - if(meridian == 0 && !(hourlo & 1)) tick_day(); + if(meridian == 0 && !(hourlo & 1)) tickDay(); } } } -auto EpsonRTC::tick_day() -> void { +auto EpsonRTC::tickDay() -> void { if(calendar == 0) return; weekday = (weekday + 1) + (weekday == 6); @@ -124,25 +124,25 @@ auto EpsonRTC::tick_day() -> void { if(days == 28 && (dayhi == 3 || (dayhi == 2 && daylo >= 8))) { daylo = 1; dayhi = 0; - return tick_month(); + return tickMonth(); } if(days == 29 && (dayhi == 3 || (dayhi == 2 && (daylo > 8 && daylo != 12)))) { daylo = 1; dayhi = 0; - return tick_month(); + return tickMonth(); } if(days == 30 && (dayhi == 3 || (dayhi == 2 && (daylo == 10 || daylo == 14)))) { daylo = 1; dayhi = 0; - return tick_month(); + return tickMonth(); } if(days == 31 && (dayhi == 3 && (daylo & 3))) { daylo = 1; dayhi = 0; - return tick_month(); + return tickMonth(); } if(daylo <= 8 || daylo == 12) { @@ -153,7 +153,7 @@ auto EpsonRTC::tick_day() -> void { } } -auto EpsonRTC::tick_month() -> void { +auto EpsonRTC::tickMonth() -> void { if(monthhi == 0 || !(monthlo & 2)) { if(monthlo <= 8 || monthlo == 12) { monthlo++; @@ -164,11 +164,11 @@ auto EpsonRTC::tick_month() -> void { } else { monthlo = !(monthlo & 1); monthhi = 0; - tick_year(); + tickYear(); } } -auto EpsonRTC::tick_year() -> void { +auto EpsonRTC::tickYear() -> void { if(yearlo <= 8 || yearlo == 12) { yearlo++; } else { diff --git a/higan/sfc/coprocessor/hitachidsp/hitachidsp.cpp b/higan/sfc/coprocessor/hitachidsp/hitachidsp.cpp index 047f1fab..37770b00 100644 --- a/higan/sfc/coprocessor/hitachidsp/hitachidsp.cpp +++ b/higan/sfc/coprocessor/hitachidsp/hitachidsp.cpp @@ -13,7 +13,7 @@ auto HitachiDSP::Enter() -> void { auto HitachiDSP::main() -> void { if(mmio.dma) { for(auto n : range(mmio.dma_length)) { - bus_write(mmio.dma_target + n, bus_read(mmio.dma_source + n)); + write(mmio.dma_target + n, read(mmio.dma_source + n)); step(2); } mmio.dma = false; diff --git a/higan/sfc/coprocessor/hitachidsp/hitachidsp.hpp b/higan/sfc/coprocessor/hitachidsp/hitachidsp.hpp index 18256f82..753797ce 100644 --- a/higan/sfc/coprocessor/hitachidsp/hitachidsp.hpp +++ b/higan/sfc/coprocessor/hitachidsp/hitachidsp.hpp @@ -14,24 +14,24 @@ struct HitachiDSP : Processor::HG51B, Cothread { auto reset() -> void; //HG51B read/write - auto bus_read(uint24 addr) -> uint8; - auto bus_write(uint24 addr, uint8 data) -> void; + auto read(uint24 addr) -> uint8 override; + auto write(uint24 addr, uint8 data) -> void override; //CPU ROM read/write - auto rom_read(uint24 addr, uint8 data) -> uint8; - auto rom_write(uint24 addr, uint8 data) -> void; + auto romRead(uint24 addr, uint8 data) -> uint8; + auto romWrite(uint24 addr, uint8 data) -> void; //CPU RAM read/write - auto ram_read(uint24 addr, uint8 data) -> uint8; - auto ram_write(uint24 addr, uint8 data) -> void; + auto ramRead(uint24 addr, uint8 data) -> uint8; + auto ramWrite(uint24 addr, uint8 data) -> void; //HG51B data RAM read/write - auto dram_read(uint24 addr, uint8 data) -> uint8; - auto dram_write(uint24 addr, uint8 data) -> void; + auto dramRead(uint24 addr, uint8 data) -> uint8; + auto dramWrite(uint24 addr, uint8 data) -> void; //CPU MMIO read/write - auto dsp_read(uint24 addr, uint8 data) -> uint8; - auto dsp_write(uint24 addr, uint8 data) -> void; + auto dspRead(uint24 addr, uint8 data) -> uint8; + auto dspWrite(uint24 addr, uint8 data) -> void; auto firmware() const -> vector; auto serialize(serializer&) -> void; diff --git a/higan/sfc/coprocessor/hitachidsp/memory.cpp b/higan/sfc/coprocessor/hitachidsp/memory.cpp index 9537ee75..1c609889 100644 --- a/higan/sfc/coprocessor/hitachidsp/memory.cpp +++ b/higan/sfc/coprocessor/hitachidsp/memory.cpp @@ -1,9 +1,9 @@ -auto HitachiDSP::bus_read(uint24 addr) -> uint8 { +auto HitachiDSP::read(uint24 addr) -> uint8 { if((addr & 0x40ec00) == 0x006c00) { //$00-3f,80-bf:6c00-6cff,7c00-7cff - return dsp_read(addr, 0x00); + return dspRead(addr, 0x00); } if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-6bff,7000-7bff - return dram_read(addr, 0x00); + return dramRead(addr, 0x00); } if((addr & 0x408000) == 0x008000) { //$00-3f,80-bf:8000-ffff if(rom.size() == 0) return 0x00; @@ -20,12 +20,12 @@ auto HitachiDSP::bus_read(uint24 addr) -> uint8 { return 0x00; } -auto HitachiDSP::bus_write(uint24 addr, uint8 data) -> void { +auto HitachiDSP::write(uint24 addr, uint8 data) -> void { if((addr & 0x40ec00) == 0x006c00) { //$00-3f,80-bf:6c00-6fff,7c00-7fff - return dsp_write(addr, data); + return dspWrite(addr, data); } if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-6bff,7000-7bff - return dram_write(addr, data); + return dramWrite(addr, data); } if((addr & 0xf88000) == 0x700000) { //$70-77:0000-7fff if(ram.size() == 0) return; @@ -35,7 +35,7 @@ auto HitachiDSP::bus_write(uint24 addr, uint8 data) -> void { } } -auto HitachiDSP::rom_read(uint24 addr, uint8 data) -> uint8 { +auto HitachiDSP::romRead(uint24 addr, uint8 data) -> uint8 { if(co_active() == hitachidsp.thread || regs.halt) { addr = Bus::mirror(addr, rom.size()); //if(Roms == 2 && mmio.r1f52 == 1 && addr >= (bit::round(rom.size()) >> 1)) return 0x00; @@ -45,32 +45,32 @@ auto HitachiDSP::rom_read(uint24 addr, uint8 data) -> uint8 { return data; } -auto HitachiDSP::rom_write(uint24 addr, uint8 data) -> void { +auto HitachiDSP::romWrite(uint24 addr, uint8 data) -> void { } -auto HitachiDSP::ram_read(uint24 addr, uint8 data) -> uint8 { +auto HitachiDSP::ramRead(uint24 addr, uint8 data) -> uint8 { if(ram.size() == 0) return 0x00; //not open bus return ram.read(Bus::mirror(addr, ram.size()), data); } -auto HitachiDSP::ram_write(uint24 addr, uint8 data) -> void { +auto HitachiDSP::ramWrite(uint24 addr, uint8 data) -> void { if(ram.size() == 0) return; return ram.write(Bus::mirror(addr, ram.size()), data); } -auto HitachiDSP::dram_read(uint24 addr, uint8 data) -> uint8 { +auto HitachiDSP::dramRead(uint24 addr, uint8 data) -> uint8 { addr &= 0xfff; if(addr >= 0xc00) return data; return dataRAM[addr]; } -auto HitachiDSP::dram_write(uint24 addr, uint8 data) -> void { +auto HitachiDSP::dramWrite(uint24 addr, uint8 data) -> void { addr &= 0xfff; if(addr >= 0xc00) return; dataRAM[addr] = data; } -auto HitachiDSP::dsp_read(uint24 addr, uint8) -> uint8 { +auto HitachiDSP::dspRead(uint24 addr, uint8) -> uint8 { addr = 0x7c00 | (addr & 0x03ff); //MMIO @@ -115,7 +115,7 @@ auto HitachiDSP::dsp_read(uint24 addr, uint8) -> uint8 { return 0x00; } -auto HitachiDSP::dsp_write(uint24 addr, uint8 data) -> void { +auto HitachiDSP::dspWrite(uint24 addr, uint8 data) -> void { addr = 0x7c00 | (addr & 0x03ff); //MMIO diff --git a/higan/sfc/coprocessor/icd2/icd2.cpp b/higan/sfc/coprocessor/icd2/icd2.cpp index 7eb3fe93..f317f29d 100644 --- a/higan/sfc/coprocessor/icd2/icd2.cpp +++ b/higan/sfc/coprocessor/icd2/icd2.cpp @@ -24,7 +24,7 @@ auto ICD2::main() -> void { step(GameBoy::system._clocksExecuted); GameBoy::system._clocksExecuted = 0; } else { //DMG halted - audio.coprocessorSample(0, 0); + stream->sample(0, 0); step(1); } synchronizeCPU(); @@ -50,12 +50,11 @@ auto ICD2::unload() -> void { } auto ICD2::power() -> void { - audio.coprocessorEnable(true); - audio.coprocessorFrequency(2 * 1024 * 1024); } -auto ICD2::reset() -> void { +auto ICD2::reset(bool soft) -> void { create(ICD2::Enter, cpu.frequency / 5); + if(!soft) stream = Emulator::audio.createStream(4194304.0 / 2.0); r6003 = 0x00; r6004 = 0xff; diff --git a/higan/sfc/coprocessor/icd2/icd2.hpp b/higan/sfc/coprocessor/icd2/icd2.hpp index a73b2f72..9a619214 100644 --- a/higan/sfc/coprocessor/icd2/icd2.hpp +++ b/higan/sfc/coprocessor/icd2/icd2.hpp @@ -1,6 +1,8 @@ #if defined(SFC_SUPERGAMEBOY) struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread { + shared_pointer stream; + static auto Enter() -> void; auto main() -> void; @@ -8,7 +10,7 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread { auto load() -> void; auto unload() -> void; auto power() -> void; - auto reset() -> void; + auto reset(bool soft = false) -> void; auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; diff --git a/higan/sfc/coprocessor/icd2/interface/interface.cpp b/higan/sfc/coprocessor/icd2/interface/interface.cpp index 0f93a78e..6440abef 100644 --- a/higan/sfc/coprocessor/icd2/interface/interface.cpp +++ b/higan/sfc/coprocessor/icd2/interface/interface.cpp @@ -120,7 +120,7 @@ auto ICD2::videoRefresh(const uint32* data, uint pitch, uint width, uint height) } auto ICD2::audioSample(int16 left, int16 right) -> void { - audio.coprocessorSample(left, right); + stream->sample(left, right); } auto ICD2::inputPoll(uint port, uint device, uint id) -> int16 { diff --git a/higan/sfc/coprocessor/icd2/mmio/mmio.cpp b/higan/sfc/coprocessor/icd2/mmio/mmio.cpp index e735ad53..ffbe4933 100644 --- a/higan/sfc/coprocessor/icd2/mmio/mmio.cpp +++ b/higan/sfc/coprocessor/icd2/mmio/mmio.cpp @@ -54,7 +54,7 @@ auto ICD2::write(uint24 addr, uint8 data) -> void { //d1,d0: 0 = frequency divider (clock rate adjust) if(addr == 0x6003) { if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) { - reset(); + reset(true); } switch(data & 3) { case 0: frequency = cpu.frequency / 4; break; //fast (glitchy, even on real hardware) diff --git a/higan/sfc/coprocessor/mcc/mcc.cpp b/higan/sfc/coprocessor/mcc/mcc.cpp index 6f85da84..7daa64be 100644 --- a/higan/sfc/coprocessor/mcc/mcc.cpp +++ b/higan/sfc/coprocessor/mcc/mcc.cpp @@ -26,7 +26,7 @@ auto MCC::reset() -> void { commit(); } -auto MCC::memory_access(bool write, Memory& memory, uint24 addr, uint8 data) -> uint8 { +auto MCC::memoryAccess(bool write, Memory& memory, uint24 addr, uint8 data) -> uint8 { addr = bus.mirror(addr, memory.size()); if(!write) { return memory.read(addr, data); @@ -37,7 +37,7 @@ auto MCC::memory_access(bool write, Memory& memory, uint24 addr, uint8 data) -> //map address=00-3f,80-bf:8000-ffff mask=0x408000 //map address=40-7d,c0-ff:0000-ffff -auto MCC::mcu_access(bool write, uint24 addr, uint8 data) -> uint8 { +auto MCC::mcuAccess(bool write, uint24 addr, uint8 data) -> uint8 { if(addr < 0x400000) { //note: manifest maps 00-3f,80-bf:8000-ffff mask=0x408000 => 00-3f:0000-ffff //the intention is consistency in pre-decoding as much as possible @@ -50,31 +50,31 @@ auto MCC::mcu_access(bool write, uint24 addr, uint8 data) -> uint8 { if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff if(r07 == 1) { addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); - return memory_access(write, rom, addr, data); + return memoryAccess(write, rom, addr, data); } } if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff if(r08 == 1) { addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); - return memory_access(write, rom, addr, data); + return memoryAccess(write, rom, addr, data); } } if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff - if(r05 == 0) return memory_access(write, ram, addr & 0x0fffff, data); + if(r05 == 0) return memoryAccess(write, ram, addr & 0x0fffff, data); } if((addr & 0xf00000) == 0x500000) { //$50-5f:0000-ffff - if(r06 == 0) return memory_access(write, ram, addr & 0x0fffff, data); + if(r06 == 0) return memoryAccess(write, ram, addr & 0x0fffff, data); } if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff - if(r03 == 1) return memory_access(write, ram, addr & 0x0fffff, data); + if(r03 == 1) return memoryAccess(write, ram, addr & 0x0fffff, data); } if((addr & 0xf80000) == 0x700000) { //$70-77:0000-ffff - return memory_access(write, ram, addr & 0x07ffff, data); + return memoryAccess(write, ram, addr & 0x07ffff, data); } if(((addr & 0x408000) == 0x008000) //$00-3f,80-bf:8000-ffff @@ -82,18 +82,18 @@ auto MCC::mcu_access(bool write, uint24 addr, uint8 data) -> uint8 { ) { if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff); Memory& memory = (r01 == 0 ? (Memory&)bsmemory : (Memory&)ram); - return memory_access(write, memory, addr & 0x7fffff, data); + return memoryAccess(write, memory, addr & 0x7fffff, data); } return 0x00; } -auto MCC::mcu_read(uint24 addr, uint8 data) -> uint8 { - return mcu_access(false, addr, data); +auto MCC::mcuRead(uint24 addr, uint8 data) -> uint8 { + return mcuAccess(false, addr, data); } -auto MCC::mcu_write(uint24 addr, uint8 data) -> void { - mcu_access(true, addr, data); +auto MCC::mcuWrite(uint24 addr, uint8 data) -> void { + mcuAccess(true, addr, data); } auto MCC::read(uint24 addr, uint8 data) -> uint8 { diff --git a/higan/sfc/coprocessor/mcc/mcc.hpp b/higan/sfc/coprocessor/mcc/mcc.hpp index 442b8c30..0558b3cb 100644 --- a/higan/sfc/coprocessor/mcc/mcc.hpp +++ b/higan/sfc/coprocessor/mcc/mcc.hpp @@ -10,11 +10,11 @@ struct MCC { auto power() -> void; auto reset() -> void; - auto memory_access(bool write, Memory& memory, uint24 addr, uint8 data) -> uint8; - auto mcu_access(bool write, uint24 addr, uint8 data) -> uint8; + auto memoryAccess(bool write, Memory& memory, uint24 addr, uint8 data) -> uint8; + auto mcuAccess(bool write, uint24 addr, uint8 data) -> uint8; - auto mcu_read(uint24 addr, uint8 data) -> uint8; - auto mcu_write(uint24 addr, uint8 data) -> void; + auto mcuRead(uint24 addr, uint8 data) -> uint8; + auto mcuWrite(uint24 addr, uint8 data) -> void; auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; diff --git a/higan/sfc/coprocessor/msu1/msu1.cpp b/higan/sfc/coprocessor/msu1/msu1.cpp index 7b671924..05ebbaf5 100644 --- a/higan/sfc/coprocessor/msu1/msu1.cpp +++ b/higan/sfc/coprocessor/msu1/msu1.cpp @@ -38,7 +38,7 @@ auto MSU1::main() -> void { right = sclamp<16>(rchannel); if(dsp.mute()) left = 0, right = 0; - audio.coprocessorSample(left, right); + stream->sample(left, right); step(1); synchronizeCPU(); } @@ -55,12 +55,11 @@ auto MSU1::unload() -> void { } auto MSU1::power() -> void { - audio.coprocessorEnable(true); - audio.coprocessorFrequency(44100.0); } auto MSU1::reset() -> void { create(MSU1::Enter, 44100); + stream = Emulator::audio.createStream(44100.0); mmio.dataSeekOffset = 0; mmio.dataReadOffset = 0; @@ -119,7 +118,7 @@ auto MSU1::audioOpen() -> void { mmio.audioError = true; } -auto MSU1::mmioRead(uint24 addr, uint8) -> uint8 { +auto MSU1::read(uint24 addr, uint8) -> uint8 { cpu.synchronizeCoprocessors(); addr = 0x2000 | (addr & 7); @@ -147,7 +146,7 @@ auto MSU1::mmioRead(uint24 addr, uint8) -> uint8 { } } -auto MSU1::mmioWrite(uint24 addr, uint8 data) -> void { +auto MSU1::write(uint24 addr, uint8 data) -> void { cpu.synchronizeCoprocessors(); addr = 0x2000 | (addr & 7); diff --git a/higan/sfc/coprocessor/msu1/msu1.hpp b/higan/sfc/coprocessor/msu1/msu1.hpp index bd24cf7e..899a0309 100644 --- a/higan/sfc/coprocessor/msu1/msu1.hpp +++ b/higan/sfc/coprocessor/msu1/msu1.hpp @@ -1,4 +1,6 @@ struct MSU1 : Cothread { + shared_pointer stream; + static auto Enter() -> void; auto main() -> void; auto init() -> void; @@ -10,8 +12,8 @@ struct MSU1 : Cothread { auto dataOpen() -> void; auto audioOpen() -> void; - auto mmioRead(uint24 addr, uint8 data) -> uint8; - auto mmioWrite(uint24 addr, uint8 data) -> void; + auto read(uint24 addr, uint8 data) -> uint8; + auto write(uint24 addr, uint8 data) -> void; auto serialize(serializer&) -> void; diff --git a/higan/sfc/coprocessor/nss/nss.cpp b/higan/sfc/coprocessor/nss/nss.cpp index 35db10ef..3274215e 100644 --- a/higan/sfc/coprocessor/nss/nss.cpp +++ b/higan/sfc/coprocessor/nss/nss.cpp @@ -19,7 +19,7 @@ auto NSS::power() -> void { auto NSS::reset() -> void { } -auto NSS::set_dip(uint16 dip) -> void { +auto NSS::setDip(uint16 dip) -> void { this->dip = dip; } diff --git a/higan/sfc/coprocessor/nss/nss.hpp b/higan/sfc/coprocessor/nss/nss.hpp index 3a2c7255..cbdb0cd1 100644 --- a/higan/sfc/coprocessor/nss/nss.hpp +++ b/higan/sfc/coprocessor/nss/nss.hpp @@ -5,7 +5,7 @@ struct NSS { auto power() -> void; auto reset() -> void; - auto set_dip(uint16 dip) -> void; + auto setDip(uint16 dip) -> void; auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; diff --git a/higan/sfc/coprocessor/sharprtc/memory.cpp b/higan/sfc/coprocessor/sharprtc/memory.cpp index f3e66ec8..3803f1ec 100644 --- a/higan/sfc/coprocessor/sharprtc/memory.cpp +++ b/higan/sfc/coprocessor/sharprtc/memory.cpp @@ -1,4 +1,4 @@ -auto SharpRTC::rtc_read(uint4 addr) -> uint4 { +auto SharpRTC::rtcRead(uint4 addr) -> uint4 { switch(addr) { case 0: return second % 10; case 1: return second / 10; @@ -17,7 +17,7 @@ auto SharpRTC::rtc_read(uint4 addr) -> uint4 { } } -auto SharpRTC::rtc_write(uint4 addr, uint4 data) -> void { +auto SharpRTC::rtcWrite(uint4 addr, uint4 data) -> void { switch(addr) { case 0: second = second / 10 * 10 + data; break; case 1: second = data * 10 + second % 10; break; @@ -37,8 +37,8 @@ auto SharpRTC::rtc_write(uint4 addr, uint4 data) -> void { auto SharpRTC::load(const uint8* data) -> void { for(auto byte : range(8)) { - rtc_write(byte * 2 + 0, data[byte] >> 0); - rtc_write(byte * 2 + 1, data[byte] >> 4); + rtcWrite(byte * 2 + 0, data[byte] >> 0); + rtcWrite(byte * 2 + 1, data[byte] >> 4); } uint64 timestamp = 0; @@ -47,16 +47,16 @@ auto SharpRTC::load(const uint8* data) -> void { } uint64 diff = (uint64)time(0) - timestamp; - while(diff >= 60 * 60 * 24) { tick_day(); diff -= 60 * 60 * 24; } - while(diff >= 60 * 60) { tick_hour(); diff -= 60 * 60; } - while(diff >= 60) { tick_minute(); diff -= 60; } - while(diff--) tick_second(); + while(diff >= 60 * 60 * 24) { tickDay(); diff -= 60 * 60 * 24; } + while(diff >= 60 * 60) { tickHour(); diff -= 60 * 60; } + while(diff >= 60) { tickMinute(); diff -= 60; } + while(diff--) tickSecond(); } auto SharpRTC::save(uint8* data) -> void { for(auto byte : range(8)) { - data[byte] = rtc_read(byte * 2 + 0) << 0; - data[byte] |= rtc_read(byte * 2 + 1) << 4; + data[byte] = rtcRead(byte * 2 + 0) << 0; + data[byte] |= rtcRead(byte * 2 + 1) << 4; } uint64 timestamp = (uint64)time(nullptr); diff --git a/higan/sfc/coprocessor/sharprtc/serialization.cpp b/higan/sfc/coprocessor/sharprtc/serialization.cpp index 0a6d3179..d4666a19 100644 --- a/higan/sfc/coprocessor/sharprtc/serialization.cpp +++ b/higan/sfc/coprocessor/sharprtc/serialization.cpp @@ -1,8 +1,8 @@ auto SharpRTC::serialize(serializer& s) -> void { Thread::serialize(s); - s.integer((uint&)rtc_state); - s.integer(rtc_index); + s.integer((uint&)state); + s.integer(index); s.integer(second); s.integer(minute); diff --git a/higan/sfc/coprocessor/sharprtc/sharprtc.cpp b/higan/sfc/coprocessor/sharprtc/sharprtc.cpp index 3b6d202f..6dc86b42 100644 --- a/higan/sfc/coprocessor/sharprtc/sharprtc.cpp +++ b/higan/sfc/coprocessor/sharprtc/sharprtc.cpp @@ -12,7 +12,7 @@ auto SharpRTC::Enter() -> void { } auto SharpRTC::main() -> void { - tick_second(); + tickSecond(); step(1); synchronizeCPU(); @@ -42,8 +42,8 @@ auto SharpRTC::power() -> void { auto SharpRTC::reset() -> void { create(SharpRTC::Enter, 1); - rtc_state = State::Read; - rtc_index = -1; + state = State::Read; + index = -1; } auto SharpRTC::sync() -> void { @@ -63,16 +63,16 @@ auto SharpRTC::read(uint24 addr, uint8 data) -> uint8 { addr &= 1; if(addr == 0) { - if(rtc_state != State::Read) return 0; + if(state != State::Read) return 0; - if(rtc_index < 0) { - rtc_index++; + if(index < 0) { + index++; return 15; - } else if(rtc_index > 12) { - rtc_index = -1; + } else if(index > 12) { + index = -1; return 15; } else { - return rtc_read(rtc_index++); + return rtcRead(index++); } } @@ -84,25 +84,25 @@ auto SharpRTC::write(uint24 addr, uint8 data) -> void { if(addr == 1) { if(data == 0x0d) { - rtc_state = State::Read; - rtc_index = -1; + state = State::Read; + index = -1; return; } if(data == 0x0e) { - rtc_state = State::Command; + state = State::Command; return; } if(data == 0x0f) return; //unknown behavior - if(rtc_state == State::Command) { + if(state == State::Command) { if(data == 0) { - rtc_state = State::Write; - rtc_index = 0; + state = State::Write; + index = 0; } else if(data == 4) { - rtc_state = State::Ready; - rtc_index = -1; + state = State::Ready; + index = -1; //reset time second = 0; minute = 0; @@ -113,17 +113,17 @@ auto SharpRTC::write(uint24 addr, uint8 data) -> void { weekday = 0; } else { //unknown behavior - rtc_state = State::Ready; + state = State::Ready; } return; } - if(rtc_state == State::Write) { - if(rtc_index >= 0 && rtc_index < 12) { - rtc_write(rtc_index++, data); - if(rtc_index == 12) { + if(state == State::Write) { + if(index >= 0 && index < 12) { + rtcWrite(index++, data); + if(index == 12) { //day of week is automatically calculated and written - weekday = calculate_weekday(1000 + year, month, day); + weekday = calculateWeekday(1000 + year, month, day); } } return; diff --git a/higan/sfc/coprocessor/sharprtc/sharprtc.hpp b/higan/sfc/coprocessor/sharprtc/sharprtc.hpp index 50737363..20153b52 100644 --- a/higan/sfc/coprocessor/sharprtc/sharprtc.hpp +++ b/higan/sfc/coprocessor/sharprtc/sharprtc.hpp @@ -14,8 +14,8 @@ struct SharpRTC : Cothread { auto serialize(serializer&) -> void; - enum class State : uint { Ready, Command, Read, Write } rtc_state; - int rtc_index; + enum class State : uint { Ready, Command, Read, Write } state; + int index; uint second; uint minute; @@ -26,22 +26,22 @@ struct SharpRTC : Cothread { uint weekday; //memory.cpp - auto rtc_read(uint4 addr) -> uint4; - auto rtc_write(uint4 addr, uint4 data) -> void; + auto rtcRead(uint4 addr) -> uint4; + auto rtcWrite(uint4 addr, uint4 data) -> void; auto load(const uint8* data) -> void; auto save(uint8* data) -> void; //time.cpp - static const uint daysinmonth[12]; - auto tick_second() -> void; - auto tick_minute() -> void; - auto tick_hour() -> void; - auto tick_day() -> void; - auto tick_month() -> void; - auto tick_year() -> void; + static const uint daysInMonth[12]; + auto tickSecond() -> void; + auto tickMinute() -> void; + auto tickHour() -> void; + auto tickDay() -> void; + auto tickMonth() -> void; + auto tickYear() -> void; - auto calculate_weekday(uint year, uint month, uint day) -> uint; + auto calculateWeekday(uint year, uint month, uint day) -> uint; }; extern SharpRTC sharprtc; diff --git a/higan/sfc/coprocessor/sharprtc/time.cpp b/higan/sfc/coprocessor/sharprtc/time.cpp index 3fb05327..be7355df 100644 --- a/higan/sfc/coprocessor/sharprtc/time.cpp +++ b/higan/sfc/coprocessor/sharprtc/time.cpp @@ -1,28 +1,28 @@ -const uint SharpRTC::daysinmonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +const uint SharpRTC::daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -auto SharpRTC::tick_second() -> void { +auto SharpRTC::tickSecond() -> void { if(++second < 60) return; second = 0; - tick_minute(); + tickMinute(); } -auto SharpRTC::tick_minute() -> void { +auto SharpRTC::tickMinute() -> void { if(++minute < 60) return; minute = 0; - tick_hour(); + tickHour(); } -auto SharpRTC::tick_hour() -> void { +auto SharpRTC::tickHour() -> void { if(++hour < 24) return; hour = 0; - tick_day(); + tickDay(); } -auto SharpRTC::tick_day() -> void { - uint days = daysinmonth[month % 12]; +auto SharpRTC::tickDay() -> void { + uint days = daysInMonth[(month - 1) % 12]; //add one day in February for leap years - if(month == 1) { + if(month == 2) { if(year % 400 == 0) days++; else if(year % 100 == 0); else if(year % 4 == 0) days++; @@ -30,16 +30,16 @@ auto SharpRTC::tick_day() -> void { if(day++ < days) return; day = 1; - tick_month(); + tickMonth(); } -auto SharpRTC::tick_month() -> void { +auto SharpRTC::tickMonth() -> void { if(month++ < 12) return; month = 1; - tick_year(); + tickYear(); } -auto SharpRTC::tick_year() -> void { +auto SharpRTC::tickYear() -> void { year++; year = (uint12)year; } @@ -47,7 +47,7 @@ auto SharpRTC::tick_year() -> void { //returns day of week for specified date //eg 0 = Sunday, 1 = Monday, ... 6 = Saturday //usage: calculate_weekday(2008, 1, 1) returns weekday of January 1st, 2008 -auto SharpRTC::calculate_weekday(uint year, uint month, uint day) -> uint { +auto SharpRTC::calculateWeekday(uint year, uint month, uint day) -> uint { uint y = 1000, m = 1; //SharpRTC epoch is 1000-01-01 uint sum = 0; //number of days passed since epoch @@ -66,7 +66,7 @@ auto SharpRTC::calculate_weekday(uint year, uint month, uint day) -> uint { } while(m < month) { - uint days = daysinmonth[m - 1]; + uint days = daysInMonth[(m - 1) % 12]; bool leapyearmonth = false; if(days == 28) { if(y % 4 == 0) { diff --git a/higan/sfc/dsp/audio.cpp b/higan/sfc/dsp/audio.cpp deleted file mode 100644 index b167bcb3..00000000 --- a/higan/sfc/dsp/audio.cpp +++ /dev/null @@ -1,46 +0,0 @@ -Audio audio; - -auto Audio::coprocessorEnable(bool enable) -> void { - mixer.clear(); - mixerEnable = enable; - dsp.read = dsp.write = 0; - mix.read = mix.write = 0; -} - -auto Audio::coprocessorFrequency(double frequency) -> void { - mixer.setFrequency(frequency); - mixer.setResampler(nall::DSP::ResampleEngine::Sinc); - mixer.setResamplerFrequency(system.apuFrequency() / 768.0); -} - -auto Audio::sample(int16 left, int16 right) -> void { - if(!mixerEnable) return interface->audioSample(left, right); - - dsp.left[dsp.write] = left; - dsp.right[dsp.write] = right; - dsp.write++; - flush(); -} - -auto Audio::coprocessorSample(int16 left, int16 right) -> void { - int samples[] = {left, right}; - mixer.sample(samples); - while(mixer.pending()) { - mixer.read(samples); - mix.left[mix.write] = samples[0]; - mix.right[mix.write] = samples[1]; - mix.write++; - flush(); - } -} - -auto Audio::flush() -> void { - while(dsp.read != dsp.write && mix.read != mix.write) { - interface->audioSample( - sclamp<16>(dsp.left[dsp.read] + mix.left[mix.read]), - sclamp<16>(dsp.right[dsp.read] + mix.right[mix.read]) - ); - dsp.read++; - mix.read++; - } -} diff --git a/higan/sfc/dsp/audio.hpp b/higan/sfc/dsp/audio.hpp deleted file mode 100644 index 14188d7a..00000000 --- a/higan/sfc/dsp/audio.hpp +++ /dev/null @@ -1,20 +0,0 @@ -struct Audio { - auto sample(int16 left, int16 right) -> void; - - auto coprocessorEnable(bool enable) -> void; - auto coprocessorFrequency(double frequency) -> void; - auto coprocessorSample(int16 left, int16 right) -> void; - auto flush() -> void; - -private: - nall::DSP mixer; - bool mixerEnable = false; - struct Buffer { - int16 left[256]; - int16 right[256]; - uint8 read; - uint8 write; - } dsp, mix; -}; - -extern Audio audio; diff --git a/higan/sfc/dsp/dsp.cpp b/higan/sfc/dsp/dsp.cpp index 99712c76..84b96bf8 100644 --- a/higan/sfc/dsp/dsp.cpp +++ b/higan/sfc/dsp/dsp.cpp @@ -3,7 +3,6 @@ namespace SuperFamicom { DSP dsp; -#include "audio.cpp" #define REG(n) state.regs[n] #define VREG(n) state.regs[v.vidx + n] @@ -238,12 +237,11 @@ auto DSP::power() -> void { voice[n].vbit = 1 << n; voice[n].vidx = n * 0x10; } - - audio.coprocessorEnable(false); } auto DSP::reset() -> void { create(Enter, system.apuFrequency()); + stream = Emulator::audio.createStream(system.apuFrequency() / 768.0); REG(FLG) = 0xe0; state.noise = 0x4000; diff --git a/higan/sfc/dsp/dsp.hpp b/higan/sfc/dsp/dsp.hpp index 665e36a5..747f0941 100644 --- a/higan/sfc/dsp/dsp.hpp +++ b/higan/sfc/dsp/dsp.hpp @@ -1,8 +1,8 @@ //Sony CXD1222Q-1 -#include "audio.hpp" - struct DSP : Thread { + shared_pointer stream; + DSP(); alwaysinline auto step(uint clocks) -> void; diff --git a/higan/sfc/dsp/echo.cpp b/higan/sfc/dsp/echo.cpp index c31fd295..b8f3e751 100644 --- a/higan/sfc/dsp/echo.cpp +++ b/higan/sfc/dsp/echo.cpp @@ -103,7 +103,7 @@ auto DSP::echo27() -> void { } //output sample to DAC - audio.sample(outl, outr); + stream->sample(outl, outr); } auto DSP::echo28() -> void { diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index ee3b626f..a8c0e9ae 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -153,6 +153,36 @@ auto Interface::videoFrequency() -> double { } } +auto Interface::videoColors() -> uint32 { + return 1 << 19; +} + +auto Interface::videoColor(uint32 color) -> uint64 { + uint r = color.bits( 0, 4); + uint g = color.bits( 5, 9); + uint b = color.bits(10,14); + uint l = color.bits(15,18); + + double L = (1.0 + l) / 16.0 * (l ? 1.0 : 0.5); + uint64 R = L * image::normalize(r, 5, 16); + uint64 G = L * image::normalize(g, 5, 16); + uint64 B = L * image::normalize(b, 5, 16); + + if(settings.colorEmulation) { + static const uint8 gammaRamp[32] = { + 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, + 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, + 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, + 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, + }; + R = L * gammaRamp[r] * 0x0101; + G = L * gammaRamp[g] * 0x0101; + B = L * gammaRamp[b] * 0x0101; + } + + return R << 32 | G << 16 | B << 0; +} + auto Interface::audioFrequency() -> double { return system.apuFrequency() / 768.0; } diff --git a/higan/sfc/interface/interface.hpp b/higan/sfc/interface/interface.hpp index 3d9995a4..f24663ec 100644 --- a/higan/sfc/interface/interface.hpp +++ b/higan/sfc/interface/interface.hpp @@ -94,6 +94,8 @@ struct Interface : Emulator::Interface { auto manifest() -> string; auto title() -> string; auto videoFrequency() -> double; + auto videoColors() -> uint32; + auto videoColor(uint32 color) -> uint64; auto audioFrequency() -> double; auto loaded() -> bool; diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index 1fa24d51..5ef771f7 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -213,12 +213,6 @@ auto PPU::scanline() -> void { screen.scanline(); if(vcounter() == 241) { - auto output = this->output; - if(!overscan()) output -= 14 * 512; - auto pitch = 1024 >> interlace(); - auto width = 512; - auto height = !interlace() ? 240 : 480; - Emulator::video.refresh(output, pitch * sizeof(uint32), width, height); scheduler.exit(Scheduler::Event::Frame); } } @@ -230,4 +224,13 @@ auto PPU::frame() -> void { display.overscan = regs.overscan; } +auto PPU::refresh() -> void { + auto output = this->output; + if(!overscan()) output -= 14 * 512; + auto pitch = 1024 >> interlace(); + auto width = 512; + auto height = !interlace() ? 240 : 480; + Emulator::video.refresh(output, pitch * sizeof(uint32), width, height); +} + } diff --git a/higan/sfc/ppu/ppu.hpp b/higan/sfc/ppu/ppu.hpp index 393cd5fc..4bdaf20b 100644 --- a/higan/sfc/ppu/ppu.hpp +++ b/higan/sfc/ppu/ppu.hpp @@ -50,6 +50,7 @@ privileged: auto scanline() -> void; auto frame() -> void; + auto refresh() -> void; struct Registers { uint8 ppu1_mdr; @@ -152,7 +153,7 @@ privileged: friend class PPU::Sprite; friend class PPU::Window; friend class PPU::Screen; - friend class Video; + friend class Scheduler; struct Debugger { hook void> vram_read; diff --git a/higan/sfc/scheduler/scheduler.cpp b/higan/sfc/scheduler/scheduler.cpp index 7f9d327e..b02987c2 100644 --- a/higan/sfc/scheduler/scheduler.cpp +++ b/higan/sfc/scheduler/scheduler.cpp @@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event { mode = mode_; host = co_active(); co_switch(resume); + if(event == Event::Frame) ppu.refresh(); return event; } diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index 87aecc83..0afc409b 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -31,7 +31,7 @@ namespace SuperFamicom { auto create(auto (*entrypoint)() -> void, uint frequency) -> void { if(thread) co_delete(thread); - thread = co_create(262'144 * sizeof(void*), entrypoint); + thread = co_create(65'536 * sizeof(void*), entrypoint); this->frequency = frequency; clock = 0; } diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 67cb2c01..01467661 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -91,7 +91,6 @@ auto System::load() -> void { if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load(); serializeInit(); - configureVideo(); _loaded = true; } @@ -152,6 +151,14 @@ auto System::power() -> void { } auto System::reset() -> void { + Emulator::video.reset(); + Emulator::video.setInterface(interface); + configureVideoPalette(); + configureVideoEffects(); + + Emulator::audio.reset(); + Emulator::audio.setInterface(interface); + cpu.reset(); smp.reset(); dsp.reset(); diff --git a/higan/sfc/system/system.hpp b/higan/sfc/system/system.hpp index cc1bf49b..cbb79bdf 100644 --- a/higan/sfc/system/system.hpp +++ b/higan/sfc/system/system.hpp @@ -21,7 +21,6 @@ struct System { auto reset() -> void; //video.cpp - auto configureVideo() -> void; auto configureVideoPalette() -> void; auto configureVideoEffects() -> void; diff --git a/higan/sfc/system/video.cpp b/higan/sfc/system/video.cpp index e2c88c34..f537903b 100644 --- a/higan/sfc/system/video.cpp +++ b/higan/sfc/system/video.cpp @@ -1,36 +1,5 @@ -auto System::configureVideo() -> void { - Emulator::video.reset(); - Emulator::video.setInterface(interface); - configureVideoPalette(); - configureVideoEffects(); -} - auto System::configureVideoPalette() -> void { - Emulator::video.setPalette(1 << 19, [&](uint32 color) -> uint64 { - uint r = color.bits( 0, 4); - uint g = color.bits( 5, 9); - uint b = color.bits(10,14); - uint l = color.bits(15,18); - - double L = (1.0 + l) / 16.0 * (l ? 1.0 : 0.5); - uint64 R = L * image::normalize(r, 5, 16); - uint64 G = L * image::normalize(g, 5, 16); - uint64 B = L * image::normalize(b, 5, 16); - - if(settings.colorEmulation) { - static const uint8 gammaRamp[32] = { - 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, - 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, - 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, - 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, - }; - R = L * gammaRamp[r] * 0x0101; - G = L * gammaRamp[g] * 0x0101; - B = L * gammaRamp[b] * 0x0101; - } - - return R << 32 | G << 16 | B << 0; - }); + Emulator::video.setPalette(); } auto System::configureVideoEffects() -> void { diff --git a/higan/target-tomoko/configuration/configuration.cpp b/higan/target-tomoko/configuration/configuration.cpp index 078067cc..887cffcb 100644 --- a/higan/target-tomoko/configuration/configuration.cpp +++ b/higan/target-tomoko/configuration/configuration.cpp @@ -23,6 +23,10 @@ Settings::Settings() { set("Video/ColorEmulation", true); set("Video/ScanlineEmulation", false); + set("Video/Saturation", 100); + set("Video/Gamma", 100); + set("Video/Luminance", 100); + set("Video/Overscan/Mask", false); set("Video/Overscan/Horizontal", 8); set("Video/Overscan/Vertical", 8); @@ -33,6 +37,9 @@ Settings::Settings() { set("Audio/Synchronize", true); set("Audio/Mute", false); set("Audio/Volume", 100); + set("Audio/Balance", 50); + set("Audio/Reverb/Delay", 0); + set("Audio/Reverb/Level", 0); set("Audio/Latency", 60); set("Audio/Resampler", "Sinc"); diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index 1cb6505f..2b580513 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -99,7 +99,7 @@ Presentation::Presentation() { }); muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] { settings["Audio/Mute"].setValue(muteAudio.checked()); - program->updateAudioVolume(); + program->updateAudioEffects(); }); showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] { settings["UserInterface/ShowStatusBar"].setValue(showStatusBar.checked()); diff --git a/higan/target-tomoko/program/interface.cpp b/higan/target-tomoko/program/interface.cpp index 04a8c247..b0c8ba03 100644 --- a/higan/target-tomoko/program/interface.cpp +++ b/higan/target-tomoko/program/interface.cpp @@ -90,12 +90,13 @@ auto Program::videoRefresh(const uint32* data, uint pitch, uint width, uint heig } auto Program::audioSample(int16 lsample, int16 rsample) -> void { - int samples[] = {lsample, rsample}; - dsp.sample(samples); - while(dsp.pending()) { - dsp.read(samples); - audio->sample(samples[0], samples[1]); - } + audio->sample(lsample, rsample); +//int samples[] = {lsample, rsample}; +//dsp.sample(samples); +//while(dsp.pending()) { +// dsp.read(samples); +// audio->sample(samples[0], samples[1]); +//} } auto Program::inputPoll(uint port, uint device, uint input) -> int16 { diff --git a/higan/target-tomoko/program/media.cpp b/higan/target-tomoko/program/media.cpp index 870ad26c..028ab820 100644 --- a/higan/target-tomoko/program/media.cpp +++ b/higan/target-tomoko/program/media.cpp @@ -21,10 +21,13 @@ auto Program::loadMedia(Emulator::Interface& interface, Emulator::Interface::Med folderPaths.append(location); //note: the order of operations in this block of code is critical + Emulator::audio.reset(); + Emulator::audio.setFrequency(audio->get(Audio::Frequency).get()); emulator = &interface; connectDevices(); emulator->load(media.id); - updateAudio(); + updateAudioDriver(); + updateAudioEffects(); emulator->power(); presentation->resizeViewport(); diff --git a/higan/target-tomoko/program/program.cpp b/higan/target-tomoko/program/program.cpp index 2318ce86..68f247a4 100644 --- a/higan/target-tomoko/program/program.cpp +++ b/higan/target-tomoko/program/program.cpp @@ -41,12 +41,6 @@ Program::Program(lstring args) { input->onChange({&InputManager::onChange, &inputManager()}); if(!input->init()) input = Input::create("None"); - dsp.setPrecision(16); - dsp.setBalance(0.0); - dsp.setFrequency(44100); - dsp.setResampler(DSP::ResampleEngine::Sinc); - dsp.setResamplerFrequency(audio->get(Audio::Frequency).get()); - presentation->drawSplashScreen(); new InputManager; @@ -55,7 +49,8 @@ Program::Program(lstring args) { new ToolsManager; updateVideoShader(); - updateAudio(); + updateAudioDriver(); + updateAudioEffects(); args.takeFirst(); //ignore program location in argument parsing for(auto& argument : args) { diff --git a/higan/target-tomoko/program/program.hpp b/higan/target-tomoko/program/program.hpp index f7e2d5d8..f00bbfb5 100644 --- a/higan/target-tomoko/program/program.hpp +++ b/higan/target-tomoko/program/program.hpp @@ -33,13 +33,11 @@ struct Program : Emulator::Interface::Bind { auto connectDevices() -> void; auto showMessage(const string& text) -> void; auto updateStatusText() -> void; + auto updateVideoPalette() -> void; auto updateVideoShader() -> void; - auto updateAudio() -> void; - auto updateAudioMode() -> void; - auto updateAudioVolume() -> void; - auto updateDSP() -> void; + auto updateAudioDriver() -> void; + auto updateAudioEffects() -> void; - DSP dsp; bool pause = false; vector emulators; diff --git a/higan/target-tomoko/program/utility.cpp b/higan/target-tomoko/program/utility.cpp index e32fdef3..a258cb81 100644 --- a/higan/target-tomoko/program/utility.cpp +++ b/higan/target-tomoko/program/utility.cpp @@ -49,6 +49,16 @@ auto Program::updateStatusText() -> void { } } +auto Program::updateVideoPalette() -> void { + double saturation = settings["Video/Saturation"].natural() / 100.0; + double gamma = settings["Video/Gamma"].natural() / 100.0; + double luminance = settings["Video/Luminance"].natural() / 100.0; + Emulator::video.setSaturation(saturation); + Emulator::video.setGamma(gamma); + Emulator::video.setLuminance(luminance); + Emulator::video.setPalette(); +} + auto Program::updateVideoShader() -> void { if(settings["Video/Driver"].text() == "OpenGL" && settings["Video/Shader"].text() != "None" @@ -63,28 +73,23 @@ auto Program::updateVideoShader() -> void { } } -auto Program::updateAudio() -> void { +auto Program::updateAudioDriver() -> void { if(!audio) return; audio->clear(); - audio->set(Audio::Latency, (uint)settings["Audio/Latency"].natural()); - if(settings["Audio/Resampler"].text() == "Linear" ) dsp.setResampler(DSP::ResampleEngine::Linear); - if(settings["Audio/Resampler"].text() == "Hermite") dsp.setResampler(DSP::ResampleEngine::Hermite); - if(settings["Audio/Resampler"].text() == "Sinc" ) dsp.setResampler(DSP::ResampleEngine::Sinc); - dsp.setResamplerFrequency(audio->get(Audio::Frequency).get()); - updateAudioMode(); - updateAudioVolume(); - updateDSP(); -} - -auto Program::updateAudioMode() -> void { audio->set(Audio::Exclusive, settings["Audio/Exclusive"].boolean()); + audio->set(Audio::Latency, (uint)settings["Audio/Latency"].natural()); } -auto Program::updateAudioVolume() -> void { - dsp.setVolume(settings["Audio/Mute"].boolean() ? 0.0 : settings["Audio/Volume"].natural() * 0.01); -} +auto Program::updateAudioEffects() -> void { + auto volume = settings["Audio/Mute"].boolean() ? 0.0 : settings["Audio/Volume"].natural() * 0.01; + Emulator::audio.setVolume(volume); -auto Program::updateDSP() -> void { - if(!emulator) return; - return dsp.setFrequency(emulator->audioFrequency()); + auto balance = max(-1.0, min(1.0, (settings["Audio/Balance"].integer() - 50) / 50.0)); + Emulator::audio.setBalance(balance); + + auto reverbDelay = settings["Audio/Reverb/Delay"].natural(); + Emulator::audio.setReverbDelay(reverbDelay); + + auto reverbLevel = settings["Audio/Reverb/Level"].natural() / 100.0; + Emulator::audio.setReverbLevel(reverbLevel); } diff --git a/higan/target-tomoko/settings/audio.cpp b/higan/target-tomoko/settings/audio.cpp index c2c0ea26..5067c5e3 100644 --- a/higan/target-tomoko/settings/audio.cpp +++ b/higan/target-tomoko/settings/audio.cpp @@ -4,10 +4,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { layout.setMargin(5); - frequencyLabel.setText("Frequency:"); - auto frequencyValue = audio->get(Audio::Frequency).get(); - frequencyCombo.append(ComboButtonItem().setText({frequencyValue, "hz"})); - frequencyCombo.setEnabled(false); //not user configurable + driverLabel.setFont(Font().setBold()).setText("Driver Settings"); latencyLabel.setText("Latency:"); latencyCombo.append(ComboButtonItem().setText("0ms")); @@ -24,27 +21,44 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { case 80: latencyCombo.item(4)->setSelected(); break; case 100: latencyCombo.item(5)->setSelected(); break; } - latencyCombo.onChange([&] { update(); }); + latencyCombo.onChange([&] { updateDriver(); }); + + frequencyLabel.setText("Frequency:"); + auto frequencyValue = audio->get(Audio::Frequency).get(); + frequencyCombo.append(ComboButtonItem().setText({frequencyValue, "hz"})); + frequencyCombo.setEnabled(false); resamplerLabel.setText("Resampler:"); - resamplerCombo.append(ComboButtonItem().setText("Linear")); - resamplerCombo.append(ComboButtonItem().setText("Hermite")); resamplerCombo.append(ComboButtonItem().setText("Sinc")); - if(settings["Audio/Resampler"].text() == "Linear" ) resamplerCombo.item(0)->setSelected(); - if(settings["Audio/Resampler"].text() == "Hermite") resamplerCombo.item(1)->setSelected(); - if(settings["Audio/Resampler"].text() == "Sinc" ) resamplerCombo.item(2)->setSelected(); - resamplerCombo.onChange([&] { update(); }); + resamplerCombo.setEnabled(false); + + exclusiveMode.setText("Exclusive Mode"); + exclusiveMode.setChecked(settings["Audio/Exclusive"].boolean()).onToggle([&] { updateDriver(); }); + if(!audio->cap(Audio::Exclusive)) exclusiveMode.remove(); + + effectsLabel.setFont(Font().setBold()).setText("Effects"); volumeLabel.setText("Volume:"); - volumeSlider.setLength(201).setPosition(settings["Audio/Volume"].natural()).onChange([&] { updateVolume(); }); + volumeValue.setAlignment(0.5); + volumeSlider.setLength(201).setPosition(settings["Audio/Volume"].natural()).onChange([&] { updateEffects(); }); - exclusiveMode.setText("Exclusive Mode").setVisible(audio->cap(Audio::Exclusive)); - exclusiveMode.setChecked(settings["Audio/Exclusive"].boolean()).onToggle([&] { updateMode(); }); + balanceLabel.setText("Balance:"); + balanceValue.setAlignment(0.5); + balanceSlider.setLength(101).setPosition(settings["Audio/Balance"].natural()).onChange([&] { updateEffects(); }); - update(); + reverbDelayLabel.setText("Reverb Delay:"); + reverbDelayValue.setAlignment(0.5); + reverbDelaySlider.setLength(201).setPosition(settings["Audio/Reverb/Delay"].natural()).onChange([&] { updateEffects(); }); + + reverbLevelLabel.setText("Reverb Level:"); + reverbLevelValue.setAlignment(0.5); + reverbLevelSlider.setLength(101).setPosition(settings["Audio/Reverb/Level"].natural()).onChange([&] { updateEffects(); }); + + updateDriver(); + updateEffects(); } -auto AudioSettings::update() -> void { +auto AudioSettings::updateDriver() -> void { if(auto item = latencyCombo.selected()) { uint latency = 60; if(item->offset() == 0) latency = 0; @@ -55,24 +69,23 @@ auto AudioSettings::update() -> void { if(item->offset() == 5) latency = 100; settings["Audio/Latency"].setValue(latency); } - if(auto item = resamplerCombo.selected()) { - string resampler = "Sinc"; - if(item->offset() == 0) resampler = "Linear"; - if(item->offset() == 1) resampler = "Hermite"; - if(item->offset() == 2) resampler = "Sinc"; - settings["Audio/Resampler"].setValue(resampler); - } - updateVolume(); - updateMode(); -} -auto AudioSettings::updateMode() -> void { settings["Audio/Exclusive"].setValue(exclusiveMode.checked()); - program->updateAudioMode(); + program->updateAudioDriver(); } -auto AudioSettings::updateVolume() -> void { +auto AudioSettings::updateEffects() -> void { settings["Audio/Volume"].setValue(volumeSlider.position()); volumeValue.setText({volumeSlider.position(), "%"}); - program->updateAudioVolume(); + + settings["Audio/Balance"].setValue(balanceSlider.position()); + balanceValue.setText({balanceSlider.position(), "%"}); + + settings["Audio/Reverb/Delay"].setValue(reverbDelaySlider.position()); + reverbDelayValue.setText({reverbDelaySlider.position(), "ms"}); + + settings["Audio/Reverb/Level"].setValue(reverbLevelSlider.position()); + reverbLevelValue.setText({reverbLevelSlider.position(), "%"}); + + program->updateAudioEffects(); } diff --git a/higan/target-tomoko/settings/settings.hpp b/higan/target-tomoko/settings/settings.hpp index cb6a64f9..ef690936 100644 --- a/higan/target-tomoko/settings/settings.hpp +++ b/higan/target-tomoko/settings/settings.hpp @@ -2,39 +2,66 @@ struct VideoSettings : TabFrameItem { VideoSettings(TabFrame*); VerticalLayout layout{this}; + Label colorAdjustmentLabel{&layout, Size{~0, 0}}; + HorizontalLayout saturationLayout{&layout, Size{~0, 0}}; + Label saturationLabel{&saturationLayout, Size{80, 0}}; + Label saturationValue{&saturationLayout, Size{50, 0}}; + HorizontalSlider saturationSlider{&saturationLayout, Size{~0, 0}}; + HorizontalLayout gammaLayout{&layout, Size{~0, 0}}; + Label gammaLabel{&gammaLayout, Size{80, 0}}; + Label gammaValue{&gammaLayout, Size{50, 0}}; + HorizontalSlider gammaSlider{&gammaLayout, Size{~0, 0}}; + HorizontalLayout luminanceLayout{&layout, Size{~0, 0}}; + Label luminanceLabel{&luminanceLayout, Size{80, 0}}; + Label luminanceValue{&luminanceLayout, Size{50, 0}}; + HorizontalSlider luminanceSlider{&luminanceLayout, Size{~0, 0}}; Label overscanMaskLabel{&layout, Size{~0, 0}}; HorizontalLayout horizontalMaskLayout{&layout, Size{~0, 0}}; Label horizontalMaskLabel{&horizontalMaskLayout, Size{80, 0}}; - Label horizontalMaskValue{&horizontalMaskLayout, Size{80, 0}}; + Label horizontalMaskValue{&horizontalMaskLayout, Size{50, 0}}; HorizontalSlider horizontalMaskSlider{&horizontalMaskLayout, Size{~0, 0}}; HorizontalLayout verticalMaskLayout{&layout, Size{~0, 0}}; Label verticalMaskLabel{&verticalMaskLayout, Size{80, 0}}; - Label verticalMaskValue{&verticalMaskLayout, Size{80, 0}}; + Label verticalMaskValue{&verticalMaskLayout, Size{50, 0}}; HorizontalSlider verticalMaskSlider{&verticalMaskLayout, Size{~0, 0}}; - auto update() -> void; + auto updateColor() -> void; + auto updateOverscan() -> void; }; struct AudioSettings : TabFrameItem { AudioSettings(TabFrame*); VerticalLayout layout{this}; + Label driverLabel{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}}; - Label frequencyLabel{&controlLayout, Size{0, 0}}; - ComboButton frequencyCombo{&controlLayout, Size{~0, 0}}; Label latencyLabel{&controlLayout, Size{0, 0}}; ComboButton latencyCombo{&controlLayout, Size{~0, 0}}; + Label frequencyLabel{&controlLayout, Size{0, 0}}; + ComboButton frequencyCombo{&controlLayout, Size{~0, 0}}; Label resamplerLabel{&controlLayout, Size{0, 0}}; ComboButton resamplerCombo{&controlLayout, Size{~0, 0}}; + CheckLabel exclusiveMode{&layout, Size{~0, 0}}; + Label effectsLabel{&layout, Size{~0, 0}}; HorizontalLayout volumeLayout{&layout, Size{~0, 0}}; Label volumeLabel{&volumeLayout, Size{80, 0}}; - Label volumeValue{&volumeLayout, Size{80, 0}}; + Label volumeValue{&volumeLayout, Size{50, 0}}; HorizontalSlider volumeSlider{&volumeLayout, Size{~0, 0}}; - CheckLabel exclusiveMode{&layout, Size{~0, 0}}; + HorizontalLayout balanceLayout{&layout, Size{~0, 0}}; + Label balanceLabel{&balanceLayout, Size{80, 0}}; + Label balanceValue{&balanceLayout, Size{50, 0}}; + HorizontalSlider balanceSlider{&balanceLayout, Size{~0, 0}}; + HorizontalLayout reverbDelayLayout{&layout, Size{~0, 0}}; + Label reverbDelayLabel{&reverbDelayLayout, Size{80, 0}}; + Label reverbDelayValue{&reverbDelayLayout, Size{50, 0}}; + HorizontalSlider reverbDelaySlider{&reverbDelayLayout, Size{~0, 0}}; + HorizontalLayout reverbLevelLayout{&layout, Size{~0, 0}}; + Label reverbLevelLabel{&reverbLevelLayout, Size{80, 0}}; + Label reverbLevelValue{&reverbLevelLayout, Size{50, 0}}; + HorizontalSlider reverbLevelSlider{&reverbLevelLayout, Size{~0, 0}}; - auto update() -> void; - auto updateMode() -> void; - auto updateVolume() -> void; + auto updateDriver() -> void; + auto updateEffects() -> void; }; struct InputSettings : TabFrameItem { diff --git a/higan/target-tomoko/settings/video.cpp b/higan/target-tomoko/settings/video.cpp index fc3ce544..07cbaa8a 100644 --- a/higan/target-tomoko/settings/video.cpp +++ b/higan/target-tomoko/settings/video.cpp @@ -4,16 +4,40 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { layout.setMargin(5); + colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment"); + saturationLabel.setText("Saturation:"); + saturationValue.setAlignment(0.5); + saturationSlider.setLength(201).setPosition(settings["Video/Saturation"].natural()).onChange([&] { updateColor(); }); + gammaLabel.setText("Gamma:"); + gammaValue.setAlignment(0.5); + gammaSlider.setLength(101).setPosition(settings["Video/Gamma"].natural() - 100).onChange([&] { updateColor(); }); + luminanceLabel.setText("Luminance:"); + luminanceValue.setAlignment(0.5); + luminanceSlider.setLength(101).setPosition(settings["Video/Luminance"].natural()).onChange([&] { updateColor(); }); + overscanMaskLabel.setFont(Font().setBold()).setText("Overscan Mask"); horizontalMaskLabel.setText("Horizontal:"); - horizontalMaskSlider.setLength(17).setPosition(settings["Video/Overscan/Horizontal"].natural()).onChange([&] { update(); }); + horizontalMaskValue.setAlignment(0.5); + horizontalMaskSlider.setLength(17).setPosition(settings["Video/Overscan/Horizontal"].natural()).onChange([&] { updateOverscan(); }); verticalMaskLabel.setText("Vertical:"); - verticalMaskSlider.setLength(17).setPosition(settings["Video/Overscan/Vertical"].natural()).onChange([&] { update(); }); + verticalMaskValue.setAlignment(0.5); + verticalMaskSlider.setLength(17).setPosition(settings["Video/Overscan/Vertical"].natural()).onChange([&] { updateOverscan(); }); - update(); + updateColor(); + updateOverscan(); } -auto VideoSettings::update() -> void { +auto VideoSettings::updateColor() -> void { + settings["Video/Saturation"].setValue(saturationSlider.position()); + settings["Video/Gamma"].setValue(100 + gammaSlider.position()); + settings["Video/Luminance"].setValue(luminanceSlider.position()); + saturationValue.setText({saturationSlider.position(), "%"}); + gammaValue.setText({100 + gammaSlider.position(), "%"}); + luminanceValue.setText({luminanceSlider.position(), "%"}); + program->updateVideoPalette(); +} + +auto VideoSettings::updateOverscan() -> void { settings["Video/Overscan/Horizontal"].setValue(horizontalMaskSlider.position()); settings["Video/Overscan/Vertical"].setValue(verticalMaskSlider.position()); horizontalMaskValue.setText({horizontalMaskSlider.position(), "px"}); diff --git a/higan/video/video.cpp b/higan/video/video.cpp index 4775593d..1d616e1a 100644 --- a/higan/video/video.cpp +++ b/higan/video/video.cpp @@ -8,6 +8,83 @@ Video::~Video() { reset(); } +auto Video::reset() -> void { + interface = nullptr; + delete output; + output = nullptr; + delete palette; + palette = nullptr; + width = 0; + height = 0; + effects.colorBleed = false; + effects.interframeBlending = false; +} + +auto Video::setInterface(Interface* interface) -> void { + this->interface = interface; +} + +auto Video::setPalette() -> void { + if(!interface) return; + + delete palette; + colors = interface->videoColors(); + palette = new uint32[colors]; + for(auto index : range(colors)) { + uint64 color = interface->videoColor(index); + uint16 b = color.bits( 0,15); + uint16 g = color.bits(16,31); + uint16 r = color.bits(32,47); + uint16 a = 0xffff; + + if(saturation != 1.0) { + uint16 grayscale = uclamp<16>((r + g + b) / 3); + double inverse = max(0.0, 1.0 - saturation); + r = uclamp<16>(r * saturation + grayscale * inverse); + g = uclamp<16>(g * saturation + grayscale * inverse); + b = uclamp<16>(b * saturation + grayscale * inverse); + } + + if(gamma != 1.0) { + double reciprocal = 1.0 / 32767.0; + r = r > 32767 ? r : uint16(32767 * pow(r * reciprocal, gamma)); + g = g > 32767 ? g : uint16(32767 * pow(g * reciprocal, gamma)); + b = b > 32767 ? b : uint16(32767 * pow(b * reciprocal, gamma)); + } + + if(luminance != 1.0) { + r = uclamp<16>(r * luminance); + g = uclamp<16>(g * luminance); + b = uclamp<16>(b * luminance); + } + + //convert color from 16-bits/channel to 8-bits/channel; force alpha to 1.0 + palette[index] = a.byte(1) << 24 | r.byte(1) << 16 | g.byte(1) << 8 | b.byte(1) << 0; + } +} + +auto Video::setSaturation(double saturation) -> void { + this->saturation = saturation; +} + +auto Video::setGamma(double gamma) -> void { + this->gamma = gamma; +} + +auto Video::setLuminance(double luminance) -> void { + this->luminance = luminance; +} + +auto Video::setEffect(Effect effect, const any& value) -> void { + if(effect == Effect::ColorBleed && value.is()) { + effects.colorBleed = value.get(); + } + + if(effect == Effect::InterframeBlending && value.is()) { + effects.interframeBlending = value.get(); + } +} + auto Video::refresh(uint32* input, uint pitch, uint width, uint height) -> void { if(this->width != width || this->height != height) { delete output; @@ -49,41 +126,4 @@ auto Video::refresh(uint32* input, uint pitch, uint width, uint height) -> void interface->videoRefresh(output, width * sizeof(uint32), width, height); } -auto Video::reset() -> void { - interface = nullptr; - delete output; - output = nullptr; - delete palette; - palette = nullptr; - width = 0; - height = 0; - effects.colorBleed = false; - effects.interframeBlending = false; -} - -auto Video::setInterface(Interface* interface) -> void { - this->interface = interface; -} - -auto Video::setPalette(uint32 size, function callback) -> void { - delete palette; - palette = new uint32[size]; - for(auto index : range(size)) { - //convert color from 16-bits/channel to 8-bits/channel; force alpha to 1.0 - uint64 color = callback(index); - palette[index] = 255u << 24 | color.bits(40,47) << 16 | color.bits(24,31) << 8 | color.bits(8,15) << 0; - } - colors = size; -} - -auto Video::setEffect(Effect effect, const any& value) -> void { - if(effect == Effect::ColorBleed && value.is()) { - effects.colorBleed = value.get(); - } - - if(effect == Effect::InterframeBlending && value.is()) { - effects.interframeBlending = value.get(); - } -} - } diff --git a/higan/video/video.hpp b/higan/video/video.hpp index d630734d..acc2c3da 100644 --- a/higan/video/video.hpp +++ b/higan/video/video.hpp @@ -11,12 +11,19 @@ struct Video { }; ~Video(); - auto refresh(uint32* input, uint pitch, uint width, uint height) -> void; + auto reset() -> void; auto setInterface(Interface* interface) -> void; - auto setPalette(uint32 size, function callback) -> void; + + auto setPalette() -> void; + auto setSaturation(double saturation) -> void; + auto setGamma(double gamma) -> void; + auto setLuminance(double luminance) -> void; + auto setEffect(Effect effect, const any& value) -> void; + auto refresh(uint32* input, uint pitch, uint width, uint height) -> void; + private: Emulator::Interface* interface = nullptr; uint32* output = nullptr; @@ -25,6 +32,10 @@ private: uint height = 0; uint colors = 0; + double saturation = 1.0; + double gamma = 1.0; + double luminance = 1.0; + struct Effects { bool colorBleed = false; bool interframeBlending = false; diff --git a/higan/ws/apu/apu.cpp b/higan/ws/apu/apu.cpp index 30bba573..e148a878 100644 --- a/higan/ws/apu/apu.cpp +++ b/higan/ws/apu/apu.cpp @@ -56,7 +56,7 @@ auto APU::dacRun() -> void { right = 0; } - interface->audioSample(left, right); + stream->sample(left, right); } auto APU::step(uint clocks) -> void { @@ -66,6 +66,7 @@ auto APU::step(uint clocks) -> void { auto APU::power() -> void { create(APU::Enter, 3'072'000); + stream = Emulator::audio.createStream(3'072'000.0); bus.map(this, 0x004a, 0x004c); bus.map(this, 0x004e, 0x0050); diff --git a/higan/ws/apu/apu.hpp b/higan/ws/apu/apu.hpp index 02c286ba..940c96f9 100644 --- a/higan/ws/apu/apu.hpp +++ b/higan/ws/apu/apu.hpp @@ -1,4 +1,6 @@ struct APU : Thread, IO { + shared_pointer stream; + static auto Enter() -> void; auto main() -> void; auto sample(uint channel, uint5 index) -> uint4; diff --git a/higan/ws/interface/interface.cpp b/higan/ws/interface/interface.cpp index 1d1ae3b8..5b8ca805 100644 --- a/higan/ws/interface/interface.cpp +++ b/higan/ws/interface/interface.cpp @@ -72,6 +72,31 @@ auto Interface::videoFrequency() -> double { return 3072000.0 / (159.0 * 256.0); //~75.47hz } +auto Interface::videoColors() -> uint32 { + return 1 << 12; +} + +auto Interface::videoColor(uint32 color) -> uint64 { + uint b = color.bits(0, 3); + uint g = color.bits(4, 7); + uint r = color.bits(8,11); + + uint64_t R = image::normalize(r, 4, 16); + uint64_t G = image::normalize(g, 4, 16); + uint64_t B = image::normalize(b, 4, 16); + + if(settings.colorEmulation) { + R = (r * 26 + g * 4 + b * 2); + G = ( g * 24 + b * 8); + B = (r * 6 + g * 4 + b * 22); + R = image::normalize(min(480, R), 9, 16); + G = image::normalize(min(480, G), 9, 16); + B = image::normalize(min(480, B), 9, 16); + } + + return R << 32 | G << 16 | B << 0; +} + auto Interface::audioFrequency() -> double { return 3072000.0; } diff --git a/higan/ws/interface/interface.hpp b/higan/ws/interface/interface.hpp index 2901c2c3..c9b85f0d 100644 --- a/higan/ws/interface/interface.hpp +++ b/higan/ws/interface/interface.hpp @@ -31,6 +31,8 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; auto videoFrequency() -> double override; + auto videoColors() -> uint32; + auto videoColor(uint32 color) -> uint64; auto audioFrequency() -> double override; auto loaded() -> bool override; diff --git a/higan/ws/ppu/ppu.cpp b/higan/ws/ppu/ppu.cpp index 37d20ac1..38984658 100644 --- a/higan/ws/ppu/ppu.cpp +++ b/higan/ws/ppu/ppu.cpp @@ -75,12 +75,15 @@ auto PPU::scanline() -> void { auto PPU::frame() -> void { s.field = !s.field; s.vclk = 0; - Emulator::video.refresh(output, 224 * sizeof(uint32), 224, 224); + scheduler.exit(Scheduler::Event::Frame); if(l.orientation != system.orientation()) { l.orientation = system.orientation(); memory::fill(output, 224 * 224 * sizeof(uint32)); } - scheduler.exit(Scheduler::Event::Frame); +} + +auto PPU::refresh() -> void { + Emulator::video.refresh(output, 224 * sizeof(uint32), 224, 224); } auto PPU::step(uint clocks) -> void { diff --git a/higan/ws/ppu/ppu.hpp b/higan/ws/ppu/ppu.hpp index 550137a9..4a2f94f1 100644 --- a/higan/ws/ppu/ppu.hpp +++ b/higan/ws/ppu/ppu.hpp @@ -3,6 +3,7 @@ struct PPU : Thread, IO { auto main() -> void; auto scanline() -> void; auto frame() -> void; + auto refresh() -> void; auto step(uint clocks) -> void; auto power() -> void; diff --git a/higan/ws/scheduler/scheduler.cpp b/higan/ws/scheduler/scheduler.cpp index 0a1d9d5f..a8ff677b 100644 --- a/higan/ws/scheduler/scheduler.cpp +++ b/higan/ws/scheduler/scheduler.cpp @@ -13,6 +13,7 @@ auto Scheduler::enter(Mode mode_) -> Event { mode = mode_; host = co_active(); co_switch(resume); + if(event == Event::Frame) ppu.refresh(); return event; } diff --git a/higan/ws/system/system.cpp b/higan/ws/system/system.cpp index 63eaad1a..bd652887 100644 --- a/higan/ws/system/system.cpp +++ b/higan/ws/system/system.cpp @@ -41,7 +41,6 @@ auto System::load(Model model) -> void { cartridge.load(); serializeInit(); - configureVideo(); _orientation = cartridge.information.orientation; _loaded = true; } @@ -57,6 +56,14 @@ auto System::unload() -> void { } auto System::power() -> void { + Emulator::video.reset(); + Emulator::video.setInterface(interface); + configureVideoPalette(); + configureVideoEffects(); + + Emulator::audio.reset(); + Emulator::audio.setInterface(interface); + bus.power(); iram.power(); eeprom.power(); diff --git a/higan/ws/system/system.hpp b/higan/ws/system/system.hpp index e8eafcdf..c27ac3de 100644 --- a/higan/ws/system/system.hpp +++ b/higan/ws/system/system.hpp @@ -21,7 +21,6 @@ struct System : IO { auto portWrite(uint16 addr, uint8 data) -> void override; //video.cpp - auto configureVideo() -> void; auto configureVideoPalette() -> void; auto configureVideoEffects() -> void; diff --git a/higan/ws/system/video.cpp b/higan/ws/system/video.cpp index 6b65376d..f77e7ae9 100644 --- a/higan/ws/system/video.cpp +++ b/higan/ws/system/video.cpp @@ -1,31 +1,5 @@ -auto System::configureVideo() -> void { - Emulator::video.reset(); - Emulator::video.setInterface(interface); - configureVideoPalette(); - configureVideoEffects(); -} - auto System::configureVideoPalette() -> void { - Emulator::video.setPalette(1 << 12, [&](uint32 color) -> uint64 { - uint b = color.bits(0, 3); - uint g = color.bits(4, 7); - uint r = color.bits(8,11); - - uint64_t R = image::normalize(r, 4, 16); - uint64_t G = image::normalize(g, 4, 16); - uint64_t B = image::normalize(b, 4, 16); - - if(settings.colorEmulation) { - R = (r * 26 + g * 4 + b * 2); - G = ( g * 24 + b * 8); - B = (r * 6 + g * 4 + b * 22); - R = image::normalize(min(480, R), 9, 16); - G = image::normalize(min(480, G), 9, 16); - B = image::normalize(min(480, B), 9, 16); - } - - return R << 32 | G << 16 | B << 0; - }); + Emulator::video.setPalette(); } auto System::configureVideoEffects() -> void { diff --git a/higan/ws/ws.hpp b/higan/ws/ws.hpp index b9bf02bf..6c089fc2 100644 --- a/higan/ws/ws.hpp +++ b/higan/ws/ws.hpp @@ -30,7 +30,7 @@ namespace WonderSwan { auto create(auto (*entrypoint)() -> void, uint frequency) -> void { if(thread) co_delete(thread); - thread = co_create(262'144 * sizeof(void*), entrypoint); + thread = co_create(65'536 * sizeof(void*), entrypoint); this->frequency = frequency; clock = 0; }