diff --git a/bsnes/gameboy/Makefile b/bsnes/gameboy/Makefile index 27362024..6b55bc6e 100755 --- a/bsnes/gameboy/Makefile +++ b/bsnes/gameboy/Makefile @@ -1,9 +1,10 @@ -gameboy_objects := gameboy-system gameboy-scheduler +gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler gameboy_objects += gameboy-memory gameboy-cartridge gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd gameboy_objects += gameboy-cheat objects += $(gameboy_objects) +obj/gameboy-interface.o: $(gameboy)/interface/interface.cpp $(call rwildcard,$(gameboy)/interface/) obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/) obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(gameboy)/scheduler/) obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/) diff --git a/bsnes/gameboy/apu/apu.cpp b/bsnes/gameboy/apu/apu.cpp index eaf5916e..d45d2a6e 100755 --- a/bsnes/gameboy/apu/apu.cpp +++ b/bsnes/gameboy/apu/apu.cpp @@ -46,7 +46,7 @@ void APU::main() { noise.run(); master.run(); - system.interface->audio_sample(master.center, master.left, master.right); + interface->audioSample(master.center, master.left, master.right); if(++clock >= 0) co_switch(scheduler.active_thread = cpu.thread); } } diff --git a/bsnes/gameboy/cheat/cheat.cpp b/bsnes/gameboy/cheat/cheat.cpp index e43fa0a7..c7a83241 100755 --- a/bsnes/gameboy/cheat/cheat.cpp +++ b/bsnes/gameboy/cheat/cheat.cpp @@ -54,38 +54,8 @@ void Cheat::synchronize() { foreach(n, override) n = false; for(unsigned n = 0; n < size(); n++) { - const CheatCode &code = operator[](n); - - for(unsigned n = 0; n < code.addr.size(); n++) { - override[code.addr[n]] = true; - } + override[operator[](n).addr] = true; } } -bool CheatCode::operator=(const string &s) { - addr.reset(), data.reset(), comp.reset(); - - lstring list; - list.split("+", s); - - for(unsigned n = 0; n < list.size(); n++) { - unsigned codeaddr, codedata, codecomp; - if(Cheat::decode(list[n], codeaddr, codedata, codecomp) == false) { - addr.reset(), data.reset(), comp.reset(); - return false; - } - addr.append(codeaddr), data.append(codedata), comp.append(codecomp); - } - - return true; -} - -CheatCode::CheatCode(const string &s) { - operator=(s); -} - -CheatCode::CheatCode() { - enable = false; -} - } diff --git a/bsnes/gameboy/cheat/cheat.hpp b/bsnes/gameboy/cheat/cheat.hpp index 2899cc46..4446a52b 100755 --- a/bsnes/gameboy/cheat/cheat.hpp +++ b/bsnes/gameboy/cheat/cheat.hpp @@ -1,12 +1,7 @@ struct CheatCode { - bool enable; - array addr; - array data; - array comp; - - bool operator=(const string&); - CheatCode(const string&); - CheatCode(); + unsigned addr; + unsigned data; + unsigned comp; }; struct Cheat : public linear_vector { diff --git a/bsnes/gameboy/cpu/mmio/mmio.cpp b/bsnes/gameboy/cpu/mmio/mmio.cpp index 6bbf6104..8932c3d4 100755 --- a/bsnes/gameboy/cpu/mmio/mmio.cpp +++ b/bsnes/gameboy/cpu/mmio/mmio.cpp @@ -3,15 +3,15 @@ void CPU::mmio_joyp_poll() { unsigned button = 0, dpad = 0; - button |= system.interface->input_poll((unsigned)Input::Start) << 3; - button |= system.interface->input_poll((unsigned)Input::Select) << 2; - button |= system.interface->input_poll((unsigned)Input::B) << 1; - button |= system.interface->input_poll((unsigned)Input::A) << 0; + button |= interface->inputPoll((unsigned)Input::Start) << 3; + button |= interface->inputPoll((unsigned)Input::Select) << 2; + button |= interface->inputPoll((unsigned)Input::B) << 1; + button |= interface->inputPoll((unsigned)Input::A) << 0; - dpad |= system.interface->input_poll((unsigned)Input::Down) << 3; - dpad |= system.interface->input_poll((unsigned)Input::Up) << 2; - dpad |= system.interface->input_poll((unsigned)Input::Left) << 1; - dpad |= system.interface->input_poll((unsigned)Input::Right) << 0; + dpad |= interface->inputPoll((unsigned)Input::Down) << 3; + dpad |= interface->inputPoll((unsigned)Input::Up) << 2; + dpad |= interface->inputPoll((unsigned)Input::Left) << 1; + dpad |= interface->inputPoll((unsigned)Input::Right) << 0; status.joyp = 0x0f; if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req; @@ -84,7 +84,7 @@ void CPU::mmio_write(uint16 addr, uint8 data) { if(addr == 0xff00) { //JOYP status.p15 = data & 0x20; status.p14 = data & 0x10; - system.interface->joyp_write(status.p15, status.p14); + interface->joypWrite(status.p15, status.p14); mmio_joyp_poll(); return; } diff --git a/bsnes/gameboy/interface/interface.cpp b/bsnes/gameboy/interface/interface.cpp new file mode 100755 index 00000000..5ab8fc51 --- /dev/null +++ b/bsnes/gameboy/interface/interface.cpp @@ -0,0 +1,79 @@ +#include + +namespace GameBoy { + +Interface *interface = 0; + +void Interface::lcdScanline() { +} + +void Interface::joypWrite(bool p15, bool p14) { +} + +void Interface::videoRefresh(const uint8_t *data) { +} + +void Interface::audioSample(int16_t center, int16_t left, int16_t right) { +} + +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(const string &xml, const uint8_t *data, unsigned size) { + cartridge.load(xml, data, size); + system.power(); +} + +void Interface::unloadCartridge() { + cartridge.unload(); +} + +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(); + foreach(code, list) { + lstring codelist; + codelist.split("+", code); + foreach(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 1097716b..56dea02e 100755 --- a/bsnes/gameboy/interface/interface.hpp +++ b/bsnes/gameboy/interface/interface.hpp @@ -1,12 +1,27 @@ class Interface { public: - virtual void lcd_scanline() {} - virtual void joyp_write(bool p15, bool p14) {} + virtual void lcdScanline(); + virtual void joypWrite(bool p15, bool p14); - virtual void video_refresh(const uint8_t *data) {} - virtual void audio_sample(int16_t center, int16_t left, int16_t right) {} - virtual void input_poll() {} - virtual bool input_poll(unsigned id) {} + virtual void videoRefresh(const uint8_t *data); + virtual void audioSample(int16_t center, int16_t left, int16_t right); + virtual bool inputPoll(unsigned id); - virtual void message(const string &text) { print(text, "\n"); } + virtual void initialize(Interface*); + + virtual bool cartridgeLoaded(); + virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size); + virtual void unloadCartridge(); + + 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); }; + +extern Interface *interface; diff --git a/bsnes/gameboy/lcd/lcd.cpp b/bsnes/gameboy/lcd/lcd.cpp index ee2da967..2e1da7af 100755 --- a/bsnes/gameboy/lcd/lcd.cpp +++ b/bsnes/gameboy/lcd/lcd.cpp @@ -57,8 +57,7 @@ void LCD::scanline() { } void LCD::frame() { - system.interface->video_refresh(screen); - system.interface->input_poll(); + interface->videoRefresh(screen); cpu.mmio_joyp_poll(); status.ly = 0; @@ -80,7 +79,7 @@ void LCD::render() { uint8_t *output = screen + status.ly * 160; for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55; - system.interface->lcd_scanline(); + interface->lcdScanline(); } uint16 LCD::read_tile(bool select, unsigned x, unsigned y) { diff --git a/bsnes/gameboy/memory/memory.cpp b/bsnes/gameboy/memory/memory.cpp index c9d14826..5eab4749 100755 --- a/bsnes/gameboy/memory/memory.cpp +++ b/bsnes/gameboy/memory/memory.cpp @@ -45,13 +45,10 @@ uint8 Bus::read(uint16 addr) { uint8 data = mmio[addr]->mmio_read(addr); if(cheat.override[addr]) { - for(unsigned x = 0; x < cheat.size(); x++) { - const CheatCode &code = cheat[x]; - for(unsigned y = 0; y < code.addr.size(); y++) { - if(code.addr[y] == addr) { - if(code.comp[y] > 255 || code.comp[y] == data) { - return code.data[y]; - } + for(unsigned n = 0; n < cheat.size(); n++) { + if(cheat[n].addr == addr) { + if(cheat[n].comp > 255 || cheat[n].comp == data) { + return cheat[n].data; } } } diff --git a/bsnes/gameboy/system/system.cpp b/bsnes/gameboy/system/system.cpp index 0e086410..d38b1564 100755 --- a/bsnes/gameboy/system/system.cpp +++ b/bsnes/gameboy/system/system.cpp @@ -33,8 +33,8 @@ void System::runthreadtosave() { } } -void System::init(Interface *interface_) { - interface = interface_; +void System::init() { + assert(interface != 0); } void System::load() { @@ -49,11 +49,6 @@ void System::power() { lcd.power(); scheduler.init(); -// cheat.reset(); -// cheat.append(CheatCode("3EB-81B-4CA")); -// cheat[0].enable = true; -// cheat.synchronize(); - clocks_executed = 0; } diff --git a/bsnes/gameboy/system/system.hpp b/bsnes/gameboy/system/system.hpp index 8a5e9582..25f4013d 100755 --- a/bsnes/gameboy/system/system.hpp +++ b/bsnes/gameboy/system/system.hpp @@ -14,11 +14,10 @@ struct System { void runtosave(); void runthreadtosave(); - void init(Interface*); + void init(); void load(); void power(); - Interface *interface; unsigned clocks_executed; //serialization.cpp diff --git a/bsnes/nes/Makefile b/bsnes/nes/Makefile index 6216d067..fbac28e0 100755 --- a/bsnes/nes/Makefile +++ b/bsnes/nes/Makefile @@ -1,9 +1,10 @@ -nes_objects := nes-system nes-scheduler +nes_objects := nes-interface nes-system nes-scheduler nes_objects += nes-mapper nes-cartridge nes-memory nes_objects += nes-cpu nes-apu nes-ppu nes_objects += nes-cheat objects += $(nes_objects) +obj/nes-interface.o: $(nes)/interface/interface.cpp $(call rwildcard,$(nes)/interface/) obj/nes-system.o: $(nes)/system/system.cpp $(call rwildcard,$(nes)/system/) obj/nes-scheduler.o: $(nes)/scheduler/scheduler.cpp $(call rwildcard,$(nes)/scheduler/) obj/nes-mapper.o: $(nes)/mapper/mapper.cpp $(call rwildcard,$(nes)/mapper/) diff --git a/bsnes/nes/apu/apu.cpp b/bsnes/nes/apu/apu.cpp index f58f14c9..e3c7ab43 100755 --- a/bsnes/nes/apu/apu.cpp +++ b/bsnes/nes/apu/apu.cpp @@ -42,7 +42,7 @@ void APU::main() { clock_frame_counter_divider(); signed output = rectangle_dac[rectangle_output] + dmc_triangle_noise_dac[dmc_output][triangle_output][noise_output]; - system.interface->audio_sample(output); + interface->audioSample(output); tick(); } @@ -257,8 +257,8 @@ void APU::Sweep::clock() { signed delta = rectangle_period >> shift; if(decrement) { - rectangle_period -= delta; - //decrement first square wave by one extra + //first rectangle decrements by one extra + rectangle_period -= delta + (channel == 0); } else if((rectangle_period + delta) < 0x800) { rectangle_period += delta; } @@ -328,7 +328,7 @@ void APU::Triangle::clock_length() { } } -void APU::Triangle::clock_length_counter() { +void APU::Triangle::clock_linear_length() { if(reload_linear) { linear_length_counter = linear_length; } else if(linear_length_counter) { @@ -339,7 +339,8 @@ void APU::Triangle::clock_length_counter() { } uint8 APU::Triangle::clock() { - uint8 result = (step_counter & 0x0f) ^ ((step_counter & 0x10) ? 0x0f : 0x00); + uint8 result = step_counter & 0x0f; + if(step_counter & 0x10) result ^= 0x0f; if(length_counter == 0 || linear_length_counter == 0) return result; if(--period_counter == 0) { @@ -397,7 +398,7 @@ void APU::clock_frame_counter() { rectangle[0].envelope.clock(); rectangle[1].envelope.clock(); - triangle.clock_length_counter(); + triangle.clock_linear_length(); noise.envelope.clock(); if(frame.counter == 0) { @@ -414,6 +415,9 @@ void APU::clock_frame_counter_divider() { } APU::APU() { + rectangle[0].sweep.channel = 0; + rectangle[1].sweep.channel = 1; + for(unsigned amp = 0; amp < 32; amp++) { if(amp == 0) { rectangle_dac[amp] = 0; diff --git a/bsnes/nes/apu/apu.hpp b/bsnes/nes/apu/apu.hpp index ec4f9bef..29ca723f 100755 --- a/bsnes/nes/apu/apu.hpp +++ b/bsnes/nes/apu/apu.hpp @@ -25,6 +25,8 @@ struct APU : Processor { }; struct Sweep { + bool channel; + uint8 shift; bool decrement; uint3 period; @@ -67,7 +69,7 @@ struct APU : Processor { bool reload_linear; void clock_length(); - void clock_length_counter(); + void clock_linear_length(); uint8 clock(); } triangle; @@ -113,10 +115,10 @@ struct APU : Processor { int16 dmc_triangle_noise_dac[128][16][16]; static const uint8 length_counter_table[32]; - static const uint16 ntsc_noise_period_table[16]; - static const uint16 pal_noise_period_table[16]; static const uint16 ntsc_dmc_period_table[16]; static const uint16 pal_dmc_period_table[16]; + static const uint16 ntsc_noise_period_table[16]; + static const uint16 pal_noise_period_table[16]; }; extern APU apu; diff --git a/bsnes/nes/cheat/cheat.cpp b/bsnes/nes/cheat/cheat.cpp index 84f6e5c3..0c76e5ea 100755 --- a/bsnes/nes/cheat/cheat.cpp +++ b/bsnes/nes/cheat/cheat.cpp @@ -51,38 +51,8 @@ void Cheat::synchronize() { foreach(n, override) n = false; for(unsigned n = 0; n < size(); n++) { - const CheatCode &code = operator[](n); - - for(unsigned n = 0; n < code.addr.size(); n++) { - override[code.addr[n]] = true; - } + override[operator[](n).addr] = true; } } -bool CheatCode::operator=(const string &s) { - addr.reset(), data.reset(), comp.reset(); - - lstring list; - list.split("+", s); - - for(unsigned n = 0; n < list.size(); n++) { - unsigned codeaddr, codedata, codecomp; - if(Cheat::decode(list[n], codeaddr, codedata, codecomp) == false) { - addr.reset(), data.reset(), comp.reset(); - return false; - } - addr.append(codeaddr), data.append(codedata), comp.append(codecomp); - } - - return true; -} - -CheatCode::CheatCode(const string &s) { - operator=(s); -} - -CheatCode::CheatCode() { - enable = false; -} - } diff --git a/bsnes/nes/cheat/cheat.hpp b/bsnes/nes/cheat/cheat.hpp index 2899cc46..4446a52b 100755 --- a/bsnes/nes/cheat/cheat.hpp +++ b/bsnes/nes/cheat/cheat.hpp @@ -1,12 +1,7 @@ struct CheatCode { - bool enable; - array addr; - array data; - array comp; - - bool operator=(const string&); - CheatCode(const string&); - CheatCode(); + unsigned addr; + unsigned data; + unsigned comp; }; struct Cheat : public linear_vector { diff --git a/bsnes/nes/cpu/cpu.cpp b/bsnes/nes/cpu/cpu.cpp index 8207b6dd..df50108a 100755 --- a/bsnes/nes/cpu/cpu.cpp +++ b/bsnes/nes/cpu/cpu.cpp @@ -91,12 +91,12 @@ void CPU::ram_write(uint16 addr, uint8 data) { uint8 CPU::read(uint16 addr) { if(addr == 0x4016) { if(status.controller_port0 >= 8) return (mdr() & 0xc0) | 1; - return system.interface->input_poll(0, 0u, status.controller_port0++); + return interface->inputPoll(0, 0u, status.controller_port0++); } if(addr == 0x4017) { if(status.controller_port1 >= 8) return (mdr() & 0xc0) | 1; - return system.interface->input_poll(1, 0u, status.controller_port1++); + return interface->inputPoll(1, 0u, status.controller_port1++); } return apu.read(addr); diff --git a/bsnes/nes/interface/interface.cpp b/bsnes/nes/interface/interface.cpp new file mode 100755 index 00000000..01359e33 --- /dev/null +++ b/bsnes/nes/interface/interface.cpp @@ -0,0 +1,66 @@ +#include + +namespace NES { + +Interface *interface = 0; + +void Interface::videoRefresh(const uint16_t *data) { +} + +void Interface::audioSample(const int16_t sample) { +} + +int16_t Interface::inputPoll(bool port, unsigned device, unsigned id) { + return 0; +} + +void Interface::initialize(Interface *derived_interface) { + interface = derived_interface; + system.init(); +} + +bool Interface::cartridgeLoaded() { + return cartridge.loaded(); +} + +void Interface::loadCartridge(const string &xml, const uint8_t *data, unsigned size) { + cartridge.load(xml, data, size); + system.power(); +} + +void Interface::unloadCartridge() { + cartridge.unload(); +} + +void Interface::power() { + system.power(); +} + +void Interface::reset() { + system.reset(); +} + +void Interface::run() { + system.run(); +} + +void Interface::setCheats(const lstring &list) { + cheat.reset(); + foreach(code, list) { + lstring codelist; + codelist.split("+", code); + foreach(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 4618bb57..8208ae72 100755 --- a/bsnes/nes/interface/interface.hpp +++ b/bsnes/nes/interface/interface.hpp @@ -1,7 +1,21 @@ struct Interface { - virtual void video_refresh(const uint16_t *data) {} - virtual void audio_sample(int16_t sample) {} - virtual int16_t input_poll(bool port, unsigned device, unsigned id) { return 0; } + virtual void videoRefresh(const uint16_t *data); + virtual void audioSample(int16_t sample); + virtual int16_t inputPoll(bool port, unsigned device, unsigned id); - virtual void message(const string &text) { print(text, "\n"); } + virtual void initialize(Interface*); + + virtual bool cartridgeLoaded(); + virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size); + virtual void unloadCartridge(); + + virtual void power(); + virtual void reset(); + virtual void run(); + + virtual void setCheats(const lstring &list = lstring{}); + + virtual void message(const string &text); }; + +extern Interface *interface; diff --git a/bsnes/nes/memory/memory.cpp b/bsnes/nes/memory/memory.cpp index 09e7c990..239ed8c1 100755 --- a/bsnes/nes/memory/memory.cpp +++ b/bsnes/nes/memory/memory.cpp @@ -18,13 +18,10 @@ uint8 Bus::read(uint16 addr) { if(addr <= 0x4017) return cpu.read(addr); if(cheat.override[addr]) { - for(unsigned x = 0; x < cheat.size(); x++) { - const CheatCode &code = cheat[x]; - for(unsigned y = 0; y < code.addr.size(); y++) { - if(code.addr[y] == addr) { - if(code.comp[y] > 255 || code.comp[y] == data) { - return code.data[y]; - } + for(unsigned n = 0; n < cheat.size(); n++) { + if(cheat[n].addr == addr) { + if(cheat[n].comp > 255 || cheat[n].comp == data) { + return cheat[n].data; } } } diff --git a/bsnes/nes/nes.hpp b/bsnes/nes/nes.hpp index 2226c715..07148dc7 100755 --- a/bsnes/nes/nes.hpp +++ b/bsnes/nes/nes.hpp @@ -4,7 +4,7 @@ namespace NES { namespace Info { static const char Name[] = "bnes"; - static const char Version[] = "000.08"; + static const char Version[] = "000.09"; } } diff --git a/bsnes/nes/ppu/ppu.cpp b/bsnes/nes/ppu/ppu.cpp index 83ad9663..7dded077 100755 --- a/bsnes/nes/ppu/ppu.cpp +++ b/bsnes/nes/ppu/ppu.cpp @@ -33,7 +33,7 @@ void PPU::scanline_edge() { void PPU::frame_edge() { status.field ^= 1; - system.interface->video_refresh(buffer); + interface->videoRefresh(buffer); scheduler.exit(); } diff --git a/bsnes/nes/system/system.cpp b/bsnes/nes/system/system.cpp index 2b5893ba..3c21a8a9 100755 --- a/bsnes/nes/system/system.cpp +++ b/bsnes/nes/system/system.cpp @@ -14,11 +14,6 @@ void System::power() { apu.power(); ppu.power(); scheduler.power(); - -// cheat.reset(); -// cheat.append(CheatCode("GXXZZLVI")); -// cheat[0].enable = true; -// cheat.synchronize(); } void System::reset() { @@ -29,8 +24,8 @@ void System::reset() { scheduler.reset(); } -void System::init(Interface *interface) { - this->interface = interface; +void System::init() { + assert(interface != 0); } void System::term() { diff --git a/bsnes/nes/system/system.hpp b/bsnes/nes/system/system.hpp index 4324abb0..78d2892b 100755 --- a/bsnes/nes/system/system.hpp +++ b/bsnes/nes/system/system.hpp @@ -1,11 +1,9 @@ struct System { - Interface *interface; - void run(); void power(); void reset(); - void init(Interface *interface); + void init(); void term(); }; diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index 30096db4..d380cd8a 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -1,4 +1,4 @@ -snes_objects := snes-system snes-controller +snes_objects := snes-interface snes-system snes-controller snes_objects += snes-cartridge snes-cheat snes_objects += snes-memory snes-cpucore snes-smpcore snes_objects += snes-cpu snes-smp snes-dsp snes-ppu @@ -28,6 +28,7 @@ else ifeq ($(profile),performance) snesppu := $(snes)/alt/ppu-performance endif +obj/snes-interface.o : $(snes)/interface/interface.cpp $(call rwildcard,$(snes)/interface) obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/) $(call rwildcard,$(snes)/audio/) $(call rwildcard,$(snes)/input/) obj/snes-controller.o: $(snes)/controller/controller.cpp $(call rwildcard,$(snes)/controller/) obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/) diff --git a/bsnes/snes/audio/audio.cpp b/bsnes/snes/audio/audio.cpp index d715c69c..1e0d9886 100755 --- a/bsnes/snes/audio/audio.cpp +++ b/bsnes/snes/audio/audio.cpp @@ -19,7 +19,7 @@ void Audio::coprocessor_frequency(double input_frequency) { void Audio::sample(int16 left, int16 right) { if(coprocessor == false) { - system.interface->audio_sample(left, right); + interface->audioSample(left, right); } else { dsp_buffer[dsp_wroffset] = ((uint16)left << 0) + ((uint16)right << 16); dsp_wroffset = (dsp_wroffset + 1) & buffer_mask; @@ -61,7 +61,7 @@ void Audio::flush() { int cop_left = (int16)(cop_sample >> 0); int cop_right = (int16)(cop_sample >> 16); - system.interface->audio_sample( + interface->audioSample( sclamp<16>((dsp_left + cop_left ) / 2), sclamp<16>((dsp_right + cop_right) / 2) ); diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp index 76cb44ff..c8ebc888 100755 --- a/bsnes/snes/cartridge/xml.cpp +++ b/bsnes/snes/cartridge/xml.cpp @@ -299,16 +299,16 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { } } - string path = { dir(system.interface->path(Slot::Base, ".dsp")), firmware }; + string path = { dir(interface->path(Slot::Base, ".dsp")), firmware }; unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384); unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048); unsigned filesize = promsize * 3 + dromsize * 2; file fp; if(fp.open(path, file::mode::read) == false) { - system.interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." }); + interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." }); } else if(fp.size() != filesize) { - system.interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." }); + interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." }); fp.close(); } else { for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3); @@ -321,7 +321,7 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { fp.read(data, filesize); if(sha256 != nall::sha256(data, filesize)) { - system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." }); + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." }); } } @@ -381,12 +381,12 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) { } } - string path = { dir(system.interface->path(Slot::Base, ".dsp")), firmware }; + string path = { dir(interface->path(Slot::Base, ".dsp")), firmware }; file fp; if(fp.open(path, file::mode::read) == false) { - system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." }); + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." }); } else if(fp.size() != 1024 * 3) { - system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." }); + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." }); fp.close(); } else { for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3); @@ -398,7 +398,7 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) { fp.read(data, 3072); if(sha256 != nall::sha256(data, 3072)) { - system.interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." }); + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." }); } } diff --git a/bsnes/snes/cheat/cheat.cpp b/bsnes/snes/cheat/cheat.cpp index 695de58a..06e79d08 100755 --- a/bsnes/snes/cheat/cheat.cpp +++ b/bsnes/snes/cheat/cheat.cpp @@ -16,27 +16,22 @@ void Cheat::enable(bool state) { void Cheat::synchronize() { memset(override, 0x00, 16 * 1024 * 1024); - code_enabled = false; + code_enabled = size() > 0; for(unsigned i = 0; i < size(); i++) { const CheatCode &code = operator[](i); - if(code.enabled == false) continue; - for(unsigned n = 0; n < code.addr.size(); n++) { - code_enabled = true; + unsigned addr = mirror(code.addr); + override[addr] = true; + if((addr & 0xffe000) == 0x7e0000) { + //mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff + unsigned mirroraddr; + for(unsigned x = 0; x <= 0x3f; x++) { + mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff); + override[mirroraddr] = true; - unsigned addr = mirror(code.addr[n]); - override[addr] = true; - if((addr & 0xffe000) == 0x7e0000) { - //mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff - unsigned mirroraddr; - for(unsigned x = 0; x <= 0x3f; x++) { - mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff); - override[mirroraddr] = true; - - mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff); - override[mirroraddr] = true; - } + mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff); + override[mirroraddr] = true; } } } @@ -49,12 +44,8 @@ uint8 Cheat::read(unsigned addr) const { for(unsigned i = 0; i < size(); i++) { const CheatCode &code = operator[](i); - if(code.enabled == false) continue; - - for(unsigned n = 0; n < code.addr.size(); n++) { - if(addr == mirror(code.addr[n])) { - return code.data[n]; - } + if(addr == mirror(code.addr)) { + return code.data; } } @@ -78,7 +69,7 @@ Cheat::~Cheat() { //encode / decode //=============== -bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) { +bool Cheat::decode(const char *s, unsigned &addr, unsigned &data, Type &type) { string t = s; t.lower(); @@ -128,7 +119,7 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) { #undef ischr } -bool Cheat::encode(string &s, unsigned addr, uint8 data, Type type) { +bool Cheat::encode(string &s, unsigned addr, unsigned data, Type type) { char t[16]; if(type == Type::ProActionReplay) { @@ -166,36 +157,4 @@ unsigned Cheat::mirror(unsigned addr) const { return addr; } -//========= -//CheatCode -//========= - -bool CheatCode::operator=(string s) { - addr.reset(); - data.reset(); - - lstring list; - list.split("+", s.replace(" ", "")); - - for(unsigned i = 0; i < list.size(); i++) { - unsigned addr_; - uint8 data_; - Cheat::Type type_; - if(Cheat::decode(list[i], addr_, data_, type_) == false) { - addr.reset(); - data.reset(); - return false; - } - - addr.append(addr_); - data.append(data_); - } - - return true; -} - -CheatCode::CheatCode() { - enabled = false; -} - } diff --git a/bsnes/snes/cheat/cheat.hpp b/bsnes/snes/cheat/cheat.hpp index 8e608029..d2c2c17a 100755 --- a/bsnes/snes/cheat/cheat.hpp +++ b/bsnes/snes/cheat/cheat.hpp @@ -1,10 +1,6 @@ struct CheatCode { - bool enabled; - array addr; - array data; - - bool operator=(string); - CheatCode(); + unsigned addr; + unsigned data; }; class Cheat : public linear_vector { @@ -21,8 +17,8 @@ public: Cheat(); ~Cheat(); - static bool decode(const char*, unsigned&, uint8&, Type&); - static bool encode(string&, unsigned, uint8, Type); + static bool decode(const char*, unsigned&, unsigned&, Type&); + static bool encode(string&, unsigned, unsigned, Type); private: bool system_enabled; diff --git a/bsnes/snes/chip/icd2/icd2.cpp b/bsnes/snes/chip/icd2/icd2.cpp index 4f332139..45208c6b 100755 --- a/bsnes/snes/chip/icd2/icd2.cpp +++ b/bsnes/snes/chip/icd2/icd2.cpp @@ -69,8 +69,8 @@ void ICD2::reset() { joyp14lock = 0; pulselock = true; - GameBoy::system.init(this); - GameBoy::system.power(); + GameBoy::Interface::initialize(this); + GameBoy::Interface::power(); } } diff --git a/bsnes/snes/chip/icd2/interface/interface.cpp b/bsnes/snes/chip/icd2/interface/interface.cpp index 7e996b85..36bf30a7 100755 --- a/bsnes/snes/chip/icd2/interface/interface.cpp +++ b/bsnes/snes/chip/icd2/interface/interface.cpp @@ -1,7 +1,7 @@ #ifdef ICD2_CPP //called on rendered lines 0-143 (not on Vblank lines 144-153) -void ICD2::lcd_scanline() { +void ICD2::lcdScanline() { if((GameBoy::lcd.status.ly & 7) == 0) { lcd.row = (lcd.row + 1) & 3; } @@ -10,7 +10,7 @@ void ICD2::lcd_scanline() { memcpy(lcd.buffer + offset, GameBoy::lcd.screen + GameBoy::lcd.status.ly * 160, 160); } -void ICD2::joyp_write(bool p15, bool p14) { +void ICD2::joypWrite(bool p15, bool p14) { //joypad handling if(p15 == 1 && p14 == 1) { if(joyp15lock == 0 && joyp14lock == 0) { @@ -80,17 +80,14 @@ void ICD2::joyp_write(bool p15, bool p14) { packetlock = true; } -void ICD2::video_refresh(const uint8_t *data) { +void ICD2::videoRefresh(const uint8_t *data) { } -void ICD2::audio_sample(int16_t center, int16_t left, int16_t right) { +void ICD2::audioSample(int16_t center, int16_t left, int16_t right) { audio.coprocessor_sample(left, right); } -void ICD2::input_poll() { -} - -bool ICD2::input_poll(unsigned id) { +bool ICD2::inputPoll(unsigned id) { GameBoy::cpu.status.mlt_req = joyp_id & mlt_req; unsigned data = 0x00; diff --git a/bsnes/snes/chip/icd2/interface/interface.hpp b/bsnes/snes/chip/icd2/interface/interface.hpp index 531a9ce7..ab8b63c4 100755 --- a/bsnes/snes/chip/icd2/interface/interface.hpp +++ b/bsnes/snes/chip/icd2/interface/interface.hpp @@ -1,9 +1,8 @@ -void lcd_scanline(); -void joyp_write(bool p15, bool p14); -void video_refresh(const uint8_t *data); -void audio_sample(int16_t center, int16_t left, int16_t right); -void input_poll(); -bool input_poll(unsigned id); +void lcdScanline(); +void joypWrite(bool p15, bool p14); +void videoRefresh(const uint8_t *data); +void audioSample(int16_t center, int16_t left, int16_t right); +bool inputPoll(unsigned id); struct Packet { uint8 data[16]; diff --git a/bsnes/snes/chip/link/link.cpp b/bsnes/snes/chip/link/link.cpp index 6f61a189..a5736933 100755 --- a/bsnes/snes/chip/link/link.cpp +++ b/bsnes/snes/chip/link/link.cpp @@ -22,7 +22,7 @@ void Link::init() { void Link::load() { if(opened()) close(); - string basename = system.interface->path(Cartridge::Slot::Base, ""); + string basename = interface->path(Cartridge::Slot::Base, ""); string name = program != "" ? program : notdir(basename); string path = dir(basename); if(open(name, path)) { diff --git a/bsnes/snes/chip/msu1/msu1.cpp b/bsnes/snes/chip/msu1/msu1.cpp index 3c3335cc..af19acea 100755 --- a/bsnes/snes/chip/msu1/msu1.cpp +++ b/bsnes/snes/chip/msu1/msu1.cpp @@ -50,7 +50,7 @@ void MSU1::init() { void MSU1::load() { if(datafile.open()) datafile.close(); - datafile.open(system.interface->path(Cartridge::Slot::Base, ".msu"), file::mode::read); + datafile.open(interface->path(Cartridge::Slot::Base, ".msu"), file::mode::read); } void MSU1::unload() { @@ -133,7 +133,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) { if(addr == 0x2005) { mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8); if(audiofile.open()) audiofile.close(); - if(audiofile.open(system.interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { + if(audiofile.open(interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { uint32 header = audiofile.readm(4); if(header != 0x4d535531) { //verify 'MSU1' header audiofile.close(); diff --git a/bsnes/snes/chip/msu1/serialization.cpp b/bsnes/snes/chip/msu1/serialization.cpp index ba1a6b8d..a5806b75 100755 --- a/bsnes/snes/chip/msu1/serialization.cpp +++ b/bsnes/snes/chip/msu1/serialization.cpp @@ -16,12 +16,12 @@ void MSU1::serialize(serializer &s) { s.integer(mmio.audio_play); if(datafile.open()) datafile.close(); - if(datafile.open(system.interface->path(Cartridge::Slot::Base, ".msu"), file::mode::read)) { + if(datafile.open(interface->path(Cartridge::Slot::Base, ".msu"), file::mode::read)) { datafile.seek(mmio.data_offset); } if(audiofile.open()) audiofile.close(); - if(audiofile.open(system.interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { + if(audiofile.open(interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { audiofile.seek(mmio.audio_offset); } } diff --git a/bsnes/snes/controller/gamepad/gamepad.cpp b/bsnes/snes/controller/gamepad/gamepad.cpp index d0830234..594020d2 100755 --- a/bsnes/snes/controller/gamepad/gamepad.cpp +++ b/bsnes/snes/controller/gamepad/gamepad.cpp @@ -2,7 +2,7 @@ uint2 Gamepad::data() { if(counter >= 16) return 1; - uint2 result = system.interface->input_poll(port, Input::Device::Joypad, 0, counter); + uint2 result = interface->inputPoll(port, Input::Device::Joypad, 0, counter); if(latched == 0) counter++; return result; } diff --git a/bsnes/snes/controller/justifier/justifier.cpp b/bsnes/snes/controller/justifier/justifier.cpp index dd4c2e1f..8b2d3ee4 100755 --- a/bsnes/snes/controller/justifier/justifier.cpp +++ b/bsnes/snes/controller/justifier/justifier.cpp @@ -18,16 +18,16 @@ void Justifier::enter() { } if(next < prev) { - int nx1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X); - int ny1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y); + int nx1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X); + int ny1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y); nx1 += x1; ny1 += y1; x1 = max(-16, min(256 + 16, nx1)); y1 = max(-16, min(240 + 16, ny1)); if(chained == true) { - int nx2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X); - int ny2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y); + int nx2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X); + int ny2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y); nx2 += x2; ny2 += y2; x2 = max(-16, min(256 + 16, nx2)); @@ -48,11 +48,11 @@ uint2 Justifier::data() { if(counter >= 32) return 1; if(counter == 0) { - trigger1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger); - start1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start); + trigger1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger); + start1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start); if(chained) { - trigger2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger); - start2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start); + trigger2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger); + start2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start); } } diff --git a/bsnes/snes/controller/mouse/mouse.cpp b/bsnes/snes/controller/mouse/mouse.cpp index 0b05e5db..c9f5d16b 100755 --- a/bsnes/snes/controller/mouse/mouse.cpp +++ b/bsnes/snes/controller/mouse/mouse.cpp @@ -3,8 +3,8 @@ uint2 Mouse::data() { if(counter >= 32) return 1; - int position_x = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right - int position_y = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down + int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right + int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down bool direction_x = position_x < 0; //0 = right, 1 = left bool direction_y = position_y < 0; //0 = down, 1 = up @@ -25,8 +25,8 @@ uint2 Mouse::data() { case 6: return 0; case 7: return 0; - case 8: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right); - case 9: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left); + case 8: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right); + case 9: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left); case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused) case 11: return 0; // || diff --git a/bsnes/snes/controller/multitap/multitap.cpp b/bsnes/snes/controller/multitap/multitap.cpp index df04054b..3a6eb720 100755 --- a/bsnes/snes/controller/multitap/multitap.cpp +++ b/bsnes/snes/controller/multitap/multitap.cpp @@ -18,8 +18,8 @@ uint2 Multitap::data() { port2 = 3; //controller 4 } - bool data1 = system.interface->input_poll(port, Input::Device::Multitap, port1, index); - bool data2 = system.interface->input_poll(port, Input::Device::Multitap, port2, index); + bool data1 = interface->inputPoll(port, Input::Device::Multitap, port1, index); + bool data2 = interface->inputPoll(port, Input::Device::Multitap, port2, index); return (data2 << 1) | (data1 << 0); } diff --git a/bsnes/snes/controller/serial/serial.cpp b/bsnes/snes/controller/serial/serial.cpp index c3ba69c7..24491146 100755 --- a/bsnes/snes/controller/serial/serial.cpp +++ b/bsnes/snes/controller/serial/serial.cpp @@ -79,7 +79,7 @@ void Serial::latch(bool data) { Serial::Serial(bool port) : Controller(port) { enable = false; - string basename = system.interface->path(Cartridge::Slot::Base, ""); + string basename = interface->path(Cartridge::Slot::Base, ""); string name = notdir(basename); string path = dir(basename); if(open(name, path)) { diff --git a/bsnes/snes/controller/superscope/superscope.cpp b/bsnes/snes/controller/superscope/superscope.cpp index 46d5734f..e97a2ff5 100755 --- a/bsnes/snes/controller/superscope/superscope.cpp +++ b/bsnes/snes/controller/superscope/superscope.cpp @@ -28,8 +28,8 @@ void SuperScope::enter() { if(next < prev) { //Vcounter wrapped back to zero; update cursor coordinates for start of new frame - int nx = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X); - int ny = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y); + int nx = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X); + int ny = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y); nx += x; ny += y; x = max(-16, min(256 + 16, nx)); @@ -51,7 +51,7 @@ uint2 SuperScope::data() { if(counter == 0) { //turbo is a switch; toggle is edge sensitive - bool newturbo = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo); + bool newturbo = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo); if(newturbo && !turbo) { turbo = !turbo; //toggle state turbolock = true; @@ -62,7 +62,7 @@ uint2 SuperScope::data() { //trigger is a button //if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive trigger = false; - bool newtrigger = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger); + bool newtrigger = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger); if(newtrigger && (turbo || !triggerlock)) { trigger = true; triggerlock = true; @@ -71,11 +71,11 @@ uint2 SuperScope::data() { } //cursor is a button; it is always level sensitive - cursor = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor); + cursor = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor); //pause is a button; it is always edge sensitive pause = false; - bool newpause = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause); + bool newpause = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause); if(newpause && !pauselock) { pause = true; pauselock = true; diff --git a/bsnes/snes/interface/interface.cpp b/bsnes/snes/interface/interface.cpp new file mode 100755 index 00000000..b120a5c9 --- /dev/null +++ b/bsnes/snes/interface/interface.cpp @@ -0,0 +1,77 @@ +#include + +namespace SNES { + +Interface *interface = 0; + +void Interface::videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan) { +} + +void Interface::audioSample(int16_t l_sample, int16_t r_sample) { +} + +int16_t Interface::inputPoll(bool port, Input::Device device, unsigned index, unsigned id) { + return 0; +} + +void Interface::initialize(Interface *derived_interface) { + interface = derived_interface; + system.init(); +} + +bool Interface::cartridgeLoaded() { + return cartridge.loaded(); +} + +void Interface::loadCartridge(const string &xml, const uint8_t *data, unsigned size) { + cartridge.rom.copy(data, size); + cartridge.load(Cartridge::Mode::Normal, { xml }); + system.power(); +} + +void Interface::unloadCartridge() { + cartridge.unload(); +} + +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(); + foreach(code, list) { + lstring codelist; + codelist.split("+", code); + foreach(part, codelist) { + unsigned addr, data; + Cheat::Type type; + if(Cheat::decode(part, addr, data, type)) { + 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 342956af..8a18b9ab 100755 --- a/bsnes/snes/interface/interface.hpp +++ b/bsnes/snes/interface/interface.hpp @@ -1,9 +1,26 @@ class Interface { public: - virtual void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {} - virtual void audio_sample(int16_t l_sample, int16_t r_sample) {} - virtual int16_t input_poll(bool port, Input::Device device, unsigned index, unsigned id) { return 0; } + virtual void videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan); + virtual void audioSample(int16_t lsample, int16_t rsample); + virtual int16_t inputPoll(bool port, Input::Device device, unsigned index, unsigned id); - virtual void message(const string &text) { print(text, "\n"); } + virtual void initialize(Interface*); + + virtual bool cartridgeLoaded(); + virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size); + virtual void unloadCartridge(); + + virtual void power(); + virtual void reset(); + virtual void run(); + + virtual serializer serialize(); + virtual bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); + + virtual void message(const string &text); virtual string path(Cartridge::Slot slot, const string &hint) = 0; }; + +extern Interface *interface; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index ff9cb345..24f4e2ac 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -4,8 +4,8 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "082.12"; - static const unsigned SerializerVersion = 21; + static const char Version[] = "082.13"; + static const unsigned SerializerVersion = 22; } } diff --git a/bsnes/snes/system/serialization.cpp b/bsnes/snes/system/serialization.cpp index d97f73b7..ba12302f 100755 --- a/bsnes/snes/system/serialization.cpp +++ b/bsnes/snes/system/serialization.cpp @@ -4,16 +4,16 @@ serializer System::serialize() { serializer s(serialize_size); unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = cartridge.crc32(); - char profile[16], description[512]; - memset(&profile, 0, sizeof profile); + char description[512], profile[16]; memset(&description, 0, sizeof description); + memset(&profile, 0, sizeof profile); strlcpy(profile, Info::Profile, sizeof profile); s.integer(signature); s.integer(version); s.integer(crc32); - s.array(profile); s.array(description); + s.array(profile); serialize_all(s); return s; @@ -21,13 +21,13 @@ serializer System::serialize() { bool System::unserialize(serializer &s) { unsigned signature, version, crc32; - char profile[16], description[512]; + char description[512], profile[16]; s.integer(signature); s.integer(version); s.integer(crc32); - s.array(profile); s.array(description); + s.array(profile); if(signature != 0x31545342) return false; if(version != Info::SerializerVersion) return false; diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 37118b43..68818109 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -63,8 +63,7 @@ void System::runthreadtosave() { } } -void System::init(Interface *interface_) { - interface = interface_; +void System::init() { assert(interface != 0); icd2.init(); @@ -241,7 +240,7 @@ void System::scanline() { void System::frame() { } -System::System() : interface(0) { +System::System() { region = Region::Autodetect; expansion = ExpansionPortDevice::BSX; } diff --git a/bsnes/snes/system/system.hpp b/bsnes/snes/system/system.hpp index 8bfbeddc..cbff9517 100755 --- a/bsnes/snes/system/system.hpp +++ b/bsnes/snes/system/system.hpp @@ -2,14 +2,13 @@ class Interface; class System : property { public: - Interface *interface; enum class Region : unsigned { NTSC = 0, PAL = 1, Autodetect = 2 }; enum class ExpansionPortDevice : unsigned { None = 0, BSX = 1 }; void run(); void runtosave(); - void init(Interface*); + void init(); void term(); void load(); void unload(); diff --git a/bsnes/snes/video/video.cpp b/bsnes/snes/video/video.cpp index 2bcf7b10..b2bd1810 100755 --- a/bsnes/snes/video/video.cpp +++ b/bsnes/snes/video/video.cpp @@ -79,7 +79,7 @@ void Video::update() { } } - system.interface->video_refresh(ppu.surface, hires, ppu.interlace(), ppu.overscan()); + interface->videoRefresh(ppu.surface, hires, ppu.interlace(), ppu.overscan()); hires = false; } diff --git a/bsnes/ui-libsnes/libsnes.cpp b/bsnes/ui-libsnes/libsnes.cpp index 4b4dd373..3a875912 100755 --- a/bsnes/ui-libsnes/libsnes.cpp +++ b/bsnes/ui-libsnes/libsnes.cpp @@ -12,7 +12,7 @@ struct Interface : public SNES::Interface { snes_input_state_t pinput_state; string basename; - void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) { + void videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan) { unsigned width = hires ? 512 : 256; unsigned height = overscan ? 239 : 224; if(interlace) height <<= 1; @@ -21,15 +21,11 @@ struct Interface : public SNES::Interface { if(pinput_poll) pinput_poll(); } - void audio_sample(int16_t left, int16_t right) { + void audioSample(int16_t left, int16_t right) { if(paudio_sample) return paudio_sample(left, right); } - void input_poll() { - if(pinput_poll) return pinput_poll(); - } - - int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { + int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { if(pinput_state) return pinput_state(port, (unsigned)device, index, id); return 0; } @@ -86,7 +82,7 @@ void snes_set_cartridge_basename(const char *basename) { } void snes_init(void) { - SNES::system.init(&interface); + interface.initialize(&interface); SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); } @@ -124,15 +120,27 @@ bool snes_unserialize(const uint8_t *data, unsigned size) { return SNES::system.unserialize(s); } +struct CheatList { + bool enable; + string code; + CheatList() : enable(false) {} +}; + +static linear_vector cheatList; + void snes_cheat_reset(void) { - SNES::cheat.reset(); - SNES::cheat.synchronize(); + cheatList.reset(); + interface.setCheats(); } -void snes_cheat_set(unsigned index, bool enabled, const char *code) { - SNES::cheat[index] = code; - SNES::cheat[index].enabled = enabled; - SNES::cheat.synchronize(); +void snes_cheat_set(unsigned index, bool enable, const char *code) { + cheatList[index].enable = enable; + cheatList[index].code = code; + lstring list; + for(unsigned n = 0; n < cheatList.size(); n++) { + if(cheatList[n].enable) list.append(cheatList[n].code); + } + interface.setCheats(list); } bool snes_load_cartridge_normal( diff --git a/bsnes/ui-libsnes/libsnes.hpp b/bsnes/ui-libsnes/libsnes.hpp index 5d7f50e1..18b269f1 100755 --- a/bsnes/ui-libsnes/libsnes.hpp +++ b/bsnes/ui-libsnes/libsnes.hpp @@ -95,7 +95,7 @@ bool snes_serialize(uint8_t *data, unsigned size); bool snes_unserialize(const uint8_t *data, unsigned size); void snes_cheat_reset(void); -void snes_cheat_set(unsigned index, bool enabled, const char *code); +void snes_cheat_set(unsigned index, bool enable, const char *code); bool snes_load_cartridge_normal( const char *rom_xml, const uint8_t *rom_data, unsigned rom_size diff --git a/bsnes/ui/general/main-window.cpp b/bsnes/ui/general/main-window.cpp index 2ef25ffe..7ebf1759 100755 --- a/bsnes/ui/general/main-window.cpp +++ b/bsnes/ui/general/main-window.cpp @@ -26,7 +26,7 @@ MainWindow::MainWindow() { settingsMenu.setText("Settings"); settingsSynchronizeVideo.setText("Synchronize Video"); - settingsSynchronizeVideo.setChecked(); + settingsSynchronizeVideo.setChecked(false); settingsSynchronizeAudio.setText("Synchronize Audio"); settingsSynchronizeAudio.setChecked(); settingsMuteAudio.setText("Mute Audio"); @@ -46,6 +46,7 @@ MainWindow::MainWindow() { toolsStateLoad5.setText("Slot 5"); toolsShrinkWindow.setText("Shrink Window"); toolsCheatEditor.setText("Cheat Editor ..."); + toolsStateManager.setText("State Manager ..."); toolsTest.setText("Test"); helpMenu.setText("Help"); @@ -94,6 +95,7 @@ MainWindow::MainWindow() { toolsMenu.append(toolsSeparator); toolsMenu.append(toolsShrinkWindow); toolsMenu.append(toolsCheatEditor); + toolsMenu.append(toolsStateManager); toolsMenu.append(toolsTest); append(helpMenu); @@ -168,6 +170,7 @@ MainWindow::MainWindow() { toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); }; toolsCheatEditor.onTick = [&] { cheatEditor->setVisible(); }; + toolsStateManager.onTick = [&] { stateManager->setVisible(); }; toolsTest.onTick = [&] { NES::cpu.trace = toolsTest.checked(); diff --git a/bsnes/ui/general/main-window.hpp b/bsnes/ui/general/main-window.hpp index f66ce42b..7c13432e 100755 --- a/bsnes/ui/general/main-window.hpp +++ b/bsnes/ui/general/main-window.hpp @@ -45,6 +45,7 @@ struct MainWindow : Window { Separator toolsSeparator; Item toolsShrinkWindow; Item toolsCheatEditor; + Item toolsStateManager; CheckItem toolsTest; Menu helpMenu; diff --git a/bsnes/ui/interface/gameboy.cpp b/bsnes/ui/interface/gameboy.cpp index 88f608c0..b18bf2c8 100755 --- a/bsnes/ui/interface/gameboy.cpp +++ b/bsnes/ui/interface/gameboy.cpp @@ -5,21 +5,19 @@ bool InterfaceGameBoy::loadCartridge(const string &filename) { interface->baseName = nall::basename(filename); GameBoyCartridge info(data, size); - GameBoy::cartridge.load(info.xml, data, size); - GameBoy::system.power(); + GameBoy::Interface::loadCartridge(info.xml, data, size); delete[] data; return true; } void InterfaceGameBoy::unloadCartridge() { - GameBoy::cartridge.unload(); + GameBoy::Interface::unloadCartridge(); interface->baseName = ""; } bool InterfaceGameBoy::saveState(const string &filename) { - GameBoy::system.runtosave(); - serializer s = GameBoy::system.serialize(); + serializer s = serialize(); return file::write(filename, s.data(), s.size()); } @@ -29,21 +27,12 @@ bool InterfaceGameBoy::loadState(const string &filename) { if(file::read(filename, data, size) == false) return false; serializer s(data, size); delete[] data; - return GameBoy::system.unserialize(s); -} - -void InterfaceGameBoy::setCheatCodes(const lstring &list) { - GameBoy::cheat.reset(); - for(unsigned n = 0; n < list.size(); n++) { - GameBoy::cheat[n] = list[n]; - GameBoy::cheat[n].enable = true; - } - GameBoy::cheat.synchronize(); + return unserialize(s); } // -void InterfaceGameBoy::video_refresh(const uint8_t *data) { +void InterfaceGameBoy::videoRefresh(const uint8_t *data) { interface->video_refresh(); uint32_t *output; @@ -63,7 +52,7 @@ void InterfaceGameBoy::video_refresh(const uint8_t *data) { } } -void InterfaceGameBoy::audio_sample(int16_t csample, int16_t lsample, int16_t rsample) { +void InterfaceGameBoy::audioSample(int16_t csample, int16_t lsample, int16_t rsample) { dspaudio.sample(lsample, rsample); while(dspaudio.pending()) { signed lsample, rsample; @@ -72,7 +61,7 @@ void InterfaceGameBoy::audio_sample(int16_t csample, int16_t lsample, int16_t rs } } -bool InterfaceGameBoy::input_poll(unsigned id) { +bool InterfaceGameBoy::inputPoll(unsigned id) { switch((GameBoy::Input)id) { case GameBoy::Input::Up: return interface->inputState[keyboard(0)[Keyboard::Up]]; case GameBoy::Input::Down: return interface->inputState[keyboard(0)[Keyboard::Down]]; diff --git a/bsnes/ui/interface/gameboy.hpp b/bsnes/ui/interface/gameboy.hpp index 41891cb5..35177641 100755 --- a/bsnes/ui/interface/gameboy.hpp +++ b/bsnes/ui/interface/gameboy.hpp @@ -4,9 +4,8 @@ struct InterfaceGameBoy : GameBoy::Interface { bool saveState(const string &filename); bool loadState(const string &filename); - void setCheatCodes(const lstring &list); - void video_refresh(const uint8_t *data); - void audio_sample(int16_t csample, int16_t lsample, int16_t rsample); - bool input_poll(unsigned id); + void videoRefresh(const uint8_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 6bfed70c..0bc157ad 100755 --- a/bsnes/ui/interface/interface.cpp +++ b/bsnes/ui/interface/interface.cpp @@ -6,21 +6,25 @@ Interface *interface = 0; bool Interface::loaded() { switch(mode()) { - case Mode::NES: return NES::cartridge.loaded(); - case Mode::SNES: return SNES::cartridge.loaded(); - case Mode::GameBoy: return GameBoy::cartridge.loaded(); - default: return false; + case Mode::NES: return nes.cartridgeLoaded(); + case Mode::SNES: return snes.cartridgeLoaded(); + case Mode::GameBoy: return gameBoy.cartridgeLoaded(); } + return false; } bool Interface::loadCartridge(const string &filename) { bool result = false; + setCheatCodes(); unloadCartridge(); if(filename.endswith(".nes")) result = loadCartridgeNES(filename); if(filename.endswith(".sfc")) result = loadCartridgeSNES(filename); if(filename.endswith(".gb" )) result = loadCartridgeGameBoy(filename); if(filename.endswith(".gbc")) result = loadCartridgeGameBoy(filename); - if(result == true) cheatEditor->load({ baseName, ".cht" }); + if(result == true) { + cheatEditor->load({ baseName, ".cht" }); + stateManager->load({ baseName, ".bsa" }, 0u); + } return result; } @@ -33,10 +37,11 @@ bool Interface::loadCartridgeNES(const string &filename) { void Interface::unloadCartridge() { if(loaded() == false) return; cheatEditor->save({ baseName, ".cht" }); + stateManager->save({ baseName, ".bsa" }, 0u); switch(mode()) { - case Mode::NES: nes.unloadCartridge(); break; - case Mode::SNES: snes.unloadCartridge(); break; + case Mode::NES: nes.unloadCartridge(); break; + case Mode::SNES: snes.unloadCartridge(); break; case Mode::GameBoy: gameBoy.unloadCartridge(); break; } @@ -72,36 +77,44 @@ void Interface::unloadCartridgeGameBoy() { void Interface::power() { switch(mode()) { - case Mode::NES: return NES::system.power(); - case Mode::SNES: return SNES::system.power(); - case Mode::GameBoy: return GameBoy::system.power(); + case Mode::NES: return nes.power(); + case Mode::SNES: return snes.power(); + case Mode::GameBoy: return gameBoy.power(); } } void Interface::reset() { switch(mode()) { - case Mode::NES: return NES::system.reset(); - case Mode::SNES: return SNES::system.reset(); - case Mode::GameBoy: return GameBoy::system.power(); //Game Boy lacks reset button + case Mode::NES: return nes.reset(); + case Mode::SNES: return snes.reset(); + case Mode::GameBoy: return gameBoy.power(); //Game Boy lacks reset button } } void Interface::run() { switch(mode()) { - case Mode::NES: - return NES::system.run(); - - case Mode::SNES: - return SNES::system.run(); - - case Mode::GameBoy: - do { - GameBoy::system.run(); - } while(GameBoy::scheduler.exit_reason() != GameBoy::Scheduler::ExitReason::FrameEvent); - return; + case Mode::NES: return nes.run(); + case Mode::SNES: return snes.run(); + case Mode::GameBoy: return gameBoy.run(); } } +serializer Interface::serialize() { + switch(mode()) { + case Mode::SNES: return snes.serialize(); + case Mode::GameBoy: return gameBoy.serialize(); + } + return serializer(); +} + +bool Interface::unserialize(serializer &s) { + switch(mode()) { + case Mode::SNES: return snes.unserialize(s); + case Mode::GameBoy: return gameBoy.unserialize(s); + } + return false; +} + bool Interface::saveState(const string &filename) { switch(mode()) { case Mode::SNES: return snes.saveState(filename); @@ -120,17 +133,17 @@ bool Interface::loadState(const string &filename) { void Interface::setCheatCodes(const lstring &list) { switch(mode()) { - case Mode::NES: return nes.setCheatCodes(list); - case Mode::SNES: return snes.setCheatCodes(list); - case Mode::GameBoy: return gameBoy.setCheatCodes(list); + case Mode::NES: return nes.setCheats(list); + case Mode::SNES: return snes.setCheats(list); + case Mode::GameBoy: return gameBoy.setCheats(list); } } Interface::Interface() { mode = Mode::None; - NES::system.init(&nes); - SNES::system.init(&snes); - GameBoy::system.init(&gameBoy); + nes.initialize(&nes); + snes.initialize(&snes); + gameBoy.initialize(&gameBoy); } //internal diff --git a/bsnes/ui/interface/interface.hpp b/bsnes/ui/interface/interface.hpp index cb51639c..c30ee27e 100755 --- a/bsnes/ui/interface/interface.hpp +++ b/bsnes/ui/interface/interface.hpp @@ -22,9 +22,12 @@ struct Interface : property { void reset(); void run(); + serializer serialize(); + bool unserialize(serializer&); + bool saveState(const string &filename); bool loadState(const string &filename); - void setCheatCodes(const lstring &list); + void setCheatCodes(const lstring &list = lstring{}); Interface(); diff --git a/bsnes/ui/interface/nes.cpp b/bsnes/ui/interface/nes.cpp index 43d59add..8971655c 100755 --- a/bsnes/ui/interface/nes.cpp +++ b/bsnes/ui/interface/nes.cpp @@ -3,30 +3,20 @@ bool InterfaceNES::loadCartridge(const string &filename) { if(fp.open(filename, filemap::mode::read) == false) return false; interface->baseName = nall::basename(filename); - NES::cartridge.load("", fp.data(), fp.size()); - NES::system.power(); + NES::Interface::loadCartridge("", fp.data(), fp.size()); fp.close(); return true; } void InterfaceNES::unloadCartridge() { - NES::cartridge.unload(); + NES::Interface::unloadCartridge(); interface->baseName = ""; } -void InterfaceNES::setCheatCodes(const lstring &list) { - NES::cheat.reset(); - for(unsigned n = 0; n < list.size(); n++) { - NES::cheat[n] = list[n]; - NES::cheat[n].enable = true; - } - NES::cheat.synchronize(); -} - // -void InterfaceNES::video_refresh(const uint16_t *data) { +void InterfaceNES::videoRefresh(const uint16_t *data) { interface->video_refresh(); uint32_t *output; @@ -45,7 +35,7 @@ void InterfaceNES::video_refresh(const uint16_t *data) { } } -void InterfaceNES::audio_sample(int16_t sample) { +void InterfaceNES::audioSample(int16_t sample) { dspaudio.sample(sample, sample); while(dspaudio.pending()) { signed lsample, rsample; @@ -54,7 +44,7 @@ void InterfaceNES::audio_sample(int16_t sample) { } } -int16_t InterfaceNES::input_poll(bool port, unsigned device, unsigned id) { +int16_t InterfaceNES::inputPoll(bool port, unsigned device, unsigned id) { if(port == 0 && device == 0) { switch(id) { case 0: return interface->inputState[keyboard(0)[Keyboard::X]]; diff --git a/bsnes/ui/interface/nes.hpp b/bsnes/ui/interface/nes.hpp index e3db78c6..59aaaf5f 100755 --- a/bsnes/ui/interface/nes.hpp +++ b/bsnes/ui/interface/nes.hpp @@ -2,11 +2,9 @@ struct InterfaceNES : NES::Interface { bool loadCartridge(const string &filename); void unloadCartridge(); - void setCheatCodes(const lstring &list); - - void video_refresh(const uint16_t *data); - void audio_sample(int16_t sample); - int16_t input_poll(bool port, unsigned device, unsigned id); + void videoRefresh(const uint16_t *data); + void audioSample(int16_t sample); + int16_t inputPoll(bool port, unsigned device, unsigned id); InterfaceNES(); diff --git a/bsnes/ui/interface/snes.cpp b/bsnes/ui/interface/snes.cpp index 8d0a3456..85732a35 100755 --- a/bsnes/ui/interface/snes.cpp +++ b/bsnes/ui/interface/snes.cpp @@ -5,22 +5,19 @@ bool InterfaceSNES::loadCartridge(const string &filename) { interface->baseName = nall::basename(filename); string xml = SNESCartridge(data, size).xmlMemoryMap; - SNES::cartridge.rom.copy(data, size); - SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xml }); - SNES::system.power(); + SNES::Interface::loadCartridge(xml, data, size); delete[] data; return true; } void InterfaceSNES::unloadCartridge() { - SNES::cartridge.unload(); + SNES::Interface::unloadCartridge(); interface->baseName = ""; } bool InterfaceSNES::saveState(const string &filename) { - SNES::system.runtosave(); - serializer s = SNES::system.serialize(); + serializer s = serialize(); return file::write(filename, s.data(), s.size()); } @@ -30,21 +27,12 @@ bool InterfaceSNES::loadState(const string &filename) { if(file::read(filename, data, size) == false) return false; serializer s(data, size); delete[] data; - return SNES::system.unserialize(s); -} - -void InterfaceSNES::setCheatCodes(const lstring &list) { - SNES::cheat.reset(); - for(unsigned n = 0; n < list.size(); n++) { - SNES::cheat[n] = list[n]; - SNES::cheat[n].enabled = true; - } - SNES::cheat.synchronize(); + return unserialize(s); } // -void InterfaceSNES::video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) { +void InterfaceSNES::videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan) { interface->video_refresh(); unsigned width = hires ? 512 : 256; @@ -80,7 +68,7 @@ void InterfaceSNES::video_refresh(const uint16_t *data, bool hires, bool interla } } -void InterfaceSNES::audio_sample(int16_t lsample, int16_t rsample) { +void InterfaceSNES::audioSample(int16_t lsample, int16_t rsample) { dspaudio.sample(lsample, rsample); while(dspaudio.pending()) { signed lsample, rsample; @@ -89,7 +77,7 @@ void InterfaceSNES::audio_sample(int16_t lsample, int16_t rsample) { } } -int16_t InterfaceSNES::input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { +int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { if(port == 0 && device == SNES::Input::Device::Joypad) { switch((SNES::Input::JoypadID)id) { case SNES::Input::JoypadID::Up: return interface->inputState[keyboard(0)[Keyboard::Up]]; diff --git a/bsnes/ui/interface/snes.hpp b/bsnes/ui/interface/snes.hpp index f0e17dc6..ce255af2 100755 --- a/bsnes/ui/interface/snes.hpp +++ b/bsnes/ui/interface/snes.hpp @@ -4,11 +4,10 @@ struct InterfaceSNES : SNES::Interface { bool saveState(const string &filename); bool loadState(const string &filename); - void setCheatCodes(const lstring &list); - void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan); - void audio_sample(int16_t lsample, int16_t rsample); - int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id); + void videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan); + void audioSample(int16_t lsample, int16_t rsample); + int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id); string path(SNES::Cartridge::Slot slot, const string &hint); }; diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 1a77a291..f5c380b8 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -42,12 +42,13 @@ Application::Application(int argc, char **argv) : quit(false) { mainWindow = new MainWindow; fileBrowser = new FileBrowser; cheatEditor = new CheatEditor; + stateManager = new StateManager; utility->setMode(Interface::Mode::None); mainWindow->setVisible(); video.driver(videoDriver); video.set(Video::Handle, mainWindow->viewport.handle()); - video.set(Video::Synchronize, true); + video.set(Video::Synchronize, false); video.set(Video::Filter, 0u); video.init(); @@ -79,6 +80,7 @@ Application::Application(int argc, char **argv) : quit(false) { } Application::~Application() { + delete stateManager; delete cheatEditor; delete fileBrowser; delete mainWindow; diff --git a/bsnes/ui/tools/state-manager.cpp b/bsnes/ui/tools/state-manager.cpp new file mode 100755 index 00000000..d6313dda --- /dev/null +++ b/bsnes/ui/tools/state-manager.cpp @@ -0,0 +1,148 @@ +StateManager *stateManager = 0; + +StateManager::StateManager() { + setTitle("State Manager"); + setGeometry({ 128, 128, 600, 360 }); + + stateList.setHeaderText("Slot", "Description"); + stateList.setHeaderVisible(); + descLabel.setText("Description:"); + loadButton.setText("Load"); + saveButton.setText("Save"); + eraseButton.setText("Erase"); + + append(layout); + layout.setMargin(5); + layout.append(stateList, ~0, ~0, 5); + layout.append(descLayout, ~0, 0, 5); + descLayout.append(descLabel, 0, 0, 5); + descLayout.append(descEdit, ~0, 0); + layout.append(controlLayout, ~0, 0); + controlLayout.append(spacer, ~0, 0); + controlLayout.append(loadButton, 80, 0, 5); + controlLayout.append(saveButton, 80, 0, 5); + controlLayout.append(eraseButton, 80, 0); + + for(unsigned n = 0; n < 32; n++) stateList.append(decimal<2>(n + 1), "(empty)"); + stateList.autoSizeColumns(); + + synchronize(); + + stateList.onActivate = { &StateManager::slotLoad, this }; + stateList.onChange = { &StateManager::synchronize, this }; + descEdit.onChange = { &StateManager::slotSaveDescription, this }; + loadButton.onTick = { &StateManager::slotLoad, this }; + saveButton.onTick = { &StateManager::slotSave, this }; + eraseButton.onTick = { &StateManager::slotErase, this }; +} + +void StateManager::synchronize() { + layout.setEnabled(interface->loaded()); + + descEdit.setText(""); + descEdit.setEnabled(false); + controlLayout.setEnabled(stateList.selected()); + if(stateList.selected() == false) return; + + if(slot[stateList.selection()].capacity() > 0) { + descEdit.setText(slotLoadDescription(stateList.selection())); + descEdit.setEnabled(true); + } +} + +void StateManager::refresh() { + for(unsigned n = 0; n < 32; n++) { + stateList.modify(n, decimal<2>(n + 1), slotLoadDescription(n)); + } + stateList.autoSizeColumns(); +} + +bool StateManager::load(const string &filename, unsigned revision) { + for(unsigned n = 0; n < 32; n++) slot[n] = serializer(); + synchronize(); + + file fp; + if(fp.open(filename, file::mode::read) == false) return false; + + if(fp.readl(4) == 0x31415342) { + if(fp.readl(4) == revision) { //'BSA1' + for(unsigned n = 0; n < 32; n++) { + if(fp.read() == false) continue; + unsigned size = fp.readl(4); + uint8_t *data = new uint8_t[size]; + fp.read(data, size); + slot[n] = serializer(data, size); + delete[] data; + } + } + } + + refresh(); + return true; +} + +bool StateManager::save(const string &filename, unsigned revision) { + bool hasSave = false; + for(unsigned n = 0; n < 32; n++) { + if(slot[n].capacity() > 0) hasSave = true; + } + + if(hasSave == false) { + unlink(filename); + return true; + } + + file fp; + if(fp.open(filename, file::mode::write) == false) return false; + + fp.writel(0x31415342, 4); //'BSA1' + fp.writel(revision, 4); + for(unsigned n = 0; n < 32; n++) { + if(slot[n].capacity() == 0) { + fp.write(false); + } else { + fp.write(true); + fp.writel(slot[n].size(), 4); + fp.write(slot[n].data(), slot[n].size()); + } + } +} + +void StateManager::slotLoad() { + if(stateList.selected() == false) return; + serializer s(slot[stateList.selection()].data(), slot[stateList.selection()].capacity()); + interface->unserialize(s); +} + +void StateManager::slotSave() { + if(stateList.selected()) { + slot[stateList.selection()] = interface->serialize(); + } + refresh(); + synchronize(); + descEdit.setFocused(); +} + +void StateManager::slotErase() { + if(stateList.selected()) { + slot[stateList.selection()] = serializer(); + } + refresh(); + synchronize(); +} + +string StateManager::slotLoadDescription(unsigned n) { + if(slot[n].capacity() == 0) return "(empty)"; + char text[DescriptionLength]; + strlcpy(text, (const char*)slot[n].data() + HeaderLength, DescriptionLength); + return text; +} + +void StateManager::slotSaveDescription() { + if(stateList.selected() == false) return; + string text = descEdit.text(); + if(slot[stateList.selection()].capacity() > 0) { + strlcpy((char*)slot[stateList.selection()].data() + HeaderLength, (const char*)text, DescriptionLength); + } + refresh(); +} diff --git a/bsnes/ui/tools/state-manager.hpp b/bsnes/ui/tools/state-manager.hpp new file mode 100755 index 00000000..123de05f --- /dev/null +++ b/bsnes/ui/tools/state-manager.hpp @@ -0,0 +1,38 @@ +struct StateManager : Window { + VerticalLayout layout; + ListView stateList; + HorizontalLayout descLayout; + Label descLabel; + LineEdit descEdit; + HorizontalLayout controlLayout; + Widget spacer; + Button loadButton; + Button saveButton; + Button eraseButton; + + void synchronize(); + void refresh(); + + bool load(const string &filename, unsigned revision); + bool save(const string &filename, unsigned revision); + + void slotLoad(); + void slotSave(); + void slotErase(); + + string slotLoadDescription(unsigned n); + void slotSaveDescription(); + + StateManager(); + +private: + enum : unsigned { + //these valus are standardized across all emulated platforms: + //{ uint32 signature, version, checksum; char description[512]; ... } + HeaderLength = 12, + DescriptionLength = 512, + }; + serializer slot[32]; +}; + +extern StateManager *stateManager; diff --git a/bsnes/ui/tools/tools.cpp b/bsnes/ui/tools/tools.cpp index 5e37026e..5ec3021d 100755 --- a/bsnes/ui/tools/tools.cpp +++ b/bsnes/ui/tools/tools.cpp @@ -1,2 +1,3 @@ #include "../base.hpp" #include "cheat-editor.cpp" +#include "state-manager.cpp" diff --git a/bsnes/ui/tools/tools.hpp b/bsnes/ui/tools/tools.hpp index 97db5ccf..e7834f88 100755 --- a/bsnes/ui/tools/tools.hpp +++ b/bsnes/ui/tools/tools.hpp @@ -1 +1,2 @@ #include "cheat-editor.hpp" +#include "state-manager.hpp"