Add sdcard delta save/load states

This commit is contained in:
meepingsnesroms
2018-04-10 16:34:00 -07:00
parent dca4e48134
commit 0f008c09cd
14 changed files with 307 additions and 248 deletions

View File

@@ -17,4 +17,4 @@ endif
include $(EMU_PATH)/makefile.all
SOURCES_C := $(CORE_DIR)/libretro.c \
$(EMU_SOURCES)
$(EMU_SOURCES_C)

View File

@@ -1,4 +1,4 @@
TARGET_NAME ?= snes9x2010
TARGET_NAME ?= mu
ifeq ($(STATIC_LINKING), 1)
TARGET = $(TARGET_NAME)_libretro_$(platform).a

21
src/bps/crc32.c Executable file
View File

@@ -0,0 +1,21 @@
//Module name: crc32
//Author: Alcaro
//Date: June 3, 2015
//Licence: GPL v3.0 or higher
#include "crc32.h"
static const uint32_t crctable_4bits[]={
0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C,
0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C, 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C,
};
uint32_t crc32_update(const uint8_t* data, size_t len, uint32_t crc)
{
crc = ~crc;
for (size_t i=0;i<len;i++)
{
crc = crctable_4bits[(crc^ data[i] )&0x0F] ^ (crc>>4);
crc = crctable_4bits[(crc^(data[i]>>4))&0x0F] ^ (crc>>4);
}
return ~crc;
}

10
src/bps/crc32.h Executable file
View File

@@ -0,0 +1,10 @@
//Module name: crc32
//Author: Alcaro
//Date: June 3, 2015
//Licence: GPL v3.0 or higher
#include <stdint.h>
#include <stdlib.h>
uint32_t crc32_update(const uint8_t* data, size_t len, uint32_t crc);
static inline uint32_t crc32(const uint8_t* data, size_t len) { return crc32_update(data, len, 0); }

34
src/bps/global.h Normal file → Executable file
View File

@@ -1,6 +1,6 @@
//Module name: Floating IPS, global header
//Author: Alcaro
//Date: June 18, 2015
//Date: See Git history
//Licence: GPL v3.0 or higher
#ifndef struct_mem
@@ -15,38 +15,8 @@
#endif
struct mem {
unsigned char * ptr;
uint8_t * ptr;
size_t len;
};
#if defined(FLIPS_WINDOWS)
#define LPCWSTR const wchar_t *
#else
#define LPCWSTR const char *
#endif
class file {
public:
static file* create(LPCWSTR filename);
virtual size_t len() = 0;
virtual bool read(uint8_t* target, size_t start, size_t len) = 0;
static struct mem read(LPCWSTR filename); // provided by Flips core
struct mem read(); // provided by Flips core
virtual ~file() {}
};
class filewrite {
public:
static filewrite* create(LPCWSTR filename);
virtual bool append(const uint8_t* data, size_t len) = 0;
static bool write(LPCWSTR filename, struct mem data); // provided by Flips core
virtual ~filewrite() {}
};
#endif

201
src/bps/libbps.cpp → src/bps/libbps.c Normal file → Executable file
View File

@@ -1,6 +1,6 @@
//Module name: libbps
//Author: Alcaro
//Date: December 20, 2014
//Date: November 7, 2015
//Licence: GPL v3.0 or higher
#include "libbps.h"
@@ -22,6 +22,37 @@ static uint32_t read32(uint8_t * ptr)
enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
static bool try_add(size_t* a, size_t b)
{
if (SIZE_MAX-*a < b) return false;
*a+=b;
return true;
}
static bool try_shift(size_t* a, size_t b)
{
if (SIZE_MAX>>b < *a) return false;
*a<<=b;
return true;
}
static bool decodenum(const uint8_t* ptr, size_t* out)
{
*out=0;
unsigned int shift=0;
while (true)
{
uint8_t next=*ptr++;
size_t addthis=(next&0x7F);
if (shift) addthis++;
if (!try_shift(&addthis, shift)) return false;
// unchecked because if it was shifted, the lowest bit is zero, and if not, it's <=0x7F.
if (!try_add(out, addthis)) return false;
if (next&0x80) return true;
shift+=7;
}
}
#define error(which) do { error=which; goto exit; } while(0)
#define assert_sum(a,b) do { if (SIZE_MAX-(a)<(b)) error(bps_too_big); } while(0)
#define assert_shift(a,b) do { if (SIZE_MAX>>(b)<(a)) error(bps_too_big); } while(0)
@@ -42,20 +73,7 @@ enum bpserror bps_apply(struct mem patch, struct mem in, struct mem * out, struc
#define read8() (*(patchat++))
#define decodeto(var) \
do { \
var=0; \
unsigned int shift=0; \
while (true) \
{ \
uint8_t next=read8(); \
assert_shift(next&0x7F, shift); \
size_t addthis=(next&0x7F)<<shift; \
assert_sum(var, addthis); \
var+=addthis; \
if (next&0x80) break; \
shift+=7; \
assert_sum(var, 1U<<shift); \
var+=1<<shift; \
} \
if (!decodenum(patchat, &var)) error(bps_too_big); \
} while(false)
#define write8(byte) (*(outat++)=byte)
@@ -197,6 +215,8 @@ exit:
return error;
}
#define write(val) \
do { \
out[outlen++]=(val); \
@@ -264,7 +284,7 @@ enum bpserror bps_create_linear(struct mem sourcemem, struct mem targetmem, stru
{
size_t numunchanged=0;
while (source+numunchanged<sourceend && source[numunchanged]==target[numunchanged]) numunchanged++;
if (numunchanged>1)
if (numunchanged>1 || numunchanged == (uintptr_t)(targetend-target))
{
//assert_shift((numunchanged-1), 2);
writenum((numunchanged-1)<<2 | 0);//SourceRead
@@ -367,155 +387,8 @@ enum bpserror bps_create_linear(struct mem sourcemem, struct mem targetmem, stru
#undef write
#undef writenum
enum bpserror bps_get_checksums(file* patch, uint32_t * inromsum, uint32_t * outromsum, uint32_t * patchsum)
{
size_t len = patch->len();
if (len<4+3+12) return bps_broken;
uint8_t verify[4];
if (!patch->read(verify, 0, 4) || memcmp(verify, "BPS1", 4)) return bps_broken;
uint8_t checksums[12];
if (!patch->read(checksums, len-12, 12)) return bps_broken;
if (inromsum) *inromsum =read32(checksums+0);
if (outromsum) *outromsum=read32(checksums+4);
if (patchsum) *patchsum =read32(checksums+8);
return bps_ok;
}
void bps_free(struct mem mem)
{
free(mem.ptr);
}
#if 0
#warning Disable this in release versions.
#include <stdio.h>
//Congratulations, you found the undocumented feature! It compares two equivalent BPS patches and
// tells where each one is more compact. (It crashes or gives bogus answers on invalid or
// non-equivalent patches.) Have fun.
void bps_compare(struct mem patch1mem, struct mem patch2mem)
{
const uint8_t * patch[2]={patch1mem.ptr, patch2mem.ptr};
size_t patchpos[2]={0,0};
size_t patchlen[2]={patch1mem.len-12, patch2mem.len-12};
size_t patchoutpos[2]={0,0};
size_t patchcopypos[2][4]={0,0};//[0] and [1] are unused, but this is just debug code, it doesn't need to be neat.
#define read8(id) (patch[id][patchpos[id]++])
#define decodeto(id, var) \
do { \
var=0; \
int shift=0; \
while (true) \
{ \
uint8_t next=read8(id); \
size_t addthis=(next&0x7F)<<shift; \
var+=addthis; \
if (next&0x80) break; \
shift+=7; \
var+=1<<shift; \
} \
} while(false)
size_t lastmatch=0;
size_t patchposatmatch[2]={0,0};
size_t outlen;
patch[0]+=4; patch[1]+=4;//BPS1
size_t tempuint;
decodeto(0, tempuint); decodeto(1, tempuint);//source-size
decodeto(0, outlen); decodeto(1, outlen);//target-size
decodeto(0, tempuint); patch[0]+=tempuint;//metadata
decodeto(1, tempuint); patch[1]+=tempuint;//metadata
bool show=false;
while (patchpos[0]<patchlen[0] && patchpos[1]<patchlen[1])
{
bool step[2]={(patchoutpos[0]<=patchoutpos[1]), (patchoutpos[0]>=patchoutpos[1])};
char describe[2][256];
for (int i=0;i<2;i++)
{
if (step[i])
{
size_t patchposstart=patchpos[i];
decodeto(i, tempuint);
size_t len=(tempuint>>2)+1;
patchoutpos[i]+=len;
int action=(tempuint&3);
//enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
const char * actionnames[]={"SourceRead", "TargetRead", "SourceCopy", "TargetCopy"};
if (action==TargetRead) patchpos[i]+=len;
if (action==SourceCopy || action==TargetCopy)
{
decodeto(i, tempuint);
int delta = tempuint>>1;
if (tempuint&1) delta=-delta;
patchcopypos[i][action]+=delta;
sprintf(describe[i], "%s from %i (%+i) for %i in %i", actionnames[action], patchcopypos[i][action], delta, len, patchpos[i]-patchposstart);
patchcopypos[i][action]+=len;
}
else sprintf(describe[i], "%s from %i for %i in %i", actionnames[action], patchoutpos[i], len, patchpos[i]-patchposstart);
if (!step[i^1])
{
printf("%i: %s\n", i+1, describe[i]);
show=true;
}
}
}
if (step[0] && step[1])
{
if (!strcmp(describe[0], describe[1])) /*printf("3: %s\n", describe[0])*/;
else
{
printf("1: %s\n2: %s\n", describe[0], describe[1]);
show=true;
}
}
if (patchoutpos[0]==patchoutpos[1])
{
size_t used[2]={patchpos[0]-patchposatmatch[0], patchpos[1]-patchposatmatch[1]};
char which='=';
if (used[0]<used[1]) which='+';
if (used[0]>used[1]) which='-';
if (show)
{
printf("%c: %i,%i bytes since last match (%i)\n", which, used[0], used[1], patchoutpos[0]);
show=false;
}
patchposatmatch[0]=patchpos[0];
patchposatmatch[1]=patchpos[1];
lastmatch=patchoutpos[0];
}
}
}
static struct mem ReadWholeFile(const char * filename)
{
struct mem null = {NULL, 0};
FILE * file=fopen(filename, "rb");
if (!file) return null;
fseek(file, 0, SEEK_END);
size_t len=ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char * data=(unsigned char*)malloc(len);
size_t truelen=fread(data, 1,len, file);
fclose(file);
if (len!=truelen)
{
free(data);
return null;
}
struct mem ret = { (unsigned char*)data, len };
return ret;
}
int main(int argc,char**argv)
{
bps_compare(ReadWholeFile(argv[1]),ReadWholeFile(argv[2]));
}
#endif
#undef error

48
src/bps/libbps.h Normal file → Executable file
View File

@@ -1,6 +1,6 @@
//Module name: libbps
//Author: Alcaro
//Date: June 18, 2015
//Date: November 30, 2015
//Licence: GPL v3.0 or higher
#include "global.h"
@@ -23,13 +23,14 @@ enum bpserror {
bps_to_output,//You attempted to apply a patch to its output.
bps_not_this, //This is not the intended input file for this patch.
bps_broken, //This is not a BPS patch, or it's malformed somehow.
bps_io, //The patch could not be read.
bps_identical, //The input files are identical.
bps_too_big, //Somehow, you're asking for something a size_t can't represent.
bps_out_of_mem,//Memory allocation failure.
bps_canceled, //The callback returned false.
bps_shut_the_fuck_up_gcc//This one isn't used, it's just to kill a stray comma warning.
bps_shut_up_gcc//This one isn't used, it's just to kill a stray comma warning.
};
//Applies the given BPS patch to the given ROM and puts it in 'out'. Metadata, if present and
@@ -41,30 +42,35 @@ enum bpserror bps_apply(struct mem patch, struct mem in, struct mem * out, struc
// {NULL,0} as metadata.
enum bpserror bps_create_linear(struct mem source, struct mem target, struct mem metadata, struct mem * patch);
//Very similar to bps_create_linear; the difference is that this one takes longer to run, but
// generates smaller patches.
//Because it can take much longer, a progress meter is supplied; total is guaranteed to be constant
// between every call until this function returns, done is guaranteed to increase between each
// call, and done/total is an approximate percentage counter. Anything else is undefined; for
// example, progress may or may not be called for done=0, progress may or may not be called for
// done=total, done may or may not increase by the same amount between each call, and the duration
// between each call may or may not be constant. In fact, it can
//To cancel the patch creation, return false from the callback.
//It is safe to pass in NULL for the progress indicator if you're not interested. If the callback is
// NULL, it can obviously not be canceled that way (though if it's a CLI program, you can always
// Ctrl-C it).
//The 'moremem' flag makes it use about twice as much memory (9*(source+target) instead of 5*), but is usually slightly faster.
enum bpserror bps_create_delta(file* source, file* target, struct mem metadata, struct mem * patch,
bool (*progress)(void* userdata, size_t done, size_t total), void* userdata,
bool moremem);
enum bpserror bps_get_checksums(file* patch, uint32_t * inromsum, uint32_t * outromsum, uint32_t * patchsum);
//Frees the memory returned in the output parameters of the above. Do not call it twice on the same
// input, nor on anything you got from anywhere else. bps_free is guaranteed to be equivalent to
// calling stdlib.h's free() on mem.ptr.
void bps_free(struct mem mem);
struct bpsinfo {
enum bpserror error; // If this is not bps_ok, all other values are undefined.
size_t size_in;
size_t size_out;
uint32_t crc_in;
uint32_t crc_out;
uint32_t crc_patch;
size_t meta_start;
size_t meta_size;
//Tells approximately how much of the input ROM is changed compared to the output ROM.
//It's quite heuristic. The algorithm may change with or without notice.
//As of writing, I believe this is accurate to 2 significant digits in base 10.
//It's also more expensive to calculate than the other data, so it's optional.
//If you don't want it, their values are undefined.
//The denominator is always guaranteed nonzero, even if something else says it's undefined.
//Note that this can return success for invalid patches.
size_t change_num;
size_t change_denom;
};
#ifdef __cplusplus
}
#endif

View File

@@ -10,6 +10,7 @@
#include "hardwareRegisters.h"
#include "memoryAccess.h"
#include "sed1376.h"
#include "sdcard.h"
#include "silkscreen.h"
#include "emuFeatureRegistersSpec.h"
@@ -69,6 +70,7 @@ void emulatorInit(uint8_t* palmRomDump, uint32_t specialFeatures){
memcpy(&palmFramebuffer[160 * 160], silkscreenData, SILKSCREEN_WIDTH * SILKSCREEN_HEIGHT * (SILKSCREEN_BPP / 8));
resetAddressSpace();
sed1376Reset();
sdCardInit();
//input
palmInput.buttonUp = false;
@@ -107,8 +109,12 @@ void emulatorInit(uint8_t* palmRomDump, uint32_t specialFeatures){
m68k_pulse_reset();
}
void emulatorExit(){
sdCardExit();
}
void emulatorReset(){
//reset doesnt clear ram, all programs are stored in ram
//reset doesnt clear ram or sdcard, all programs are stored in ram or on sdcard
resetHwRegisters();
resetAddressSpace();//address space must be reset after hardware registers because it is dependant on them
sed1376Reset();
@@ -137,10 +143,16 @@ uint32_t emulatorGetStateSize(){
}
void emulatorSaveState(uint8_t* data){
//save sdcard here
uint32_t offset = 0;
m68k_get_context(data + offset);
//update sdcard struct, save sdcard data
if(allSdCardCallbacksPresent() && palmSdCard.type != CARD_NONE){
uint64_t stateId = emulatorGetSysTime();
sdCardSaveState(palmSdCard.sessionId, stateId);
palmSdCard.stateId = stateId;
}
m68k_get_context(data + offset);//not endian safe
offset += m68k_context_size();
memcpy(data + offset, palmRam, RAM_SIZE);
offset += RAM_SIZE;
@@ -148,32 +160,30 @@ void emulatorSaveState(uint8_t* data){
offset += REG_SIZE;
memcpy(data + offset, bankType, TOTAL_MEMORY_BANKS);
offset += TOTAL_MEMORY_BANKS;
memcpy(data + offset, &palmMisc, sizeof(misc_hw_t));
memcpy(data + offset, &palmMisc, sizeof(misc_hw_t));//not endian safe
offset += sizeof(misc_hw_t);
memcpy(data + offset, &palmSdCard, sizeof(sdcard_t));
memcpy(data + offset, &palmSdCard, sizeof(sdcard_t));//not endian safe
offset += sizeof(sdcard_t);
//input is not part of savestates
memcpy(data + offset, &palmSpecialFeatures, sizeof(uint32_t));
memcpy(data + offset, &palmSpecialFeatures, sizeof(uint32_t));//not endian safe
offset += sizeof(uint32_t);
memcpy(data + offset, &palmCrystalCycles, sizeof(double));
memcpy(data + offset, &palmCrystalCycles, sizeof(double));//not endian safe
offset += sizeof(double);
memcpy(data + offset, &palmCycleCounter, sizeof(double));
memcpy(data + offset, &palmCycleCounter, sizeof(double));//not endian safe
offset += sizeof(double);
memcpy(data + offset, &clk32Counter, sizeof(uint32_t));
memcpy(data + offset, &clk32Counter, sizeof(uint32_t));//not endian safe
offset += sizeof(uint32_t);
memcpy(data + offset, &timer1CycleCounter, sizeof(double));
memcpy(data + offset, &timer1CycleCounter, sizeof(double));//not endian safe
offset += sizeof(double);
memcpy(data + offset, &timer2CycleCounter, sizeof(double));
memcpy(data + offset, &timer2CycleCounter, sizeof(double));//not endian safe
offset += sizeof(double);
data[offset] = lowPowerStopActive;
offset += 1;
}
void emulatorLoadState(uint8_t* data){
//load sdcard here
uint32_t offset = 0;
m68k_set_context(data + offset);
m68k_set_context(data + offset);//not endian safe
offset += m68k_context_size();
memcpy(palmRam, data + offset, RAM_SIZE);
offset += RAM_SIZE;
@@ -181,27 +191,32 @@ void emulatorLoadState(uint8_t* data){
offset += REG_SIZE;
memcpy(bankType, data + offset, TOTAL_MEMORY_BANKS);
offset += TOTAL_MEMORY_BANKS;
memcpy(&palmMisc, data + offset, sizeof(misc_hw_t));
memcpy(&palmMisc, data + offset, sizeof(misc_hw_t));//not endian safe
offset += sizeof(misc_hw_t);
memcpy(&palmSdCard, data + offset, sizeof(sdcard_t));
memcpy(&palmSdCard, data + offset, sizeof(sdcard_t));//not endian safe
offset += sizeof(sdcard_t);
//input is not part of savestates
memcpy(&palmSpecialFeatures, data + offset, sizeof(uint32_t));
memcpy(&palmSpecialFeatures, data + offset, sizeof(uint32_t));//not endian safe
offset += sizeof(uint32_t);
memcpy(&palmCrystalCycles, data + offset, sizeof(double));
memcpy(&palmCrystalCycles, data + offset, sizeof(double));//not endian safe
offset += sizeof(double);
memcpy(&palmCycleCounter, data + offset, sizeof(double));
memcpy(&palmCycleCounter, data + offset, sizeof(double));//not endian safe
offset += sizeof(double);
memcpy(&clk32Counter, data + offset, sizeof(uint32_t));
memcpy(&clk32Counter, data + offset, sizeof(uint32_t));//not endian safe
offset += sizeof(uint32_t);
memcpy(&timer1CycleCounter, data + offset, sizeof(double));
memcpy(&timer1CycleCounter, data + offset, sizeof(double));//not endian safe
offset += sizeof(double);
memcpy(&timer2CycleCounter, data + offset, sizeof(double));
memcpy(&timer2CycleCounter, data + offset, sizeof(double));//not endian safe
offset += sizeof(double);
lowPowerStopActive = data[offset];
offset += 1;
refreshBankHandlers();
//update sdcard data from sdcard struct
if(allSdCardCallbacksPresent() && palmSdCard.type != CARD_NONE){
sdCardLoadState(palmSdCard.sessionId, palmSdCard.stateId);
}
}
uint32_t emulatorInstallPrcPdb(uint8_t* data, uint32_t size){

View File

@@ -12,6 +12,7 @@ enum{
EMU_ERROR_NONE = 0,
EMU_ERROR_NOT_IMPLEMENTED,
EMU_ERROR_CALLBACKS_NOT_SET,
EMU_ERROR_OUT_OF_MEMORY,
EMU_ERROR_NOT_DOCUMENTED
};
@@ -89,8 +90,7 @@ typedef struct{
#define INACCURATE_SYNCED_RTC 0x00000010//rtc always equals host system time
#define INACCURATE_HLE_APIS 0x00000020//memcpy, memcmp, wait on timer will be replaced with the hosts function
//config options
#define EMU_FPS 60.0
//cpu
#define CRYSTAL_FREQUENCY 32768.0
#define CPU_FREQUENCY (palmCrystalCycles * CRYSTAL_FREQUENCY)
@@ -115,6 +115,10 @@ typedef struct{
#define SED1376_REG_SIZE 0xB4//it has 0x20000 used address space entrys but only 0xB4 registers
#define SED1376_FB_SIZE 0x20000//0x14000 in size, likely also has 0x20000 used address space entrys, using 0x20000 to prevent speed penalty of checking validity on every access
//config options
#define EMU_FPS 60.0
#define SDCARD_STATE_CHUNKS_VECTOR_SIZE 100
//emulator data
extern uint8_t palmRam[];
extern uint8_t palmRom[];
@@ -136,6 +140,7 @@ void (*emulatorSetSdCardChunk)(uint64_t sessionId, uint64_t chunkId, uint8_t* da
//functions
void emulatorInit(uint8_t* palmRomDump, uint32_t specialFeatures);
void emulatorExit();
void emulatorReset();
void emulatorSetRtc(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds);
uint32_t emulatorSetSdCard(uint64_t size, uint8_t type);

View File

@@ -1,4 +1,4 @@
EMU_SOURCES := $(EMU_PATH)/emulator.c \
EMU_SOURCES_C := $(EMU_PATH)/emulator.c \
$(EMU_PATH)/memoryAccess.c \
$(EMU_PATH)/hardwareRegisters.c \
$(EMU_PATH)/sed1376.c \
@@ -10,4 +10,6 @@ EMU_SOURCES := $(EMU_PATH)/emulator.c \
$(EMU_PATH)/m68k/m68kopdm.c \
$(EMU_PATH)/m68k/m68kopac.c \
$(EMU_PATH)/m68k/m68kdasm.c \
$(EMU_PATH)/m68k/m68kcpu.c
$(EMU_PATH)/m68k/m68kcpu.c \
$(EMU_PATH)/bps/libbps.c \
$(EMU_PATH)/bps/crc32.c

View File

@@ -1 +1,144 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "emulator.h"
#include "bps/libbps.h"
static uint8_t* sdCardData;
static uint8_t* sdCardOldData;
static uint64_t* sdCardChunks;//0 terminated array
static uint64_t sdCardChunkIndex;
static uint64_t sdCardChunkMaxIndex;
static uint64_t sdCardSize;
static inline void updateChunkBufferLength(){
uint64_t newChunkLength = 0;
while(true){
newChunkLength++;
if(sdCardChunks[newChunkLength] == 0x0000000000000000)
break;
}
sdCardChunkIndex = newChunkLength;
sdCardChunkMaxIndex = newChunkLength;
}
void sdCardInit(){
sdCardData = NULL;
sdCardOldData = NULL;
sdCardChunks = NULL;
sdCardChunkIndex = 0;
sdCardChunkMaxIndex = 0;
sdCardSize = 0;
}
void sdCardExit(){
if(sdCardData)
free(sdCardData);
if(sdCardOldData)
free(sdCardOldData);
sdCardData = NULL;
sdCardOldData = NULL;
sdCardChunks = NULL;
sdCardChunkIndex = 0;
sdCardChunkMaxIndex = 0;
sdCardSize = 0;
}
uint32_t sdCardReconfigure(uint64_t size){
if(sdCardData)
free(sdCardData);
if(sdCardOldData)
free(sdCardOldData);
if(sdCardChunks)
free(sdCardChunks);
sdCardData = malloc(size);
if(!sdCardData)
return EMU_ERROR_OUT_OF_MEMORY;
sdCardOldData = malloc(size);
if(!sdCardOldData)
return EMU_ERROR_OUT_OF_MEMORY;
sdCardChunks = malloc(sizeof(uint64_t) * SDCARD_STATE_CHUNKS_VECTOR_SIZE);
if(!sdCardChunks)
return EMU_ERROR_OUT_OF_MEMORY;
memset(sdCardData, 0x00, size);
memset(sdCardOldData, 0x00, size);
sdCardChunks[0] = 0x0000000000000000;//0 terminated array
sdCardSize = size;
sdCardChunkIndex = 0;
return EMU_ERROR_NONE;
}
void sdCardSaveState(uint64_t sessionId, uint64_t stateId){
//make single bps if sdcard data has changed
if(memcmp(sdCardOldData, sdCardData, sdCardSize) != 0){
struct mem source;
struct mem target;
struct mem metadata;
struct mem patch;
source.ptr = sdCardOldData;
source.len = sdCardSize;
target.ptr = sdCardData;
target.len = sdCardSize;
metadata.ptr = NULL;
metadata.len = 0;
bps_create_linear(source, target, metadata, &patch);
emulatorSetSdCardChunk(sessionId, stateId, patch.ptr, patch.len);
bps_free(patch);
if(sdCardChunkIndex + 2 >= sdCardChunkMaxIndex){
//resize vector if needed
sdCardChunks = realloc(sdCardChunks, sizeof(uint64_t) * (sdCardChunkMaxIndex + SDCARD_STATE_CHUNKS_VECTOR_SIZE));
sdCardChunkMaxIndex += SDCARD_STATE_CHUNKS_VECTOR_SIZE;
}
sdCardChunks[sdCardChunkIndex] = stateId;
sdCardChunkIndex++;
sdCardChunks[sdCardChunkIndex] = 0x0000000000000000;
emulatorSetSdCardStateChunkList(sessionId, stateId, sdCardChunks);
memcpy(sdCardOldData, sdCardData, sdCardSize);
}
}
void sdCardLoadState(uint64_t sessionId, uint64_t stateId){
//rebuild sdcard from bps chain
free(sdCardChunks);
sdCardChunks = emulatorGetSdCardStateChunkList(sessionId, stateId);
updateChunkBufferLength();
memset(sdCardData, 0x00, sdCardSize);
for(uint64_t index = 0; index < sdCardChunkIndex; index++){
struct mem patch;
struct mem input;
struct mem output;
patch.ptr = emulatorGetSdCardChunk(sessionId, sdCardChunks[index]);
patch.len = sdCardSize;
input.ptr = sdCardData;
input.len = sdCardSize;
output.ptr = sdCardData;
output.len = sdCardSize;
//bps_apply(patch, input, output, NULL, true);//bps_apply needs to be modified to patch the existing buffer instead of making a new one
}
memcpy(sdCardOldData, sdCardData, sdCardSize);
}

View File

@@ -1 +1,9 @@
#pragma once
#include <stdint.h>
void sdCardInit();
void sdCardExit();
uint32_t sdCardReconfigure(uint64_t size);
void sdCardSaveState(uint64_t sessionId, uint64_t stateId);
void sdCardLoadState(uint64_t sessionId, uint64_t stateId);

View File

@@ -44,8 +44,11 @@ void sed1376Reset(){
}
void sed1376Render(){
//only render if lcd on and backlight on
if(0){
if(palmMisc.lcdOn && palmMisc.backlightOn){
//only render if lcd on and backlight on
}
else{
}
}

View File

@@ -16,6 +16,9 @@ All of DRAMMC
Chip select registers
Setting the battery dead bit(PDDATA 0x80) if the emulated battery percent gets too low
endian safe savestates
sdcard can't be read or written to
sdcard can't be inserted or removed
sdcard has no error handling in save/load state
Fixed:
System Control Register, 0xXXFFF000 all upper banks are registers mode