mirror of https://github.com/bsnes-emu/bsnes.git
parent
c2a181dbc5
commit
2f67beeba9
|
@ -1,6 +1,5 @@
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
#include <emulator/audio/audio.cpp>
|
#include <emulator/audio/audio.cpp>
|
||||||
#include <emulator/resource/resource.cpp>
|
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,10 @@ using namespace nall;
|
||||||
#include <emulator/memory/readable.hpp>
|
#include <emulator/memory/readable.hpp>
|
||||||
#include <emulator/memory/writable.hpp>
|
#include <emulator/memory/writable.hpp>
|
||||||
#include <emulator/audio/audio.hpp>
|
#include <emulator/audio/audio.hpp>
|
||||||
#include <emulator/resource/resource.hpp>
|
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "bsnes";
|
static const string Name = "bsnes";
|
||||||
static const string Version = "107.14";
|
static const string Version = "107.15";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org";
|
static const string Website = "https://byuu.org";
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
all:
|
|
||||||
sourcery resource.bml resource.cpp resource.hpp
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm resource.cpp
|
|
||||||
rm resource.hpp
|
|
|
@ -1,5 +0,0 @@
|
||||||
namespace name=Resource
|
|
||||||
namespace name=Sprite
|
|
||||||
binary name=CrosshairRed file=sprite/crosshair-red.png
|
|
||||||
binary name=CrosshairGreen file=sprite/crosshair-green.png
|
|
||||||
binary name=CrosshairBlue file=sprite/crosshair-blue.png
|
|
|
@ -1,45 +0,0 @@
|
||||||
#include "resource.hpp"
|
|
||||||
|
|
||||||
namespace Resource {
|
|
||||||
namespace Sprite {
|
|
||||||
const unsigned char CrosshairRed[342] = {
|
|
||||||
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
|
|
||||||
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14,
|
|
||||||
196,1,149,43,14,27,0,0,0,248,73,68,65,84,88,133,205,87,65,14,196,32,8,132,102,255,255,101,246,176,177,139,
|
|
||||||
148,81,80,27,229,212,70,102,6,212,0,50,229,77,26,107,156,37,139,2,228,241,209,39,11,113,71,156,68,139,106,128,
|
|
||||||
56,255,198,175,203,223,114,16,79,68,253,138,90,99,141,113,112,80,231,131,196,11,83,52,19,43,196,53,135,147,7,38,
|
|
||||||
150,104,244,212,32,86,235,228,236,20,6,200,207,191,117,215,70,12,242,94,139,133,166,236,173,236,67,252,111,139,67,157,
|
|
||||||
237,71,48,27,192,244,142,93,228,23,148,144,184,228,131,96,254,3,164,4,176,213,108,37,52,5,208,53,47,227,81,28,
|
|
||||||
49,153,102,163,88,96,149,68,150,193,21,223,59,128,68,43,69,13,103,4,199,246,8,34,151,240,209,249,38,112,251,47,
|
|
||||||
97,177,209,74,152,246,95,93,9,211,51,160,181,99,142,128,104,115,55,124,59,136,115,7,146,237,51,33,2,71,166,226,
|
|
||||||
94,23,13,77,214,104,44,103,174,163,143,86,189,244,187,224,232,151,81,21,132,39,210,33,91,246,54,132,193,44,226,219,
|
|
||||||
107,95,57,136,120,253,172,254,16,23,0,0,0,0,73,69,78,68,174,66,96,130,
|
|
||||||
};
|
|
||||||
const unsigned char CrosshairGreen[329] = {
|
|
||||||
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
|
|
||||||
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14,
|
|
||||||
196,1,149,43,14,27,0,0,0,235,73,68,65,84,88,133,213,87,65,18,195,32,8,196,78,31,230,211,253,153,61,180,
|
|
||||||
52,18,145,1,193,97,178,39,141,44,139,24,69,11,216,209,133,177,98,117,166,37,92,162,77,176,170,118,223,26,163,78,
|
|
||||||
68,71,145,198,244,169,157,57,35,84,248,43,222,255,109,154,254,113,140,114,102,222,18,239,165,120,251,181,42,0,232,103,
|
|
||||||
114,217,85,226,163,27,124,232,163,87,142,115,153,82,137,71,98,233,247,21,44,228,194,169,217,171,252,159,22,95,234,164,
|
|
||||||
47,129,55,128,144,140,237,166,63,132,151,190,4,247,147,16,103,35,157,90,220,140,119,121,80,224,94,108,0,164,227,119,
|
|
||||||
182,221,229,13,182,82,193,225,176,42,56,59,188,105,9,52,5,3,109,58,243,205,202,203,255,9,17,251,91,202,169,227,
|
|
||||||
205,128,235,198,19,17,64,40,82,171,225,233,32,158,113,33,65,164,222,9,105,16,50,81,55,238,88,210,212,119,1,0,
|
|
||||||
238,241,241,126,143,125,62,216,173,151,209,35,222,134,235,96,98,252,229,226,3,112,72,179,236,202,138,114,18,0,0,0,
|
|
||||||
0,73,69,78,68,174,66,96,130,
|
|
||||||
};
|
|
||||||
const unsigned char CrosshairBlue[332] = {
|
|
||||||
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
|
|
||||||
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14,
|
|
||||||
196,1,149,43,14,27,0,0,0,238,73,68,65,84,88,133,213,87,91,18,195,32,8,196,78,15,232,81,189,161,253,9,
|
|
||||||
25,52,98,121,57,76,246,43,137,44,11,24,69,11,232,209,55,99,69,235,76,74,184,69,107,229,245,91,27,220,137,124,
|
|
||||||
75,140,58,21,165,34,181,246,199,251,100,167,174,200,32,124,137,119,124,134,177,252,116,108,224,44,120,44,190,156,56,102,
|
|
||||||
163,204,228,182,107,173,80,31,93,225,67,30,189,112,124,85,41,145,120,36,88,191,159,96,33,23,78,101,47,242,127,90,
|
|
||||||
156,213,73,159,2,111,0,33,21,179,150,63,132,151,62,5,243,78,136,217,236,118,173,85,198,86,30,20,152,154,13,192,
|
|
||||||
118,251,125,216,90,121,212,118,215,112,86,224,26,142,133,247,152,2,73,195,64,155,190,248,166,229,229,255,132,8,243,146,
|
|
||||||
242,234,120,43,224,58,241,68,4,16,138,212,110,120,58,136,119,28,72,16,169,103,194,33,136,63,68,209,184,103,74,83,
|
|
||||||
239,5,0,215,26,167,231,123,124,103,130,53,221,140,94,113,55,100,131,9,242,151,139,31,79,50,234,237,105,206,30,22,
|
|
||||||
0,0,0,0,73,69,78,68,174,66,96,130,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Resource {
|
|
||||||
namespace Sprite {
|
|
||||||
extern const unsigned char CrosshairRed[342];
|
|
||||||
extern const unsigned char CrosshairGreen[329];
|
|
||||||
extern const unsigned char CrosshairBlue[332];
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 332 B |
Binary file not shown.
Before Width: | Height: | Size: 329 B |
Binary file not shown.
Before Width: | Height: | Size: 342 B |
|
@ -250,6 +250,48 @@ typedef union {
|
||||||
} vba64;
|
} vba64;
|
||||||
} GB_rtc_save_t;
|
} GB_rtc_save_t;
|
||||||
|
|
||||||
|
int GB_save_battery_size(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
||||||
|
if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */
|
||||||
|
|
||||||
|
GB_rtc_save_t rtc_save_size;
|
||||||
|
return gb->mbc_ram_size + (gb->cartridge_type->has_rtc ? sizeof(rtc_save_size.vba64) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
||||||
|
if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */
|
||||||
|
|
||||||
|
if (size < GB_save_battery_size(gb)) return EIO;
|
||||||
|
|
||||||
|
memcpy(buffer, gb->mbc_ram, gb->mbc_ram_size);
|
||||||
|
|
||||||
|
if (gb->cartridge_type->has_rtc) {
|
||||||
|
GB_rtc_save_t rtc_save = {{{{0,}},},};
|
||||||
|
rtc_save.vba64.rtc_real.seconds = gb->rtc_real.seconds;
|
||||||
|
rtc_save.vba64.rtc_real.minutes = gb->rtc_real.minutes;
|
||||||
|
rtc_save.vba64.rtc_real.hours = gb->rtc_real.hours;
|
||||||
|
rtc_save.vba64.rtc_real.days = gb->rtc_real.days;
|
||||||
|
rtc_save.vba64.rtc_real.high = gb->rtc_real.high;
|
||||||
|
rtc_save.vba64.rtc_latched.seconds = gb->rtc_latched.seconds;
|
||||||
|
rtc_save.vba64.rtc_latched.minutes = gb->rtc_latched.minutes;
|
||||||
|
rtc_save.vba64.rtc_latched.hours = gb->rtc_latched.hours;
|
||||||
|
rtc_save.vba64.rtc_latched.days = gb->rtc_latched.days;
|
||||||
|
rtc_save.vba64.rtc_latched.high = gb->rtc_latched.high;
|
||||||
|
#ifdef GB_BIG_ENDIAN
|
||||||
|
rtc_save.vba64.last_rtc_second = __builtin_bswap64(gb->last_rtc_second);
|
||||||
|
#else
|
||||||
|
rtc_save.vba64.last_rtc_second = gb->last_rtc_second;
|
||||||
|
#endif
|
||||||
|
memcpy(buffer + gb->mbc_ram_size, &rtc_save.vba64, sizeof(rtc_save.vba64));
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
||||||
{
|
{
|
||||||
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
||||||
|
@ -293,6 +335,79 @@ int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size)
|
||||||
|
{
|
||||||
|
memcpy(gb->mbc_ram, buffer, MIN(gb->mbc_ram_size, size));
|
||||||
|
if (size <= gb->mbc_ram_size) {
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_rtc_save_t rtc_save;
|
||||||
|
memcpy(&rtc_save, buffer + gb->mbc_ram_size, MIN(sizeof(rtc_save), size));
|
||||||
|
switch (size - gb->mbc_ram_size) {
|
||||||
|
case sizeof(rtc_save.sameboy_legacy):
|
||||||
|
memcpy(&gb->rtc_real, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real));
|
||||||
|
memcpy(&gb->rtc_latched, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real));
|
||||||
|
gb->last_rtc_second = rtc_save.sameboy_legacy.last_rtc_second;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sizeof(rtc_save.vba32):
|
||||||
|
gb->rtc_real.seconds = rtc_save.vba32.rtc_real.seconds;
|
||||||
|
gb->rtc_real.minutes = rtc_save.vba32.rtc_real.minutes;
|
||||||
|
gb->rtc_real.hours = rtc_save.vba32.rtc_real.hours;
|
||||||
|
gb->rtc_real.days = rtc_save.vba32.rtc_real.days;
|
||||||
|
gb->rtc_real.high = rtc_save.vba32.rtc_real.high;
|
||||||
|
gb->rtc_latched.seconds = rtc_save.vba32.rtc_latched.seconds;
|
||||||
|
gb->rtc_latched.minutes = rtc_save.vba32.rtc_latched.minutes;
|
||||||
|
gb->rtc_latched.hours = rtc_save.vba32.rtc_latched.hours;
|
||||||
|
gb->rtc_latched.days = rtc_save.vba32.rtc_latched.days;
|
||||||
|
gb->rtc_latched.high = rtc_save.vba32.rtc_latched.high;
|
||||||
|
#ifdef GB_BIG_ENDIAN
|
||||||
|
gb->last_rtc_second = __builtin_bswap32(rtc_save.vba32.last_rtc_second);
|
||||||
|
#else
|
||||||
|
gb->last_rtc_second = rtc_save.vba32.last_rtc_second;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sizeof(rtc_save.vba64):
|
||||||
|
gb->rtc_real.seconds = rtc_save.vba64.rtc_real.seconds;
|
||||||
|
gb->rtc_real.minutes = rtc_save.vba64.rtc_real.minutes;
|
||||||
|
gb->rtc_real.hours = rtc_save.vba64.rtc_real.hours;
|
||||||
|
gb->rtc_real.days = rtc_save.vba64.rtc_real.days;
|
||||||
|
gb->rtc_real.high = rtc_save.vba64.rtc_real.high;
|
||||||
|
gb->rtc_latched.seconds = rtc_save.vba64.rtc_latched.seconds;
|
||||||
|
gb->rtc_latched.minutes = rtc_save.vba64.rtc_latched.minutes;
|
||||||
|
gb->rtc_latched.hours = rtc_save.vba64.rtc_latched.hours;
|
||||||
|
gb->rtc_latched.days = rtc_save.vba64.rtc_latched.days;
|
||||||
|
gb->rtc_latched.high = rtc_save.vba64.rtc_latched.high;
|
||||||
|
#ifdef GB_BIG_ENDIAN
|
||||||
|
gb->last_rtc_second = __builtin_bswap64(rtc_save.vba64.last_rtc_second);
|
||||||
|
#else
|
||||||
|
gb->last_rtc_second = rtc_save.vba64.last_rtc_second;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
if (gb->last_rtc_second > time(NULL)) {
|
||||||
|
/* We must reset RTC here, or it will not advance. */
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gb->last_rtc_second < 852076800) { /* 1/1/97. There weren't any RTC games that time,
|
||||||
|
so if the value we read is lower it means it wasn't
|
||||||
|
really RTC data. */
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
goto exit;
|
||||||
|
reset_rtc:
|
||||||
|
gb->last_rtc_second = time(NULL);
|
||||||
|
gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */
|
||||||
|
exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Loading will silently stop if the format is incomplete */
|
/* Loading will silently stop if the format is incomplete */
|
||||||
void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -670,8 +670,12 @@ int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||||
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
||||||
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
||||||
void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
||||||
|
|
||||||
|
int GB_save_battery_size(GB_gameboy_t *gb);
|
||||||
|
int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size);
|
||||||
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
||||||
|
|
||||||
|
void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
||||||
void GB_load_battery(GB_gameboy_t *gb, const char *path);
|
void GB_load_battery(GB_gameboy_t *gb, const char *path);
|
||||||
|
|
||||||
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip);
|
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip);
|
||||||
|
|
|
@ -128,7 +128,7 @@ auto Cartridge::loadSufamiTurboB() -> bool {
|
||||||
auto Cartridge::save() -> void {
|
auto Cartridge::save() -> void {
|
||||||
saveCartridge(game.document);
|
saveCartridge(game.document);
|
||||||
if(has.GameBoySlot) {
|
if(has.GameBoySlot) {
|
||||||
saveCartridgeGameBoy(slotGameBoy.document);
|
icd.save();
|
||||||
}
|
}
|
||||||
if(has.BSMemorySlot) {
|
if(has.BSMemorySlot) {
|
||||||
saveCartridgeBSMemory(slotBSMemory.document);
|
saveCartridgeBSMemory(slotBSMemory.document);
|
||||||
|
|
|
@ -98,7 +98,6 @@ private:
|
||||||
|
|
||||||
//save.cpp
|
//save.cpp
|
||||||
auto saveCartridge(Markup::Node) -> void;
|
auto saveCartridge(Markup::Node) -> void;
|
||||||
auto saveCartridgeGameBoy(Markup::Node) -> void;
|
|
||||||
auto saveCartridgeBSMemory(Markup::Node) -> void;
|
auto saveCartridgeBSMemory(Markup::Node) -> void;
|
||||||
auto saveCartridgeSufamiTurboA(Markup::Node) -> void;
|
auto saveCartridgeSufamiTurboA(Markup::Node) -> void;
|
||||||
auto saveCartridgeSufamiTurboB(Markup::Node) -> void;
|
auto saveCartridgeSufamiTurboB(Markup::Node) -> void;
|
||||||
|
|
|
@ -13,9 +13,6 @@ auto Cartridge::saveCartridge(Markup::Node node) -> void {
|
||||||
if(auto node = board["processor(identifier=OBC1)"]) saveOBC1(node);
|
if(auto node = board["processor(identifier=OBC1)"]) saveOBC1(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::saveCartridgeGameBoy(Markup::Node node) -> void {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::saveCartridgeBSMemory(Markup::Node node) -> void {
|
auto Cartridge::saveCartridgeBSMemory(Markup::Node node) -> void {
|
||||||
if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=Flash,content=Program)"]}) {
|
if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=Flash,content=Program)"]}) {
|
||||||
if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Write)) {
|
if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Write)) {
|
||||||
|
|
|
@ -101,11 +101,31 @@ auto ICD::load() -> bool {
|
||||||
cartridge.information.sha256 = Hash::SHA256({data, (uint64_t)size}).digest();
|
cartridge.information.sha256 = Hash::SHA256({data, (uint64_t)size}).digest();
|
||||||
fp->read(data, size);
|
fp->read(data, size);
|
||||||
GB_load_rom_from_buffer(&sameboy, data, size);
|
GB_load_rom_from_buffer(&sameboy, data, size);
|
||||||
|
free(data);
|
||||||
} else return unload(), false;
|
} else return unload(), false;
|
||||||
|
if(auto fp = platform->open(pathID(), "save.ram", File::Read)) {
|
||||||
|
auto size = fp->size();
|
||||||
|
auto data = (uint8_t*)malloc(size);
|
||||||
|
fp->read(data, size);
|
||||||
|
GB_load_battery_from_buffer(&sameboy, data, size);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ICD::save() -> void {
|
||||||
|
if(auto size = GB_save_battery_size(&sameboy)) {
|
||||||
|
auto data = (uint8_t*)malloc(size);
|
||||||
|
GB_save_battery_to_buffer(&sameboy, data, size);
|
||||||
|
if(auto fp = platform->open(pathID(), "save.ram", File::Write)) {
|
||||||
|
fp->write(data, size);
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto ICD::unload() -> void {
|
auto ICD::unload() -> void {
|
||||||
|
save();
|
||||||
GB_free(&sameboy);
|
GB_free(&sameboy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ struct ICD : Emulator::Platform, Thread {
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
|
|
||||||
auto load() -> bool;
|
auto load() -> bool;
|
||||||
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power(bool reset = false) -> void;
|
auto power(bool reset = false) -> void;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue