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;