345 lines
8.8 KiB
C++
345 lines
8.8 KiB
C++
#include <stdio.h>
|
|
|
|
#include "octoshock.h"
|
|
#include "psx/psx.h"
|
|
|
|
// lookup table for crc calculation
|
|
static uint16 subq_crctab[256] =
|
|
{
|
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
|
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
|
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
|
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
|
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
|
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
|
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
|
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
|
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
|
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
|
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
|
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
|
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
|
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
|
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
|
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
|
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
|
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
|
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
|
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
|
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
|
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
|
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
|
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
|
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
|
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
|
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
|
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
|
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
|
};
|
|
|
|
#ifndef __PACKED
|
|
#ifdef __GNUC__
|
|
#define __PACKED __attribute__((__packed__))
|
|
#else
|
|
#define __PACKED
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef __GNUC__
|
|
#pragma pack(push, 1)
|
|
#pragma warning(disable : 4103)
|
|
#endif
|
|
struct bmpimgheader_struct
|
|
{
|
|
u32 size;
|
|
s32 width;
|
|
s32 height;
|
|
u16 planes;
|
|
u16 bpp;
|
|
u32 cmptype;
|
|
u32 imgsize;
|
|
s32 hppm;
|
|
s32 vppm;
|
|
u32 numcol;
|
|
u32 numimpcol;
|
|
} ;
|
|
struct bmpfileheader_struct
|
|
{
|
|
u16 id __PACKED;
|
|
u32 size __PACKED;
|
|
u16 reserved1 __PACKED;
|
|
u16 reserved2 __PACKED;
|
|
u32 imgoffset __PACKED;
|
|
};
|
|
#ifndef __GNUC__
|
|
#pragma pack(pop)
|
|
#endif
|
|
|
|
int WriteBMP32(int width, int height, const void* buf, const char *filename)
|
|
{
|
|
bmpfileheader_struct fileheader;
|
|
bmpimgheader_struct imageheader;
|
|
FILE *file;
|
|
size_t elems_written = 0;
|
|
memset(&fileheader, 0, sizeof(fileheader));
|
|
fileheader.size = sizeof(fileheader);
|
|
fileheader.id = 'B' | ('M' << 8);
|
|
fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader);
|
|
|
|
memset(&imageheader, 0, sizeof(imageheader));
|
|
imageheader.size = sizeof(imageheader);
|
|
imageheader.width = width;
|
|
imageheader.height = height;
|
|
imageheader.planes = 1;
|
|
imageheader.bpp = 32;
|
|
imageheader.cmptype = 0; // None
|
|
imageheader.imgsize = imageheader.width * imageheader.height * 4;
|
|
|
|
if ((file = fopen(filename,"wb")) == NULL)
|
|
return 0;
|
|
|
|
elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file);
|
|
elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file);
|
|
|
|
for(int i=0;i<height;i++)
|
|
for(int x=0;x<width;x++)
|
|
{
|
|
u8* pixel = (u8*)buf + (height-i-1)*width*4;
|
|
pixel += (x*4);
|
|
elems_written += fwrite(pixel+0,1,1,file);
|
|
elems_written += fwrite(pixel+1,1,1,file);
|
|
elems_written += fwrite(pixel+2,1,1,file);
|
|
elems_written += fwrite(pixel+3,1,1,file);
|
|
}
|
|
fclose(file);
|
|
|
|
return 1;
|
|
}
|
|
|
|
class BinReader2352
|
|
{
|
|
public:
|
|
BinReader2352(const char* path)
|
|
{
|
|
inf = fopen(path,"rb");
|
|
fseek(inf,0,SEEK_END);
|
|
size_t sz = ftell(inf);
|
|
fseek(inf,0,SEEK_SET);
|
|
lbaCount = (int)(sz/2352);
|
|
|
|
shock_CreateDisc(&disc,this,lbaCount,s_ReadTOC,s_ReadLBA2448,false);
|
|
}
|
|
|
|
ShockDiscRef* disc;
|
|
|
|
static s32 s_ReadTOC(void* opaque, ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]) { return ((BinReader2352*)opaque)->ReadTOC(read_target, tracks); }
|
|
static s32 s_ReadLBA2448(void* opaque, s32 lba, void* dst) { return ((BinReader2352*)opaque)->ReadLBA2448(lba,dst); }
|
|
|
|
~BinReader2352()
|
|
{
|
|
fclose(inf);
|
|
shock_DestroyDisc(disc);
|
|
}
|
|
|
|
private:
|
|
int lbaCount;
|
|
FILE* inf;
|
|
|
|
|
|
union Sector {
|
|
struct {
|
|
u8 sync[12];
|
|
u8 adr[3];
|
|
u8 mode;
|
|
union {
|
|
struct {
|
|
u8 data2048[2048];
|
|
u8 ecc[4];
|
|
u8 reserved[8];
|
|
u8 ecm[276];
|
|
};
|
|
u8 data2336[2336];
|
|
};
|
|
};
|
|
u8 buf[2352];
|
|
};
|
|
|
|
union XASector {
|
|
struct {
|
|
u8 sync[12];
|
|
u8 adr[3];
|
|
u8 mode;
|
|
u8 subheader[8];
|
|
union {
|
|
u8 data2048[2048];
|
|
u8 ecc[4];
|
|
u8 ecm[276];
|
|
} form1;
|
|
union {
|
|
u8 data2334[2334];
|
|
u8 ecc[4];
|
|
} form2;
|
|
};
|
|
u8 buf[2352];
|
|
};
|
|
|
|
union {
|
|
XASector xasector;
|
|
Sector sector;
|
|
};
|
|
|
|
|
|
s32 ReadTOC( ShockTOC *read_target, ShockTOCTrack tracks[100 + 1])
|
|
{
|
|
memset(read_target,0,sizeof(*read_target));
|
|
read_target->disc_type = 0;
|
|
read_target->first_track = 1;
|
|
read_target->last_track = 1;
|
|
tracks[1].adr = 1;
|
|
tracks[1].lba = 0;
|
|
tracks[1].control = 4;
|
|
tracks[2].adr = 1;
|
|
tracks[2].lba = lbaCount;
|
|
tracks[2].control = 0;
|
|
tracks[100].adr = 1;
|
|
tracks[100].lba = lbaCount;
|
|
tracks[100].control = 0;
|
|
return SHOCK_OK;
|
|
}
|
|
|
|
s32 ReadLBA2448(s32 lba, void* dst)
|
|
{
|
|
fseek(inf,lba*2352,SEEK_SET);
|
|
fread(dst,1,2352,inf);
|
|
//do something for subcode I guess
|
|
memset((u8*)dst+2352,0,96);
|
|
hacky_MakeSubPQ(lba,(u8*)dst+2352,1,0);
|
|
|
|
//not the right thing to do
|
|
//return ((Sector*)dst)->mode;
|
|
|
|
return SHOCK_OK;
|
|
}
|
|
|
|
uint8 U8_to_BCD(uint8 num)
|
|
{
|
|
return( ((num / 10) << 4) + (num % 10) );
|
|
}
|
|
|
|
void subq_generate_checksum(uint8 *buf)
|
|
{
|
|
uint16 crc = 0;
|
|
|
|
for(int i = 0; i < 0xA; i++)
|
|
crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
|
|
|
|
// Checksum
|
|
buf[0xa] = ~(crc >> 8);
|
|
buf[0xb] = ~(crc);
|
|
}
|
|
void hacky_MakeSubPQ(int lba, u8* SubPWBuf, int track, int track_start)
|
|
{
|
|
uint8 buf[0xC];
|
|
uint32 lba_relative;
|
|
uint32 ma, sa, fa;
|
|
uint32 m, s, f;
|
|
uint8 pause_or = 0x00;
|
|
|
|
lba_relative = abs((int32)lba - track_start);
|
|
|
|
f = (lba_relative % 75);
|
|
s = ((lba_relative / 75) % 60);
|
|
m = (lba_relative / 75 / 60);
|
|
|
|
fa = (lba + 150) % 75;
|
|
sa = ((lba + 150) / 75) % 60;
|
|
ma = ((lba + 150) / 75 / 60);
|
|
|
|
uint8 adr = 0x1; // Q channel data encodes position
|
|
|
|
memset(buf, 0, 0xC);
|
|
buf[0] = (adr << 0) | (0x04 << 4);
|
|
buf[1] = U8_to_BCD(track);
|
|
|
|
buf[2] = U8_to_BCD(0x01);
|
|
|
|
// Track relative MSF address
|
|
buf[3] = U8_to_BCD(m);
|
|
buf[4] = U8_to_BCD(s);
|
|
buf[5] = U8_to_BCD(f);
|
|
|
|
buf[6] = 0; // Zerroooo
|
|
|
|
// Absolute MSF address
|
|
buf[7] = U8_to_BCD(ma);
|
|
buf[8] = U8_to_BCD(sa);
|
|
buf[9] = U8_to_BCD(fa);
|
|
|
|
subq_generate_checksum(buf);
|
|
|
|
for(int i = 0; i < 96; i++)
|
|
SubPWBuf[i] |= (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | pause_or;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const char* fwpath = argv[1];
|
|
const char* discpath = argv[2];
|
|
const char* outdir = argv[3];
|
|
|
|
FILE* inf;
|
|
|
|
//load up the firmware
|
|
char firmware[512*1024];
|
|
inf = fopen(fwpath,"rb");
|
|
fread(firmware,1,512*1024,inf);
|
|
fclose(inf);
|
|
|
|
BinReader2352 bin(discpath);
|
|
ShockDiscInfo info;
|
|
shock_AnalyzeDisc(bin.disc, &info);
|
|
printf("disc id: %s\n",info.id);
|
|
|
|
//placeholder for instance
|
|
void* psx = NULL;
|
|
|
|
ShockRenderOptions renderOpts;
|
|
renderOpts.deinterlaceMode = eShockDeinterlaceMode_Weave;
|
|
renderOpts.renderType = eShockRenderType_Normal;
|
|
renderOpts.scanline_start = 0;
|
|
renderOpts.scanline_end = 239;
|
|
renderOpts.skip = false;
|
|
|
|
|
|
shock_Create(&psx, REGION_NA, firmware);
|
|
shock_OpenTray(psx);
|
|
shock_SetDisc(psx,bin.disc);
|
|
shock_CloseTray(psx);
|
|
shock_SetRenderOptions(psx, &renderOpts);
|
|
shock_Peripheral_Connect(psx,0x01,ePeripheralType_DualShock);
|
|
shock_PowerOn(psx);
|
|
|
|
int framectr = 0;
|
|
for(;;)
|
|
{
|
|
printf("frame %d\n",framectr);
|
|
shock_Step(psx,eShockStep_Frame);
|
|
if(framectr%60==0)
|
|
{
|
|
//dump a screen grab
|
|
ShockFramebufferInfo fbinfo;
|
|
static u32 buf[1024*1024];
|
|
fbinfo.ptr = buf;
|
|
fbinfo.flags = eShockFramebufferFlags_Normalize;
|
|
shock_GetFramebuffer(psx,&fbinfo);
|
|
char fname[128];
|
|
sprintf(fname,"%s\\test%03d.bmp",outdir,framectr/60);
|
|
WriteBMP32(fbinfo.width,fbinfo.height,buf,fname); //rgb is backwards
|
|
}
|
|
|
|
framectr++;
|
|
}
|
|
} |