PSFINFO *sexy_load(char *path,const char *pathDir,int loop_infinite) { PSFINFO *ret; if( psxInit() < 0 ) return(0); psxReset(); sexySPUinit(); sexySPUopen(); if(!(ret=LoadPSF(path,0,0,pathDir))) { psxShutdown(); return(0); } strcpy(save_path,path); strcpy(save_pathDir,pathDir); // Taken from aosdk's eng_psf.c file ... // patch illegal Chocobo Dungeon 2 code - CaitSith2 put a jump in the delay slot from a BNE // and rely on Highly Experimental's buggy-ass CPU to rescue them. Verified on real hardware // that the initial code is wrong. if (ret->game) { if (!strcmp(ret->game, "Chocobo Dungeon 2")) { if (psxMu32(0xbc090) == (0x0802f040)) { psxMemWrite32(0xbc090, 0); psxMemWrite32(0xbc094, 0x0802f040); psxMemWrite32(0xbc098, 0); } } } if(ret->stop==~0) { ret->fade=10000; // Infinity ? limit to 3 minutes ret->stop=170000; } if (loop_infinite) { ret->stop=~0; } sexysetlength(ret->stop,ret->fade); ret->length=ret->stop+ret->fade; return(ret); }
PSFINFO *sexy_memload(char *addr, int size) { PSFINFO *ret; psxInit(); psxReset(); sexySPUinit(); sexySPUopen(); if(!(ret=memLoadPSF(addr,size,0,0))) { psxShutdown(); return(0); } // Taken from aosdk's eng_psf.c file ... // patch illegal Chocobo Dungeon 2 code - CaitSith2 put a jump in the delay slot from a BNE // and rely on Highly Experimental's buggy-ass CPU to rescue them. Verified on real hardware // that the initial code is wrong. if (ret->game) { if (!strcmp(ret->game, "Chocobo Dungeon 2")) { if (psxMu32(0xbc090) == (0x0802f040)) { psxMemWrite32(0xbc090, 0); psxMemWrite32(0xbc094, 0x0802f040); psxMemWrite32(0xbc098, 0); } } } if(ret->stop==~0) ret->fade=0; // Infinity+anything is still infinity...or is it? setlength(ret->stop,ret->fade); ret->length=ret->stop+ret->fade; return(ret); }
static void write_mem32() { memprintf("ari64_write_mem32 %08x, %08x @%08x %u\n", address, word, psxRegs.pc, psxRegs.cycle); psxMemWrite32(address, word); }
static PSFINFO *LoadPSF(char *path, int level, int type,const char *pathDir) // Type==1 for just info load. { FILE *fp; u8 *in,*out=0; u8 head[4]; u32 reserved; u32 complen; u32 crc32; uLongf outlen; PSFINFO *psfi=NULL; PSFINFO *tmpi=NULL; u32 offset, plength; sexypsf_missing_psflib=0; #ifdef DEBUG fprintf(stderr, "Searching (%s)\n", path); #endif fp=fopen(path,"rb"); if(!fp) return 0; fread(head,1,4,fp); if(memcmp(head,"PSF\x01",4)) return(0); psfi=malloc(sizeof(PSFINFO)); if( psfi == NULL ) return(0); memset(psfi,0,sizeof(PSFINFO)); psfi->stop=~0; psfi->fade=0; fread(&reserved,1,4,fp); fread(&complen,1,4,fp); complen=BFLIP32(complen); fread(&crc32,1,4,fp); crc32=BFLIP32(crc32); #ifdef DEBUG fprintf(stderr, "CRC32 = 0x%x\n", crc32); #endif fseek(fp,reserved,SEEK_CUR); if(type) fseek(fp,complen,SEEK_CUR); else { in=malloc(complen); if( !in ) return(0); out=malloc(1024*1024*2+0x800); if( !out ) { free(in); return(0); } fread(in,1,complen,fp); outlen=1024*1024*2; uncompress(out,&outlen,in,complen); free(in); psxRegs->pc = out[0x10] | out[0x11]<<8 | out[0x12]<<16 | out[0x13]<<24; psxRegs->GPR.n.gp = out[0x14] | out[0x15]<<8 | out[0x16]<<16 | out[0x17]<<24; psxRegs->GPR.n.sp = out[0x30] | out[0x31]<<8 | out[0x32]<<16 | out[0x33]<<24; if (psxRegs->GPR.n.sp == 0) psxRegs->GPR.n.sp = 0x801fff00; #ifdef DEBUG fprintf(stderr, "%d Level: PC %x GP %x SP %x\n", level, psxRegs->pc, psxRegs->GPR.n.gp, psxRegs->GPR.n.sp); #endif if(level) { offset = out[0x18] | out[0x19]<<8 | out[0x1a]<<16 | out[0x1b]<<24; offset &= 0x3fffffff; // kill any MIPS cache segment indicators plength = out[0x1c] | out[0x1d]<<8 | out[0x1e]<<16 | out[0x1f]<<24; #ifdef DEBUG fprintf(stderr, "%d Level: offset %x plength: %d [%d]\n", level, offset, plength, plength); #endif LoadPSXMem(offset,plength,(char*)out+0x800); free(out); // I don't really know how does this // work, but apparently it breaks the // loop that makes ff6 and ct to take // several seconds to start ... if( crc32 == 0xEFDE8EEE || crc32 == 0x545D9F65 ) psxMemWrite32(0x5A66C, 0); // Same as above for Popolocrois if( crc32 == 0xF535726 ) psxMemWrite32(0x5A990, 0); } } { u8 tagdata[5]; if(fread(tagdata,1,5,fp)==5) { if(!memcmp(tagdata,"[TAG]",5)) { char linebuf[1024]; while(fgets(linebuf,1024,fp)>0) { int x; char *key=0,*value=0; if(!GetKeyVal(linebuf,&key,&value)) { if(key) free(key); if(value) free(value); continue; } AddKV(&psfi->tags,key,value); if(!level) { static char *yoinks[8]={"title","artist","game","year","genre", "copyright","psfby","comment"}; char **yoinks2[8]={&psfi->title,&psfi->artist,&psfi->game,&psfi->year,&psfi->genre, &psfi->copyright,&psfi->psfby,&psfi->comment}; for(x=0;x<8;x++) if(!strcasecmp(key,yoinks[x])) *yoinks2[x]=value; if(!strcasecmp(key,"length")) psfi->stop=TimeToMS(value); else if(!strcasecmp(key,"fade")) psfi->fade=TimeToMS(value); } if(!strcasecmp(key,"_lib") && !type) { char *tmpfn; /* Load file name "value" from the directory specified in the full path(directory + file name) "path" */ //printf("yo %s\nya %s\nyu%s\n",path,value,pathDir); tmpfn=GetFileWithBase(path,value,pathDir); //printf("ru: %s\n",tmpfn); if(!(tmpi=LoadPSF(tmpfn,level+1,0,pathDir))) { //free(key); //free(value); sexypsf_missing_psflib=1; strcpy(sexypsf_psflib_str,value); free(tmpfn); if(!level) free(out); fclose(fp); FreeTags(psfi->tags); free(psfi); return(0); } FreeTags(tmpi->tags); free(tmpi); free(tmpfn); } } } } } fclose(fp); /* Now, if we're at level 0(main PSF), load the main executable, and any libN stuff */ if(!level && !type) { offset = out[0x18] | out[0x19]<<8 | out[0x1a]<<16 | out[0x1b]<<24; offset &= 0x3fffffff; // kill any MIPS cache segment indicators plength = out[0x1c] | out[0x1d]<<8 | out[0x1e]<<16 | out[0x1f]<<24; // TODO - investigate: should i just make // plength = outlen-0x800? // Philosoma has an illegal "plength". *sigh* if (plength > (outlen-0x800)) { plength = outlen-0x800; } if( psfi->game ) { // Suikoden Tenmei has an illegal "plength". *sigh sigh* if( !strncmp(psfi->game, "Suikoden: Tenmei no Chikai", 26) ) { plength = outlen-0x800; } // Einhänder has an illegal "plength". *sigh sigh sigh* if( !strncmp(psfi->game, "Einhänder", 9) ) { plength = outlen-0x800; } } #ifdef DEBUG fprintf(stderr, "%d Level: offset %x plength: %d [%d]\n", level, offset, plength, outlen-2048); #endif LoadPSXMem(offset,plength,(char*)out+0x800); free(out); } if(!type) /* Load libN */{ LIBNCACHE *cache; PSFTAG *tag; unsigned int libncount=0; unsigned int cur=0; tag=psfi->tags; while(tag) { if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) libncount++; tag=tag->next; } if(libncount) { cache=malloc(sizeof(LIBNCACHE)*libncount); tag=psfi->tags; while(tag) { if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) { cache[cur].num=atoi(&tag->key[4]); cache[cur].value=tag->value; cur++; } tag=tag->next; } qsort(cache, libncount, sizeof(LIBNCACHE), ccomp); for(cur=0;cur<libncount;cur++) { u32 ba[3]; char *tmpfn; if(cache[cur].num < 2) continue; ba[0]=psxRegs->pc; ba[1]=psxRegs->GPR.n.gp; ba[2]=psxRegs->GPR.n.sp; /* Load file name "value" from the directory specified in the full path(directory + file name) "path" */ tmpfn=GetFileWithBase(path,cache[cur].value,pathDir); if(!(tmpi=LoadPSF(tmpfn,level+1,0,pathDir))) { //free(key); //free(value); //free(tmpfn); //fclose(fp); //return(0); } else { FreeTags(tmpi->tags); free(tmpi); } free(tmpfn); psxRegs->pc=ba[0]; psxRegs->GPR.n.gp=ba[1]; psxRegs->GPR.n.sp=ba[2]; } free(cache); } // if(libncount) } // if(!type) return(psfi); }
// LoadPSF for Memory static PSFINFO *memLoadPSF(char *addr, long size, int level, int type) // Type==1 for just info load. { u8 *in,*out=0; u8 head[4]; u32 reserved; u32 complen; u32 crc32; uLongf outlen; PSFINFO *psfi=NULL; PSFINFO *tmpi=NULL; u32 poffset, plength; u32 offset = 0; if( addr == NULL || size == 0 ) return(0); memread((void*)(head), 4, addr, size, &offset); if(memcmp(head,"PSF\x01",4)) return(0); psfi=malloc(sizeof(PSFINFO)); memset(psfi,0,sizeof(PSFINFO)); psfi->stop=~0; psfi->fade=0; memread((void*)(&reserved), 4, addr, size, &offset); memread((void*)(&complen), 4, addr, size, &offset); complen=BFLIP32(complen); memread((void*)(&crc32), 4, addr, size, &offset); crc32=BFLIP32(crc32); memseek(reserved, size, &offset); if(type) { memseek(complen, size, &offset); } else { in=malloc(complen); out=malloc(1024*1024*2+0x800); if( !in || !out ) { free(psfi); return (0); } memread((void*)(in), complen, addr, size, &offset); outlen=1024*1024*2; uncompress(out,&outlen,in,complen); free(in); psxRegs->pc = out[0x10] | out[0x11]<<8 | out[0x12]<<16 | out[0x13]<<24; psxRegs->GPR.n.gp = out[0x14] | out[0x15]<<8 | out[0x16]<<16 | out[0x17]<<24; psxRegs->GPR.n.sp = out[0x30] | out[0x31]<<8 | out[0x32]<<16 | out[0x33]<<24; if (psxRegs->GPR.n.sp == 0) psxRegs->GPR.n.sp = 0x801fff00; #ifdef DEBUG fprintf(stderr, "%d Level: PC %x GP %x SP %x\n", level, psxRegs->pc, psxRegs->GPR.n.gp, psxRegs->GPR.n.sp); #endif if(level) { poffset = out[0x18] | out[0x19]<<8 | out[0x1a]<<16 | out[0x1b]<<24; poffset &= 0x3fffffff; // kill any MIPS cache segment indicators plength = out[0x1c] | out[0x1d]<<8 | out[0x1e]<<16 | out[0x1f]<<24; #ifdef DEBUG fprintf(stderr, "%d Level: offset %x plength: %d\n", level, poffset, plength); #endif LoadPSXMem(poffset,plength,out+0x800); free(out); // I don't really know how does this // work, but apparently it breaks the // loop that makes ff6 and ct to take // several seconds to start ... if( crc32 == 0xEFDE8EEE || crc32 == 0x545D9F65 ) psxMemWrite32(0x5A66C, 0); // Same as above for Popolocrois and Einhänder if( crc32 == 0xF535726 ) psxMemWrite32(0x5A990, 0); } } { u8 tagdata[5]; if( memread((void*)(tagdata), 5, addr, size, &offset) == 5 ) { if(!memcmp(tagdata,"[TAG]",5)) { char linebuf[1024]; while( memfgets(linebuf, 1024, addr, size, &offset)>0 ) { int x; char *key=0,*value=0; if(!GetKeyVal(linebuf,&key,&value)) { if(key) free(key); if(value) free(value); continue; } AddKV(&psfi->tags,key,value); if(!level) { static char *yoinks[8]={"title","artist","game","year","genre", "copyright","psfby","comment"}; char **yoinks2[8]={&psfi->title,&psfi->artist,&psfi->game,&psfi->year,&psfi->genre, &psfi->copyright,&psfi->psfby,&psfi->comment}; for(x=0;x<8;x++) if(!strcasecmp(key,yoinks[x])) *yoinks2[x]=value; if(!strcasecmp(key,"length")) psfi->stop=TimeToMS(value); else if(!strcasecmp(key,"fade")) psfi->fade=TimeToMS(value); } if(!strcasecmp(key,"_lib") && !type && __psflibs) { /* Search file name "value" from the __psflibs array */ int n, found = 0; for(n=0;n<__psflibs->count;n++) if( !strcasecmp(value, __psflibs->libn[n].name) ) { found = 1; break; } if(!found || !(tmpi=memLoadPSF(__psflibs->libn[n].addr, __psflibs->libn[n].size, level+1,0))) { free(key); free(value); if(!level) free(out); FreeTags(psfi->tags); free(psfi); return(0); } FreeTags(tmpi->tags); free(tmpi); } } } } } /* Now, if we're at level 0(main PSF), load the main executable, and any libN stuff*/ if(!level && !type) { poffset = out[0x18] | out[0x19]<<8 | out[0x1a]<<16 | out[0x1b]<<24; poffset &= 0x3fffffff; // kill any MIPS cache segment indicators plength = out[0x1c] | out[0x1d]<<8 | out[0x1e]<<16 | out[0x1f]<<24; // TODO - investigate: should i just make // plength = outlen-0x800? // Philosoma has an illegal "plength". *sigh* if (plength > (outlen-0x800)) { plength = outlen-0x800; } if( psfi->game ) { // Suikoden Tenmei has an illegal "plength". *sigh sigh* if( !strncmp(psfi->game, "Suikoden: Tenmei no Chikai", 26) ) { plength = outlen-0x800; } // Einhänder has an illegal "plength". *sigh sigh sigh* if( !strncmp(psfi->game, "Einhänder", 9) ) { plength = outlen-0x800; } } #ifdef DEBUG fprintf(stderr, "%d Level: offset %x plength: %d\n", level, poffset, plength); #endif LoadPSXMem(poffset,plength,out+0x800); free(out); } if(!type && __psflibs) /* Load libN */ { LIBNCACHE *cache; PSFTAG *tag; unsigned int libncount=0; unsigned int cur=0; tag=psfi->tags; while(tag) { if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) libncount++; tag=tag->next; } if(libncount) { cache=malloc(sizeof(LIBNCACHE)*libncount); tag=psfi->tags; while(tag) { if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) { cache[cur].num=atoi(&tag->key[4]); cache[cur].value=tag->value; cur++; } tag=tag->next; } qsort(cache, libncount, sizeof(LIBNCACHE), ccomp); for(cur=0;cur<libncount;cur++) { u32 ba[3]; if(cache[cur].num < 2) continue; ba[0]=psxRegs->pc; ba[1]=psxRegs->GPR.n.gp; ba[2]=psxRegs->GPR.n.sp; /* Search file name "value" from the __psflibs array */ int n, found = 0; for(n=0;n<__psflibs->count;n++) if( !strcasecmp(cache[cur].value, __psflibs->libn[n].name) ) { found = 1; break; } if(!found || !(tmpi=memLoadPSF(__psflibs->libn[n].addr,__psflibs->libn[n].size,level+1,0))) { //free(key); //free(value); //free(tmpfn); //fclose(fp); //return(0); } FreeTags(tmpi->tags); free(tmpi); psxRegs->pc=ba[0]; psxRegs->GPR.n.gp=ba[1]; psxRegs->GPR.n.sp=ba[2]; } free(cache); } // if(libncount) } // if(!type) return(psfi); }