mirror of https://github.com/bsnes-emu/bsnes.git
Update to v082r26 release.
byuu says: .cht files now use BML-formatted data. I'm still going to request the cheats.xml file as-is, and will write my own converter for embedding during releases. This is where parsing 2MB markup files in 10ms is really going to be nice. Had to use an evil hack before for actually searching for games. This has the start of the board/chip separation from mappers for NES, and it has a barebones iNES->board markup converter. You can specify your own board markup and bypass the need for an iNES header, so in other words it will load No-Intro style games with a proper board file. Long-term, we'll have an internal database for commercial boards, and probably folder.fc/prg.rom{,chr.rom} loading support. Since they can't co-exist, the mappers are currently disabled, and I've only ported the easy ones. So no MMC1/MMC3/VRC6 in this release. I need to make them into chips first.
This commit is contained in:
parent
e8b1af0917
commit
7115047d85
|
@ -34,7 +34,7 @@ protected:
|
||||||
unsigned sourceSize;
|
unsigned sourceSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline lzss() : sourceData(nullptr), sourceSize(nullptr) {}
|
inline lzss() : sourceData(nullptr), sourceSize(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void lzss::source(const uint8_t *data, unsigned size) {
|
void lzss::source(const uint8_t *data, unsigned size) {
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
#include <nall/windows/utf8.hpp>
|
#include <nall/windows/utf8.hpp>
|
||||||
|
|
||||||
|
#define NALL_STRING_INTERNAL_HPP
|
||||||
#include <nall/string/base.hpp>
|
#include <nall/string/base.hpp>
|
||||||
|
#include <nall/string/bml.hpp>
|
||||||
#include <nall/string/bsv.hpp>
|
#include <nall/string/bsv.hpp>
|
||||||
#include <nall/string/core.hpp>
|
#include <nall/string/core.hpp>
|
||||||
#include <nall/string/cast.hpp>
|
#include <nall/string/cast.hpp>
|
||||||
|
@ -38,5 +40,6 @@
|
||||||
#include <nall/string/variadic.hpp>
|
#include <nall/string/variadic.hpp>
|
||||||
#include <nall/string/wrapper.hpp>
|
#include <nall/string/wrapper.hpp>
|
||||||
#include <nall/string/xml.hpp>
|
#include <nall/string/xml.hpp>
|
||||||
|
#undef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
|
|
||||||
|
//BML parser
|
||||||
|
//version 0.02
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
namespace BML {
|
||||||
|
|
||||||
|
struct Node : linear_vector<Node> {
|
||||||
|
Node *parent;
|
||||||
|
const char *cname;
|
||||||
|
const char *cvalue;
|
||||||
|
|
||||||
|
inline string name() { return cname; }
|
||||||
|
inline string value() { return cvalue; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline bool valid(char p) const {
|
||||||
|
if(p >= 'A' && p <= 'Z') return true;
|
||||||
|
if(p >= 'a' && p <= 'z') return true;
|
||||||
|
if(p >= '0' && p <= '9') return true;
|
||||||
|
if(p == '+' || p == '-') return true;
|
||||||
|
if(p == '.' || p == '_') return true;
|
||||||
|
if(p == ':') return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool space(char p) const {
|
||||||
|
return p == ' ' || p == '\t';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned parseDepth(char *p) {
|
||||||
|
unsigned depth = 0;
|
||||||
|
while(space(*p)) depth++, p++;
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void parseNode(char *&p) {
|
||||||
|
if(valid(*p)) {
|
||||||
|
cname = p;
|
||||||
|
while(valid(*p)) p++;
|
||||||
|
if(*p != '=') return;
|
||||||
|
*p++ = 0;
|
||||||
|
}
|
||||||
|
if(*p == '\n') throw "Missing node value";
|
||||||
|
|
||||||
|
if(valid(*p)) {
|
||||||
|
cvalue = p;
|
||||||
|
while(valid(*p)) p++;
|
||||||
|
} else {
|
||||||
|
char terminal = *p++;
|
||||||
|
cvalue = p;
|
||||||
|
while(*p && *p != terminal) p++;
|
||||||
|
if(*p == 0) throw "Unclosed terminal";
|
||||||
|
*p++ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void parseLine(char *&p) {
|
||||||
|
unsigned depth = parseDepth(p);
|
||||||
|
while(space(*p)) p++;
|
||||||
|
parseNode(p);
|
||||||
|
|
||||||
|
while(space(*p)) {
|
||||||
|
*p++ = 0;
|
||||||
|
Node node(this);
|
||||||
|
node.parseNode(p);
|
||||||
|
append(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*p == '\n') *p++ = 0;
|
||||||
|
|
||||||
|
while(parseDepth(p) > depth) {
|
||||||
|
Node node(this);
|
||||||
|
node.parseLine(p);
|
||||||
|
append(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void parse(char *&p, unsigned parentDepth = 0) {
|
||||||
|
while(*p) {
|
||||||
|
while(*p == '\n') *p++ = 0;
|
||||||
|
Node node(this);
|
||||||
|
node.parseLine(p);
|
||||||
|
append(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline Node& operator[](const string &name) {
|
||||||
|
for(auto &node : *this) {
|
||||||
|
if(!strcmp(node.cname, name)) return node;
|
||||||
|
}
|
||||||
|
static Node node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool exists() {
|
||||||
|
return parent != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline string content(const string &separator = "\n") const {
|
||||||
|
string result;
|
||||||
|
for(auto &node : *this) result.append(node.cvalue, separator);
|
||||||
|
result.rtrim<1>(separator);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Node(const string &document) : parent(nullptr), cname(nullptr), cvalue(nullptr) {
|
||||||
|
char *p = strdup(document);
|
||||||
|
cvalue = p;
|
||||||
|
try {
|
||||||
|
parse(p);
|
||||||
|
} catch(const char *error) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Node(Node *parent) : parent(parent), cname(""), cvalue("") {}
|
||||||
|
inline Node() : parent(nullptr), cname(""), cvalue("") {}
|
||||||
|
inline ~Node() { if(cname == nullptr && cvalue) free((void*)cvalue); }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,12 +1,12 @@
|
||||||
#ifndef NALL_STRING_BSV_HPP
|
#ifdef NALL_STRING_INTERNAL_HPP
|
||||||
#define NALL_STRING_BSV_HPP
|
|
||||||
|
|
||||||
//BSV parser
|
//BSV parser
|
||||||
//version 0.01
|
//version 0.02
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
inline string bsv_decode(const char *input) {
|
struct BSV {
|
||||||
|
static inline string decode(const char *input) {
|
||||||
string output;
|
string output;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
while(*input) {
|
while(*input) {
|
||||||
|
@ -30,7 +30,7 @@ inline string bsv_decode(const char *input) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline string bsv_encode(const char *input) {
|
static inline string encode(const char *input) {
|
||||||
string output;
|
string output;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
while(*input) {
|
while(*input) {
|
||||||
|
@ -69,6 +69,7 @@ inline string bsv_encode(const char *input) {
|
||||||
output[offset] = 0;
|
output[offset] = 0;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
nes_objects := nes-interface nes-system nes-scheduler nes-input
|
nes_objects := nes-interface nes-system nes-scheduler nes-input
|
||||||
nes_objects += nes-mapper nes-cartridge nes-memory
|
nes_objects += nes-memory nes-cartridge nes-cpu nes-apu nes-ppu
|
||||||
nes_objects += nes-cpu nes-apu nes-ppu
|
|
||||||
nes_objects += nes-cheat
|
nes_objects += nes-cheat
|
||||||
objects += $(nes_objects)
|
objects += $(nes_objects)
|
||||||
|
|
||||||
|
@ -8,9 +7,8 @@ obj/nes-interface.o: $(nes)/interface/interface.cpp $(call rwildcard,$(nes)/inte
|
||||||
obj/nes-system.o: $(nes)/system/system.cpp $(call rwildcard,$(nes)/system/)
|
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-scheduler.o: $(nes)/scheduler/scheduler.cpp $(call rwildcard,$(nes)/scheduler/)
|
||||||
obj/nes-input.o: $(nes)/input/input.cpp $(call rwildcard,$(nes)/input/)
|
obj/nes-input.o: $(nes)/input/input.cpp $(call rwildcard,$(nes)/input/)
|
||||||
obj/nes-mapper.o: $(nes)/mapper/mapper.cpp $(call rwildcard,$(nes)/mapper/)
|
|
||||||
obj/nes-cartridge.o: $(nes)/cartridge/cartridge.cpp $(call rwildcard,$(nes)/cartridge/)
|
|
||||||
obj/nes-memory.o: $(nes)/memory/memory.cpp $(call rwildcard,$(nes)/memory/)
|
obj/nes-memory.o: $(nes)/memory/memory.cpp $(call rwildcard,$(nes)/memory/)
|
||||||
|
obj/nes-cartridge.o: $(nes)/cartridge/cartridge.cpp $(call rwildcard,$(nes)/cartridge/)
|
||||||
obj/nes-cpu.o: $(nes)/cpu/cpu.cpp $(call rwildcard,$(nes)/cpu/)
|
obj/nes-cpu.o: $(nes)/cpu/cpu.cpp $(call rwildcard,$(nes)/cpu/)
|
||||||
obj/nes-apu.o: $(nes)/apu/apu.cpp $(call rwildcard,$(nes)/apu/)
|
obj/nes-apu.o: $(nes)/apu/apu.cpp $(call rwildcard,$(nes)/apu/)
|
||||||
obj/nes-ppu.o: $(nes)/ppu/ppu.cpp $(call rwildcard,$(nes)/ppu/)
|
obj/nes-ppu.o: $(nes)/ppu/ppu.cpp $(call rwildcard,$(nes)/ppu/)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
//NES-AMROM
|
||||||
|
//NES-ANROM
|
||||||
|
//NES-AN1ROM
|
||||||
|
//NES-AOROM
|
||||||
|
|
||||||
|
struct AxROM : Board {
|
||||||
|
|
||||||
|
uint4 prg_bank;
|
||||||
|
bool mirror_select;
|
||||||
|
|
||||||
|
uint8 prg_read(unsigned addr) {
|
||||||
|
if(addr & 0x8000) return Board::prg_read((prg_bank << 15) | (addr & 0x7fff));
|
||||||
|
return cpu.mdr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prg_write(unsigned addr, uint8 data) {
|
||||||
|
if(addr & 0x8000) {
|
||||||
|
prg_bank = data & 0x0f;
|
||||||
|
mirror_select = data & 0x10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 chr_read(unsigned addr) {
|
||||||
|
if(addr & 0x2000) return ppu.ciram_read((mirror_select << 10) | (addr & 0x03ff));
|
||||||
|
return Board::chr_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chr_write(unsigned addr, uint8 data) {
|
||||||
|
if(addr & 0x2000) return ppu.ciram_write((mirror_select << 10) | (addr & 0x03ff), data);
|
||||||
|
return Board::chr_write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
prg_bank = 0x0f;
|
||||||
|
mirror_select = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(serializer &s) {
|
||||||
|
s.integer(prg_bank);
|
||||||
|
s.integer(mirror_select);
|
||||||
|
}
|
||||||
|
|
||||||
|
AxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -1,4 +1,8 @@
|
||||||
|
#include "axrom.cpp"
|
||||||
|
#include "cnrom.cpp"
|
||||||
#include "nrom.cpp"
|
#include "nrom.cpp"
|
||||||
|
#include "sxrom.cpp"
|
||||||
|
#include "uxrom.cpp"
|
||||||
|
|
||||||
unsigned Board::mirror(unsigned addr, unsigned size) const {
|
unsigned Board::mirror(unsigned addr, unsigned size) const {
|
||||||
unsigned base = 0;
|
unsigned base = 0;
|
||||||
|
@ -18,73 +22,94 @@ unsigned Board::mirror(unsigned addr, unsigned size) const {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Board::main() {
|
||||||
|
while(true) {
|
||||||
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
cartridge.clock += 12 * 4095;
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::tick() {
|
||||||
|
cartridge.clock += 12;
|
||||||
|
if(cartridge.clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||||
|
}
|
||||||
|
|
||||||
uint8 Board::prg_read(unsigned addr) {
|
uint8 Board::prg_read(unsigned addr) {
|
||||||
return prg.data[mirror(addr, prg.size)];
|
return prgrom.data[mirror(addr, prgrom.size)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::prg_write(unsigned addr, uint8 data) {
|
void Board::prg_write(unsigned addr, uint8 data) {
|
||||||
prg.data[mirror(addr, prg.size)] = data;
|
prgrom.data[mirror(addr, prgrom.size)] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 Board::chr_read(unsigned addr) {
|
uint8 Board::chr_read(unsigned addr) {
|
||||||
return chr.data[mirror(addr, chr.size)];
|
if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)];
|
||||||
|
if(chrram.size) return chrram.data[mirror(addr, chrram.size)];
|
||||||
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::chr_write(unsigned addr, uint8 data) {
|
void Board::chr_write(unsigned addr, uint8 data) {
|
||||||
chr.data[mirror(addr, chr.size)] = data;
|
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Board* Board::create(const string &xml, const uint8_t *data, unsigned size) {
|
Board::Memory Board::memory() {
|
||||||
string type;
|
return prgram;
|
||||||
string configuration;
|
|
||||||
|
|
||||||
xml_element document = xml_parse(xml);
|
|
||||||
for(auto &head : document.element) {
|
|
||||||
if(head.name == "cartridge") {
|
|
||||||
for(auto &node : head.element) {
|
|
||||||
if(node.name == "board") {
|
|
||||||
configuration = node.content;
|
|
||||||
for(auto &attr : node.attribute) {
|
|
||||||
if(attr.name == "type") type = attr.parse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Board *board = nullptr;
|
void Board::power() {
|
||||||
if(type == "NES-NROM-256") board = new NROM;
|
|
||||||
assert(board != nullptr);
|
|
||||||
|
|
||||||
for(auto &head : document.element) {
|
|
||||||
if(head.name == "cartridge") {
|
|
||||||
for(auto &node : head.element) {
|
|
||||||
if(node.name == "board") {
|
|
||||||
for(auto &leaf : node.element) {
|
|
||||||
if(leaf.name == "prg") {
|
|
||||||
for(auto &attr : leaf.attribute) {
|
|
||||||
if(attr.name == "size") board->prg.size = decimal(attr.content);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(leaf.name == "chr") {
|
void Board::reset() {
|
||||||
for(auto &attr : leaf.attribute) {
|
|
||||||
if(attr.name == "size") board->chr.size = decimal(attr.content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
board->prg.data = new uint8[board->prg.size];
|
void Board::serialize(serializer &s) {
|
||||||
memcpy(board->prg.data, data, board->prg.size);
|
if(prgram.size) s.array(prgram.data, prgram.size);
|
||||||
|
if(chrram.size) s.array(chrram.data, chrram.size);
|
||||||
board->chr.data = new uint8[board->chr.size];
|
}
|
||||||
memcpy(board->chr.data, data + board->prg.size, board->chr.size);
|
|
||||||
|
Board::Board(BML::Node &board, const uint8_t *data, unsigned size) {
|
||||||
board->configure({ "<board>\n", configuration, "</board>\n" });
|
information.type = board["type"].value();
|
||||||
|
information.battery = board["prg"]["battery"].value();
|
||||||
return board;
|
|
||||||
|
prgrom.size = decimal(board["prg"]["rom"].value());
|
||||||
|
prgram.size = decimal(board["prg"]["ram"].value());
|
||||||
|
chrrom.size = decimal(board["chr"]["rom"].value());
|
||||||
|
chrram.size = decimal(board["chr"]["ram"].value());
|
||||||
|
|
||||||
|
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
||||||
|
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
||||||
|
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
||||||
|
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
||||||
|
|
||||||
|
if(prgrom.size) memcpy(prgrom.data, data, prgrom.size);
|
||||||
|
if(chrrom.size) memcpy(chrrom.data, data + prgrom.size, chrrom.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Board::~Board() {
|
||||||
|
if(prgrom.size) delete[] prgrom.data;
|
||||||
|
if(prgram.size) delete[] prgram.data;
|
||||||
|
if(chrrom.size) delete[] chrrom.data;
|
||||||
|
if(chrram.size) delete[] chrram.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Board* Board::load(const string &markup, const uint8_t *data, unsigned size) {
|
||||||
|
BML::Node document(markup);
|
||||||
|
auto &board = document["cartridge"]["board"];
|
||||||
|
string type = board["type"].value();
|
||||||
|
|
||||||
|
if(type == "NES-AMROM" ) return new AxROM(board, data, size);
|
||||||
|
if(type == "NES-ANROM" ) return new AxROM(board, data, size);
|
||||||
|
if(type == "NES-AN1ROM" ) return new AxROM(board, data, size);
|
||||||
|
if(type == "NES-AOROM" ) return new AxROM(board, data, size);
|
||||||
|
if(type == "NES-CNROM" ) return new CNROM(board, data, size);
|
||||||
|
if(type == "NES-NROM-256") return new NROM(board, data, size);
|
||||||
|
if(type == "NES-UNROM" ) return new UxROM(board, data, size);
|
||||||
|
if(type == "NES-SXROM" ) return new SxROM(board, data, size);
|
||||||
|
if(type == "NES-UOROM" ) return new UxROM(board, data, size);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,40 @@
|
||||||
struct Board {
|
struct Board {
|
||||||
|
struct Memory {
|
||||||
|
uint8_t *data;
|
||||||
|
unsigned size;
|
||||||
|
inline Memory() : data(nullptr), size(0u) {}
|
||||||
|
};
|
||||||
|
|
||||||
unsigned mirror(unsigned addr, unsigned size) const;
|
unsigned mirror(unsigned addr, unsigned size) const;
|
||||||
|
|
||||||
|
virtual void main();
|
||||||
|
virtual void tick();
|
||||||
|
|
||||||
virtual uint8 prg_read(unsigned addr);
|
virtual uint8 prg_read(unsigned addr);
|
||||||
virtual void prg_write(unsigned addr, uint8 data);
|
virtual void prg_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
virtual uint8 chr_read(unsigned addr);
|
virtual uint8 chr_read(unsigned addr);
|
||||||
virtual void chr_write(unsigned addr, uint8 data);
|
virtual void chr_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
virtual void configure(const string &xml) = 0;
|
virtual Memory memory();
|
||||||
|
|
||||||
static Board* create(const string &xml, const uint8_t *data, unsigned size);
|
virtual void power();
|
||||||
|
virtual void reset();
|
||||||
|
|
||||||
|
virtual void serialize(serializer&);
|
||||||
|
Board(BML::Node &board, const uint8_t *data, unsigned size);
|
||||||
|
~Board();
|
||||||
|
|
||||||
|
static Board* load(const string &markup, const uint8_t *data, unsigned size);
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string type;
|
string type;
|
||||||
|
bool battery;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
struct Memory {
|
protected:
|
||||||
uint8_t *data;
|
Memory prgrom;
|
||||||
unsigned size;
|
Memory prgram;
|
||||||
};
|
Memory chrrom;
|
||||||
|
Memory chrram;
|
||||||
Memory prg;
|
|
||||||
Memory chr;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
//NES-CNROM
|
||||||
|
|
||||||
|
struct CNROM : Board {
|
||||||
|
|
||||||
|
struct Settings {
|
||||||
|
bool mirror; //0 = horizontal, 1 = vertical
|
||||||
|
} settings;
|
||||||
|
|
||||||
|
uint2 chr_bank;
|
||||||
|
|
||||||
|
uint8 prg_read(unsigned addr) {
|
||||||
|
if(addr & 0x8000) return Board::prg_read(addr & 0x7fff);
|
||||||
|
return cpu.mdr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prg_write(unsigned addr, uint8 data) {
|
||||||
|
if(addr & 0x8000) chr_bank = data & 0x03;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 chr_read(unsigned addr) {
|
||||||
|
if(addr & 0x2000) {
|
||||||
|
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||||
|
return ppu.ciram_read(addr & 0x07ff);
|
||||||
|
}
|
||||||
|
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
|
||||||
|
return Board::chr_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chr_write(unsigned addr, uint8 data) {
|
||||||
|
if(addr & 0x2000) {
|
||||||
|
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||||
|
return ppu.ciram_write(addr & 0x07ff, data);
|
||||||
|
}
|
||||||
|
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
|
||||||
|
Board::chr_write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
chr_bank = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(serializer &s) {
|
||||||
|
s.integer(chr_bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
CNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||||
|
settings.mirror = board["mirror"].value() == "vertical" ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -1,7 +1,10 @@
|
||||||
|
//NES-NROM-128
|
||||||
|
//NES-NROM-256
|
||||||
|
|
||||||
struct NROM : Board {
|
struct NROM : Board {
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
enum class Mirror : unsigned { Horizontal, Vertical } mirror;
|
bool mirror; //0 = horizontal, 1 = vertical
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
uint8 prg_read(unsigned addr) {
|
uint8 prg_read(unsigned addr) {
|
||||||
|
@ -14,7 +17,7 @@ void prg_write(unsigned addr, uint8 data) {
|
||||||
|
|
||||||
uint8 chr_read(unsigned addr) {
|
uint8 chr_read(unsigned addr) {
|
||||||
if(addr & 0x2000) {
|
if(addr & 0x2000) {
|
||||||
if(settings.mirror == Settings::Mirror::Horizontal) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||||
return ppu.ciram_read(addr & 0x07ff);
|
return ppu.ciram_read(addr & 0x07ff);
|
||||||
}
|
}
|
||||||
return Board::chr_read(addr);
|
return Board::chr_read(addr);
|
||||||
|
@ -22,26 +25,14 @@ uint8 chr_read(unsigned addr) {
|
||||||
|
|
||||||
void chr_write(unsigned addr, uint8 data) {
|
void chr_write(unsigned addr, uint8 data) {
|
||||||
if(addr & 0x2000) {
|
if(addr & 0x2000) {
|
||||||
if(settings.mirror == Settings::Mirror::Horizontal) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||||
return ppu.ciram_write(addr, data);
|
return ppu.ciram_write(addr & 0x07ff, data);
|
||||||
}
|
}
|
||||||
return Board::chr_write(addr, data);
|
return Board::chr_write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void configure(const string &xml) {
|
NROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||||
xml_element document = xml_parse(xml);
|
settings.mirror = board["mirror"].value() == "vertical" ? 1 : 0;
|
||||||
for(auto &node : document.element) {
|
|
||||||
if(node.name == "mirror") {
|
|
||||||
for(auto &attr : node.attribute) {
|
|
||||||
if(attr.name == "type") {
|
|
||||||
if(attr.content == "horizontal") settings.mirror = Settings::Mirror::Horizontal;
|
|
||||||
if(attr.content == "vertical" ) settings.mirror = Settings::Mirror::Vertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NROM nrom;
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
//NES-SAROM
|
||||||
|
//NES-SBROM
|
||||||
|
//NES-SCROM
|
||||||
|
//NES-SC1ROM
|
||||||
|
//NES-SEROM
|
||||||
|
//NES-SFROM
|
||||||
|
//NES-SGROM
|
||||||
|
//NES-SHROM
|
||||||
|
//NES-SH1ROM
|
||||||
|
//NES-SIROM
|
||||||
|
//NES-SJROM
|
||||||
|
//NES-SKROM
|
||||||
|
//NES-SLROM
|
||||||
|
//NES-SL1ROM
|
||||||
|
//NES-SL2ROM
|
||||||
|
//NES-SL3ROM
|
||||||
|
//NES-SLRROM
|
||||||
|
//NES-SMROM
|
||||||
|
//NES-SNROM
|
||||||
|
//NES-SOROM
|
||||||
|
//NES-SUROM
|
||||||
|
//NES-SXROM
|
||||||
|
|
||||||
|
struct SxROM : Board {
|
||||||
|
|
||||||
|
SxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,54 @@
|
||||||
|
//NES-UNROM
|
||||||
|
//NES-UOROM
|
||||||
|
|
||||||
|
struct UxROM : Board {
|
||||||
|
|
||||||
|
struct Settings {
|
||||||
|
bool mirror; //0 = horizontal, 1 = vertical
|
||||||
|
} settings;
|
||||||
|
|
||||||
|
uint4 prg_bank;
|
||||||
|
|
||||||
|
uint8 prg_read(unsigned addr) {
|
||||||
|
if((addr & 0xc000) == 0x8000) return Board::prg_read((prg_bank << 14) | (addr & 0x3fff));
|
||||||
|
if((addr & 0xc000) == 0xc000) return Board::prg_read(( 0x0f << 14) | (addr & 0x3fff));
|
||||||
|
return cpu.mdr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prg_write(unsigned addr, uint8 data) {
|
||||||
|
if(addr & 0x8000) prg_bank = data & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 chr_read(unsigned addr) {
|
||||||
|
if(addr & 0x2000) {
|
||||||
|
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||||
|
return ppu.ciram_read(addr);
|
||||||
|
}
|
||||||
|
return Board::chr_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chr_write(unsigned addr, uint8 data) {
|
||||||
|
if(addr & 0x2000) {
|
||||||
|
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||||
|
return ppu.ciram_write(addr, data);
|
||||||
|
}
|
||||||
|
return Board::chr_write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
prg_bank = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(serializer &s) {
|
||||||
|
s.integer(prg_bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
UxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||||
|
settings.mirror = board["mirror"].value() == "vertical" ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
namespace NES {
|
namespace NES {
|
||||||
|
|
||||||
|
#include "ines.cpp"
|
||||||
|
#include "chip/chip.cpp"
|
||||||
#include "board/board.cpp"
|
#include "board/board.cpp"
|
||||||
|
|
||||||
//#define BOARD
|
|
||||||
|
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
void Cartridge::Main() {
|
void Cartridge::Main() {
|
||||||
|
@ -13,92 +12,42 @@ void Cartridge::Main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::main() {
|
void Cartridge::main() {
|
||||||
mapper->main();
|
board->main();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
|
void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
|
||||||
#ifdef BOARD
|
if((size & 0xff) == 0) {
|
||||||
rom_size = size;
|
sha256 = nall::sha256(data, size);
|
||||||
rom_data = new uint8[rom_size];
|
board = Board::load(markup, data, size);
|
||||||
memcpy(rom_data, data, size);
|
|
||||||
#else
|
|
||||||
rom_size = size - 16;
|
|
||||||
rom_data = new uint8[rom_size];
|
|
||||||
memcpy(rom_data, data + 16, size - 16);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BOARD
|
|
||||||
prg_size = 32768;
|
|
||||||
chr_size = 8192;
|
|
||||||
#else
|
|
||||||
prg_size = data[4] * 0x4000;
|
|
||||||
chr_size = data[5] * 0x2000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
prg_data = new uint8[prg_size];
|
|
||||||
memcpy(prg_data, rom_data, prg_size);
|
|
||||||
|
|
||||||
if(chr_size) {
|
|
||||||
chr_ram = false;
|
|
||||||
chr_data = new uint8[chr_size];
|
|
||||||
memcpy(chr_data, rom_data + prg_size, chr_size);
|
|
||||||
} else {
|
} else {
|
||||||
chr_ram = true;
|
board = Board::load(markup != "" ? markup : iNES(data, size), data + 16, size - 16);
|
||||||
chr_size = 0x2000;
|
|
||||||
chr_data = new uint8[chr_size]();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mirroring = ((data[6] & 0x08) >> 2) | (data[6] & 0x01);
|
|
||||||
|
|
||||||
uint8 mapperNumber = ((data[7] >> 4) << 4) | (data[6] >> 4);
|
|
||||||
switch(mapperNumber) {
|
|
||||||
default : mapper = &Mapper::none; break;
|
|
||||||
case 1: mapper = &Mapper::mmc1; break;
|
|
||||||
case 2: mapper = &Mapper::uorom; break;
|
|
||||||
case 3: mapper = &Mapper::cnrom; break;
|
|
||||||
case 4: mapper = &Mapper::mmc3; break;
|
|
||||||
case 7: mapper = &Mapper::aorom; break;
|
|
||||||
case 16: mapper = &Mapper::bandaiFCG; break;
|
|
||||||
case 24: mapper = &Mapper::vrc6; Mapper::vrc6.abus_swap = 0; break;
|
|
||||||
case 26: mapper = &Mapper::vrc6; Mapper::vrc6.abus_swap = 1; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sha256 = nall::sha256(rom_data, rom_size);
|
|
||||||
|
|
||||||
#ifdef BOARD
|
|
||||||
board = Board::create(xml, rom_data, rom_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
system.load();
|
system.load();
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::unload() {
|
void Cartridge::unload() {
|
||||||
if(loaded == false) return;
|
if(loaded == false) return;
|
||||||
|
|
||||||
delete[] rom_data;
|
|
||||||
delete[] prg_data;
|
|
||||||
delete[] chr_data;
|
|
||||||
|
|
||||||
loaded = false;
|
loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Cartridge::ram_size() {
|
unsigned Cartridge::ram_size() {
|
||||||
return mapper->ram_size();
|
return board->memory().size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8* Cartridge::ram_data() {
|
uint8* Cartridge::ram_data() {
|
||||||
return mapper->ram_data();
|
return board->memory().data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::power() {
|
void Cartridge::power() {
|
||||||
create(Cartridge::Main, 21477272);
|
create(Cartridge::Main, 21477272);
|
||||||
mapper->power();
|
board->power();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::reset() {
|
void Cartridge::reset() {
|
||||||
create(Cartridge::Main, 21477272);
|
create(Cartridge::Main, 21477272);
|
||||||
mapper->reset();
|
board->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
Cartridge::Cartridge() {
|
||||||
|
@ -106,37 +55,23 @@ Cartridge::Cartridge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 Cartridge::prg_read(unsigned addr) {
|
uint8 Cartridge::prg_read(unsigned addr) {
|
||||||
#ifdef BOARD
|
|
||||||
return board->prg_read(addr);
|
return board->prg_read(addr);
|
||||||
#endif
|
|
||||||
return mapper->prg_read(addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::prg_write(unsigned addr, uint8 data) {
|
void Cartridge::prg_write(unsigned addr, uint8 data) {
|
||||||
#ifdef BOARD
|
|
||||||
return board->prg_write(addr, data);
|
return board->prg_write(addr, data);
|
||||||
#endif
|
|
||||||
return mapper->prg_write(addr, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 Cartridge::chr_read(unsigned addr) {
|
uint8 Cartridge::chr_read(unsigned addr) {
|
||||||
#ifdef BOARD
|
|
||||||
return board->chr_read(addr);
|
return board->chr_read(addr);
|
||||||
#endif
|
|
||||||
return mapper->chr_read(addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::chr_write(unsigned addr, uint8 data) {
|
void Cartridge::chr_write(unsigned addr, uint8 data) {
|
||||||
#ifdef BOARD
|
|
||||||
return board->chr_write(addr, data);
|
return board->chr_write(addr, data);
|
||||||
#endif
|
|
||||||
return mapper->chr_write(addr, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::serialize(serializer &s) {
|
void Cartridge::serialize(serializer &s) {
|
||||||
if(chr_ram) s.array(chr_data, chr_size);
|
return board->serialize(s);
|
||||||
|
|
||||||
return mapper->serialize(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
#include "chip/chip.hpp"
|
||||||
#include "board/board.hpp"
|
#include "board/board.hpp"
|
||||||
|
|
||||||
struct Cartridge : Processor, property<Cartridge> {
|
struct Cartridge : Processor, property<Cartridge> {
|
||||||
static void Main();
|
static void Main();
|
||||||
void main();
|
void main();
|
||||||
|
|
||||||
void load(const string &xml, const uint8_t *data, unsigned size);
|
void load(const string &markup, const uint8_t *data, unsigned size);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
unsigned ram_size();
|
unsigned ram_size();
|
||||||
|
@ -21,25 +22,12 @@ struct Cartridge : Processor, property<Cartridge> {
|
||||||
|
|
||||||
//privileged:
|
//privileged:
|
||||||
Board *board;
|
Board *board;
|
||||||
Mapper::Mapper *mapper;
|
|
||||||
|
|
||||||
uint8 prg_read(unsigned addr);
|
uint8 prg_read(unsigned addr);
|
||||||
void prg_write(unsigned addr, uint8 data);
|
void prg_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
uint8 chr_read(unsigned addr);
|
uint8 chr_read(unsigned addr);
|
||||||
void chr_write(unsigned addr, uint8 data);
|
void chr_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
uint8 *rom_data;
|
|
||||||
unsigned rom_size;
|
|
||||||
|
|
||||||
uint8 *prg_data;
|
|
||||||
unsigned prg_size;
|
|
||||||
|
|
||||||
uint8 *chr_data;
|
|
||||||
unsigned chr_size;
|
|
||||||
|
|
||||||
bool chr_ram;
|
|
||||||
unsigned mirroring;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Cartridge cartridge;
|
extern Cartridge cartridge;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
struct Chip {
|
||||||
|
};
|
|
@ -0,0 +1,66 @@
|
||||||
|
static string iNES(const uint8_t *data, unsigned size) {
|
||||||
|
if(size < 16) return "";
|
||||||
|
if(data[0] != 'N') return "";
|
||||||
|
if(data[1] != 'E') return "";
|
||||||
|
if(data[2] != 'S') return "";
|
||||||
|
if(data[3] != 0x1a) return "";
|
||||||
|
|
||||||
|
string output;
|
||||||
|
|
||||||
|
unsigned mapper = ((data[7] >> 4) << 4) | (data[6] >> 4);
|
||||||
|
unsigned mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01);
|
||||||
|
unsigned prgrom = data[4] * 0x4000;
|
||||||
|
unsigned chrrom = data[5] * 0x2000;
|
||||||
|
unsigned prgram = 0;
|
||||||
|
unsigned chrram = chrrom == 0 ? 8192 : 0;
|
||||||
|
|
||||||
|
print("iNES mapper: ", mapper, "\n");
|
||||||
|
|
||||||
|
output.append("cartridge\n");
|
||||||
|
|
||||||
|
switch(mapper) {
|
||||||
|
default:
|
||||||
|
output.append(" board type=NES-NROM-256\n");
|
||||||
|
output.append(" mirror=", mirror == 0 ? "horizontal" : "vertical", "\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
output.append(" board type=NES-SXROM\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
output.append(" board type=NES-UOROM\n");
|
||||||
|
output.append(" mirror=", mirror == 0 ? "horizontal" : "vertical", "\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
output.append(" board type=NES-CNROM\n");
|
||||||
|
output.append(" mirror=", mirror == 0 ? "horizontal" : "vertical", "\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
output.append(" board type=NES-AOROM\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.append(" prg rom=", prgrom, " ram=", prgram, "\n");
|
||||||
|
output.append(" chr rom=", chrrom, " ram=", chrram, "\n");
|
||||||
|
|
||||||
|
print(output, "\n");
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
switch(mapperNumber) {
|
||||||
|
//default : mapper = &Mapper::none; break;
|
||||||
|
//case 1: mapper = &Mapper::mmc1; break;
|
||||||
|
//case 2: mapper = &Mapper::uorom; break;
|
||||||
|
//case 3: mapper = &Mapper::cnrom; break;
|
||||||
|
case 4: mapper = &Mapper::mmc3; break;
|
||||||
|
//case 7: mapper = &Mapper::aorom; break;
|
||||||
|
case 16: mapper = &Mapper::bandaiFCG; break;
|
||||||
|
case 24: mapper = &Mapper::vrc6; Mapper::vrc6.abus_swap = 0; break;
|
||||||
|
case 26: mapper = &Mapper::vrc6; Mapper::vrc6.abus_swap = 1; break;
|
||||||
|
}
|
||||||
|
*/
|
|
@ -27,8 +27,8 @@ bool Interface::cartridgeLoaded() {
|
||||||
return cartridge.loaded();
|
return cartridge.loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::loadCartridge(const string &xml, const uint8_t *data, unsigned size) {
|
void Interface::loadCartridge(const string &markup, const uint8_t *data, unsigned size) {
|
||||||
cartridge.load(xml, data, size);
|
cartridge.load(markup, data, size);
|
||||||
system.power();
|
system.power();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct Interface {
|
||||||
virtual void initialize(Interface*);
|
virtual void initialize(Interface*);
|
||||||
|
|
||||||
virtual bool cartridgeLoaded();
|
virtual bool cartridgeLoaded();
|
||||||
virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size);
|
virtual void loadCartridge(const string &markup, const uint8_t *data, unsigned size);
|
||||||
virtual void unloadCartridge();
|
virtual void unloadCartridge();
|
||||||
|
|
||||||
enum class Memory : unsigned {
|
enum class Memory : unsigned {
|
||||||
|
|
|
@ -99,9 +99,8 @@ namespace NES {
|
||||||
#include <nes/system/system.hpp>
|
#include <nes/system/system.hpp>
|
||||||
#include <nes/scheduler/scheduler.hpp>
|
#include <nes/scheduler/scheduler.hpp>
|
||||||
#include <nes/input/input.hpp>
|
#include <nes/input/input.hpp>
|
||||||
#include <nes/mapper/mapper.hpp>
|
|
||||||
#include <nes/cartridge/cartridge.hpp>
|
|
||||||
#include <nes/memory/memory.hpp>
|
#include <nes/memory/memory.hpp>
|
||||||
|
#include <nes/cartridge/cartridge.hpp>
|
||||||
#include <nes/cpu/cpu.hpp>
|
#include <nes/cpu/cpu.hpp>
|
||||||
#include <nes/apu/apu.hpp>
|
#include <nes/apu/apu.hpp>
|
||||||
#include <nes/ppu/ppu.hpp>
|
#include <nes/ppu/ppu.hpp>
|
||||||
|
|
|
@ -20,10 +20,10 @@ bool InterfaceNES::loadCartridge(const string &filename) {
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
interface->baseName = nall::basename(filename);
|
interface->baseName = nall::basename(filename);
|
||||||
|
|
||||||
string xml;
|
string markup;
|
||||||
xml.readfile({ interface->baseName, ".xml" });
|
markup.readfile({ interface->baseName, ".bml" });
|
||||||
|
|
||||||
NES::Interface::loadCartridge(xml, fp.data(), fp.size());
|
NES::Interface::loadCartridge(markup, fp.data(), fp.size());
|
||||||
fp.close();
|
fp.close();
|
||||||
|
|
||||||
if(NES::Interface::memorySize(NES::Interface::Memory::RAM) > 0) {
|
if(NES::Interface::memorySize(NES::Interface::Memory::RAM) > 0) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ Application::Application(int argc, char **argv) {
|
||||||
inputManager = new InputManager;
|
inputManager = new InputManager;
|
||||||
utility = new Utility;
|
utility = new Utility;
|
||||||
|
|
||||||
title = "bsnes v082.25";
|
title = "bsnes v082.26";
|
||||||
|
|
||||||
string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, ";
|
string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, ";
|
||||||
normalFont = { fontFamily, "8" };
|
normalFont = { fontFamily, "8" };
|
||||||
|
|
|
@ -129,32 +129,14 @@ bool CheatEditor::load(const string &filename) {
|
||||||
if(data.readfile(filename) == false) return false;
|
if(data.readfile(filename) == false) return false;
|
||||||
|
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
xml_element document = xml_parse(data);
|
BML::Node document(data);
|
||||||
for(auto &head : document.element) {
|
for(auto &cheat : document["cartridge"]) {
|
||||||
if(head.name == "cartridge") {
|
if(cheat.name() != "cheat") continue;
|
||||||
for(auto &node : head.element) {
|
cheatList.setChecked(n, cheat["enable"].exists());
|
||||||
if(node.name == "cheat") {
|
cheatText[n][Code] = cheat["code"].value();
|
||||||
bool enable = false;
|
cheatText[n][Desc] = cheat["description"].value();
|
||||||
string description;
|
|
||||||
string code;
|
|
||||||
for(auto &attribute : node.attribute) {
|
|
||||||
if(attribute.name == "enabled") enable = (attribute.parse() == "true");
|
|
||||||
}
|
|
||||||
for(auto &element : node.element) {
|
|
||||||
if(element.name == "description") description = element.parse();
|
|
||||||
else if(element.name == "code") code.append(element.parse(), "+");
|
|
||||||
}
|
|
||||||
code.rtrim<1>("+");
|
|
||||||
|
|
||||||
cheatList.setChecked(n, enable);
|
|
||||||
cheatText[n][Code] = code;
|
|
||||||
cheatText[n][Desc] = description;
|
|
||||||
|
|
||||||
if(++n >= 128) break;
|
if(++n >= 128) break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUI(), updateInterface();
|
updateUI(), updateInterface();
|
||||||
return true;
|
return true;
|
||||||
|
@ -179,21 +161,14 @@ bool CheatEditor::save(const string &filename) {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, file::mode::write) == false) return false;
|
if(fp.open(filename, file::mode::write) == false) return false;
|
||||||
|
|
||||||
fp.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
fp.print("cartridge sha256=", interface->sha256(), "\n");
|
||||||
fp.print("<cartridge>\n");
|
|
||||||
for(unsigned n = 0; n <= lastSave; n++) {
|
for(unsigned n = 0; n <= lastSave; n++) {
|
||||||
fp.print(" <cheat enabled=\"", cheatList.checked(n) ? "true" : "false", "\">\n");
|
fp.print(" cheat", cheatList.checked(n) ? " enable" : "", "\n");
|
||||||
fp.print(" <description>", cheatText[n][Desc], "</description>\n");
|
fp.print(" description=|", cheatText[n][Desc], "|\n");
|
||||||
lstring list;
|
fp.print(" code=|", cheatText[n][Code], "|\n");
|
||||||
list.split("+", cheatText[n][Code]);
|
|
||||||
for(auto &code : list) {
|
|
||||||
fp.print(" <code>", code, "</code>\n");
|
|
||||||
}
|
}
|
||||||
fp.print(" </cheat>\n");
|
|
||||||
}
|
|
||||||
fp.print("</cartridge>\n");
|
|
||||||
fp.close();
|
|
||||||
|
|
||||||
|
fp.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue