mirror of https://github.com/bsnes-emu/bsnes.git
Update to v075r01 release.
byuu says: Changelog: - fixed Super Game Boy save state support - both SNES and GameBoy only initialize serialize size on cartridge load once now, just like I've already done with memory mapping - added nall/public_cast.hpp for fun ... don't worry, I'm never actually going to use it in production code :D
This commit is contained in:
parent
6b4104867f
commit
eecc085e42
|
@ -1,7 +1,7 @@
|
||||||
include nall/Makefile
|
include nall/Makefile
|
||||||
snes := snes
|
snes := snes
|
||||||
gameboy := gameboy
|
gameboy := gameboy
|
||||||
profile := accuracy
|
profile := compatibility
|
||||||
ui := ui
|
ui := ui
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
|
|
|
@ -70,7 +70,19 @@ void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(info.mapper) { default:
|
||||||
|
case Mapper::MBC0: mapper = &mbc0; break;
|
||||||
|
case Mapper::MBC1: mapper = &mbc1; break;
|
||||||
|
case Mapper::MBC2: mapper = &mbc2; break;
|
||||||
|
case Mapper::MBC3: mapper = &mbc3; break;
|
||||||
|
case Mapper::MBC5: mapper = &mbc5; break;
|
||||||
|
case Mapper::MMM01: mapper = &mmm01; break;
|
||||||
|
case Mapper::HuC1: mapper = &huc1; break;
|
||||||
|
case Mapper::HuC3: mapper = &huc3; break;
|
||||||
|
}
|
||||||
|
|
||||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||||
|
system.load();
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +116,19 @@ void Cartridge::ram_write(unsigned addr, uint8 data) {
|
||||||
ramdata[addr] = data;
|
ramdata[addr] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 Cartridge::mmio_read(uint16 addr) {
|
||||||
|
if(bootrom_enable && within<0x0000, 0x00ff>(addr)) return System::BootROM::sgb[addr];
|
||||||
|
return mapper->mmio_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::mmio_write(uint16 addr, uint8 data) {
|
||||||
|
if(bootrom_enable && addr == 0xff50) bootrom_enable = false;
|
||||||
|
mapper->mmio_write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
void Cartridge::power() {
|
void Cartridge::power() {
|
||||||
|
bootrom_enable = true;
|
||||||
|
|
||||||
mbc0.power();
|
mbc0.power();
|
||||||
mbc1.power();
|
mbc1.power();
|
||||||
mbc2.power();
|
mbc2.power();
|
||||||
|
@ -113,26 +137,10 @@ void Cartridge::power() {
|
||||||
mmm01.power();
|
mmm01.power();
|
||||||
huc1.power();
|
huc1.power();
|
||||||
huc3.power();
|
huc3.power();
|
||||||
map();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cartridge::map() {
|
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
||||||
MMIO *mapper = 0;
|
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
||||||
switch(info.mapper) { default:
|
bus.mmio[0xff50] = this;
|
||||||
case Mapper::MBC0: mapper = &mbc0; break;
|
|
||||||
case Mapper::MBC1: mapper = &mbc1; break;
|
|
||||||
case Mapper::MBC2: mapper = &mbc2; break;
|
|
||||||
case Mapper::MBC3: mapper = &mbc3; break;
|
|
||||||
case Mapper::MBC5: mapper = &mbc5; break;
|
|
||||||
case Mapper::MMM01: mapper = &mmm01; break;
|
|
||||||
case Mapper::HuC1: mapper = &huc1; break;
|
|
||||||
case Mapper::HuC3: mapper = &huc3; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mapper) {
|
|
||||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = mapper;
|
|
||||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = mapper;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
Cartridge::Cartridge() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
struct Cartridge : property<Cartridge> {
|
struct Cartridge : MMIO, property<Cartridge> {
|
||||||
#include "mbc0/mbc0.hpp"
|
#include "mbc0/mbc0.hpp"
|
||||||
#include "mbc1/mbc1.hpp"
|
#include "mbc1/mbc1.hpp"
|
||||||
#include "mbc2/mbc2.hpp"
|
#include "mbc2/mbc2.hpp"
|
||||||
|
@ -41,6 +41,9 @@ struct Cartridge : property<Cartridge> {
|
||||||
uint8_t *ramdata;
|
uint8_t *ramdata;
|
||||||
unsigned ramsize;
|
unsigned ramsize;
|
||||||
|
|
||||||
|
MMIO *mapper;
|
||||||
|
bool bootrom_enable;
|
||||||
|
|
||||||
void load(const string &xml, const uint8_t *data, unsigned size);
|
void load(const string &xml, const uint8_t *data, unsigned size);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
|
@ -49,8 +52,10 @@ struct Cartridge : property<Cartridge> {
|
||||||
uint8 ram_read(unsigned addr);
|
uint8 ram_read(unsigned addr);
|
||||||
void ram_write(unsigned addr, uint8 data);
|
void ram_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
uint8 mmio_read(uint16 addr);
|
||||||
|
void mmio_write(uint16 addr, uint8 data);
|
||||||
|
|
||||||
void power();
|
void power();
|
||||||
void map();
|
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
Cartridge();
|
Cartridge();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
void Cartridge::serialize(serializer &s) {
|
void Cartridge::serialize(serializer &s) {
|
||||||
if(info.battery) s.array(ramdata, ramsize);
|
if(info.battery) s.array(ramdata, ramsize);
|
||||||
|
s.integer(bootrom_enable);
|
||||||
|
|
||||||
s.integer(mbc1.ram_enable);
|
s.integer(mbc1.ram_enable);
|
||||||
s.integer(mbc1.rom_select);
|
s.integer(mbc1.rom_select);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bgameboy";
|
static const char Name[] = "bgameboy";
|
||||||
static const char Version[] = "000.13";
|
static const char Version[] = "000.14";
|
||||||
static unsigned SerializerVersion = 1;
|
static unsigned SerializerVersion = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ void Bus::write(uint16 addr, uint8 data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::power() {
|
void Bus::power() {
|
||||||
for(unsigned n = 0; n < 65536; n++) mmio[n] = &unmapped;
|
for(unsigned n = 0x0000; n <= 0xffff; n++) mmio[n] = &unmapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,23 +33,14 @@ void System::runthreadtosave() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 System::mmio_read(uint16 addr) {
|
|
||||||
if((addr & 0xff00) == 0x0000) {
|
|
||||||
return BootROM::sgb[addr];
|
|
||||||
}
|
|
||||||
return 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::mmio_write(uint16 addr, uint8 data) {
|
|
||||||
if(addr == 0xff50) {
|
|
||||||
if(data == 0x01) cartridge.map();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::init(Interface *interface_) {
|
void System::init(Interface *interface_) {
|
||||||
interface = interface_;
|
interface = interface_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::load() {
|
||||||
|
serialize_init();
|
||||||
|
}
|
||||||
|
|
||||||
void System::power() {
|
void System::power() {
|
||||||
bus.power();
|
bus.power();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
|
@ -58,11 +49,7 @@ void System::power() {
|
||||||
lcd.power();
|
lcd.power();
|
||||||
scheduler.init();
|
scheduler.init();
|
||||||
|
|
||||||
for(unsigned n = 0x0000; n <= 0x00ff; n++) bus.mmio[n] = this;
|
|
||||||
bus.mmio[0xff50] = this;
|
|
||||||
|
|
||||||
clocks_executed = 0;
|
clocks_executed = 0;
|
||||||
serialize_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ enum class Input : unsigned {
|
||||||
Up, Down, Left, Right, B, A, Select, Start,
|
Up, Down, Left, Right, B, A, Select, Start,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct System : MMIO {
|
struct System {
|
||||||
struct BootROM {
|
struct BootROM {
|
||||||
static const uint8 dmg[256];
|
static const uint8 dmg[256];
|
||||||
static const uint8 sgb[256];
|
static const uint8 sgb[256];
|
||||||
|
@ -14,10 +14,8 @@ struct System : MMIO {
|
||||||
void runtosave();
|
void runtosave();
|
||||||
void runthreadtosave();
|
void runthreadtosave();
|
||||||
|
|
||||||
uint8 mmio_read(uint16 addr);
|
|
||||||
void mmio_write(uint16 addr, uint8 data);
|
|
||||||
|
|
||||||
void init(Interface*);
|
void init(Interface*);
|
||||||
|
void load();
|
||||||
void power();
|
void power();
|
||||||
|
|
||||||
Interface *interface;
|
Interface *interface;
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef NALL_PUBLIC_CAST_HPP
|
||||||
|
#define NALL_PUBLIC_CAST_HPP
|
||||||
|
|
||||||
|
//this is a proof-of-concept-*only* C++ access-privilege elevation exploit.
|
||||||
|
//it allows full access to both protected and private member variables, objects and functions
|
||||||
|
//from the global scope, regardless of inheritance and/or friendship privileges.
|
||||||
|
//the code itself is 100% legal C++, per C++98 section 14.7.2 paragraph 8:
|
||||||
|
//"Access checking rules do not apply to names in explicit instantiations."
|
||||||
|
|
||||||
|
//C++0x variadic templates are used simply to allow public_cast name to be used
|
||||||
|
//on second derived class name for simplification, however the basic idea also
|
||||||
|
//works on C++98.
|
||||||
|
|
||||||
|
//usage example:
|
||||||
|
//struct N { typedef void (Class::*)(); };
|
||||||
|
//template class public_cast<N, &Class::Function>;
|
||||||
|
//(class.*public_cast<N>::value)();
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
template<typename T, typename T::type... P> struct public_cast;
|
||||||
|
|
||||||
|
template<typename T> struct public_cast<T> {
|
||||||
|
static typename T::type value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> typename T::type public_cast<T>::value;
|
||||||
|
|
||||||
|
template<typename T, typename T::type P> struct public_cast<T, P> : public_cast<T> {
|
||||||
|
struct ref_t {
|
||||||
|
ref_t() { public_cast<T>::value = P; }
|
||||||
|
};
|
||||||
|
static ref_t ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename T::type P> typename public_cast<T, P>::ref_t public_cast<T, P>::ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -25,7 +25,7 @@ namespace nall {
|
||||||
inline string& append(unsigned int value);
|
inline string& append(unsigned int value);
|
||||||
inline string& append(double value);
|
inline string& append(double value);
|
||||||
|
|
||||||
inline bool readfile(const char*);
|
inline bool readfile(const string&);
|
||||||
|
|
||||||
inline string& replace (const char*, const char*);
|
inline string& replace (const char*, const char*);
|
||||||
inline string& qreplace(const char*, const char*);
|
inline string& qreplace(const char*, const char*);
|
||||||
|
|
|
@ -95,7 +95,7 @@ string::~string() {
|
||||||
if(data) free(data);
|
if(data) free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string::readfile(const char *filename) {
|
bool string::readfile(const string &filename) {
|
||||||
assign("");
|
assign("");
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|
|
@ -53,7 +53,7 @@ string integer(intmax_t value) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length> string linteger(intmax_t value) {
|
template<unsigned length_> string linteger(intmax_t value) {
|
||||||
bool negative = value < 0;
|
bool negative = value < 0;
|
||||||
if(negative) value = abs(value);
|
if(negative) value = abs(value);
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ template<unsigned length> string linteger(intmax_t value) {
|
||||||
buffer[size++] = negative ? '-' : '+';
|
buffer[size++] = negative ? '-' : '+';
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
unsigned length = (length_ == 0 ? size : length_);
|
||||||
char result[length + 1];
|
char result[length + 1];
|
||||||
memset(result, ' ', length);
|
memset(result, ' ', length);
|
||||||
result[length] = 0;
|
result[length] = 0;
|
||||||
|
@ -79,7 +80,7 @@ template<unsigned length> string linteger(intmax_t value) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length> string rinteger(intmax_t value) {
|
template<unsigned length_> string rinteger(intmax_t value) {
|
||||||
bool negative = value < 0;
|
bool negative = value < 0;
|
||||||
if(negative) value = abs(value);
|
if(negative) value = abs(value);
|
||||||
|
|
||||||
|
@ -94,6 +95,7 @@ template<unsigned length> string rinteger(intmax_t value) {
|
||||||
buffer[size++] = negative ? '-' : '+';
|
buffer[size++] = negative ? '-' : '+';
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
unsigned length = (length_ == 0 ? size : length_);
|
||||||
char result[length + 1];
|
char result[length + 1];
|
||||||
memset(result, ' ', length);
|
memset(result, ' ', length);
|
||||||
result[length] = 0;
|
result[length] = 0;
|
||||||
|
@ -127,7 +129,7 @@ string decimal(uintmax_t value) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length> string ldecimal(uintmax_t value) {
|
template<unsigned length_> string ldecimal(uintmax_t value) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
|
|
||||||
|
@ -138,6 +140,7 @@ template<unsigned length> string ldecimal(uintmax_t value) {
|
||||||
} while(value);
|
} while(value);
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
unsigned length = (length_ == 0 ? size : length_);
|
||||||
char result[length + 1];
|
char result[length + 1];
|
||||||
memset(result, ' ', length);
|
memset(result, ' ', length);
|
||||||
result[length] = 0;
|
result[length] = 0;
|
||||||
|
@ -149,7 +152,7 @@ template<unsigned length> string ldecimal(uintmax_t value) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length> string rdecimal(uintmax_t value) {
|
template<unsigned length_> string rdecimal(uintmax_t value) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
|
|
||||||
|
@ -160,6 +163,7 @@ template<unsigned length> string rdecimal(uintmax_t value) {
|
||||||
} while(value);
|
} while(value);
|
||||||
buffer[size] = 0;
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
unsigned length = (length_ == 0 ? size : length_);
|
||||||
char result[length + 1];
|
char result[length + 1];
|
||||||
memset(result, ' ', length);
|
memset(result, ' ', length);
|
||||||
result[length] = 0;
|
result[length] = 0;
|
||||||
|
@ -171,50 +175,48 @@ template<unsigned length> string rdecimal(uintmax_t value) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length> string hex(uintmax_t value) {
|
template<unsigned length_> string hex(uintmax_t value) {
|
||||||
string output;
|
char buffer[64];
|
||||||
unsigned offset = 0;
|
unsigned size = 0;
|
||||||
|
|
||||||
//render string backwards, as we do not know its length yet
|
|
||||||
do {
|
do {
|
||||||
unsigned n = value & 15;
|
unsigned n = value & 15;
|
||||||
output[offset++] = n < 10 ? '0' + n : 'a' + n - 10;
|
buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10;
|
||||||
value >>= 4;
|
value >>= 4;
|
||||||
} while(value);
|
} while(value);
|
||||||
|
|
||||||
while(offset < length) output[offset++] = '0';
|
unsigned length = (length_ == 0 ? size : length_);
|
||||||
output[offset--] = 0;
|
char result[length + 1];
|
||||||
|
memset(result, '0', length);
|
||||||
|
result[length] = 0;
|
||||||
|
|
||||||
//reverse the string in-place
|
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
result[x] = buffer[y];
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length> string binary(uintmax_t value) {
|
template<unsigned length_> string binary(uintmax_t value) {
|
||||||
string output;
|
char buffer[256];
|
||||||
unsigned offset = 0;
|
unsigned size = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
unsigned n = value & 1;
|
unsigned n = value & 1;
|
||||||
output[offset++] = '0' + n;
|
buffer[size++] = '0' + n;
|
||||||
value >>= 1;
|
value >>= 1;
|
||||||
} while(value);
|
} while(value);
|
||||||
|
|
||||||
while(offset < length) output[offset++] = '0';
|
unsigned length = (length_ == 0 ? size : length_);
|
||||||
output[offset--] = 0;
|
char result[length + 1];
|
||||||
|
memset(result, '0', length);
|
||||||
|
result[length] = 0;
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||||
char temp = output[i];
|
result[x] = buffer[y];
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//using sprintf is certainly not the most ideal method to convert
|
//using sprintf is certainly not the most ideal method to convert
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "075";
|
static const char Version[] = "075.01";
|
||||||
static const unsigned SerializerVersion = 17;
|
static const unsigned SerializerVersion = 18;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,8 @@ void System::load() {
|
||||||
if(cartridge.has_st0018()) st0018.load();
|
if(cartridge.has_st0018()) st0018.load();
|
||||||
if(cartridge.has_msu1()) msu1.load();
|
if(cartridge.has_msu1()) msu1.load();
|
||||||
if(cartridge.has_serial()) serial.load();
|
if(cartridge.has_serial()) serial.load();
|
||||||
|
|
||||||
|
serialize_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::unload() {
|
void System::unload() {
|
||||||
|
@ -183,7 +185,6 @@ void System::power() {
|
||||||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||||
|
|
||||||
scheduler.init();
|
scheduler.init();
|
||||||
serialize_init();
|
|
||||||
cheat.init();
|
cheat.init();
|
||||||
|
|
||||||
input.update();
|
input.update();
|
||||||
|
@ -221,7 +222,6 @@ void System::reset() {
|
||||||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||||
|
|
||||||
scheduler.init();
|
scheduler.init();
|
||||||
serialize_init();
|
|
||||||
cheat.init();
|
cheat.init();
|
||||||
|
|
||||||
input.port_set_device(0, config.controller_port1);
|
input.port_set_device(0, config.controller_port1);
|
||||||
|
|
|
@ -41,6 +41,7 @@ bool Utility::loadState(unsigned slot) {
|
||||||
fp.read(data, size);
|
fp.read(data, size);
|
||||||
fp.close();
|
fp.close();
|
||||||
serializer s(data, size);
|
serializer s(data, size);
|
||||||
|
GameBoy::system.power();
|
||||||
return GameBoy::system.unserialize(s);
|
return GameBoy::system.unserialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue