From 52443936e6e0cb730419450afdb6df50ea82cbc7 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 7 May 2011 00:16:46 +1000 Subject: [PATCH] Update to v078r05 release. byuu says: This WIP adds Nintendo Super System emulation, at least of its DIP switches. This is done via XML mapping, like so: ActRaiser The value field is a 16-bit value. All selected options are ORed together to produce the final DIP switch values. The number of options per setting is unlimited, but there are only sixteen settings allowed (you can't have more settings than you have switches, that's just stupid.) In the example above, d0-d1 controls difficulty, and d2-d3 controls # of lives. d4-d15 appear to be unused, as far as I can tell. --- bsnes/Makefile | 2 +- bsnes/phoenix/core/layout/vertical-layout.cpp | 4 + bsnes/phoenix/core/layout/vertical-layout.hpp | 1 + bsnes/snes/Makefile | 3 +- bsnes/snes/alt/smp/smp.cpp | 2 +- bsnes/snes/cartridge/cartridge.cpp | 1 + bsnes/snes/cartridge/cartridge.hpp | 9 ++ bsnes/snes/cartridge/xml.cpp | 31 +++++++ bsnes/snes/chip/chip.hpp | 1 + bsnes/snes/chip/nss/nss.cpp | 39 ++++++++ bsnes/snes/chip/nss/nss.hpp | 17 ++++ bsnes/snes/snes.hpp | 2 +- bsnes/snes/system/system.cpp | 5 + bsnes/ui/general/general.cpp | 1 + bsnes/ui/general/general.hpp | 1 + bsnes/ui/general/nss-dip-window.cpp | 91 +++++++++++++++++++ bsnes/ui/general/nss-dip-window.hpp | 12 +++ bsnes/ui/main.cpp | 1 + bsnes/ui/utility/utility.cpp | 6 ++ 19 files changed, 225 insertions(+), 4 deletions(-) create mode 100755 bsnes/snes/chip/nss/nss.cpp create mode 100755 bsnes/snes/chip/nss/nss.hpp create mode 100755 bsnes/ui/general/nss-dip-window.cpp create mode 100755 bsnes/ui/general/nss-dip-window.hpp diff --git a/bsnes/Makefile b/bsnes/Makefile index 4af87086..0ae818e5 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,7 +1,7 @@ include nall/Makefile snes := snes gameboy := gameboy -profile := accuracy +profile := compatibility ui := ui # debugger diff --git a/bsnes/phoenix/core/layout/vertical-layout.cpp b/bsnes/phoenix/core/layout/vertical-layout.cpp index 373c8249..e3185001 100755 --- a/bsnes/phoenix/core/layout/vertical-layout.cpp +++ b/bsnes/phoenix/core/layout/vertical-layout.cpp @@ -69,6 +69,10 @@ Geometry VerticalLayout::minimumLayoutGeometry() { return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height }; } +void VerticalLayout::reset() { + children.reset(); +} + void VerticalLayout::setGeometry(const Geometry &containerGeometry) { auto children = this->children; foreach(child, children) { diff --git a/bsnes/phoenix/core/layout/vertical-layout.hpp b/bsnes/phoenix/core/layout/vertical-layout.hpp index a280c269..fb78247e 100755 --- a/bsnes/phoenix/core/layout/vertical-layout.hpp +++ b/bsnes/phoenix/core/layout/vertical-layout.hpp @@ -5,6 +5,7 @@ struct VerticalLayout : public Layout { void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0); Geometry minimumGeometry(); Geometry minimumLayoutGeometry(); + void reset(); void setGeometry(const Geometry &geometry); void setMargin(unsigned margin); void setParent(Window &parent); diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index d9c24d55..c0ee05bb 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -2,7 +2,7 @@ snes_objects := snes-system snes_objects += snes-cartridge snes-cheat snes_objects += snes-memory snes-cpucore snes-smpcore snes_objects += snes-cpu snes-smp snes-dsp snes-ppu -snes_objects += snes-icd2 snes-superfx snes-sa1 snes-necdsp +snes_objects += snes-nss snes-icd2 snes-superfx snes-sa1 snes-necdsp snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-cx4 snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo snes_objects += snes-msu1 snes-serial @@ -39,6 +39,7 @@ obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/) obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/* obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/* +obj/snes-nss.o : $(snes)/chip/nss/nss.cpp $(call rwildcard,$(snes)/chip/nss/) obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/) obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/) obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/) diff --git a/bsnes/snes/alt/smp/smp.cpp b/bsnes/snes/alt/smp/smp.cpp index a309db05..08a67ef0 100755 --- a/bsnes/snes/alt/smp/smp.cpp +++ b/bsnes/snes/alt/smp/smp.cpp @@ -1,4 +1,4 @@ -//#define CYCLE_ACCURATE +#define CYCLE_ACCURATE #include diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index db47d958..4d2db951 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -17,6 +17,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) { ram_size = 0; has_bsx_slot = false; + has_nss_dip = false; has_superfx = false; has_sa1 = false; has_necdsp = false; diff --git a/bsnes/snes/cartridge/cartridge.hpp b/bsnes/snes/cartridge/cartridge.hpp index 5678e028..9817ac41 100755 --- a/bsnes/snes/cartridge/cartridge.hpp +++ b/bsnes/snes/cartridge/cartridge.hpp @@ -34,6 +34,7 @@ public: readonly ram_size; readonly has_bsx_slot; + readonly has_nss_dip; readonly has_superfx; readonly has_sa1; readonly has_necdsp; @@ -75,6 +76,13 @@ public: }; linear_vector mapping; + struct Information { + struct NSS { + lstring setting; + lstring option[16]; + } nss; + } information; + void load(Mode, const lstring&); void unload(); @@ -91,6 +99,7 @@ private: void xml_parse_rom(xml_element&); void xml_parse_ram(xml_element&); + void xml_parse_nss(xml_element&); void xml_parse_icd2(xml_element&); void xml_parse_superfx(xml_element&); void xml_parse_sa1(xml_element&); diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp index 24731888..59801eff 100755 --- a/bsnes/snes/cartridge/xml.cpp +++ b/bsnes/snes/cartridge/xml.cpp @@ -17,6 +17,9 @@ void Cartridge::parse_xml(const lstring &list) { } void Cartridge::parse_xml_cartridge(const char *data) { + //reset cartridge information + information.nss.setting.reset(); + xml_element document = xml_parse(data); if(document.element.size() == 0) return; @@ -32,6 +35,7 @@ void Cartridge::parse_xml_cartridge(const char *data) { foreach(node, head.element) { if(node.name == "rom") xml_parse_rom(node); if(node.name == "ram") xml_parse_ram(node); + if(node.name == "nss") xml_parse_nss(node); if(node.name == "icd2") xml_parse_icd2(node); if(node.name == "superfx") xml_parse_superfx(node); if(node.name == "sa1") xml_parse_sa1(node); @@ -97,6 +101,33 @@ void Cartridge::xml_parse_ram(xml_element &root) { } } +void Cartridge::xml_parse_nss(xml_element &root) { + has_nss_dip = true; + + foreach(node, root.element) { + if(node.name == "setting") { + unsigned number = information.nss.setting.size(); + if(number >= 16) break; //more than 16 DIP switches is not possible + + information.nss.option[number].reset(); + foreach(attr, node.attribute) { + if(attr.name == "name") { + information.nss.setting[number] = attr.parse(); + } + } + foreach(leaf, node.element) { + string name; + unsigned value = 0x0000; + foreach(attr, leaf.attribute) { + if(attr.name == "name") name = attr.parse(); + if(attr.name == "value") value = (uint16)hex(attr.content); + } + information.nss.option[number].append({ hex<4>(value), ":", name }); + } + } + } +} + void Cartridge::xml_parse_icd2(xml_element &root) { if(mode != Mode::SuperGameBoy) return; icd2.revision = 1; diff --git a/bsnes/snes/chip/chip.hpp b/bsnes/snes/chip/chip.hpp index c6a61700..fda6775f 100755 --- a/bsnes/snes/chip/chip.hpp +++ b/bsnes/snes/chip/chip.hpp @@ -3,6 +3,7 @@ struct Coprocessor : Processor { alwaysinline void synchronize_cpu(); }; +#include #include #include #include diff --git a/bsnes/snes/chip/nss/nss.cpp b/bsnes/snes/chip/nss/nss.cpp new file mode 100755 index 00000000..964973d0 --- /dev/null +++ b/bsnes/snes/chip/nss/nss.cpp @@ -0,0 +1,39 @@ +#include + +#define NSS_CPP +namespace SNES { + +NSS nss; + +void NSS::init() { +} + +void NSS::load() { + dip = 0x0000; + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this }); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this }); +} + +void NSS::unload() { +} + +void NSS::power() { +} + +void NSS::reset() { +} + +void NSS::set_dip(uint16 dip) { + this->dip = dip; +} + +uint8 NSS::read(unsigned addr) { + if((addr & 0x40ffff) == 0x004100) return dip >> 0; + if((addr & 0x40ffff) == 0x004101) return dip >> 8; + return cpu.regs.mdr; +} + +void NSS::write(unsigned addr, uint8 data) { +} + +} diff --git a/bsnes/snes/chip/nss/nss.hpp b/bsnes/snes/chip/nss/nss.hpp new file mode 100755 index 00000000..3cab46da --- /dev/null +++ b/bsnes/snes/chip/nss/nss.hpp @@ -0,0 +1,17 @@ +class NSS { +public: + void init(); + void load(); + void unload(); + void power(); + void reset(); + + void set_dip(uint16 dip); + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + +private: + uint16 dip; +}; + +extern NSS nss; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 0cafa6c0..d4991082 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "078.04"; + static const char Version[] = "078.05"; static const unsigned SerializerVersion = 20; } } diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 56316e55..2060160f 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -70,6 +70,7 @@ void System::init(Interface *interface_) { assert(interface != 0); icd2.init(); + nss.init(); superfx.init(); sa1.init(); necdsp.init(); @@ -111,6 +112,7 @@ void System::load() { if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.load(); if(cartridge.has_bsx_slot()) bsxflash.load(); + if(cartridge.has_nss_dip()) nss.load(); if(cartridge.has_superfx()) superfx.load(); if(cartridge.has_sa1()) sa1.load(); if(cartridge.has_necdsp()) necdsp.load(); @@ -134,6 +136,7 @@ void System::unload() { if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.unload(); if(cartridge.has_bsx_slot()) bsxflash.unload(); + if(cartridge.has_nss_dip()) nss.unload(); if(cartridge.has_superfx()) superfx.unload(); if(cartridge.has_sa1()) sa1.unload(); if(cartridge.has_necdsp()) necdsp.unload(); @@ -169,6 +172,7 @@ void System::power() { if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power(); if(cartridge.has_bsx_slot()) bsxflash.power(); + if(cartridge.has_nss_dip()) nss.power(); if(cartridge.has_superfx()) superfx.power(); if(cartridge.has_sa1()) sa1.power(); if(cartridge.has_necdsp()) necdsp.power(); @@ -204,6 +208,7 @@ void System::reset() { if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset(); if(cartridge.has_bsx_slot()) bsxflash.reset(); + if(cartridge.has_nss_dip()) nss.reset(); if(cartridge.has_superfx()) superfx.reset(); if(cartridge.has_sa1()) sa1.reset(); if(cartridge.has_necdsp()) necdsp.reset(); diff --git a/bsnes/ui/general/general.cpp b/bsnes/ui/general/general.cpp index 50e7f351..bf5f4061 100755 --- a/bsnes/ui/general/general.cpp +++ b/bsnes/ui/general/general.cpp @@ -2,3 +2,4 @@ #include "main-window.cpp" #include "file-browser.cpp" #include "slot-loader.cpp" +#include "nss-dip-window.cpp" diff --git a/bsnes/ui/general/general.hpp b/bsnes/ui/general/general.hpp index a0f43444..350af6e3 100755 --- a/bsnes/ui/general/general.hpp +++ b/bsnes/ui/general/general.hpp @@ -1,3 +1,4 @@ #include "main-window.hpp" #include "file-browser.hpp" #include "slot-loader.hpp" +#include "nss-dip-window.hpp" diff --git a/bsnes/ui/general/nss-dip-window.cpp b/bsnes/ui/general/nss-dip-window.cpp new file mode 100755 index 00000000..70aa8454 --- /dev/null +++ b/bsnes/ui/general/nss-dip-window.cpp @@ -0,0 +1,91 @@ +NSSDipWindow nssDipWindow; + +void NSSDipWindow::create() { + application.addWindow(this, "NSSDipWindow", "160,160"); + setTitle("NSS DIP Settings"); + + for(unsigned n = 0; n < 16; n++) { + dipName[n].setText("Unused"); + dipName[n].setVisible(false); + layout.append(dipName[n], { 0, 0, 16, 16 }); + + dipValue[n].setVisible(false); + layout.append(dipValue[n], { 0, 0, 16, 16 }); + } + + loadButton.setText("Load Cartridge"); + layout.append(loadButton, { 0, 0, 16, 16 }); + + append(layout); + setResizable(false); + setGeometry({ 0, 0, 400, 240 }); + + onClose = loadButton.onTick = { &NSSDipWindow::assign, this }; +} + +void NSSDipWindow::select() { + setVisible(false); + + for(unsigned n = 0; n < 16; n++) { + dipName[n].setText({ "DIP #", 1 + n, ":" }); + dipName[n].setVisible(false); + dipValue[n].reset(); + dipValue[n].setVisible(false); + } + + unsigned dipCount = SNES::cartridge.information.nss.setting.size(); + + for(unsigned n = 0; n < dipCount; n++) { + dipName[n].setText({ "DIP #", 1 + n, ": ", SNES::cartridge.information.nss.setting[n] }); + for(unsigned z = 0; z < SNES::cartridge.information.nss.option[n].size(); z++) { + lstring part; + part.split<1>(":", SNES::cartridge.information.nss.option[n][z]); + dipValue[n].append(part[1]); + } + } + + unsigned maximumLabelWidth = 50; + unsigned maximumComboWidth = 100; + unsigned controlHeight = dipValue[0].minimumGeometry().height; + + for(unsigned n = 0; n < dipCount; n++) { + maximumLabelWidth = max(maximumLabelWidth, dipName[n].minimumGeometry().width); + maximumComboWidth = max(maximumComboWidth, dipValue[n].minimumGeometry().width); + } + + for(unsigned n = 0; n < dipCount; n++) { + dipName[n].setGeometry({ 5, 5 + (controlHeight + 5) * n, maximumLabelWidth, controlHeight }); + dipName[n].setVisible(true); + + dipValue[n].setGeometry({ 5 + maximumLabelWidth + 5, 5 + (controlHeight + 5) * n, maximumComboWidth, controlHeight }); + dipValue[n].setVisible(true); + } + + unsigned buttonWidth = loadButton.minimumGeometry().width; + unsigned buttonHeight = loadButton.minimumGeometry().height; + + unsigned windowWidth = 5 + maximumLabelWidth + 5 + maximumComboWidth + 5; + unsigned windowHeight = 5 + (controlHeight + 5) * dipCount + buttonHeight + 5; + + loadButton.setGeometry({ windowWidth - 5 - buttonWidth, windowHeight - 5 - buttonHeight, buttonWidth, buttonHeight }); + + setGeometry({ geometry().x, geometry().y, windowWidth, windowHeight }); + setVisible(true); + loadButton.setFocused(); +} + +void NSSDipWindow::assign() { + unsigned dip = 0; + + for(unsigned n = 0; n < SNES::cartridge.information.nss.setting.size(); n++) { + unsigned position = dipValue[n].selection(); + lstring part; + part.split<1>(":", SNES::cartridge.information.nss.option[n][position]); + dip |= hex(part[0]); + } + + SNES::nss.set_dip(dip); + + setVisible(false); + application.pause = false; +} diff --git a/bsnes/ui/general/nss-dip-window.hpp b/bsnes/ui/general/nss-dip-window.hpp new file mode 100755 index 00000000..885eabf5 --- /dev/null +++ b/bsnes/ui/general/nss-dip-window.hpp @@ -0,0 +1,12 @@ +struct NSSDipWindow : TopLevelWindow { + FixedLayout layout; + Label dipName[16]; + ComboBox dipValue[16]; + Button loadButton; + + void create(); + void select(); + void assign(); +}; + +extern NSSDipWindow nssDipWindow; diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 06c588c5..444b7ffc 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -54,6 +54,7 @@ void Application::main(int argc, char **argv) { fileBrowser.create(); singleSlotLoader.create(); doubleSlotLoader.create(); + nssDipWindow.create(); videoSettings.create(); audioSettings.create(); inputSettings.create(); diff --git a/bsnes/ui/utility/utility.cpp b/bsnes/ui/utility/utility.cpp index bd799a60..ed08475f 100755 --- a/bsnes/ui/utility/utility.cpp +++ b/bsnes/ui/utility/utility.cpp @@ -158,6 +158,12 @@ void Utility::cartridgeLoaded() { "Loaded ", notdir(cartridge.baseName), cartridge.patchApplied ? ", and applied UPS patch" : "" }); + + //NSS + if(SNES::cartridge.has_nss_dip()) { + nssDipWindow.select(); + application.pause = true; + } } void Utility::cartridgeUnloaded() {