mirror of https://github.com/bsnes-emu/bsnes.git
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: <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <name>ActRaiser</name> <rom> <map mode="linear" address="00-7f:8000-ffff"/> <map mode="linear" address="80-ff:8000-ffff"/> </rom> <nss> <setting name="Difficulty"> <option value="0000" name="Easy"/> <option value="0001" name="Normal"/> <option value="0002" name="Hard"/> <option value="0003" name="Expert"/> </setting> <setting name="Lives"> <option value="0000" name="5 lives"/> <option value="0004" name="4 lives"/> <option value="0008" name="3 lives"/> <option value="000c" name="2 lives"/> </setting> </nss> </cartridge> 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.
This commit is contained in:
parent
6694a1c986
commit
52443936e6
|
@ -1,7 +1,7 @@
|
|||
include nall/Makefile
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := accuracy
|
||||
profile := compatibility
|
||||
ui := ui
|
||||
|
||||
# debugger
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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/)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//#define CYCLE_ACCURATE
|
||||
#define CYCLE_ACCURATE
|
||||
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
readonly<unsigned> ram_size;
|
||||
|
||||
readonly<bool> has_bsx_slot;
|
||||
readonly<bool> has_nss_dip;
|
||||
readonly<bool> has_superfx;
|
||||
readonly<bool> has_sa1;
|
||||
readonly<bool> has_necdsp;
|
||||
|
@ -75,6 +76,13 @@ public:
|
|||
};
|
||||
linear_vector<Mapping> 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&);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,6 +3,7 @@ struct Coprocessor : Processor {
|
|||
alwaysinline void synchronize_cpu();
|
||||
};
|
||||
|
||||
#include <snes/chip/nss/nss.hpp>
|
||||
#include <snes/chip/icd2/icd2.hpp>
|
||||
#include <snes/chip/superfx/superfx.hpp>
|
||||
#include <snes/chip/sa1/sa1.hpp>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#include <snes/snes.hpp>
|
||||
|
||||
#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) {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
#include "main-window.cpp"
|
||||
#include "file-browser.cpp"
|
||||
#include "slot-loader.cpp"
|
||||
#include "nss-dip-window.cpp"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "main-window.hpp"
|
||||
#include "file-browser.hpp"
|
||||
#include "slot-loader.hpp"
|
||||
#include "nss-dip-window.hpp"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue