From 483f9f8f202b1e0d0bfe5e07d29a53b4db93fd5e Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 29 Oct 2011 18:32:20 +1100 Subject: [PATCH] Update to v083r08 release. byuu says: Fixed SA-1 IRQ regression for Super Mario RPG Added turbo B,A to NES+GB; B,A,X,Y to SNES (please don't ask for turbo L,R; you never use those keys rapidly.) Re-added video color adjustments, which are now done in full 8-bit colorspace for more precision Gamma ramp option is gone. It's now the gamma option, which now only affects the lower-half of the colors. A value of 1.0 gives you the original, washed out colors. 1.75 is what the gamma ramp checkbox used to do (roughly). The new default is 1.5, which still prevents color washout, but isn't as overly dark as before. I wanted to make the core/interface stuff abstract the complexity of setting up a new C++ class, but it really didn't make anything easier. It was all one-line stubs to internal functions, and there was just too many platform-specific things that needed to be captured, so I did away with that. Made a base class for the ui/interface stuff to get rid of a lot of switch(mode()) stuff, still a work in progress. --- bsnes/gameboy/interface/interface.cpp | 64 +------------ bsnes/gameboy/interface/interface.hpp | 24 +---- bsnes/nes/interface/interface.cpp | 70 +------------- bsnes/nes/interface/interface.hpp | 24 ----- bsnes/snes/chip/icd2/icd2.cpp | 5 +- bsnes/snes/chip/sa1/sa1.cpp | 21 +++- bsnes/snes/chip/sa1/sa1.hpp | 1 + bsnes/snes/cpu/core/core.hpp | 3 +- bsnes/snes/interface/interface.cpp | 102 +------------------- bsnes/snes/interface/interface.hpp | 30 ------ bsnes/ui/config/config.cpp | 4 +- bsnes/ui/config/config.hpp | 2 +- bsnes/ui/general/dip-switches.cpp | 4 +- bsnes/ui/input/gameboy.cpp | 7 +- bsnes/ui/input/gameboy.hpp | 1 + bsnes/ui/input/input.cpp | 12 +++ bsnes/ui/input/input.hpp | 7 ++ bsnes/ui/input/nes.cpp | 7 +- bsnes/ui/input/nes.hpp | 1 + bsnes/ui/input/snes.cpp | 10 +- bsnes/ui/input/snes.hpp | 1 + bsnes/ui/interface/gameboy.cpp | 82 ---------------- bsnes/ui/interface/gameboy.hpp | 11 --- bsnes/ui/interface/gameboy/gameboy.cpp | 111 +++++++++++++++++++++ bsnes/ui/interface/gameboy/gameboy.hpp | 20 ++++ bsnes/ui/interface/interface.cpp | 83 +++++++--------- bsnes/ui/interface/interface.hpp | 16 +++- bsnes/ui/interface/{ => nes}/nes.cpp | 82 +++++++++++----- bsnes/ui/interface/{ => nes}/nes.hpp | 14 ++- bsnes/ui/interface/palette.cpp | 46 +++------ bsnes/ui/interface/palette.hpp | 5 +- bsnes/ui/interface/{ => snes}/snes.cpp | 128 +++++++++++++++++++------ bsnes/ui/interface/{ => snes}/snes.hpp | 15 ++- bsnes/ui/main.cpp | 4 +- bsnes/ui/settings/video.cpp | 17 ++-- bsnes/ui/settings/video.hpp | 1 - 36 files changed, 449 insertions(+), 586 deletions(-) delete mode 100755 bsnes/ui/interface/gameboy.cpp delete mode 100755 bsnes/ui/interface/gameboy.hpp create mode 100755 bsnes/ui/interface/gameboy/gameboy.cpp create mode 100755 bsnes/ui/interface/gameboy/gameboy.hpp rename bsnes/ui/interface/{ => nes}/nes.cpp (58%) rename bsnes/ui/interface/{ => nes}/nes.hpp (50%) rename bsnes/ui/interface/{ => snes}/snes.cpp (72%) rename bsnes/ui/interface/{ => snes}/snes.hpp (76%) diff --git a/bsnes/gameboy/interface/interface.cpp b/bsnes/gameboy/interface/interface.cpp index 4e8c1fca..0a6d5f2a 100755 --- a/bsnes/gameboy/interface/interface.cpp +++ b/bsnes/gameboy/interface/interface.cpp @@ -2,7 +2,7 @@ namespace GameBoy { -Interface *interface = 0; +Interface *interface = nullptr; void Interface::lcdScanline() { } @@ -20,68 +20,6 @@ bool Interface::inputPoll(unsigned id) { return false; } -void Interface::initialize(Interface *derived_interface) { - interface = derived_interface; - system.init(); -} - -bool Interface::cartridgeLoaded() { - return cartridge.loaded(); -} - -void Interface::loadCartridge(GameBoy::System::Revision revision, const string &markup, const uint8_t *data, unsigned size) { - cartridge.load(revision, markup, data, size); - system.power(); -} - -void Interface::unloadCartridge() { - cartridge.unload(); -} - -unsigned Interface::memorySize(Memory memory) { - if(memory == Memory::RAM) return cartridge.ramsize; - return 0u; -} - -uint8_t* Interface::memoryData(Memory memory) { - if(memory == Memory::RAM) return cartridge.ramdata; - return 0u; -} - -void Interface::power() { - system.power(); -} - -void Interface::run() { - do { - system.run(); - } while(scheduler.exit_reason() != Scheduler::ExitReason::FrameEvent); -} - -serializer Interface::serialize() { - system.runtosave(); - return system.serialize(); -} - -bool Interface::unserialize(serializer &s) { - return system.unserialize(s); -} - -void Interface::setCheats(const lstring &list) { - cheat.reset(); - for(auto &code : list) { - lstring codelist; - codelist.split("+", code); - for(auto &part : codelist) { - unsigned addr, data, comp; - if(Cheat::decode(part, addr, data, comp)) { - cheat.append({ addr, data, comp }); - } - } - } - cheat.synchronize(); -} - void Interface::message(const string &text) { print(text, "\n"); } diff --git a/bsnes/gameboy/interface/interface.hpp b/bsnes/gameboy/interface/interface.hpp index 1e6febed..918e606b 100755 --- a/bsnes/gameboy/interface/interface.hpp +++ b/bsnes/gameboy/interface/interface.hpp @@ -1,5 +1,4 @@ -class Interface { -public: +struct Interface { virtual void lcdScanline(); virtual void joypWrite(bool p15, bool p14); @@ -7,27 +6,6 @@ public: virtual void audioSample(int16_t center, int16_t left, int16_t right); virtual bool inputPoll(unsigned id); - virtual void initialize(Interface*); - - virtual bool cartridgeLoaded(); - virtual void loadCartridge(GameBoy::System::Revision revision, const string &markup, const uint8_t *data, unsigned size); - virtual void unloadCartridge(); - - enum class Memory : unsigned { - RAM, - }; - - virtual unsigned memorySize(Memory); - virtual uint8_t* memoryData(Memory); - - virtual void power(); - virtual void run(); - - virtual serializer serialize(); - virtual bool unserialize(serializer&); - - virtual void setCheats(const lstring &list = lstring{}); - virtual void message(const string &text); }; diff --git a/bsnes/nes/interface/interface.cpp b/bsnes/nes/interface/interface.cpp index b1d6ca1d..062ad7c8 100755 --- a/bsnes/nes/interface/interface.cpp +++ b/bsnes/nes/interface/interface.cpp @@ -2,7 +2,7 @@ namespace NES { -Interface *interface = 0; +Interface *interface = nullptr; void Interface::videoRefresh(const uint16_t *data) { } @@ -14,74 +14,6 @@ int16_t Interface::inputPoll(bool port, unsigned device, unsigned id) { return 0; } -void Interface::initialize(Interface *derived_interface) { - interface = derived_interface; - system.init(); -} - -void Interface::connect(bool port, Input::Device device) { - input.connect(port, device); -} - -bool Interface::cartridgeLoaded() { - return cartridge.loaded(); -} - -void Interface::loadCartridge(const string &markup, const uint8_t *data, unsigned size) { - cartridge.load(markup, data, size); - system.power(); -} - -void Interface::unloadCartridge() { - cartridge.unload(); -} - -unsigned Interface::memorySize(Memory memory) { - if(memory == Memory::RAM) return cartridge.ram_size(); - return 0u; -} - -uint8_t* Interface::memoryData(Memory memory) { - if(memory == Memory::RAM) return cartridge.ram_data(); - return 0u; -} - -void Interface::power() { - system.power(); -} - -void Interface::reset() { - system.reset(); -} - -void Interface::run() { - system.run(); -} - -serializer Interface::serialize() { - system.runtosave(); - return system.serialize(); -} - -bool Interface::unserialize(serializer &s) { - return system.unserialize(s); -} - -void Interface::setCheats(const lstring &list) { - cheat.reset(); - for(auto &code : list) { - lstring codelist; - codelist.split("+", code); - for(auto &part : codelist) { - unsigned addr, data, comp; - if(Cheat::decode(part, addr, data, comp)) { - cheat.append({ addr, data, comp }); - } - } - } - cheat.synchronize(); -} - void Interface::message(const string &text) { print(text, "\n"); } diff --git a/bsnes/nes/interface/interface.hpp b/bsnes/nes/interface/interface.hpp index c3154896..a53af4df 100755 --- a/bsnes/nes/interface/interface.hpp +++ b/bsnes/nes/interface/interface.hpp @@ -3,30 +3,6 @@ struct Interface { virtual void audioSample(int16_t sample); virtual int16_t inputPoll(bool port, unsigned device, unsigned id); - virtual void connect(bool port, Input::Device device); - - virtual void initialize(Interface*); - - virtual bool cartridgeLoaded(); - virtual void loadCartridge(const string &markup, const uint8_t *data, unsigned size); - virtual void unloadCartridge(); - - enum class Memory : unsigned { - RAM, - }; - - virtual unsigned memorySize(Memory); - virtual uint8_t* memoryData(Memory); - - virtual void power(); - virtual void reset(); - virtual void run(); - - virtual serializer serialize(); - virtual bool unserialize(serializer&); - - virtual void setCheats(const lstring &list = lstring{}); - virtual void message(const string &text); }; diff --git a/bsnes/snes/chip/icd2/icd2.cpp b/bsnes/snes/chip/icd2/icd2.cpp index b3c5e801..c8a82df3 100755 --- a/bsnes/snes/chip/icd2/icd2.cpp +++ b/bsnes/snes/chip/icd2/icd2.cpp @@ -69,8 +69,9 @@ void ICD2::reset() { joyp14lock = 0; pulselock = true; - GameBoy::Interface::initialize(this); - GameBoy::Interface::power(); + GameBoy::interface = this; + GameBoy::system.init(); + GameBoy::system.power(); } } diff --git a/bsnes/snes/chip/sa1/sa1.cpp b/bsnes/snes/chip/sa1/sa1.cpp index c9f810ff..9620e4f9 100755 --- a/bsnes/snes/chip/sa1/sa1.cpp +++ b/bsnes/snes/chip/sa1/sa1.cpp @@ -36,27 +36,40 @@ void SA1::enter() { } } +void SA1::op_irq() { + op_read(regs.pc.d); + op_io(); + if(!regs.e) op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.e ? (regs.p & ~0x10) : regs.p); + regs.pc.w = regs.vector; + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; +} + void SA1::last_cycle() { if(mmio.sa1_nmi && !mmio.sa1_nmicl) { status.interrupt_pending = true; - regs.vector = mmio.cnv; + regs.vector = mmio.cnv; mmio.sa1_nmifl = true; mmio.sa1_nmicl = 1; regs.wai = false; } else if(!regs.p.i) { if(mmio.timer_irqen && !mmio.timer_irqcl) { status.interrupt_pending = true; - regs.vector = mmio.civ; + regs.vector = mmio.civ; mmio.timer_irqfl = true; regs.wai = false; } else if(mmio.dma_irqen && !mmio.dma_irqcl) { status.interrupt_pending = true; - regs.vector = mmio.civ; + regs.vector = mmio.civ; mmio.dma_irqfl = true; regs.wai = false; } else if(mmio.sa1_irq && !mmio.sa1_irqcl) { status.interrupt_pending = true; - regs.vector = mmio.civ; + regs.vector = mmio.civ; mmio.sa1_irqfl = true; regs.wai = false; } diff --git a/bsnes/snes/chip/sa1/sa1.hpp b/bsnes/snes/chip/sa1/sa1.hpp index 2f7a3fe7..732b2a85 100755 --- a/bsnes/snes/chip/sa1/sa1.hpp +++ b/bsnes/snes/chip/sa1/sa1.hpp @@ -18,6 +18,7 @@ public: static void Enter(); void enter(); void tick(); + void op_irq(); alwaysinline void trigger_irq(); alwaysinline void last_cycle(); diff --git a/bsnes/snes/cpu/core/core.hpp b/bsnes/snes/cpu/core/core.hpp index 5079e8a3..964bd128 100755 --- a/bsnes/snes/cpu/core/core.hpp +++ b/bsnes/snes/cpu/core/core.hpp @@ -12,14 +12,13 @@ struct CPUcore { virtual void op_write(uint32_t addr, uint8_t data) = 0; virtual void last_cycle() = 0; virtual bool interrupt_pending() = 0; + virtual void op_irq(); void op_io_irq(); void op_io_cond2(); void op_io_cond4(uint16 x, uint16 y); void op_io_cond6(uint16 addr); - void op_irq(); - void op_adc_b(); void op_adc_w(); void op_and_b(); diff --git a/bsnes/snes/interface/interface.cpp b/bsnes/snes/interface/interface.cpp index 07985615..a0e3a81b 100755 --- a/bsnes/snes/interface/interface.cpp +++ b/bsnes/snes/interface/interface.cpp @@ -2,7 +2,7 @@ namespace SNES { -Interface *interface = 0; +Interface *interface = nullptr; void Interface::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { } @@ -14,106 +14,6 @@ int16_t Interface::inputPoll(bool port, Input::Device device, unsigned index, un return 0; } -void Interface::initialize(Interface *derived_interface) { - interface = derived_interface; - system.init(); -} - -void Interface::connect(bool port, Input::Device device) { - input.connect(port, device); -} - -bool Interface::cartridgeLoaded() { - return cartridge.loaded(); -} - -void Interface::loadCartridge(const CartridgeData &base) { - cartridge.rom.copy(base.data, base.size); - cartridge.load(Cartridge::Mode::Normal, base.markup); - system.power(); -} - -void Interface::loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot) { - cartridge.rom.copy(base.data, base.size); - if(slot.data) bsxflash.memory.copy(slot.data, slot.size); - cartridge.load(Cartridge::Mode::BsxSlotted, base.markup); - system.power(); -} - -void Interface::loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot) { - cartridge.rom.copy(base.data, base.size); - if(slot.data) bsxflash.memory.copy(slot.data, slot.size); - cartridge.load(Cartridge::Mode::Bsx, base.markup); - system.power(); -} - -void Interface::loadSufamiTurboCartridge(const CartridgeData &base, const CartridgeData &slotA, const CartridgeData &slotB) { - cartridge.rom.copy(base.data, base.size); - if(slotA.data) sufamiturbo.slotA.rom.copy(slotA.data, slotA.size); - if(slotB.data) sufamiturbo.slotB.rom.copy(slotB.data, slotB.size); - cartridge.load(Cartridge::Mode::SufamiTurbo, base.markup); - system.power(); -} - -void Interface::loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot) { - cartridge.rom.copy(base.data, base.size); - GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, slot.markup, slot.data, slot.size); - cartridge.load(Cartridge::Mode::SuperGameBoy, base.markup); - system.power(); -} - -void Interface::unloadCartridge() { - cartridge.unload(); -} - -Cartridge::Information& Interface::information() { - return cartridge.information; -} - -linear_vector& Interface::memory() { - return cartridge.nvram; -} - -void Interface::power() { - system.power(); -} - -void Interface::reset() { - system.reset(); -} - -void Interface::run() { - system.run(); -} - -serializer Interface::serialize() { - system.runtosave(); - return system.serialize(); -} - -bool Interface::unserialize(serializer &s) { - return system.unserialize(s); -} - -void Interface::setCheats(const lstring &list) { - if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) { - return icd2.setCheats(list); - } - - cheat.reset(); - for(auto &code : list) { - lstring codelist; - codelist.split("+", code); - for(auto &part : codelist) { - unsigned addr, data; - if(Cheat::decode(part, addr, data)) { - cheat.append({ addr, data }); - } - } - } - cheat.synchronize(); -} - void Interface::message(const string &text) { print(text, "\n"); } diff --git a/bsnes/snes/interface/interface.hpp b/bsnes/snes/interface/interface.hpp index d3ae634e..f1a48c0f 100755 --- a/bsnes/snes/interface/interface.hpp +++ b/bsnes/snes/interface/interface.hpp @@ -3,36 +3,6 @@ struct Interface { virtual void audioSample(int16_t lsample, int16_t rsample); virtual int16_t inputPoll(bool port, Input::Device device, unsigned index, unsigned id); - virtual void initialize(Interface*); - - virtual void connect(bool port, Input::Device device); - - struct CartridgeData { - string markup; - const uint8_t *data; - unsigned size; - }; - - virtual bool cartridgeLoaded(); - virtual void loadCartridge(const CartridgeData &base); - virtual void loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot); - virtual void loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot); - virtual void loadSufamiTurboCartridge(const CartridgeData &base, const CartridgeData &slotA, const CartridgeData &slotB); - virtual void loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot); - virtual void unloadCartridge(); - - Cartridge::Information& information(); - linear_vector& memory(); - - virtual void power(); - virtual void reset(); - virtual void run(); - - virtual serializer serialize(); - virtual bool unserialize(serializer&); - - void setCheats(const lstring &list = lstring{}); - virtual string path(Cartridge::Slot slot, const string &hint) = 0; virtual void message(const string &text); }; diff --git a/bsnes/ui/config/config.cpp b/bsnes/ui/config/config.cpp index 0dfbf267..546531e3 100755 --- a/bsnes/ui/config/config.cpp +++ b/bsnes/ui/config/config.cpp @@ -14,8 +14,8 @@ Config::Config() { attach(video.brightness = 100, "Video::Brightness"); attach(video.contrast = 100, "Video::Contrast"); - attach(video.gamma = 100, "Video::Gamma"); - attach(video.gammaRamp = true, "Video::GammaRamp"); + attach(video.gamma = 50, "Video::Gamma"); + attach(video.fullScreenMode = 0, "Video::FullScreenMode"); attach(video.startFullScreen = false, "Video::StartFullScreen"); diff --git a/bsnes/ui/config/config.hpp b/bsnes/ui/config/config.hpp index a6c62163..a5fdaf1a 100755 --- a/bsnes/ui/config/config.hpp +++ b/bsnes/ui/config/config.hpp @@ -13,7 +13,7 @@ struct Config : public configuration { unsigned brightness; unsigned contrast; unsigned gamma; - bool gammaRamp; + unsigned fullScreenMode; bool startFullScreen; diff --git a/bsnes/ui/general/dip-switches.cpp b/bsnes/ui/general/dip-switches.cpp index 8920ffbd..e9f4e304 100755 --- a/bsnes/ui/general/dip-switches.cpp +++ b/bsnes/ui/general/dip-switches.cpp @@ -28,7 +28,7 @@ void DipSwitches::load() { if(interface->mode() != Interface::Mode::SNES || SNES::cartridge.has_nss_dip() == false) return; application->pause = true; - auto info = interface->snes.information().nss; + auto info = SNES::cartridge.information.nss; unsigned count = info.setting.size(); for(unsigned n = 0; n < min(8, count); n++) { @@ -55,7 +55,7 @@ void DipSwitches::load() { } void DipSwitches::accept() { - auto info = interface->snes.information().nss; + auto info = SNES::cartridge.information.nss; unsigned count = info.setting.size(); unsigned result = 0x0000; diff --git a/bsnes/ui/input/gameboy.cpp b/bsnes/ui/input/gameboy.cpp index 24644418..5b5f7357 100755 --- a/bsnes/ui/input/gameboy.cpp +++ b/bsnes/ui/input/gameboy.cpp @@ -4,8 +4,8 @@ int16_t GameBoyController::poll(unsigned n) { case 1: return down.poll() & !up.poll(); case 2: return left.poll() & !right.poll(); case 3: return right.poll() & !left.poll(); - case 4: return b.poll(); - case 5: return a.poll(); + case 4: return b.poll() | bTurbo.poll(); + case 5: return a.poll() | aTurbo.poll(); case 6: return select.poll(); case 7: return start.poll(); } @@ -23,6 +23,8 @@ GameBoyController::GameBoyController() { a.name = "A"; select.name = "Select"; start.name = "Start"; + bTurbo.name = "Turbo B"; + aTurbo.name = "Turbo A"; up.mapping = "KB0::Up"; down.mapping = "KB0::Down"; @@ -35,6 +37,7 @@ GameBoyController::GameBoyController() { append(up); append(down); append(left); append(right); append(b); append(a); append(select); append(start); + append(bTurbo); append(aTurbo); } // diff --git a/bsnes/ui/input/gameboy.hpp b/bsnes/ui/input/gameboy.hpp index ae3a4048..41159fff 100755 --- a/bsnes/ui/input/gameboy.hpp +++ b/bsnes/ui/input/gameboy.hpp @@ -1,6 +1,7 @@ struct GameBoyController : TertiaryInput { DigitalInput up, down, left, right; DigitalInput b, a, select, start; + TurboInput bTurbo, aTurbo; int16_t poll(unsigned n); GameBoyController(); diff --git a/bsnes/ui/input/input.cpp b/bsnes/ui/input/input.cpp index a7d62dcb..b64bddba 100755 --- a/bsnes/ui/input/input.cpp +++ b/bsnes/ui/input/input.cpp @@ -121,6 +121,18 @@ int16_t DigitalInput::poll() { // +int16_t TurboInput::poll() { + int16_t result = DigitalInput::poll(); + if(phase < 3) result = 0; + if(++phase >= 6) phase = 0; + return result; +} + +TurboInput::TurboInput() : phase(0) { +} + +// + void TertiaryInput::attach(const string &primaryName, const string &secondaryName) { for(unsigned n = 0; n < size(); n++) { operator[](n).attach(primaryName, secondaryName, name); diff --git a/bsnes/ui/input/input.hpp b/bsnes/ui/input/input.hpp index 3dfe6f83..ba0a5775 100755 --- a/bsnes/ui/input/input.hpp +++ b/bsnes/ui/input/input.hpp @@ -20,6 +20,13 @@ struct DigitalInput : AbstractInput { int16_t poll(); }; +struct TurboInput : DigitalInput { + unsigned phase; + + int16_t poll(); + TurboInput(); +}; + struct TertiaryInput : reference_array { string name; diff --git a/bsnes/ui/input/nes.cpp b/bsnes/ui/input/nes.cpp index ff63c0cf..95f5bbf0 100755 --- a/bsnes/ui/input/nes.cpp +++ b/bsnes/ui/input/nes.cpp @@ -1,7 +1,7 @@ int16_t NesGamepad::poll(unsigned n) { switch(n) { - case 0: return a.poll(); - case 1: return b.poll(); + case 0: return a.poll() | aTurbo.poll(); + case 1: return b.poll() | bTurbo.poll(); case 2: return select.poll(); case 3: return start.poll(); case 4: return up.poll() & !down.poll(); @@ -23,6 +23,8 @@ NesGamepad::NesGamepad() { a.name = "A"; select.name = "Select"; start.name = "Start"; + bTurbo.name = "Turbo B"; + aTurbo.name = "Turbo A"; up.mapping = "KB0::Up"; down.mapping = "KB0::Down"; @@ -35,6 +37,7 @@ NesGamepad::NesGamepad() { append(up); append(down); append(left); append(right); append(b); append(a); append(select); append(start); + append(bTurbo); append(aTurbo); } // diff --git a/bsnes/ui/input/nes.hpp b/bsnes/ui/input/nes.hpp index 06beed0e..b3199e27 100755 --- a/bsnes/ui/input/nes.hpp +++ b/bsnes/ui/input/nes.hpp @@ -1,6 +1,7 @@ struct NesGamepad : TertiaryInput { DigitalInput up, down, left, right; DigitalInput b, a, select, start; + TurboInput bTurbo, aTurbo; int16_t poll(unsigned n); NesGamepad(); diff --git a/bsnes/ui/input/snes.cpp b/bsnes/ui/input/snes.cpp index 4f895f85..e2e7ad5d 100755 --- a/bsnes/ui/input/snes.cpp +++ b/bsnes/ui/input/snes.cpp @@ -4,10 +4,10 @@ int16_t SnesGamepad::poll(unsigned n) { case SNES::Input::JoypadID::Down: return down.poll() & !up.poll(); case SNES::Input::JoypadID::Left: return left.poll() & !right.poll(); case SNES::Input::JoypadID::Right: return right.poll() & !left.poll(); - case SNES::Input::JoypadID::B: return b.poll(); - case SNES::Input::JoypadID::A: return a.poll(); - case SNES::Input::JoypadID::Y: return y.poll(); - case SNES::Input::JoypadID::X: return x.poll(); + case SNES::Input::JoypadID::B: return b.poll() | bTurbo.poll(); + case SNES::Input::JoypadID::A: return a.poll() | aTurbo.poll(); + case SNES::Input::JoypadID::Y: return y.poll() | yTurbo.poll(); + case SNES::Input::JoypadID::X: return x.poll() | xTurbo.poll(); case SNES::Input::JoypadID::L: return l.poll(); case SNES::Input::JoypadID::R: return r.poll(); case SNES::Input::JoypadID::Select: return select.poll(); @@ -22,6 +22,7 @@ SnesGamepad::SnesGamepad(const string &name, bool defaultBindings) { up.name = "Up", down.name = "Down", left.name = "Left", right.name = "Right"; b.name = "B", a.name = "A", y.name = "Y", x.name = "X"; l.name = "L", r.name = "R", select.name = "Select", start.name = "Start"; + bTurbo.name = "Turbo B", aTurbo.name = "Turbo A", yTurbo.name = "Turbo Y", xTurbo.name = "Turbo X"; if(defaultBindings) { up.mapping = "KB0::Up"; @@ -41,6 +42,7 @@ SnesGamepad::SnesGamepad(const string &name, bool defaultBindings) { append(up); append(down); append(left); append(right); append(b); append(a); append(y); append(x); append(l); append(r); append(select); append(start); + append(bTurbo); append(aTurbo); append(yTurbo); append(xTurbo); } // diff --git a/bsnes/ui/input/snes.hpp b/bsnes/ui/input/snes.hpp index 0e27ff42..65925589 100755 --- a/bsnes/ui/input/snes.hpp +++ b/bsnes/ui/input/snes.hpp @@ -2,6 +2,7 @@ struct SnesGamepad : TertiaryInput { DigitalInput up, down, left, right; DigitalInput b, a, y, x; DigitalInput l, r, select, start; + TurboInput bTurbo, aTurbo, yTurbo, xTurbo; int16_t poll(unsigned n); SnesGamepad(const string &name, bool defaultBindings); diff --git a/bsnes/ui/interface/gameboy.cpp b/bsnes/ui/interface/gameboy.cpp deleted file mode 100755 index 9dc3988e..00000000 --- a/bsnes/ui/interface/gameboy.cpp +++ /dev/null @@ -1,82 +0,0 @@ -bool InterfaceGameBoy::loadCartridge(GameBoy::System::Revision revision, const string &filename) { - uint8_t *data; - unsigned size; - if(interface->loadFile(filename, data, size) == false) return false; - - interface->unloadCartridge(); - interface->baseName = nall::basename(filename); - - GameBoyCartridge info(data, size); - GameBoy::Interface::loadCartridge(revision, info.markup, data, size); - delete[] data; - - if(GameBoy::Interface::memorySize(GameBoy::Interface::Memory::RAM) > 0) { - filemap fp; - if(fp.open(string{ interface->baseName, ".sav" }, filemap::mode::read)) { - memcpy(GameBoy::Interface::memoryData(GameBoy::Interface::Memory::RAM), fp.data(), - min(GameBoy::Interface::memorySize(GameBoy::Interface::Memory::RAM), fp.size()) - ); - } - } - - GameBoy::interface = this; - GameBoy::video.generate(GameBoy::Video::Format::RGB24); - interface->loadCartridge(::Interface::Mode::GameBoy); - return true; -} - -void InterfaceGameBoy::unloadCartridge() { - if(GameBoy::Interface::memorySize(GameBoy::Interface::Memory::RAM) > 0) { - file::write({ interface->baseName, ".sav" }, - GameBoy::Interface::memoryData(GameBoy::Interface::Memory::RAM), - GameBoy::Interface::memorySize(GameBoy::Interface::Memory::RAM) - ); - } - - GameBoy::Interface::unloadCartridge(); - interface->baseName = ""; -} - -bool InterfaceGameBoy::saveState(const string &filename) { - serializer s = serialize(); - return file::write(filename, s.data(), s.size()); -} - -bool InterfaceGameBoy::loadState(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - serializer s(data, size); - delete[] data; - return unserialize(s); -} - -// - -void InterfaceGameBoy::videoRefresh(const uint16_t *data) { - static uint32_t output[160 * 144]; - - for(unsigned y = 0; y < 144; y++) { - const uint16_t *sp = data + y * 160; - uint32_t *dp = output + y * 160; - for(unsigned x = 0; x < 160; x++) { - uint16_t color = *sp++; - *dp++ = GameBoy::video.palette[color]; - } - } - - interface->videoRefresh(output, 160 * 4, 160, 144); -} - -void InterfaceGameBoy::audioSample(int16_t csample, int16_t lsample, int16_t rsample) { - signed samples[] = { lsample, rsample }; - dspaudio.sample(samples); - while(dspaudio.pending()) { - dspaudio.read(samples); - audio.sample(samples[0], samples[1]); - } -} - -bool InterfaceGameBoy::inputPoll(unsigned id) { - return inputManager->gameBoy.device.controller.poll(id); -} diff --git a/bsnes/ui/interface/gameboy.hpp b/bsnes/ui/interface/gameboy.hpp deleted file mode 100755 index 65ba66b1..00000000 --- a/bsnes/ui/interface/gameboy.hpp +++ /dev/null @@ -1,11 +0,0 @@ -struct InterfaceGameBoy : GameBoy::Interface { - bool loadCartridge(GameBoy::System::Revision revision, const string &filename); - void unloadCartridge(); - - bool saveState(const string &filename); - bool loadState(const string &filename); - - void videoRefresh(const uint16_t *data); - void audioSample(int16_t csample, int16_t lsample, int16_t rsample); - bool inputPoll(unsigned id); -}; diff --git a/bsnes/ui/interface/gameboy/gameboy.cpp b/bsnes/ui/interface/gameboy/gameboy.cpp new file mode 100755 index 00000000..ce5fe67a --- /dev/null +++ b/bsnes/ui/interface/gameboy/gameboy.cpp @@ -0,0 +1,111 @@ +void InterfaceGameBoy::initialize() { + GameBoy::interface = this; + GameBoy::system.init(); +} + +bool InterfaceGameBoy::cartridgeLoaded() { + return GameBoy::cartridge.loaded(); +} + +bool InterfaceGameBoy::loadCartridge(GameBoy::System::Revision revision, const string &filename) { + uint8_t *data; + unsigned size; + if(interface->loadFile(filename, data, size) == false) return false; + + interface->unloadCartridge(); + interface->baseName = nall::basename(filename); + + GameBoyCartridge info(data, size); + GameBoy::cartridge.load(revision, info.markup, data, size); + GameBoy::system.power(); + delete[] data; + + if(GameBoy::cartridge.ramsize) { + filemap fp; + if(fp.open(string{ interface->baseName, ".sav" }, filemap::mode::read)) { + memcpy(GameBoy::cartridge.ramdata, fp.data(), min(GameBoy::cartridge.ramsize, fp.size())); + } + } + + GameBoy::interface = this; + GameBoy::video.generate(GameBoy::Video::Format::RGB24); + interface->loadCartridge(::Interface::Mode::GameBoy); + return true; +} + +void InterfaceGameBoy::unloadCartridge() { + if(GameBoy::cartridge.ramsize) { + file::write({ interface->baseName, ".sav" }, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize); + } + + GameBoy::cartridge.unload(); + interface->baseName = ""; +} + +void InterfaceGameBoy::power() { + GameBoy::system.power(); +} + +void InterfaceGameBoy::reset() { + GameBoy::system.power(); //Game Boy lacks reset button +} + +void InterfaceGameBoy::run() { + do { + GameBoy::system.run(); + } while(GameBoy::scheduler.exit_reason() != GameBoy::Scheduler::ExitReason::FrameEvent); +} + +serializer InterfaceGameBoy::serialize() { + GameBoy::system.runtosave(); + return GameBoy::system.serialize(); +} + +bool InterfaceGameBoy::unserialize(serializer &s) { + return GameBoy::system.unserialize(s); +} + +void InterfaceGameBoy::setCheats(const lstring &list) { + GameBoy::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(GameBoy::Cheat::decode(part, addr, data, comp)) { + GameBoy::cheat.append({ addr, data, comp }); + } + } + } + GameBoy::cheat.synchronize(); +} + +// + +void InterfaceGameBoy::videoRefresh(const uint16_t *data) { + static uint32_t output[160 * 144]; + + for(unsigned y = 0; y < 144; y++) { + const uint16_t *sp = data + y * 160; + uint32_t *dp = output + y * 160; + for(unsigned x = 0; x < 160; x++) { + uint16_t color = *sp++; + *dp++ = GameBoy::video.palette[color]; + } + } + + interface->videoRefresh(output, 160 * 4, 160, 144); +} + +void InterfaceGameBoy::audioSample(int16_t csample, int16_t lsample, int16_t rsample) { + signed samples[] = { lsample, rsample }; + dspaudio.sample(samples); + while(dspaudio.pending()) { + dspaudio.read(samples); + audio.sample(samples[0], samples[1]); + } +} + +bool InterfaceGameBoy::inputPoll(unsigned id) { + return inputManager->gameBoy.device.controller.poll(id); +} diff --git a/bsnes/ui/interface/gameboy/gameboy.hpp b/bsnes/ui/interface/gameboy/gameboy.hpp new file mode 100755 index 00000000..3b4b0d0e --- /dev/null +++ b/bsnes/ui/interface/gameboy/gameboy.hpp @@ -0,0 +1,20 @@ +struct InterfaceGameBoy : InterfaceCore, GameBoy::Interface { + void initialize(); + + bool cartridgeLoaded(); + bool loadCartridge(GameBoy::System::Revision revision, const string &filename); + void unloadCartridge(); + + void power(); + void reset(); + void run(); + + serializer serialize(); + bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); + + void videoRefresh(const uint16_t *data); + void audioSample(int16_t csample, int16_t lsample, int16_t rsample); + bool inputPoll(unsigned id); +}; diff --git a/bsnes/ui/interface/interface.cpp b/bsnes/ui/interface/interface.cpp index bd2231ca..26b4d134 100755 --- a/bsnes/ui/interface/interface.cpp +++ b/bsnes/ui/interface/interface.cpp @@ -1,9 +1,9 @@ #include "../base.hpp" #include "palette.cpp" -#include "nes.cpp" -#include "snes.cpp" -#include "gameboy.cpp" -Interface *interface = 0; +#include "nes/nes.cpp" +#include "snes/snes.cpp" +#include "gameboy/gameboy.cpp" +Interface *interface = nullptr; Filter filter; @@ -63,6 +63,13 @@ bool Interface::cartridgeLoaded() { void Interface::loadCartridge(Mode mode) { utility->setMode(this->mode = mode); + switch(mode) { + case Mode::NES: core = &nes; break; + case Mode::SNES: core = &snes; break; + case Mode::GameBoy: core = &gameBoy; break; + default: core = nullptr; break; + } + bindControllers(); cheatEditor->load({ baseName, ".cht" }); stateManager->load({ baseName, ".bsa" }, 0u); @@ -98,69 +105,50 @@ void Interface::unloadCartridge() { } void Interface::power() { - switch(mode()) { - case Mode::NES: nes.power(); break; - case Mode::SNES: snes.power(); break; - case Mode::GameBoy: gameBoy.power(); break; - } + if(core == nullptr) return; + core->power(); utility->showMessage("System power was cycled"); } void Interface::reset() { - switch(mode()) { - case Mode::NES: nes.reset(); break; - case Mode::SNES: snes.reset(); break; - case Mode::GameBoy: gameBoy.power(); break; //Game Boy lacks reset button - } + if(core == nullptr) return; + core->reset(); utility->showMessage("System was reset"); } void Interface::run() { - switch(mode()) { - case Mode::NES: return nes.run(); - case Mode::SNES: return snes.run(); - case Mode::GameBoy: return gameBoy.run(); - } + if(core == nullptr) return; + core->run(); } serializer Interface::serialize() { - switch(mode()) { - case Mode::NES: return nes.serialize(); - case Mode::SNES: return snes.serialize(); - case Mode::GameBoy: return gameBoy.serialize(); - } - return serializer(); + if(core == nullptr) return serializer(); + return core->serialize(); } bool Interface::unserialize(serializer &s) { - switch(mode()) { - case Mode::NES: return nes.unserialize(s); - case Mode::SNES: return snes.unserialize(s); - case Mode::GameBoy: return gameBoy.unserialize(s); - } - return false; + if(core == nullptr) return false; + return core->unserialize(s); } bool Interface::saveState(unsigned slot) { string filename = { baseName, "-", slot, ".bst" }; - bool result = false; - switch(mode()) { - case Mode::NES: result = nes.saveState(filename); break; - case Mode::SNES: result = snes.saveState(filename); break; - case Mode::GameBoy: result = gameBoy.saveState(filename); break; - } + serializer s = serialize(); + bool result = file::write(filename, s.data(), s.size()); utility->showMessage(result == true ? string{ "Saved state ", slot } : "Failed to save state"); return result; } bool Interface::loadState(unsigned slot) { string filename = { baseName, "-", slot, ".bst" }; - bool result = false; - switch(mode()) { - case Mode::NES: result = nes.loadState(filename); break; - case Mode::SNES: result = snes.loadState(filename); break; - case Mode::GameBoy: result = gameBoy.loadState(filename); break; + uint8_t *data; + unsigned size; + if(file::read(filename, data, size) == false) { + utility->showMessage(string{ "Slot ", slot, " save file not found" }); + return false; } + serializer s(data, size); + bool result = unserialize(s); utility->showMessage(result == true ? string{ "Loaded state ", slot } : "Failed to load state"); return result; } @@ -182,12 +170,12 @@ string Interface::sha256() { return "{None}"; } -Interface::Interface() { +Interface::Interface() : core(nullptr) { mode = Mode::None; palette.update(); - nes.initialize(&nes); - snes.initialize(&snes); - gameBoy.initialize(&gameBoy); + nes.initialize(); + snes.initialize(); + gameBoy.initialize(); } //internal @@ -234,7 +222,8 @@ void Interface::videoRefresh(const uint32_t *input, unsigned inputPitch, unsigne const uint32_t *sp = input + y * inputPitch; uint32_t *dp = output + y * outputPitch; for(unsigned x = 0; x < width; x++) { - *dp++ = *sp++; //palette[*sp++]; + uint32_t color = *sp++; + *dp++ = (palette[color >> 16] << 16) + (palette[color >> 8] << 8) + (palette[color >> 0] << 0); } } diff --git a/bsnes/ui/interface/interface.hpp b/bsnes/ui/interface/interface.hpp index bce54fa9..2b87b02b 100755 --- a/bsnes/ui/interface/interface.hpp +++ b/bsnes/ui/interface/interface.hpp @@ -1,8 +1,17 @@ #include "palette.hpp" -#include "nes.hpp" -#include "snes.hpp" -#include "gameboy.hpp" +struct InterfaceCore { + virtual void power() = 0; + virtual void reset() = 0; + virtual void run() = 0; + + virtual serializer serialize() = 0; + virtual bool unserialize(serializer&) = 0; +}; + +#include "nes/nes.hpp" +#include "snes/snes.hpp" +#include "gameboy/gameboy.hpp" struct Filter : public library { function dl_size; @@ -52,6 +61,7 @@ struct Interface : property { string baseName; // = "/path/to/cartridge" (no extension) lstring slotName; + InterfaceCore *core; InterfaceNES nes; InterfaceSNES snes; InterfaceGameBoy gameBoy; diff --git a/bsnes/ui/interface/nes.cpp b/bsnes/ui/interface/nes/nes.cpp similarity index 58% rename from bsnes/ui/interface/nes.cpp rename to bsnes/ui/interface/nes/nes.cpp index 5b5c2c0a..4ea94931 100755 --- a/bsnes/ui/interface/nes.cpp +++ b/bsnes/ui/interface/nes/nes.cpp @@ -1,18 +1,27 @@ +void InterfaceNES::initialize() { + NES::interface = this; + NES::system.init(); +} + void InterfaceNES::setController(bool port, unsigned device) { if(port == 0) config->nes.controllerPort1Device = device; if(port == 1) config->nes.controllerPort2Device = device; if(port == 0) switch(device) { - case 0: return connect(0, NES::Input::Device::None); - case 1: return connect(0, NES::Input::Device::Joypad); + case 0: return NES::input.connect(0, NES::Input::Device::None); + case 1: return NES::input.connect(0, NES::Input::Device::Joypad); } if(port == 1) switch(device) { - case 0: return connect(1, NES::Input::Device::None); - case 1: return connect(1, NES::Input::Device::Joypad); + case 0: return NES::input.connect(1, NES::Input::Device::None); + case 1: return NES::input.connect(1, NES::Input::Device::Joypad); } } +bool InterfaceNES::cartridgeLoaded() { + return NES::cartridge.loaded(); +} + bool InterfaceNES::loadCartridge(const string &filename) { uint8_t *data; unsigned size; @@ -24,15 +33,14 @@ bool InterfaceNES::loadCartridge(const string &filename) { string markup; markup.readfile({ interface->baseName, ".bml" }); - NES::Interface::loadCartridge(markup, data, size); + NES::cartridge.load(markup, data, size); + NES::system.power(); delete[] data; - if(NES::Interface::memorySize(NES::Interface::Memory::RAM) > 0) { + if(NES::cartridge.ram_size()) { filemap fp; if(fp.open(string{ interface->baseName, ".sav" }, filemap::mode::read)) { - memcpy(NES::Interface::memoryData(NES::Interface::Memory::RAM), fp.data(), - min(NES::Interface::memorySize(NES::Interface::Memory::RAM), fp.size()) - ); + memcpy(NES::cartridge.ram_data(), fp.data(), min(NES::cartridge.ram_size(), fp.size())); } } @@ -42,31 +50,53 @@ bool InterfaceNES::loadCartridge(const string &filename) { } void InterfaceNES::unloadCartridge() { - if(NES::Interface::memorySize(NES::Interface::Memory::RAM) > 0) { - file::write({ interface->baseName, ".sav" }, - NES::Interface::memoryData(NES::Interface::Memory::RAM), - NES::Interface::memorySize(NES::Interface::Memory::RAM) - ); + if(NES::cartridge.ram_size()) { + file::write({ interface->baseName, ".sav" }, NES::cartridge.ram_data(), NES::cartridge.ram_size()); } - - NES::Interface::unloadCartridge(); + NES::cartridge.unload(); interface->baseName = ""; } // -bool InterfaceNES::saveState(const string &filename) { - serializer s = serialize(); - return file::write(filename, s.data(), s.size()); +void InterfaceNES::power() { + NES::system.power(); } -bool InterfaceNES::loadState(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - serializer s(data, size); - delete[] data; - return unserialize(s); +void InterfaceNES::reset() { + NES::system.reset(); +} + +void InterfaceNES::run() { + NES::system.run(); +} + +// + +serializer InterfaceNES::serialize() { + NES::system.runtosave(); + return NES::system.serialize(); +} + +bool InterfaceNES::unserialize(serializer &s) { + return NES::system.unserialize(s); +} + +// + +void InterfaceNES::setCheats(const lstring &list) { + NES::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(NES::Cheat::decode(part, addr, data, comp)) { + NES::cheat.append({ addr, data, comp }); + } + } + } + NES::cheat.synchronize(); } // diff --git a/bsnes/ui/interface/nes.hpp b/bsnes/ui/interface/nes/nes.hpp similarity index 50% rename from bsnes/ui/interface/nes.hpp rename to bsnes/ui/interface/nes/nes.hpp index ae7654f6..1584bfbc 100755 --- a/bsnes/ui/interface/nes.hpp +++ b/bsnes/ui/interface/nes/nes.hpp @@ -1,11 +1,19 @@ -struct InterfaceNES : NES::Interface { +struct InterfaceNES : InterfaceCore, NES::Interface { + void initialize(); void setController(bool port, unsigned device); + bool cartridgeLoaded(); bool loadCartridge(const string &filename); void unloadCartridge(); - bool saveState(const string &filename); - bool loadState(const string &filename); + void power(); + void reset(); + void run(); + + serializer serialize(); + bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); void videoRefresh(const uint16_t *data); void audioSample(int16_t sample); diff --git a/bsnes/ui/interface/palette.cpp b/bsnes/ui/interface/palette.cpp index bbb7789b..c030dd62 100755 --- a/bsnes/ui/interface/palette.cpp +++ b/bsnes/ui/interface/palette.cpp @@ -1,15 +1,17 @@ Palette palette; -uint32_t Palette::operator[](unsigned n) { +uint8_t Palette::operator[](uint8_t n) { return color[n]; } +/* 5-bit -> 8-bit const uint8_t Palette::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, }; +*/ uint8_t Palette::contrastAdjust(uint8_t input) { signed contrast = config->video.contrast - 100; @@ -29,39 +31,17 @@ uint8_t Palette::gammaAdjust(uint8_t input) { } void Palette::update() { - for(unsigned i = 0; i < 32768; i++) { - unsigned r = (i >> 10) & 31; - unsigned g = (i >> 5) & 31; - unsigned b = (i >> 0) & 31; + double exponent = 1.0 + (double)config->video.gamma * 0.01; + for(unsigned n = 0; n < 256; n++) { + unsigned result = (n < 128 ? 127 * pow(((double)n / 127), exponent) : n); + color[n] = result; + } - r = (r << 3) | (r >> 2); - g = (g << 3) | (g >> 2); - b = (b << 3) | (b >> 2); + for(unsigned n = 0; n < 256; n++) { + color[n] = contrastAdjust(color[n]); + } - if(config->video.gammaRamp) { - r = gammaRamp[r >> 3]; - g = gammaRamp[g >> 3]; - b = gammaRamp[b >> 3]; - } - - if(config->video.contrast != 100) { - r = contrastAdjust(r); - g = contrastAdjust(g); - b = contrastAdjust(b); - } - - if(config->video.brightness != 100) { - r = brightnessAdjust(r); - g = brightnessAdjust(g); - b = brightnessAdjust(b); - } - - if(config->video.gamma != 100) { - r = gammaAdjust(r); - g = gammaAdjust(g); - b = gammaAdjust(b); - } - - color[i] = (r << 16) | (g << 8) | (b << 0); + for(unsigned n = 0; n < 256; n++) { + color[n] = brightnessAdjust(color[n]); } } diff --git a/bsnes/ui/interface/palette.hpp b/bsnes/ui/interface/palette.hpp index 0579ae4d..c8f8a19f 100755 --- a/bsnes/ui/interface/palette.hpp +++ b/bsnes/ui/interface/palette.hpp @@ -1,5 +1,5 @@ struct Palette { - alwaysinline uint32_t operator[](unsigned n); + alwaysinline uint8_t operator[](uint8_t color); uint8_t contrastAdjust(uint8_t); uint8_t brightnessAdjust(uint8_t); @@ -7,8 +7,7 @@ struct Palette { void update(); private: - static const uint8_t gammaRamp[32]; - uint32_t color[32768]; + uint32_t color[256]; }; extern Palette palette; diff --git a/bsnes/ui/interface/snes.cpp b/bsnes/ui/interface/snes/snes.cpp similarity index 72% rename from bsnes/ui/interface/snes.cpp rename to bsnes/ui/interface/snes/snes.cpp index 88a288ca..1ca01147 100755 --- a/bsnes/ui/interface/snes.cpp +++ b/bsnes/ui/interface/snes/snes.cpp @@ -1,26 +1,35 @@ +void InterfaceSNES::initialize() { + SNES::interface = this; + SNES::system.init(); +} + void InterfaceSNES::setController(bool port, unsigned device) { if(port == 0) config->snes.controllerPort1Device = device; if(port == 1) config->snes.controllerPort2Device = device; if(port == 0) switch(device) { - case 0: return connect(0, SNES::Input::Device::None); - case 1: return connect(0, SNES::Input::Device::Joypad); - case 2: return connect(0, SNES::Input::Device::Multitap); - case 3: return connect(0, SNES::Input::Device::Mouse); + case 0: return SNES::input.connect(0, SNES::Input::Device::None); + case 1: return SNES::input.connect(0, SNES::Input::Device::Joypad); + case 2: return SNES::input.connect(0, SNES::Input::Device::Multitap); + case 3: return SNES::input.connect(0, SNES::Input::Device::Mouse); } if(port == 1) switch(device) { - case 0: return connect(1, SNES::Input::Device::None); - case 1: return connect(1, SNES::Input::Device::Joypad); - case 2: return connect(1, SNES::Input::Device::Multitap); - case 3: return connect(1, SNES::Input::Device::Mouse); - case 4: return connect(1, SNES::Input::Device::SuperScope); - case 5: return connect(1, SNES::Input::Device::Justifier); - case 6: return connect(1, SNES::Input::Device::Justifiers); - case 7: return connect(1, SNES::Input::Device::Serial); + case 0: return SNES::input.connect(1, SNES::Input::Device::None); + case 1: return SNES::input.connect(1, SNES::Input::Device::Joypad); + case 2: return SNES::input.connect(1, SNES::Input::Device::Multitap); + case 3: return SNES::input.connect(1, SNES::Input::Device::Mouse); + case 4: return SNES::input.connect(1, SNES::Input::Device::SuperScope); + case 5: return SNES::input.connect(1, SNES::Input::Device::Justifier); + case 6: return SNES::input.connect(1, SNES::Input::Device::Justifiers); + case 7: return SNES::input.connect(1, SNES::Input::Device::Serial); } } +bool InterfaceSNES::cartridgeLoaded() { + return SNES::cartridge.loaded(); +} + bool InterfaceSNES::loadCartridge(const string &basename) { uint8_t *data; unsigned size; @@ -34,7 +43,10 @@ bool InterfaceSNES::loadCartridge(const string &basename) { markup.readfile({ interface->baseName, ".bml" }); if(markup == "") markup = SnesCartridge(data, size).markup; - SNES::Interface::loadCartridge({ markup, data, size }); + SNES::cartridge.rom.copy(data, size); + SNES::cartridge.load(SNES::Cartridge::Mode::Normal, markup); + SNES::system.power(); + delete[] data; loadMemory(); @@ -58,7 +70,11 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(const string &basename, cons markup.readfile({ interface->baseName, ".bml" }); if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; - SNES::Interface::loadSatellaviewSlottedCartridge({ markup, data[0], size[0] }, { "", data[1], size[1] }); + SNES::cartridge.rom.copy(data[0], size[0]); + if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, markup); + SNES::system.power(); + delete[] data[0]; if(data[1]) delete[] data[1]; @@ -83,7 +99,11 @@ bool InterfaceSNES::loadSatellaviewCartridge(const string &basename, const strin markup.readfile({ interface->baseName, ".bml" }); if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; - SNES::Interface::loadSatellaviewCartridge({ markup, data[0], size[0] }, { "", data[1], size[1] }); + SNES::cartridge.rom.copy(data[0], size[0]); + if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, markup); + SNES::system.power(); + delete[] data[0]; if(data[1]) delete[] data[1]; @@ -111,7 +131,12 @@ bool InterfaceSNES::loadSufamiTurboCartridge(const string &basename, const strin markup.readfile({ interface->baseName, ".bml" }); if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; - SNES::Interface::loadSufamiTurboCartridge({ markup, data[0], size[0] }, { "", data[1], size[1] }, { "", data[2], size[2] }); + SNES::cartridge.rom.copy(data[0], size[0]); + if(data[1]) SNES::sufamiturbo.slotA.rom.copy(data[1], size[1]); + if(data[2]) SNES::sufamiturbo.slotB.rom.copy(data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, markup); + SNES::system.power(); + delete[] data[0]; if(data[1]) delete[] data[1]; if(data[2]) delete[] data[2]; @@ -140,7 +165,12 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(const string &basename, const stri string gbMarkup; gbMarkup.readfile({ nall::basename(slotname), ".bml" }); if(gbMarkup == "") gbMarkup = GameBoyCartridge(data[1], size[1]).markup; - SNES::Interface::loadSuperGameBoyCartridge({ markup, data[0], size[0] }, { gbMarkup, data[1], size[1] }); + + SNES::cartridge.rom.copy(data[0], size[0]); + GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, gbMarkup, data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, markup); + SNES::system.power(); + delete[] data[0]; if(data[1]) delete[] data[1]; @@ -152,16 +182,28 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(const string &basename, const stri void InterfaceSNES::unloadCartridge() { saveMemory(); - SNES::Interface::unloadCartridge(); + SNES::cartridge.unload(); interface->baseName = ""; } +void InterfaceSNES::power() { + SNES::system.power(); +} + +void InterfaceSNES::reset() { + SNES::system.reset(); +} + +void InterfaceSNES::run() { + SNES::system.run(); +} + //slot[] array = Cartridge::Slot to slot# conversion: //{ Base, Bsx, SufamiTurbo, SufamiTurboA, SufamiTurboB, GameBoy } void InterfaceSNES::loadMemory() { static unsigned slot[] = { 0, 0, 0, 1, 2, 1 }; - for(auto &memory : SNES::Interface::memory()) { + for(auto &memory : SNES::cartridge.nvram) { if(memory.size == 0) continue; string filename = { interface->slotName[slot[(unsigned)memory.slot]], memory.id }; uint8_t *data; @@ -175,25 +217,51 @@ void InterfaceSNES::loadMemory() { void InterfaceSNES::saveMemory() { static unsigned slot[] = { 0, 0, 0, 1, 2, 1 }; - for(auto &memory : SNES::Interface::memory()) { + for(auto &memory : SNES::cartridge.nvram) { if(memory.size == 0) continue; string filename = { interface->slotName[slot[(unsigned)memory.slot]], memory.id }; file::write(filename, memory.data, memory.size); } } -bool InterfaceSNES::saveState(const string &filename) { - serializer s = serialize(); - return file::write(filename, s.data(), s.size()); +serializer InterfaceSNES::serialize() { + SNES::system.runtosave(); + return SNES::system.serialize(); } -bool InterfaceSNES::loadState(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - serializer s(data, size); - delete[] data; - return unserialize(s); +bool InterfaceSNES::unserialize(serializer &s) { + return SNES::system.unserialize(s); +} + +void InterfaceSNES::setCheats(const lstring &list) { + if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { + GameBoy::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(GameBoy::Cheat::decode(part, addr, data, comp)) { + GameBoy::cheat.append({ addr, data, comp }); + } + } + } + GameBoy::cheat.synchronize(); + return; + } + + SNES::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data; + if(SNES::Cheat::decode(part, addr, data)) { + SNES::cheat.append({ addr, data }); + } + } + } + SNES::cheat.synchronize(); } // diff --git a/bsnes/ui/interface/snes.hpp b/bsnes/ui/interface/snes/snes.hpp similarity index 76% rename from bsnes/ui/interface/snes.hpp rename to bsnes/ui/interface/snes/snes.hpp index 52711396..16ec5eec 100755 --- a/bsnes/ui/interface/snes.hpp +++ b/bsnes/ui/interface/snes/snes.hpp @@ -1,6 +1,9 @@ -struct InterfaceSNES : SNES::Interface { +struct InterfaceSNES : InterfaceCore, SNES::Interface { + void initialize(); + void setController(bool port, unsigned device); + bool cartridgeLoaded(); bool loadCartridge(const string &filename); bool loadSatellaviewSlottedCartridge(const string &basename, const string &slotname); bool loadSatellaviewCartridge(const string &basename, const string &slotname); @@ -8,11 +11,17 @@ struct InterfaceSNES : SNES::Interface { bool loadSuperGameBoyCartridge(const string &basename, const string &slotname); void unloadCartridge(); + void power(); + void reset(); + void run(); + void loadMemory(); void saveMemory(); - bool saveState(const string &filename); - bool loadState(const string &filename); + serializer serialize(); + bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan); void audioSample(int16_t lsample, int16_t rsample); diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 43176054..5966950d 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -27,7 +27,7 @@ void Application::run() { } Application::Application(int argc, char **argv) { - title = "bsnes v083.07"; + title = "bsnes v083.08"; application = this; quit = false; @@ -88,7 +88,7 @@ Application::Application(int argc, char **argv) { dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0); dspaudio.setBalance(0.0); dspaudio.setResampler(DSP::ResampleEngine::Sinc); - dspaudio.setResamplerFrequency(48000.0); + dspaudio.setResamplerFrequency(config->audio.frequency); input.driver(config->input.driver); input.set(Input::Handle, mainWindow->viewport.handle()); diff --git a/bsnes/ui/settings/video.cpp b/bsnes/ui/settings/video.cpp index 0fd915a6..cb0a651b 100755 --- a/bsnes/ui/settings/video.cpp +++ b/bsnes/ui/settings/video.cpp @@ -1,8 +1,6 @@ VideoSettings *videoSettings = 0; VideoSlider::VideoSlider() { - slider.setLength(201); - append(name, 75, 0); append(value, 75, 0); append(slider, ~0, 0); @@ -14,9 +12,11 @@ VideoSettings::VideoSettings() { colorAdjustment.setFont(application->boldFont); colorAdjustment.setText("Color adjustment:"); brightness.name.setText("Brightness:"); + brightness.slider.setLength(201); contrast.name.setText("Contrast:"); + contrast.slider.setLength(201); gamma.name.setText("Gamma:"); - gammaRamp.setText("Enable gamma ramp simulation"); + gamma.slider.setLength(101); overscanAdjustment.setFont(application->boldFont); overscanAdjustment.setText("Overscan mask:"); overscanHorizontal.name.setText("Horizontal:"); @@ -31,13 +31,10 @@ VideoSettings::VideoSettings() { RadioBox::group(fullScreen[0], fullScreen[1], fullScreen[2]); append(title, ~0, 0, 5); - #if 0 append(colorAdjustment, ~0, 0); append(brightness, ~0, 0); append(contrast, ~0, 0); - append(gamma, ~0, 0); - append(gammaRamp, ~0, 0, 5); - #endif + append(gamma, ~0, 0, 5); append(overscanAdjustment, ~0, 0); append(overscanHorizontal, ~0, 0); append(overscanVertical, ~0, 0, 5); @@ -50,14 +47,13 @@ VideoSettings::VideoSettings() { brightness.slider.setPosition(config->video.brightness); contrast.slider.setPosition(config->video.contrast); gamma.slider.setPosition(config->video.gamma); - gammaRamp.setChecked(config->video.gammaRamp); overscanHorizontal.slider.setPosition(config->video.maskOverscanHorizontal); overscanVertical.slider.setPosition(config->video.maskOverscanVertical); fullScreen[config->video.fullScreenMode].setChecked(); synchronize(); - brightness.slider.onChange = contrast.slider.onChange = gamma.slider.onChange = gammaRamp.onTick = + brightness.slider.onChange = contrast.slider.onChange = gamma.slider.onChange = overscanHorizontal.slider.onChange = overscanVertical.slider.onChange = fullScreen[0].onTick = fullScreen[1].onTick = fullScreen[2].onTick = { &VideoSettings::synchronize, this }; @@ -67,7 +63,6 @@ void VideoSettings::synchronize() { config->video.brightness = brightness.slider.position(); config->video.contrast = contrast.slider.position(); config->video.gamma = gamma.slider.position(); - config->video.gammaRamp = gammaRamp.checked(); config->video.maskOverscanHorizontal = overscanHorizontal.slider.position(); config->video.maskOverscanVertical = overscanVertical.slider.position(); if(fullScreen[0].checked()) config->video.fullScreenMode = 0; @@ -76,7 +71,7 @@ void VideoSettings::synchronize() { brightness.value.setText({ config->video.brightness, "%" }); contrast.value.setText({ config->video.contrast, "%" }); - gamma.value.setText({ config->video.gamma, "%" }); + gamma.value.setText({ 100 + config->video.gamma, "%" }); overscanHorizontal.value.setText({ config->video.maskOverscanHorizontal, "px" }); overscanVertical.value.setText({ config->video.maskOverscanVertical, "px" }); diff --git a/bsnes/ui/settings/video.hpp b/bsnes/ui/settings/video.hpp index 1164473c..111df450 100755 --- a/bsnes/ui/settings/video.hpp +++ b/bsnes/ui/settings/video.hpp @@ -12,7 +12,6 @@ struct VideoSettings : SettingsLayout { VideoSlider brightness; VideoSlider contrast; VideoSlider gamma; - CheckBox gammaRamp; Label overscanAdjustment; VideoSlider overscanHorizontal; VideoSlider overscanVertical;