From 0f008c09cd0ba3832cac1c9941c8cbb0bf622df4 Mon Sep 17 00:00:00 2001 From: meepingsnesroms Date: Tue, 10 Apr 2018 16:34:00 -0700 Subject: [PATCH] Add sdcard delta save/load states --- libretroBuildSystem/build/Makefile.common | 2 +- libretroBuildSystem/build/Makefile.rules | 2 +- src/bps/crc32.c | 21 +++ src/bps/crc32.h | 10 ++ src/bps/global.h | 34 +--- src/bps/{libbps.cpp => libbps.c} | 201 ++++------------------ src/bps/libbps.h | 48 +++--- src/emulator.c | 61 ++++--- src/emulator.h | 9 +- src/makefile.all | 6 +- src/sdcard.c | 143 +++++++++++++++ src/sdcard.h | 8 + src/sed1376.c | 7 +- unimplementedFeatures.txt | 3 + 14 files changed, 307 insertions(+), 248 deletions(-) create mode 100755 src/bps/crc32.c create mode 100755 src/bps/crc32.h mode change 100644 => 100755 src/bps/global.h rename src/bps/{libbps.cpp => libbps.c} (66%) mode change 100644 => 100755 mode change 100644 => 100755 src/bps/libbps.h diff --git a/libretroBuildSystem/build/Makefile.common b/libretroBuildSystem/build/Makefile.common index ab65e1d..6e75aa7 100644 --- a/libretroBuildSystem/build/Makefile.common +++ b/libretroBuildSystem/build/Makefile.common @@ -17,4 +17,4 @@ endif include $(EMU_PATH)/makefile.all SOURCES_C := $(CORE_DIR)/libretro.c \ - $(EMU_SOURCES) + $(EMU_SOURCES_C) diff --git a/libretroBuildSystem/build/Makefile.rules b/libretroBuildSystem/build/Makefile.rules index 3589aa4..34abee9 100644 --- a/libretroBuildSystem/build/Makefile.rules +++ b/libretroBuildSystem/build/Makefile.rules @@ -1,4 +1,4 @@ -TARGET_NAME ?= snes9x2010 +TARGET_NAME ?= mu ifeq ($(STATIC_LINKING), 1) TARGET = $(TARGET_NAME)_libretro_$(platform).a diff --git a/src/bps/crc32.c b/src/bps/crc32.c new file mode 100755 index 0000000..14bc4f0 --- /dev/null +++ b/src/bps/crc32.c @@ -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>4); + crc = crctable_4bits[(crc^(data[i]>>4))&0x0F] ^ (crc>>4); + } + return ~crc; +} diff --git a/src/bps/crc32.h b/src/bps/crc32.h new file mode 100755 index 0000000..9a28542 --- /dev/null +++ b/src/bps/crc32.h @@ -0,0 +1,10 @@ +//Module name: crc32 +//Author: Alcaro +//Date: June 3, 2015 +//Licence: GPL v3.0 or higher + +#include +#include + +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); } diff --git a/src/bps/global.h b/src/bps/global.h old mode 100644 new mode 100755 index 1a86b41..6798831 --- a/src/bps/global.h +++ b/src/bps/global.h @@ -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 diff --git a/src/bps/libbps.cpp b/src/bps/libbps.c old mode 100644 new mode 100755 similarity index 66% rename from src/bps/libbps.cpp rename to src/bps/libbps.c index e8c1cec..ea7454f --- a/src/bps/libbps.cpp +++ b/src/bps/libbps.c @@ -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)<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 - -//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)<=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 (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 diff --git a/src/bps/libbps.h b/src/bps/libbps.h old mode 100644 new mode 100755 index 8894b98..8a1fe81 --- a/src/bps/libbps.h +++ b/src/bps/libbps.h @@ -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 diff --git a/src/emulator.c b/src/emulator.c index 2e0ec82..c3af0e5 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -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){ diff --git a/src/emulator.h b/src/emulator.h index 6bc3fee..ff6b626 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -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); diff --git a/src/makefile.all b/src/makefile.all index bd396d3..49d4b48 100644 --- a/src/makefile.all +++ b/src/makefile.all @@ -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 diff --git a/src/sdcard.c b/src/sdcard.c index 8b13789..15f9007 100644 --- a/src/sdcard.c +++ b/src/sdcard.c @@ -1 +1,144 @@ +#include +#include +#include +#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); +} diff --git a/src/sdcard.h b/src/sdcard.h index 8b13789..1e4a5dd 100644 --- a/src/sdcard.h +++ b/src/sdcard.h @@ -1 +1,9 @@ +#pragma once +#include + +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); diff --git a/src/sed1376.c b/src/sed1376.c index 5276d75..47dc87a 100644 --- a/src/sed1376.c +++ b/src/sed1376.c @@ -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{ } } diff --git a/unimplementedFeatures.txt b/unimplementedFeatures.txt index 28698a2..f54b5f6 100644 --- a/unimplementedFeatures.txt +++ b/unimplementedFeatures.txt @@ -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