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:
meepingsnesroms
2018-08-11 12:49:53 -07:00
parent f1fe87a80c
commit 8b1e0e5d57
17 changed files with 89 additions and 843 deletions

View File

@@ -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

View File

@@ -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 \

View File

@@ -56,10 +56,6 @@ void frontendHandleDebugPrint(){
}
}
uint64_t frontendGetSysTime(){
return QDateTime::currentMSecsSinceEpoch();
}
EmuWrapper::EmuWrapper(){
if(alreadyExists == true)

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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/>

View File

@@ -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;
}

View File

@@ -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); }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);