Skip to content

Instantly share code, notes, and snippets.

@kode54
Created February 28, 2014 02:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kode54/9263928 to your computer and use it in GitHub Desktop.
Save kode54/9263928 to your computer and use it in GitHub Desktop.
Attempt to feed Pcsx Reloaded save states into Highly Experimental, for probing purposes.
#include <stdint.h>
#define EMU_COMPILE
#define EMU_LITTLE_ENDIAN
#include "PsxCore/Core/psx.h"
#include "PsxCore/Core/bios.h"
#include "PsxCore/Core/iop.h"
#include "PsxCore/Core/r3000.h"
#include <zlib.h>
#include "hebios.h"
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef uint8_t boolean;
typedef union {
#if defined(__BIGENDIAN__)
struct { u8 h3, h2, h, l; } b;
struct { s8 h3, h2, h, l; } sb;
struct { u16 h, l; } w;
struct { s16 h, l; } sw;
#else
struct { u8 l, h, h2, h3; } b;
struct { u16 l, h; } w;
struct { s8 l, h, h2, h3; } sb;
struct { s16 l, h; } sw;
#endif
} PAIR;
typedef union {
struct {
u32 r0, at, v0, v1, a0, a1, a2, a3,
t0, t1, t2, t3, t4, t5, t6, t7,
s0, s1, s2, s3, s4, s5, s6, s7,
t8, t9, k0, k1, gp, sp, s8, ra, lo, hi;
} n;
u32 r[34]; /* Lo, Hi in r[32] and r[33] */
PAIR p[34];
} psxGPRRegs;
typedef union {
struct {
u32 Index, Random, EntryLo0, BPC,
Context, BDA, PIDMask, DCIC,
BadVAddr, BDAM, EntryHi, BPCM,
Status, Cause, EPC, PRid,
Config, LLAddr, WatchLO, WatchHI,
XContext, Reserved1, Reserved2, Reserved3,
Reserved4, Reserved5, ECC, CacheErr,
TagLo, TagHi, ErrorEPC, Reserved6;
} n;
u32 r[32];
} psxCP0Regs;
typedef struct {
short x, y;
} SVector2D;
typedef struct {
short z, pad;
} SVector2Dz;
typedef struct {
short x, y, z, pad;
} SVector3D;
typedef struct {
short x, y, z, pad;
} LVector3D;
typedef struct {
unsigned char r, g, b, c;
} CBGR;
typedef struct {
short m11, m12, m13, m21, m22, m23, m31, m32, m33, pad;
} SMatrix3D;
typedef union {
struct {
SVector3D v0, v1, v2;
CBGR rgb;
s32 otz;
s32 ir0, ir1, ir2, ir3;
SVector2D sxy0, sxy1, sxy2, sxyp;
SVector2Dz sz0, sz1, sz2, sz3;
CBGR rgb0, rgb1, rgb2;
s32 reserved;
s32 mac0, mac1, mac2, mac3;
u32 irgb, orgb;
s32 lzcs, lzcr;
} n;
u32 r[32];
PAIR p[32];
} psxCP2Data;
typedef union {
struct {
SMatrix3D rMatrix;
s32 trX, trY, trZ;
SMatrix3D lMatrix;
s32 rbk, gbk, bbk;
SMatrix3D cMatrix;
s32 rfc, gfc, bfc;
s32 ofx, ofy;
s32 h;
s32 dqa, dqb;
s32 zsf3, zsf4;
s32 flag;
} n;
u32 r[32];
PAIR p[32];
} psxCP2Ctrl;
enum {
PSXINT_SIO = 0,
PSXINT_CDR,
PSXINT_CDREAD,
PSXINT_GPUDMA,
PSXINT_MDECOUTDMA,
PSXINT_SPUDMA,
PSXINT_GPUBUSY,
PSXINT_MDECINDMA,
PSXINT_GPUOTCDMA,
PSXINT_CDRDMA,
PSXINT_SPUASYNC,
PSXINT_CDRDBUF,
PSXINT_CDRLID,
PSXINT_CDRPLAY
};
typedef struct {
psxGPRRegs GPR; /* General Purpose Registers */
psxCP0Regs CP0; /* Coprocessor0 Registers */
psxCP2Data CP2D; /* Cop2 data registers */
psxCP2Ctrl CP2C; /* Cop2 control registers */
u32 pc; /* Program counter */
u32 code; /* The instruction */
u32 cycle;
u32 interrupt;
struct { u32 sCycle, cycle; } intCycle[32];
u8 ICache_Addr[0x1000];
u8 ICache_Code[0x1000];
boolean ICache_valid;
} psxRegisters;
typedef struct {
uint32_t ulFreezeVersion;
uint32_t ulStatus;
uint32_t ulControl[256];
unsigned char psxVRam[1024*512*2];
} GPUFreeze_t;
typedef struct {
s32 y0, y1;
} ADPCM_Decode_t;
typedef struct {
int freq;
int nbits;
int stereo;
int nsamples;
ADPCM_Decode_t left, right;
short pcm[16384];
} xa_decode_t;
typedef struct {
unsigned char PluginName[8];
uint32_t PluginVersion;
uint32_t Size;
unsigned char SPUPorts[0x200];
unsigned char SPURam[0x80000];
xa_decode_t xa;
unsigned char *SPUInfo;
} SPUFreeze_t;
typedef struct Rcnt
{
u16 mode, target;
u32 rate, irq, counterState, irqState;
u32 cycle, cycleStart;
} Rcnt;
const uint32_t KnownVersion = 0x8b410008;
u8 psxM[0x200000];
u8 psxH[0x10000];
psxRegisters psxRegs;
GPUFreeze_t gpuFreeze;
SPUFreeze_t * spuFreeze;
Rcnt rcnts[3];
u32 _psxRcntRcount( u32 index )
{
u32 count;
count = psxRegs.cycle;
count -= rcnts[index].cycleStart;
count /= rcnts[index].rate;
if( count > 0xffff )
{
count &= 0xffff;
}
return count;
}
int main(int argc, char ** argv)
{
if ( argc == 3 )
{
void * emu;
void * iop;
void * r3000;
gzFile f;
FILE * fo;
uint8_t header[32];
uint32_t saveversion;
uint8_t hle;
uint32_t spu_size;
uint32_t addr;
f = gzopen( argv[1], "rb" );
gzread(f, (void *)header, 32);
gzread(f, (void *)&saveversion, sizeof(uint32_t));
gzread(f, (void *)&hle, sizeof(uint8_t));
if ( strncmp("STv4 PCSXR", (const char *) header, 10) != 0 || saveversion != KnownVersion || hle != 0 )
{
fprintf( stderr, "Invalid save state\n" );
return 1;
}
// Skip GPU thumbnail image
gzseek(f, 128 * 96 * 3, SEEK_CUR);
bios_set_image(hebios, HEBIOS_SIZE);
psx_init();
emu = malloc( psx_get_state_size(1) );
psx_clear_state( emu, 1 );
iop = psx_get_iop_state( emu );
r3000 = iop_get_r3000_state( iop );
gzread( f, psxM, 0x200000 );
iop_upload_to_ram( iop, 0x80000000, psxM, 0x200000 );
// Skip BIOS region
gzseek( f, 0x80000, SEEK_CUR );
gzread( f, psxH, 0x10000 );
for ( addr = 0x1f800000; addr < 0x1f810000; addr += 4 )
{
u32 * word = (u32 *) (psxH + (addr & 0xffff));
// skip root counters, not stored here
if ( addr >= 0x1f801100 && addr <= 0x1f80112f ) continue;
// skip SPU registers, which aren't stored in this region anyway
if ( addr >= 0x1f801c00 && addr <= 0x1f801dff ) continue;
if ( *word )
r3000_sw( r3000, addr, *word );
}
gzread( f, (void*)&psxRegs, sizeof(psxRegs) );
for ( addr = 0; addr < 32; ++addr )
{
r3000_setreg( r3000, R3000_REG_GEN + addr, psxRegs.GPR.r[ addr ] );
}
r3000_setreg( r3000, R3000_REG_LO, psxRegs.GPR.r[ 32 ] );
r3000_setreg( r3000, R3000_REG_HI, psxRegs.GPR.r[ 33 ] );
for ( addr = 0; addr < 32; ++addr )
{
r3000_setreg( r3000, R3000_REG_C0 + addr, psxRegs.CP0.r[ addr ] );
}
r3000_setreg( r3000, R3000_REG_PC, psxRegs.pc );
gzread( f, (void*)&gpuFreeze, sizeof(gpuFreeze) );
gzread( f, (void*)&spu_size, 4 );
spuFreeze = malloc( spu_size );
if ( spu_size < sizeof(*spuFreeze) )
memset( spuFreeze, 0, sizeof(*spuFreeze) );
gzread( f, (void*)spuFreeze, spu_size );
// Skip sio, cdr, hw
gzseek( f, 0x9A0E, SEEK_CUR );
gzread( f, (void*)&rcnts, sizeof(rcnts) );
for ( addr = 0; addr < 3; ++addr )
{
fprintf( stderr, "rcnt %u: count(%u), mode(%u), target(%u)\n", addr, _psxRcntRcount( addr ), rcnts[ addr ].mode, rcnts[ addr ].target );
r3000_sw( r3000, 0x1f801100 + addr * 0x10 + 0, _psxRcntRcount( addr ) );
r3000_sw( r3000, 0x1f801100 + addr * 0x10 + 4, rcnts[ addr ].mode );
r3000_sw( r3000, 0x1f801100 + addr * 0x10 + 8, rcnts[ addr ].target );
}
gzclose( f );
r3000_sh( r3000, 0x1f801da6, 0 );
for ( addr = 0; addr < 0x80000; addr += 2 )
{
u16 * halfword = (u16 *) ( spuFreeze->SPURam + addr );
r3000_sh( r3000, 0x1f801da8, *halfword );
}
for ( addr = 0x1f801c00; addr < 0x1f801e00; addr += 2 )
{
u16 * halfword = (u16 *) ( spuFreeze->SPUPorts + ( addr & 0x1ff ) );
// Skip transfer value
if ( addr == 0x1f801da8 ) continue;
r3000_sh( r3000, addr, *halfword );
}
free( spuFreeze );
fo = fopen( argv[2], "wb" );
for ( addr = 0; addr < 44100 * 30 * 2; addr += 4096 )
{
s16 buffer[ 4096 ];
u32 howmany = 2048;
psx_execute( emu, 0x7fffffff, buffer, &howmany, 0 );
fwrite( buffer, 4, howmany, fo );
}
fclose( fo );
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment