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
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := accuracy
|
||||
profile := compatibility
|
||||
ui := ui
|
||||
|
||||
# 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]();
|
||||
system.load();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
|
@ -104,7 +116,19 @@ void Cartridge::ram_write(unsigned addr, uint8 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() {
|
||||
bootrom_enable = true;
|
||||
|
||||
mbc0.power();
|
||||
mbc1.power();
|
||||
mbc2.power();
|
||||
|
@ -113,26 +137,10 @@ void Cartridge::power() {
|
|||
mmm01.power();
|
||||
huc1.power();
|
||||
huc3.power();
|
||||
map();
|
||||
}
|
||||
|
||||
void Cartridge::map() {
|
||||
MMIO *mapper = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
if(mapper) {
|
||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = mapper;
|
||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = mapper;
|
||||
}
|
||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct Cartridge : property<Cartridge> {
|
||||
struct Cartridge : MMIO, property<Cartridge> {
|
||||
#include "mbc0/mbc0.hpp"
|
||||
#include "mbc1/mbc1.hpp"
|
||||
#include "mbc2/mbc2.hpp"
|
||||
|
@ -41,6 +41,9 @@ struct Cartridge : property<Cartridge> {
|
|||
uint8_t *ramdata;
|
||||
unsigned ramsize;
|
||||
|
||||
MMIO *mapper;
|
||||
bool bootrom_enable;
|
||||
|
||||
void load(const string &xml, const uint8_t *data, unsigned size);
|
||||
void unload();
|
||||
|
||||
|
@ -49,8 +52,10 @@ struct Cartridge : property<Cartridge> {
|
|||
uint8 ram_read(unsigned addr);
|
||||
void ram_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void map();
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(info.battery) s.array(ramdata, ramsize);
|
||||
s.integer(bootrom_enable);
|
||||
|
||||
s.integer(mbc1.ram_enable);
|
||||
s.integer(mbc1.rom_select);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.13";
|
||||
static const char Version[] = "000.14";
|
||||
static unsigned SerializerVersion = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ void Bus::write(uint16 addr, uint8 data) {
|
|||
}
|
||||
|
||||
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_) {
|
||||
interface = interface_;
|
||||
}
|
||||
|
||||
void System::load() {
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
void System::power() {
|
||||
bus.power();
|
||||
cartridge.power();
|
||||
|
@ -58,11 +49,7 @@ void System::power() {
|
|||
lcd.power();
|
||||
scheduler.init();
|
||||
|
||||
for(unsigned n = 0x0000; n <= 0x00ff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
|
||||
clocks_executed = 0;
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ enum class Input : unsigned {
|
|||
Up, Down, Left, Right, B, A, Select, Start,
|
||||
};
|
||||
|
||||
struct System : MMIO {
|
||||
struct System {
|
||||
struct BootROM {
|
||||
static const uint8 dmg[256];
|
||||
static const uint8 sgb[256];
|
||||
|
@ -14,10 +14,8 @@ struct System : MMIO {
|
|||
void runtosave();
|
||||
void runthreadtosave();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void init(Interface*);
|
||||
void load();
|
||||
void power();
|
||||
|
||||
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(double value);
|
||||
|
||||
inline bool readfile(const char*);
|
||||
inline bool readfile(const string&);
|
||||
|
||||
inline string& replace (const char*, const char*);
|
||||
inline string& qreplace(const char*, const char*);
|
||||
|
|
|
@ -95,7 +95,7 @@ string::~string() {
|
|||
if(data) free(data);
|
||||
}
|
||||
|
||||
bool string::readfile(const char *filename) {
|
||||
bool string::readfile(const string &filename) {
|
||||
assign("");
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
|
|
@ -53,7 +53,7 @@ string integer(intmax_t value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string linteger(intmax_t value) {
|
||||
template<unsigned length_> string linteger(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
|
@ -68,6 +68,7 @@ template<unsigned length> string linteger(intmax_t value) {
|
|||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
result[length] = 0;
|
||||
|
@ -79,7 +80,7 @@ template<unsigned length> string linteger(intmax_t value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string rinteger(intmax_t value) {
|
||||
template<unsigned length_> string rinteger(intmax_t value) {
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
|
@ -94,6 +95,7 @@ template<unsigned length> string rinteger(intmax_t value) {
|
|||
buffer[size++] = negative ? '-' : '+';
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
result[length] = 0;
|
||||
|
@ -127,7 +129,7 @@ string decimal(uintmax_t value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string ldecimal(uintmax_t value) {
|
||||
template<unsigned length_> string ldecimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
|
@ -138,6 +140,7 @@ template<unsigned length> string ldecimal(uintmax_t value) {
|
|||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
result[length] = 0;
|
||||
|
@ -149,7 +152,7 @@ template<unsigned length> string ldecimal(uintmax_t value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string rdecimal(uintmax_t value) {
|
||||
template<unsigned length_> string rdecimal(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
|
@ -160,6 +163,7 @@ template<unsigned length> string rdecimal(uintmax_t value) {
|
|||
} while(value);
|
||||
buffer[size] = 0;
|
||||
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, ' ', length);
|
||||
result[length] = 0;
|
||||
|
@ -171,50 +175,48 @@ template<unsigned length> string rdecimal(uintmax_t value) {
|
|||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string hex(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
template<unsigned length_> string hex(uintmax_t value) {
|
||||
char buffer[64];
|
||||
unsigned size = 0;
|
||||
|
||||
//render string backwards, as we do not know its length yet
|
||||
do {
|
||||
unsigned n = value & 15;
|
||||
output[offset++] = n < 10 ? '0' + n : 'a' + n - 10;
|
||||
buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10;
|
||||
value >>= 4;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = '0';
|
||||
output[offset--] = 0;
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, '0', length);
|
||||
result[length] = 0;
|
||||
|
||||
//reverse the string in-place
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return output;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<unsigned length> string binary(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
template<unsigned length_> string binary(uintmax_t value) {
|
||||
char buffer[256];
|
||||
unsigned size = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value & 1;
|
||||
output[offset++] = '0' + n;
|
||||
buffer[size++] = '0' + n;
|
||||
value >>= 1;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = '0';
|
||||
output[offset--] = 0;
|
||||
unsigned length = (length_ == 0 ? size : length_);
|
||||
char result[length + 1];
|
||||
memset(result, '0', length);
|
||||
result[length] = 0;
|
||||
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||
result[x] = buffer[y];
|
||||
}
|
||||
|
||||
return output;
|
||||
return result;
|
||||
}
|
||||
|
||||
//using sprintf is certainly not the most ideal method to convert
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "075";
|
||||
static const unsigned SerializerVersion = 17;
|
||||
static const char Version[] = "075.01";
|
||||
static const unsigned SerializerVersion = 18;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ void System::load() {
|
|||
if(cartridge.has_st0018()) st0018.load();
|
||||
if(cartridge.has_msu1()) msu1.load();
|
||||
if(cartridge.has_serial()) serial.load();
|
||||
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
void System::unload() {
|
||||
|
@ -183,7 +185,6 @@ void System::power() {
|
|||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||
|
||||
scheduler.init();
|
||||
serialize_init();
|
||||
cheat.init();
|
||||
|
||||
input.update();
|
||||
|
@ -221,7 +222,6 @@ void System::reset() {
|
|||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||
|
||||
scheduler.init();
|
||||
serialize_init();
|
||||
cheat.init();
|
||||
|
||||
input.port_set_device(0, config.controller_port1);
|
||||
|
|
|
@ -41,6 +41,7 @@ bool Utility::loadState(unsigned slot) {
|
|||
fp.read(data, size);
|
||||
fp.close();
|
||||
serializer s(data, size);
|
||||
GameBoy::system.power();
|
||||
return GameBoy::system.unserialize(s);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue