Prepare to add virtual sdcard access, add libretro button mappings

This commit is contained in:
meepingsnesroms
2018-04-10 13:25:34 -07:00
parent 903e41065f
commit dca4e48134
11 changed files with 780 additions and 45 deletions

View File

@@ -141,19 +141,24 @@ void retro_reset(void)
void retro_run(void)
{
/*
key_state_t ks;
input_poll_cb();
ks.up = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
ks.right = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
ks.down = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
ks.left = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
ks.start = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START);
ks.select = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT);
*/
//dpad
palmInput.buttonUp = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
palmInput.buttonRight = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
palmInput.buttonDown = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
palmInput.buttonLeft = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
palmInput.buttonSelect = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R);
//app buttons
palmInput.buttonCalender = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y);
palmInput.buttonAddress = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X);
palmInput.buttonTodo = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B);
palmInput.buttonNotes = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A);
//special buttons
palmInput.buttonPower = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START);
palmInput.buttonContrast = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT);
emulateFrame();
video_cb(palmFramebuffer, LR_SCREENWIDTH, LR_SCREENHEIGHT, LR_SCREENWIDTH * sizeof(uint16_t));
@@ -167,16 +172,18 @@ bool retro_load_game(const struct retro_game_info *info)
FILE* romFile;
size_t bytesRead;
struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "OS Menu" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Calender" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Address Book" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "ToDo" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Notes" },
{ 0 },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Dpad Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Dpad Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Dpad Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Dpad Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Dpad Middle" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Power" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Contrast" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Notes" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "ToDo" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Address Book" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Calender" },
{ 0 }
};
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
@@ -250,23 +257,13 @@ bool retro_unserialize(const void *data, size_t size)
void *retro_get_memory_data(unsigned id)
{
/*
if (id != RETRO_MEMORY_SAVE_RAM)
return NULL;
return game_data();
*/
//palm m515 is too complicated for sram, use savestates
return NULL;
}
size_t retro_get_memory_size(unsigned id)
{
/*
if (id != RETRO_MEMORY_SAVE_RAM)
return 0;
return game_data_size();
*/
//palm m515 is too complicated for sram, use savestates
return 0;
}

52
src/bps/global.h Normal file
View File

@@ -0,0 +1,52 @@
//Module name: Floating IPS, global header
//Author: Alcaro
//Date: June 18, 2015
//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 {
unsigned char * 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

521
src/bps/libbps.cpp Normal file
View File

@@ -0,0 +1,521 @@
//Module name: libbps
//Author: Alcaro
//Date: December 20, 2014
//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 };
#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 { \
var=0; \
unsigned int shift=0; \
while (true) \
{ \
uint8_t next=read8(); \
assert_shift(next&0x7F, shift); \
size_t addthis=(next&0x7F)<<shift; \
assert_sum(var, addthis); \
var+=addthis; \
if (next&0x80) break; \
shift+=7; \
assert_sum(var, 1U<<shift); \
var+=1<<shift; \
} \
} 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)
{
//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
enum bpserror bps_get_checksums(file* patch, uint32_t * inromsum, uint32_t * outromsum, uint32_t * patchsum)
{
size_t len = patch->len();
if (len<4+3+12) return bps_broken;
uint8_t verify[4];
if (!patch->read(verify, 0, 4) || memcmp(verify, "BPS1", 4)) return bps_broken;
uint8_t checksums[12];
if (!patch->read(checksums, len-12, 12)) return bps_broken;
if (inromsum) *inromsum =read32(checksums+0);
if (outromsum) *outromsum=read32(checksums+4);
if (patchsum) *patchsum =read32(checksums+8);
return bps_ok;
}
void bps_free(struct mem mem)
{
free(mem.ptr);
}
#if 0
#warning Disable this in release versions.
#include <stdio.h>
//Congratulations, you found the undocumented feature! It compares two equivalent BPS patches and
// tells where each one is more compact. (It crashes or gives bogus answers on invalid or
// non-equivalent patches.) Have fun.
void bps_compare(struct mem patch1mem, struct mem patch2mem)
{
const uint8_t * patch[2]={patch1mem.ptr, patch2mem.ptr};
size_t patchpos[2]={0,0};
size_t patchlen[2]={patch1mem.len-12, patch2mem.len-12};
size_t patchoutpos[2]={0,0};
size_t patchcopypos[2][4]={0,0};//[0] and [1] are unused, but this is just debug code, it doesn't need to be neat.
#define read8(id) (patch[id][patchpos[id]++])
#define decodeto(id, var) \
do { \
var=0; \
int shift=0; \
while (true) \
{ \
uint8_t next=read8(id); \
size_t addthis=(next&0x7F)<<shift; \
var+=addthis; \
if (next&0x80) break; \
shift+=7; \
var+=1<<shift; \
} \
} while(false)
size_t lastmatch=0;
size_t patchposatmatch[2]={0,0};
size_t outlen;
patch[0]+=4; patch[1]+=4;//BPS1
size_t tempuint;
decodeto(0, tempuint); decodeto(1, tempuint);//source-size
decodeto(0, outlen); decodeto(1, outlen);//target-size
decodeto(0, tempuint); patch[0]+=tempuint;//metadata
decodeto(1, tempuint); patch[1]+=tempuint;//metadata
bool show=false;
while (patchpos[0]<patchlen[0] && patchpos[1]<patchlen[1])
{
bool step[2]={(patchoutpos[0]<=patchoutpos[1]), (patchoutpos[0]>=patchoutpos[1])};
char describe[2][256];
for (int i=0;i<2;i++)
{
if (step[i])
{
size_t patchposstart=patchpos[i];
decodeto(i, tempuint);
size_t len=(tempuint>>2)+1;
patchoutpos[i]+=len;
int action=(tempuint&3);
//enum { SourceRead, TargetRead, SourceCopy, TargetCopy };
const char * actionnames[]={"SourceRead", "TargetRead", "SourceCopy", "TargetCopy"};
if (action==TargetRead) patchpos[i]+=len;
if (action==SourceCopy || action==TargetCopy)
{
decodeto(i, tempuint);
int delta = tempuint>>1;
if (tempuint&1) delta=-delta;
patchcopypos[i][action]+=delta;
sprintf(describe[i], "%s from %i (%+i) for %i in %i", actionnames[action], patchcopypos[i][action], delta, len, patchpos[i]-patchposstart);
patchcopypos[i][action]+=len;
}
else sprintf(describe[i], "%s from %i for %i in %i", actionnames[action], patchoutpos[i], len, patchpos[i]-patchposstart);
if (!step[i^1])
{
printf("%i: %s\n", i+1, describe[i]);
show=true;
}
}
}
if (step[0] && step[1])
{
if (!strcmp(describe[0], describe[1])) /*printf("3: %s\n", describe[0])*/;
else
{
printf("1: %s\n2: %s\n", describe[0], describe[1]);
show=true;
}
}
if (patchoutpos[0]==patchoutpos[1])
{
size_t used[2]={patchpos[0]-patchposatmatch[0], patchpos[1]-patchposatmatch[1]};
char which='=';
if (used[0]<used[1]) which='+';
if (used[0]>used[1]) which='-';
if (show)
{
printf("%c: %i,%i bytes since last match (%i)\n", which, used[0], used[1], patchoutpos[0]);
show=false;
}
patchposatmatch[0]=patchpos[0];
patchposatmatch[1]=patchpos[1];
lastmatch=patchoutpos[0];
}
}
}
static struct mem ReadWholeFile(const char * filename)
{
struct mem null = {NULL, 0};
FILE * file=fopen(filename, "rb");
if (!file) return null;
fseek(file, 0, SEEK_END);
size_t len=ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char * data=(unsigned char*)malloc(len);
size_t truelen=fread(data, 1,len, file);
fclose(file);
if (len!=truelen)
{
free(data);
return null;
}
struct mem ret = { (unsigned char*)data, len };
return ret;
}
int main(int argc,char**argv)
{
bps_compare(ReadWholeFile(argv[1]),ReadWholeFile(argv[2]));
}
#endif

70
src/bps/libbps.h Normal file
View File

@@ -0,0 +1,70 @@
//Module name: libbps
//Author: Alcaro
//Date: June 18, 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_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.
};
//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);
//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);
#ifdef __cplusplus
}
#endif

View File

@@ -36,6 +36,19 @@ double palmCrystalCycles;//how many cycles before toggling the 32.768 kHz cry
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)();
uint64_t* (*emulatorGetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId);//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);//sets the bps chunkIds for a stateId in the order they need to be applied
uint8_t* (*emulatorGetSdCardChunk)(uint64_t sessionId, uint64_t chunkId);
void (*emulatorSetSdCardChunk)(uint64_t sessionId, uint64_t chunkId, uint8_t* data, uint64_t size);
static inline bool allSdCardCallbacksPresent(){
if(emulatorGetSysTime && emulatorGetSdCardStateChunkList && emulatorSetSdCardStateChunkList && emulatorGetSdCardChunk && emulatorSetSdCardChunk)
return true;
return false;
}
void emulatorInit(uint8_t* palmRomDump, uint32_t specialFeatures){
//cpu
@@ -72,9 +85,10 @@ void emulatorInit(uint8_t* palmRomDump, uint32_t specialFeatures){
palmInput.touchscreenY = 0;
palmInput.touchscreenTouched = false;
palmSdCard.getSdCardChunk = NULL;
palmSdCard.setSdCardChunk = NULL;
palmSdCard.sessionId = 0x0000000000000000;
palmSdCard.stateId = 0x0000000000000000;
palmSdCard.size = 0;
palmSdCard.type = CARD_NONE;
palmSdCard.inserted = false;
palmMisc.powerButtonLed = false;
@@ -105,11 +119,26 @@ void emulatorSetRtc(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t se
setRtc(days, hours, minutes, seconds);
}
uint32_t emulatorSetSdCard(uint64_t size, uint8_t type){
if(!allSdCardCallbacksPresent())
return EMU_ERROR_CALLBACKS_NOT_SET;
palmSdCard.sessionId = emulatorGetSysTime();
palmSdCard.stateId = 0x0000000000000000;//set when saving state
palmSdCard.size = size;
palmSdCard.type = type;
palmSdCard.inserted = true;
return EMU_ERROR_NONE;
}
uint32_t emulatorGetStateSize(){
return m68k_context_size() + RAM_SIZE + REG_SIZE + sizeof(misc_hw_t) + TOTAL_MEMORY_BANKS + sizeof(double) * 5 + 1;
return m68k_context_size() + RAM_SIZE + REG_SIZE + TOTAL_MEMORY_BANKS + sizeof(misc_hw_t) + sizeof(sdcard_t) + sizeof(double) * 4 + sizeof(uint32_t) * 2 + 1;
}
void emulatorSaveState(uint8_t* data){
//save sdcard here
uint32_t offset = 0;
m68k_get_context(data + offset);
offset += m68k_context_size();
@@ -121,6 +150,8 @@ void emulatorSaveState(uint8_t* data){
offset += TOTAL_MEMORY_BANKS;
memcpy(data + offset, &palmMisc, sizeof(misc_hw_t));
offset += sizeof(misc_hw_t);
memcpy(data + offset, &palmSdCard, sizeof(sdcard_t));
offset += sizeof(sdcard_t);
//input is not part of savestates
memcpy(data + offset, &palmSpecialFeatures, sizeof(uint32_t));
offset += sizeof(uint32_t);
@@ -139,6 +170,8 @@ void emulatorSaveState(uint8_t* data){
}
void emulatorLoadState(uint8_t* data){
//load sdcard here
uint32_t offset = 0;
m68k_set_context(data + offset);
offset += m68k_context_size();
@@ -150,6 +183,8 @@ void emulatorLoadState(uint8_t* data){
offset += TOTAL_MEMORY_BANKS;
memcpy(&palmMisc, data + offset, sizeof(misc_hw_t));
offset += sizeof(misc_hw_t);
memcpy(&palmSdCard, data + offset, sizeof(sdcard_t));
offset += sizeof(sdcard_t);
//input is not part of savestates
memcpy(&palmSpecialFeatures, data + offset, sizeof(uint32_t));
offset += sizeof(uint32_t);

View File

@@ -8,33 +8,62 @@
#include "emuFeatureRegistersSpec.h"
//emu errors
enum emu_error_t{
enum{
EMU_ERROR_NONE = 0,
EMU_ERROR_NOT_IMPLEMENTED,
EMU_ERROR_CALLBACKS_NOT_SET,
EMU_ERROR_NOT_DOCUMENTED
};
//sdcard types
enum{
CARD_NONE = 0,
CARD_SD,
CARD_MMC
};
//memory banks
enum{
EMPTY_BANK = 0,
RAM_BANK,
ROM_BANK,
REG_BANK,
SED1376_REG_BANK,
SED1376_FB_BANK
};
//types
typedef struct{
bool buttonUp;
bool buttonDown;
bool buttonLeft;//only used in hybrid mode
bool buttonRight;//only used in hybrid mode
bool buttonSelect;//only used in hybrid mode
bool buttonCalender;//hw button 1
bool buttonAddress;//hw button 2
bool buttonTodo;//hw button 3
bool buttonNotes;//hw button 4
bool buttonPower;
bool buttonContrast;
uint16_t touchscreenX;
uint16_t touchscreenY;
bool touchscreenTouched;
}input_t;
typedef struct{
void (*getSdCardChunk)(uint8_t* data, uint32_t size);
void (*setSdCardChunk)(uint8_t* data, uint32_t size);
//the sdcard is stored as a directory structure with an /(SESSIONID)/sdcard(STATEID).info and /(SESSIONID)/sdcard(CHUNKID).bps
//each emulator instance has its own sdcard SESSIONID directory if it has an sdcard
//sdcard(STATEID).info specifys the bps files to used
//every savestate a new bps file is created with the changes made to the sdcard since the last savestate
//the first bps is a patch over a buffer of sdcard 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;
}sdcard_t;
@@ -71,12 +100,6 @@ typedef struct{
#define END_BANK(address, size) (START_BANK(address) + NUM_BANKS(size))
#define BANK_IN_RANGE(bank, address, size) (bank >= START_BANK(address) && bank <= END_BANK(address, size))
#define TOTAL_MEMORY_BANKS 0x10000
#define EMPTY_BANK 0
#define RAM_BANK 1
#define ROM_BANK 2
#define REG_BANK 3
#define SED1376_REG_BANK 4
#define SED1376_FB_BANK 5
//memory chip addresses
#define RAM_START_ADDRESS 0x00000000
@@ -104,10 +127,18 @@ extern double palmCrystalCycles;
extern double palmCycleCounter;
extern double palmClockMultiplier;
//callbacks
uint64_t (*emulatorGetSysTime)();
uint64_t* (*emulatorGetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId);//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);//sets the bps chunkIds for a stateId in the order they need to be applied
uint8_t* (*emulatorGetSdCardChunk)(uint64_t sessionId, uint64_t chunkId);
void (*emulatorSetSdCardChunk)(uint64_t sessionId, uint64_t chunkId, uint8_t* data, uint64_t size);
//functions
void emulatorInit(uint8_t* palmRomDump, uint32_t specialFeatures);
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);
uint32_t emulatorGetStateSize();
void emulatorSaveState(uint8_t* data);
void emulatorLoadState(uint8_t* data);

View File

@@ -2,6 +2,7 @@ EMU_SOURCES := $(EMU_PATH)/emulator.c \
$(EMU_PATH)/memoryAccess.c \
$(EMU_PATH)/hardwareRegisters.c \
$(EMU_PATH)/sed1376.c \
$(EMU_PATH)/sdcard.c \
$(EMU_PATH)/silkscreen.c \
$(EMU_PATH)/cpu32Opcodes.c \
$(EMU_PATH)/m68k/m68kops.c \

1
src/sdcard.c Normal file
View File

@@ -0,0 +1 @@

1
src/sdcard.h Normal file
View File

@@ -0,0 +1 @@

25
tests/HwRegTest17.txt Normal file
View File

@@ -0,0 +1,25 @@
New CPU frequency of:33161216.000000 cycles per second.
New clk32 cycle count of :1012.000000.
Cpu Wrote 8 bits of 0x00000000 to register 0x0439.
Cpu Wrote 8 bits of 0x00000020 to register 0x0449.
Cpu Wrote 8 bits of 0x00000000 to register 0x0A27.
Cpu Wrote 16 bits of 0x00008000 to register 0x0100.
Cpu Wrote 16 bits of 0x000001AB to register 0x0110.
Cpu Wrote 16 bits of 0x0000FFC0 to register 0x0102.
Cpu Wrote 16 bits of 0x000001F3 to register 0x0112.
Cpu Wrote 16 bits of 0x00008200 to register 0x0104.
Cpu Wrote 16 bits of 0x00000101 to register 0x0114.
Cpu Wrote 16 bits of 0x00000000 to register 0x0106.
Cpu Wrote 16 bits of 0x00001E83 to register 0x0116.
Cpu Wrote 16 bits of 0x00000040 to register 0x010A.
Cpu Wrote 16 bits of 0x00001A81 to register 0x0116.
Cpu Read 16 bits from register 0x0310.
Cpu Read 8 bits from register 0x0418.
Cpu Read 8 bits from register 0x0440.
Cpu Read 8 bits from register 0x0441.
Cpu Read 8 bits from register 0x0441.
New CPU frequency of:33161216.000000 cycles per second.
New clk32 cycle count of :1012.000000.
Cpu Read 16 bits from register 0x0C02.
New CPU frequency of:33161216.000000 cycles per second.
New clk32 cycle count of :1012.000000.

View File

@@ -15,6 +15,7 @@ DRAMC write enable
All of DRAMMC
Chip select registers
Setting the battery dead bit(PDDATA 0x80) if the emulated battery percent gets too low
endian safe savestates
Fixed:
System Control Register, 0xXXFFF000 all upper banks are registers mode