mirror of
https://github.com/libretro/Mu.git
synced 2026-09-23 15:15:43 +00:00
Remove delta savestate compression
Its a huge mess and the same thing can be accomplished by setting the emu directory to a zfs partition. This will make working on the SD card interface significantly easier.
This commit is contained in:
@@ -6,6 +6,7 @@ When running OS commands through callFunction() it can crash
|
||||
Only runs in debug mode because the touchscreen can only be pushed with a jump to OS function hack
|
||||
Holding the buttons emulates pressing them like a turbo button(may be caused by the lack of sound emulation, a sound plays on app switch and may block the CPU while waiting for the button to release)
|
||||
State manager goes bezerk and crashes when saving on android, also can't close the window or it won't open again(also only on android)
|
||||
Deleting a save state
|
||||
|
||||
Fixed:
|
||||
Screenshots use window size and that makes them blurry from filtering
|
||||
|
||||
@@ -51,8 +51,6 @@ SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
touchscreen.cpp \
|
||||
src/bps/crc32.c \
|
||||
src/bps/libbps.c \
|
||||
src/m68k/m68kcpu.c \
|
||||
src/m68k/m68kdasm.c \
|
||||
src/m68k/m68kopac.c \
|
||||
@@ -73,9 +71,6 @@ SOURCES += \
|
||||
statemanager.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/bps/crc32.h \
|
||||
src/bps/global.h \
|
||||
src/bps/libbps.h \
|
||||
src/m68k/m68k.h \
|
||||
src/m68k/m68kconf.h \
|
||||
src/m68k/m68kcpu.h \
|
||||
|
||||
@@ -56,10 +56,6 @@ void frontendHandleDebugPrint(){
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t frontendGetSysTime(){
|
||||
return QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
|
||||
EmuWrapper::EmuWrapper(){
|
||||
if(alreadyExists == true)
|
||||
|
||||
@@ -81,6 +81,16 @@ void StateManager::on_loadState_clicked(){
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::on_deleteState_clicked(){
|
||||
if(ui->states->currentItem()){
|
||||
QString statePath = ((MainWindow*)parentWidget())->settings.value("resourceDirectory", "").toString() + "/saveStates/" + ui->states->currentItem()->text();
|
||||
|
||||
//not hooked up yet
|
||||
//((MainWindow*)parentWidget())->emu.loadState(statePath + ".state");
|
||||
updateStatePreview();
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::on_states_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous){
|
||||
updateStatePreview();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ private slots:
|
||||
|
||||
void on_saveState_clicked();
|
||||
void on_loadState_clicked();
|
||||
void on_deleteState_clicked();
|
||||
|
||||
void on_states_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous);
|
||||
|
||||
|
||||
@@ -90,6 +90,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteState">
|
||||
<property name="text">
|
||||
<string>Delete State</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
//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;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
//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); }
|
||||
@@ -1,22 +0,0 @@
|
||||
//Module name: Floating IPS, global header
|
||||
//Author: Alcaro
|
||||
//Date: See Git history
|
||||
//Licence: GPL v3.0 or higher
|
||||
|
||||
#ifndef struct_mem
|
||||
#define struct_mem
|
||||
|
||||
//the standard library can be assumed to exist
|
||||
#include <stddef.h>//size_t, SIZE_MAX
|
||||
#include <stdint.h>//uint8_t
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
struct mem {
|
||||
uint8_t * ptr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
#endif
|
||||
394
src/bps/libbps.c
394
src/bps/libbps.c
@@ -1,394 +0,0 @@
|
||||
//Module name: libbps
|
||||
//Author: Alcaro
|
||||
//Date: November 7, 2015
|
||||
//Licence: GPL v3.0 or higher
|
||||
|
||||
#include "libbps.h"
|
||||
|
||||
#include <stdlib.h>//malloc, realloc, free
|
||||
#include <string.h>//memcpy, memset
|
||||
#include <stdint.h>//uint8_t, uint32_t
|
||||
#include "crc32.h"//crc32
|
||||
|
||||
static uint32_t read32(uint8_t * ptr)
|
||||
{
|
||||
uint32_t out;
|
||||
out =ptr[0];
|
||||
out|=ptr[1]<<8;
|
||||
out|=ptr[2]<<16;
|
||||
out|=ptr[3]<<24;
|
||||
return out;
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t 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)
|
||||
enum bpserror bps_apply(struct mem patch, struct mem in, struct mem * out, struct mem * metadata, bool accept_wrong_input)
|
||||
{
|
||||
enum bpserror error = bps_ok;
|
||||
out->len=0;
|
||||
out->ptr=NULL;
|
||||
if (metadata)
|
||||
{
|
||||
metadata->len=0;
|
||||
metadata->ptr=NULL;
|
||||
}
|
||||
if (patch.len<4+3+12) return bps_broken;
|
||||
|
||||
if (true)
|
||||
{
|
||||
#define read8() (*(patchat++))
|
||||
#define decodeto(var) \
|
||||
do { \
|
||||
if (!decodenum(patchat, &var)) error(bps_too_big); \
|
||||
} while(false)
|
||||
#define write8(byte) (*(outat++)=byte)
|
||||
|
||||
const uint8_t * patchat=patch.ptr;
|
||||
const uint8_t * patchend=patch.ptr+patch.len-12;
|
||||
|
||||
if (read8()!='B') error(bps_broken);
|
||||
if (read8()!='P') error(bps_broken);
|
||||
if (read8()!='S') error(bps_broken);
|
||||
if (read8()!='1') error(bps_broken);
|
||||
|
||||
uint32_t crc_in_e = read32(patch.ptr+patch.len-12);
|
||||
uint32_t crc_out_e = read32(patch.ptr+patch.len-8);
|
||||
uint32_t crc_patch_e = read32(patch.ptr+patch.len-4);
|
||||
|
||||
uint32_t crc_in_a = crc32(in.ptr, in.len);
|
||||
uint32_t crc_patch_a = crc32(patch.ptr, patch.len-4);
|
||||
|
||||
if (crc_patch_a != crc_patch_e) error(bps_broken);
|
||||
|
||||
size_t inlen;
|
||||
decodeto(inlen);
|
||||
|
||||
size_t outlen;
|
||||
decodeto(outlen);
|
||||
|
||||
if (inlen!=in.len || crc_in_a!=crc_in_e)
|
||||
{
|
||||
if (in.len==outlen && crc_in_a==crc_out_e) error=bps_to_output;
|
||||
else error=bps_not_this;
|
||||
if (!accept_wrong_input) goto exit;
|
||||
}
|
||||
|
||||
out->len=outlen;
|
||||
out->ptr=(uint8_t*)malloc(outlen);
|
||||
|
||||
const uint8_t * instart=in.ptr;
|
||||
const uint8_t * inreadat=in.ptr;
|
||||
const uint8_t * inend=in.ptr+in.len;
|
||||
|
||||
uint8_t * outstart=out->ptr;
|
||||
uint8_t * outreadat=out->ptr;
|
||||
uint8_t * outat=out->ptr;
|
||||
uint8_t * outend=out->ptr+out->len;
|
||||
|
||||
size_t metadatalen;
|
||||
decodeto(metadatalen);
|
||||
|
||||
if (metadata && metadatalen)
|
||||
{
|
||||
metadata->len=metadatalen;
|
||||
metadata->ptr=(uint8_t*)malloc(metadatalen+1);
|
||||
for (size_t i=0;i<metadatalen;i++) metadata->ptr[i]=read8();
|
||||
metadata->ptr[metadatalen]='\0';//just to be on the safe side - that metadata is assumed to be text, might as well terminate it
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i=0;i<metadatalen;i++) (void)read8();
|
||||
}
|
||||
|
||||
while (patchat<patchend)
|
||||
{
|
||||
size_t thisinstr;
|
||||
decodeto(thisinstr);
|
||||
size_t length=(thisinstr>>2)+1;
|
||||
int action=(thisinstr&3);
|
||||
if (outat+length>outend) error(bps_broken);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case SourceRead:
|
||||
{
|
||||
if (outat-outstart+length > in.len) error(bps_broken);
|
||||
for (size_t i=0;i<length;i++)
|
||||
{
|
||||
size_t pos = outat-outstart; // don't inline, write8 changes outat
|
||||
write8(instart[pos]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TargetRead:
|
||||
{
|
||||
if (patchat+length>patchend) error(bps_broken);
|
||||
for (size_t i=0;i<length;i++) write8(read8());
|
||||
}
|
||||
break;
|
||||
case SourceCopy:
|
||||
{
|
||||
size_t encodeddistance;
|
||||
decodeto(encodeddistance);
|
||||
size_t distance=encodeddistance>>1;
|
||||
if ((encodeddistance&1)==0) inreadat+=distance;
|
||||
else inreadat-=distance;
|
||||
|
||||
if (inreadat<instart || inreadat+length>inend) error(bps_broken);
|
||||
for (size_t i=0;i<length;i++) write8(*inreadat++);
|
||||
}
|
||||
break;
|
||||
case TargetCopy:
|
||||
{
|
||||
size_t encodeddistance;
|
||||
decodeto(encodeddistance);
|
||||
size_t distance=encodeddistance>>1;
|
||||
if ((encodeddistance&1)==0) outreadat+=distance;
|
||||
else outreadat-=distance;
|
||||
|
||||
if (outreadat<outstart || outreadat>=outat || outreadat+length>outend) error(bps_broken);
|
||||
for (size_t i=0;i<length;i++) write8(*outreadat++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patchat!=patchend) error(bps_broken);
|
||||
if (outat!=outend) error(bps_broken);
|
||||
|
||||
uint32_t crc_out_a = crc32(out->ptr, out->len);
|
||||
|
||||
if (crc_out_a!=crc_out_e)
|
||||
{
|
||||
error=bps_not_this;
|
||||
if (!accept_wrong_input) goto exit;
|
||||
}
|
||||
return error;
|
||||
#undef read8
|
||||
#undef decodeto
|
||||
#undef write8
|
||||
}
|
||||
|
||||
exit:
|
||||
free(out->ptr);
|
||||
out->len=0;
|
||||
out->ptr=NULL;
|
||||
if (metadata)
|
||||
{
|
||||
free(metadata->ptr);
|
||||
metadata->len=0;
|
||||
metadata->ptr=NULL;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define write(val) \
|
||||
do { \
|
||||
out[outlen++]=(val); \
|
||||
if (outlen==outbuflen) \
|
||||
{ \
|
||||
outbuflen*=2; \
|
||||
out=(uint8_t*)realloc(out, outbuflen); \
|
||||
} \
|
||||
} while(0)
|
||||
#define write32(val) \
|
||||
do { \
|
||||
uint32_t tmp=(val); \
|
||||
write(tmp); \
|
||||
write(tmp>>8); \
|
||||
write(tmp>>16); \
|
||||
write(tmp>>24); \
|
||||
} while(0)
|
||||
#define writenum(val) \
|
||||
do { \
|
||||
size_t tmpval=(val); \
|
||||
while (true) \
|
||||
{ \
|
||||
uint8_t tmpbyte=(tmpval&0x7F); \
|
||||
tmpval>>=7; \
|
||||
if (!tmpval) \
|
||||
{ \
|
||||
write(tmpbyte|0x80); \
|
||||
break; \
|
||||
} \
|
||||
write(tmpbyte); \
|
||||
tmpval--; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
enum bpserror bps_create_linear(struct mem sourcemem, struct mem targetmem, struct mem metadata, struct mem * patchmem)
|
||||
{
|
||||
if (sourcemem.len>=(SIZE_MAX>>2) - 16) return bps_too_big;//the 16 is just to be on the safe side, I don't think it's needed.
|
||||
if (targetmem.len>=(SIZE_MAX>>2) - 16) return bps_too_big;
|
||||
|
||||
const uint8_t * source=sourcemem.ptr;
|
||||
const uint8_t * sourceend=sourcemem.ptr+sourcemem.len;
|
||||
if (sourcemem.len>targetmem.len) sourceend=sourcemem.ptr+targetmem.len;
|
||||
const uint8_t * targetbegin=targetmem.ptr;
|
||||
const uint8_t * target=targetmem.ptr;
|
||||
const uint8_t * targetend=targetmem.ptr+targetmem.len;
|
||||
|
||||
const uint8_t * targetcopypos=targetbegin;
|
||||
|
||||
size_t outbuflen=4096;
|
||||
uint8_t * out=(uint8_t*)malloc(outbuflen);
|
||||
size_t outlen=0;
|
||||
write('B');
|
||||
write('P');
|
||||
write('S');
|
||||
write('1');
|
||||
writenum(sourcemem.len);
|
||||
writenum(targetmem.len);
|
||||
writenum(metadata.len);
|
||||
for (size_t i=0;i<metadata.len;i++) write(metadata.ptr[i]);
|
||||
|
||||
size_t mainContentPos=outlen;
|
||||
|
||||
const uint8_t * lastknownchange=targetbegin;
|
||||
while (target<targetend)
|
||||
{
|
||||
size_t numunchanged=0;
|
||||
while (source+numunchanged<sourceend && source[numunchanged]==target[numunchanged]) numunchanged++;
|
||||
if (numunchanged>1 || numunchanged == (uintptr_t)(targetend-target))
|
||||
{
|
||||
//assert_shift((numunchanged-1), 2);
|
||||
writenum((numunchanged-1)<<2 | 0);//SourceRead
|
||||
source+=numunchanged;
|
||||
target+=numunchanged;
|
||||
}
|
||||
|
||||
size_t numchanged=0;
|
||||
if (lastknownchange>target) numchanged=lastknownchange-target;
|
||||
while ((source+numchanged>=sourceend ||
|
||||
source[numchanged]!=target[numchanged] ||
|
||||
source[numchanged+1]!=target[numchanged+1] ||
|
||||
source[numchanged+2]!=target[numchanged+2]) &&
|
||||
target+numchanged<targetend)
|
||||
{
|
||||
numchanged++;
|
||||
if (source+numchanged>=sourceend) numchanged=targetend-target;
|
||||
}
|
||||
lastknownchange=target+numchanged;
|
||||
if (numchanged)
|
||||
{
|
||||
//assert_shift((numchanged-1), 2);
|
||||
size_t rle1start=(target==targetbegin);
|
||||
while (true)
|
||||
{
|
||||
if (
|
||||
target[rle1start-1]==target[rle1start+0] &&
|
||||
target[rle1start+0]==target[rle1start+1] &&
|
||||
target[rle1start+1]==target[rle1start+2] &&
|
||||
target[rle1start+2]==target[rle1start+3])
|
||||
{
|
||||
numchanged=rle1start;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
target[rle1start-2]==target[rle1start+0] &&
|
||||
target[rle1start-1]==target[rle1start+1] &&
|
||||
target[rle1start+0]==target[rle1start+2] &&
|
||||
target[rle1start+1]==target[rle1start+3] &&
|
||||
target[rle1start+2]==target[rle1start+4])
|
||||
{
|
||||
numchanged=rle1start;
|
||||
break;
|
||||
}
|
||||
if (rle1start+3>=numchanged) break;
|
||||
rle1start++;
|
||||
}
|
||||
if (numchanged)
|
||||
{
|
||||
writenum((numchanged-1)<<2 | TargetRead);
|
||||
for (size_t i=0;i<numchanged;i++)
|
||||
{
|
||||
write(target[i]);
|
||||
}
|
||||
source+=numchanged;
|
||||
target+=numchanged;
|
||||
}
|
||||
if (target[-2]==target[0] && target[-1]==target[1] && target[0]==target[2])
|
||||
{
|
||||
//two-byte RLE
|
||||
size_t rlelen=0;
|
||||
while (target+rlelen<targetend && target[0]==target[rlelen+0] && target[1]==target[rlelen+1]) rlelen+=2;
|
||||
writenum((rlelen-1)<<2 | TargetCopy);
|
||||
writenum((target-targetcopypos-2)<<1);
|
||||
source+=rlelen;
|
||||
target+=rlelen;
|
||||
targetcopypos=target-2;
|
||||
}
|
||||
else if (target[-1]==target[0] && target[0]==target[1])
|
||||
{
|
||||
//one-byte RLE
|
||||
size_t rlelen=0;
|
||||
while (target+rlelen<targetend && target[0]==target[rlelen]) rlelen++;
|
||||
writenum((rlelen-1)<<2 | TargetCopy);
|
||||
writenum((target-targetcopypos-1)<<1);
|
||||
source+=rlelen;
|
||||
target+=rlelen;
|
||||
targetcopypos=target-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write32(crc32(sourcemem.ptr, sourcemem.len));
|
||||
write32(crc32(targetmem.ptr, targetmem.len));
|
||||
write32(crc32(out, outlen));
|
||||
|
||||
patchmem->ptr=out;
|
||||
patchmem->len=outlen;
|
||||
|
||||
//while this may look like it can be fooled by a patch containing one of any other command, it
|
||||
// can't, because the ones that aren't SourceRead requires an argument.
|
||||
size_t i;
|
||||
for (i=mainContentPos;(out[i]&0x80)==0x00;i++) {}
|
||||
if (i==outlen-12-1) return bps_identical;
|
||||
|
||||
return bps_ok;
|
||||
}
|
||||
|
||||
#undef write_nocrc
|
||||
#undef write
|
||||
#undef writenum
|
||||
|
||||
void bps_free(struct mem mem)
|
||||
{
|
||||
free(mem.ptr);
|
||||
}
|
||||
#undef error
|
||||
@@ -1,76 +0,0 @@
|
||||
//Module name: libbps
|
||||
//Author: Alcaro
|
||||
//Date: November 30, 2015
|
||||
//Licence: GPL v3.0 or higher
|
||||
|
||||
#include "global.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>//bool; if this file does not exist (hi msvc), remove it and uncomment the following three lines.
|
||||
//#define bool int
|
||||
//#define true 1
|
||||
//#define false 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum bpserror {
|
||||
bps_ok,//Patch applied or created successfully.
|
||||
|
||||
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_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
|
||||
// requested ('metadata'!=NULL), is also returned. Send both to bps_free when you're done with them.
|
||||
//If accept_wrong_input is true, it may return bps_to_output or bps_not_this, while putting non-NULL in out/metadata.
|
||||
enum bpserror bps_apply(struct mem patch, struct mem in, struct mem * out, struct mem * metadata, bool accept_wrong_input);
|
||||
|
||||
//Creates a BPS patch that converts source to target and stores it to patch. It is safe to give
|
||||
// {NULL,0} as metadata.
|
||||
enum bpserror bps_create_linear(struct mem source, struct mem target, struct mem metadata, struct mem * patch);
|
||||
|
||||
//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
|
||||
152
src/emulator.c
152
src/emulator.c
@@ -35,7 +35,7 @@ uint8_t* palmRam;
|
||||
uint8_t* palmRom;
|
||||
uint8_t palmReg[REG_SIZE];
|
||||
input_t palmInput;
|
||||
sd_card_t palmSdCard;
|
||||
buffer_t palmSdCard;
|
||||
misc_hw_t palmMisc;
|
||||
uint16_t palmFramebuffer[160 * (160 + 60)];//really 160*160, the extra pixels are the silkscreened digitizer area
|
||||
uint16_t* palmExtendedFramebuffer;
|
||||
@@ -45,18 +45,6 @@ double palmCycleCounter;//can be greater then 0 if too many cycles where run
|
||||
double palmClockMultiplier;//used by the emulator to overclock the emulated Palm
|
||||
|
||||
|
||||
uint64_t (*emulatorGetSysTime)() = NULL;
|
||||
uint64_t* (*emulatorGetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId) = NULL;//returns the BPS chunkIds for a stateId in the order they need to be applied
|
||||
void (*emulatorSetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId, uint64_t* data) = NULL;//sets the BPS chunkIds for a stateId in the order they need to be applied
|
||||
buffer_t (*emulatorGetSdCardChunk)(uint64_t sessionId, uint64_t chunkId) = NULL;
|
||||
void (*emulatorSetSdCardChunk)(uint64_t sessionId, uint64_t chunkId, buffer_t chunk) = NULL;
|
||||
|
||||
static inline bool allSdCardCallbacksPresent(){
|
||||
if(emulatorGetSysTime && emulatorGetSdCardStateChunkList && emulatorSetSdCardStateChunkList && emulatorGetSdCardChunk && emulatorSetSdCardChunk)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t specialFeatures){
|
||||
if(emulatorInitialized)
|
||||
return EMU_ERROR_NONE;
|
||||
@@ -113,7 +101,6 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec
|
||||
resetAddressSpace();
|
||||
sed1376Reset();
|
||||
ads7846Reset();
|
||||
sdCardInit();
|
||||
sandboxInit();
|
||||
|
||||
memset(&palmInput, 0x00, sizeof(palmInput));
|
||||
@@ -140,7 +127,8 @@ void emulatorExit(){
|
||||
free(palmRom);
|
||||
if(palmSpecialFeatures & FEATURE_320x320)
|
||||
free(palmExtendedFramebuffer);
|
||||
sdCardExit();
|
||||
if(palmSdCard.data)
|
||||
free(palmSdCard.data);
|
||||
emulatorInitialized = false;
|
||||
}
|
||||
}
|
||||
@@ -159,51 +147,6 @@ void emulatorSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t secon
|
||||
setRtc(days, hours, minutes, seconds);
|
||||
}
|
||||
|
||||
uint32_t emulatorSetNewSdCard(uint64_t size, uint8_t type){
|
||||
if(!allSdCardCallbacksPresent())
|
||||
return EMU_ERROR_CALLBACKS_NOT_SET;
|
||||
|
||||
//more than 2gb/too large for FAT16 or not a card type
|
||||
if(size > 0x80000000 || type >= CARD_END)
|
||||
return EMU_ERROR_INVALID_PARAMETER;
|
||||
|
||||
if(type != CARD_NONE){
|
||||
palmSdCard.sessionId = emulatorGetSysTime();//completely new SD card, reset delta state chain
|
||||
palmSdCard.stateId = 0x0000000000000000;//set when saving state
|
||||
palmSdCard.size = size;
|
||||
palmSdCard.type = type;
|
||||
palmSdCard.inserted = true;
|
||||
}
|
||||
else{
|
||||
memset(&palmSdCard, 0x00, sizeof(palmSdCard));
|
||||
}
|
||||
|
||||
return EMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
buffer_t emulatorGetSdCardImage(){
|
||||
return sdCardGetImage();
|
||||
}
|
||||
|
||||
uint32_t emulatorSetSdCardFromImage(buffer_t image, uint8_t type){
|
||||
if(!allSdCardCallbacksPresent())
|
||||
return EMU_ERROR_CALLBACKS_NOT_SET;
|
||||
|
||||
//invalid pointer, more than 2gb/too large for FAT16 or not a card type
|
||||
if(!image.data || image.size > 0x80000000 || type == CARD_NONE || type >= CARD_END)
|
||||
return EMU_ERROR_INVALID_PARAMETER;
|
||||
|
||||
sdCardSetFromImage(image);
|
||||
|
||||
palmSdCard.sessionId = emulatorGetSysTime();//completely new SD card, reset delta state chain
|
||||
palmSdCard.stateId = 0x0000000000000000;//set when saving state
|
||||
palmSdCard.size = image.size;
|
||||
palmSdCard.type = type;
|
||||
palmSdCard.inserted = true;
|
||||
|
||||
return EMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint64_t emulatorGetStateSize(){
|
||||
uint64_t size = 0;
|
||||
|
||||
@@ -222,8 +165,6 @@ uint64_t emulatorGetStateSize(){
|
||||
size += TOTAL_MEMORY_BANKS;//bank handlers
|
||||
size += sizeof(uint32_t) * 4 * CHIP_END;//chip select states
|
||||
size += sizeof(uint8_t) * 5 * CHIP_END;//chip select states
|
||||
size += sizeof(uint64_t) * 3;//palmSdCard
|
||||
size += sizeof(uint8_t) * 2;//palmSdCard
|
||||
size += sizeof(uint64_t) * 4;//32.32 fixed point double, timerXCycleCounter and CPU cycle timers
|
||||
size += sizeof(int32_t);//pllWakeWait
|
||||
size += sizeof(uint32_t);//clk32Counter
|
||||
@@ -236,6 +177,8 @@ uint64_t emulatorGetStateSize(){
|
||||
size += sizeof(uint8_t);//ads7846PenIrqEnabled
|
||||
size += sizeof(uint16_t);//ads7846
|
||||
size += sizeof(uint8_t) * 7;//palmMisc
|
||||
size += sizeof(uint64_t);//palmSdCard.size
|
||||
size += palmSdCard.size;//palmSdCard.data
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -308,23 +251,6 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
memcpy(buffer.data + offset, sed1376Framebuffer, SED1376_FB_SIZE);
|
||||
offset += SED1376_FB_SIZE;
|
||||
|
||||
//SD card
|
||||
//update SD card struct and save SD card data
|
||||
if(allSdCardCallbacksPresent() && palmSdCard.type != CARD_NONE){
|
||||
palmSdCard.stateId = emulatorGetSysTime();
|
||||
sdCardSaveState(palmSdCard.sessionId, palmSdCard.stateId);
|
||||
}
|
||||
writeStateValueUint64(buffer.data + offset, palmSdCard.sessionId);
|
||||
offset += sizeof(uint64_t);
|
||||
writeStateValueUint64(buffer.data + offset, palmSdCard.stateId);
|
||||
offset += sizeof(uint64_t);
|
||||
writeStateValueUint64(buffer.data + offset, palmSdCard.size);
|
||||
offset += sizeof(uint64_t);
|
||||
writeStateValueUint8(buffer.data + offset, palmSdCard.type);
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValueBool(buffer.data + offset, palmSdCard.inserted);
|
||||
offset += sizeof(uint8_t);
|
||||
|
||||
//timing
|
||||
writeStateValueDouble(buffer.data + offset, palmCrystalCycles);
|
||||
offset += sizeof(uint64_t);
|
||||
@@ -385,6 +311,12 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
writeStateValueUint8(buffer.data + offset, palmMisc.dataPort);
|
||||
offset += sizeof(uint8_t);
|
||||
|
||||
//SD card
|
||||
writeStateValueUint64(buffer.data + offset, palmSdCard.size);
|
||||
offset += sizeof(uint64_t);
|
||||
memcpy(palmSdCard.data, buffer.data + offset, palmSdCard.size);
|
||||
offset += palmSdCard.size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -458,21 +390,6 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
offset += SED1376_FB_SIZE;
|
||||
sed1376RefreshLut();
|
||||
|
||||
//SD card
|
||||
palmSdCard.sessionId = readStateValueUint64(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
palmSdCard.stateId = readStateValueUint64(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
palmSdCard.size = readStateValueUint64(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
palmSdCard.type = readStateValueUint8(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
palmSdCard.inserted = readStateValueBool(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
//update SD card data from SD card struct
|
||||
if(allSdCardCallbacksPresent() && palmSdCard.type != CARD_NONE)
|
||||
sdCardLoadState(palmSdCard.sessionId, palmSdCard.stateId);
|
||||
|
||||
//timing
|
||||
palmCrystalCycles = readStateValueDouble(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
@@ -533,6 +450,23 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
palmMisc.dataPort = readStateValueUint8(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
|
||||
//SD card
|
||||
if(palmSdCard.data){
|
||||
free(palmSdCard.data);
|
||||
palmSdCard.data = NULL;
|
||||
}
|
||||
palmSdCard.size = readStateValueUint64(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
if(palmSdCard.size > 0){
|
||||
palmSdCard.data = malloc(palmSdCard.size);
|
||||
|
||||
if(!palmSdCard.data)
|
||||
return false;
|
||||
|
||||
memcpy(palmSdCard.data, buffer.data + offset, palmSdCard.size);
|
||||
}
|
||||
offset += palmSdCard.size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -545,6 +479,36 @@ buffer_t emulatorGetRamBuffer(){
|
||||
return ramInfo;
|
||||
}
|
||||
|
||||
buffer_t emulatorGetSdCardBuffer(){
|
||||
return palmSdCard;
|
||||
}
|
||||
|
||||
uint32_t emulatorInsertSdCard(buffer_t image){
|
||||
//SD card is currently inserted
|
||||
if(palmSdCard.data)
|
||||
return EMU_ERROR_RESOURCE_LOCKED;
|
||||
|
||||
palmSdCard.data = malloc(image.size);
|
||||
if(!palmSdCard.data)
|
||||
return EMU_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if(image.data)
|
||||
memcpy(palmSdCard.data, image.data, image.size);
|
||||
else
|
||||
memset(palmSdCard.data, 0x00, image.size);
|
||||
|
||||
palmSdCard.size = image.size;
|
||||
|
||||
return EMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
void emulatorEjectSdCard(){
|
||||
if(palmSdCard.data)
|
||||
free(palmSdCard.data);
|
||||
palmSdCard.data = NULL;
|
||||
palmSdCard.size = 0;
|
||||
}
|
||||
|
||||
uint32_t emulatorInstallPrcPdb(buffer_t file){
|
||||
//pretend to pass for now
|
||||
//return EMU_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
@@ -50,15 +50,8 @@ enum{
|
||||
EMU_ERROR_NOT_IMPLEMENTED,
|
||||
EMU_ERROR_CALLBACKS_NOT_SET,
|
||||
EMU_ERROR_OUT_OF_MEMORY,
|
||||
EMU_ERROR_INVALID_PARAMETER
|
||||
};
|
||||
|
||||
//SD card types
|
||||
enum{
|
||||
CARD_NONE = 0,
|
||||
CARD_SD,
|
||||
CARD_MMC,
|
||||
CARD_END
|
||||
EMU_ERROR_INVALID_PARAMETER,
|
||||
EMU_ERROR_RESOURCE_LOCKED
|
||||
};
|
||||
|
||||
//port types
|
||||
@@ -97,20 +90,6 @@ typedef struct{
|
||||
bool touchscreenTouched;
|
||||
}input_t;
|
||||
|
||||
typedef struct{
|
||||
//the SD card is stored as a directory structure with an /(SESSIONID)/sdCard(STATEID).info and /(SESSIONID)/sdCard(CHUNKID).bps
|
||||
//each emulator instance has its own SD card SESSIONID directory if it has an SD card
|
||||
//sdCard(STATEID).info specifys the BPS files to use
|
||||
//every savestate a new BPS file is created with the changes made to the SD card since the last savestate
|
||||
//the first BPS is a patch over a buffer of SD card size filled with 0x00
|
||||
//the frontend provides file access but the emulator does all the patching
|
||||
uint64_t sessionId;//64 bit system time when emulator starts
|
||||
uint64_t stateId;//64 bit system time when the savestate was taken
|
||||
uint64_t size;
|
||||
uint8_t type;
|
||||
bool inserted;
|
||||
}sd_card_t;
|
||||
|
||||
typedef struct{
|
||||
bool powerButtonLed;
|
||||
bool lcdOn;
|
||||
@@ -127,15 +106,14 @@ typedef struct{
|
||||
|
||||
//config options
|
||||
#define EMU_FPS 60.0
|
||||
#define SD_CARD_CHUNK_VECTOR_SIZE 100
|
||||
#define SAVE_STATE_VERSION 1
|
||||
#define SAVE_STATE_VERSION 2
|
||||
|
||||
//emulator data, some are GUI interface variables, some should be left alone
|
||||
extern uint8_t* palmRam;//dont touch
|
||||
extern uint8_t* palmRom;//dont touch
|
||||
extern uint8_t palmReg[];//dont touch
|
||||
extern input_t palmInput;//write allowed
|
||||
extern sd_card_t palmSdCard;//dont touch
|
||||
extern buffer_t palmSdCard;//dont touch
|
||||
extern misc_hw_t palmMisc;//read/write allowed
|
||||
extern uint16_t palmFramebuffer[];//read allowed if FEATURE_320x320 is off, or else invalid data will be displayed
|
||||
extern uint16_t* palmExtendedFramebuffer;//read allowed if FEATURE_320x320 is on, or else SIGSEGV
|
||||
@@ -144,25 +122,18 @@ extern double palmCrystalCycles;//dont touch
|
||||
extern double palmCycleCounter;//dont touch
|
||||
extern double palmClockMultiplier;//read/write allowed
|
||||
|
||||
//callbacks
|
||||
extern uint64_t (*emulatorGetSysTime)();
|
||||
extern uint64_t* (*emulatorGetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId);//returns the BPS chunkIds for a stateId in the order they need to be applied
|
||||
extern void (*emulatorSetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId, uint64_t* data);//sets the BPS chunkIds for a stateId in the order they need to be applied
|
||||
extern buffer_t (*emulatorGetSdCardChunk)(uint64_t sessionId, uint64_t chunkId);
|
||||
extern void (*emulatorSetSdCardChunk)(uint64_t sessionId, uint64_t chunkId, buffer_t chunk);
|
||||
|
||||
//functions
|
||||
uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t specialFeatures);//calling any emulator functions before emulatorInit results in undefined behavior
|
||||
void emulatorExit();
|
||||
void emulatorReset();
|
||||
void emulatorSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds);
|
||||
uint32_t emulatorSetNewSdCard(uint64_t size, uint8_t type);
|
||||
buffer_t emulatorGetSdCardImage();//this is a direct pointer to the SD card data, do not free it
|
||||
uint32_t emulatorSetSdCardFromImage(buffer_t image, uint8_t type);
|
||||
uint64_t emulatorGetStateSize();
|
||||
bool emulatorSaveState(buffer_t buffer);//true = success
|
||||
bool emulatorLoadState(buffer_t buffer);//true = success
|
||||
buffer_t emulatorGetRamBuffer();//this is a direct pointer to RAM, do not free it
|
||||
buffer_t emulatorGetSdCardBuffer();//this is a direct pointer to the SD card data, do not free it
|
||||
uint32_t emulatorInsertSdCard(buffer_t image);//use (NULL, desired size) to create a new empty SD card
|
||||
void emulatorEjectSdCard();
|
||||
uint32_t emulatorInstallPrcPdb(buffer_t file);
|
||||
void emulateFrame();
|
||||
|
||||
|
||||
@@ -431,7 +431,7 @@ static inline uint8_t getPortDInputPinValues(){
|
||||
|
||||
//portDInputValues |= 0x80;//battery dead bit, dont know the proper level to set this
|
||||
|
||||
if(palmSdCard.inserted)
|
||||
if(palmSdCard.data)
|
||||
portDInputValues |= 0x20;
|
||||
|
||||
//kbd row 0
|
||||
|
||||
@@ -12,6 +12,4 @@ EMU_SOURCES_C := $(EMU_PATH)/emulator.c \
|
||||
$(EMU_PATH)/m68k/m68kopac.c \
|
||||
$(EMU_PATH)/m68k/m68kdasm.c \
|
||||
$(EMU_PATH)/m68k/m68kcpu.c \
|
||||
$(EMU_PATH)/bps/libbps.c \
|
||||
$(EMU_PATH)/bps/crc32.c \
|
||||
$(EMU_PATH)/debug/sandbox.c
|
||||
|
||||
168
src/sdcard.c
168
src/sdcard.c
@@ -1,174 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "emulator.h"
|
||||
#include "bps/libbps.h"
|
||||
//#include "emulator.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) * SD_CARD_CHUNK_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;
|
||||
}
|
||||
|
||||
buffer_t sdCardGetImage(){
|
||||
buffer_t image;
|
||||
|
||||
image.data = sdCardData;
|
||||
image.size = sdCardSize;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
uint32_t sdCardSetFromImage(buffer_t image){
|
||||
uint32_t error = sdCardReconfigure(image.size);
|
||||
|
||||
if(error != EMU_ERROR_NONE)
|
||||
return error;
|
||||
|
||||
memcpy(sdCardData, image.data, image.size);
|
||||
|
||||
return EMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
void sdCardSaveState(uint64_t sessionId, uint64_t stateId){
|
||||
//make single BPS if SD card data has changed
|
||||
if(memcmp(sdCardOldData, sdCardData, sdCardSize) != 0){
|
||||
struct mem source;
|
||||
struct mem target;
|
||||
struct mem metadata;
|
||||
struct mem patch;
|
||||
buffer_t chunk;
|
||||
|
||||
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);
|
||||
chunk.data = patch.ptr;
|
||||
chunk.size = patch.len;
|
||||
emulatorSetSdCardChunk(sessionId, stateId, chunk);
|
||||
bps_free(patch);
|
||||
|
||||
if(sdCardChunkIndex + 2 >= sdCardChunkMaxIndex){
|
||||
//resize vector if needed
|
||||
sdCardChunks = realloc(sdCardChunks, sizeof(uint64_t) * (sdCardChunkMaxIndex + SD_CARD_CHUNK_VECTOR_SIZE));
|
||||
sdCardChunkMaxIndex += SD_CARD_CHUNK_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 SD card 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;
|
||||
buffer_t chunk = emulatorGetSdCardChunk(sessionId, sdCardChunks[index]);
|
||||
|
||||
patch.ptr = chunk.data;
|
||||
patch.len = chunk.size;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool sdCardExchangeBit(bool bit){
|
||||
//not done
|
||||
return true;//eek
|
||||
|
||||
11
src/sdcard.h
11
src/sdcard.h
@@ -1,16 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "emulator.h"
|
||||
|
||||
void sdCardInit();
|
||||
void sdCardExit();
|
||||
uint32_t sdCardReconfigure(uint64_t size);
|
||||
buffer_t sdCardGetImage();
|
||||
uint32_t sdCardSetFromImage(buffer_t image);
|
||||
void sdCardSaveState(uint64_t sessionId, uint64_t stateId);
|
||||
void sdCardLoadState(uint64_t sessionId, uint64_t stateId);
|
||||
|
||||
bool sdCardExchangeBit(bool bit);
|
||||
|
||||
Reference in New Issue
Block a user