/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2003 Pcsx2 Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "Common.h" #include "PsxCommon.h" #include "CDVDisodrv.h" #include "VUmicro.h" #ifdef __WIN32__ #include "RDebug/deci2.h" #endif DWORD dwSaveVersion = 0x7a30000c; extern u32 s_iLastCOP0Cycle; extern int g_psxWriteOk; PcsxConfig Config; u32 BiosVersion; char CdromId[12]; char *LabelAuthors = { N_( "PCSX2 a PS2 emulator\n\n" "written by:\n" "saqib, refraction, zerofrog,\n" "shadow, linuzappz, florin,\n" "nachbrenner, auMatt, loser, \n" "alexey silinov, goldfinger,\n" "\n" "Webmasters: CKemu, Falcon4ever") }; char *LabelGreets = { N_( "Greets to: Bobbi, Keith, CpUMasteR, Nave, Snake785, Raziel\n" "Special thanks to: Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n" "Seta-San, Skarmeth, blackd_wd, _Demo_\n" "\n" "Credits: Hiryu && Sjeep for their libcdvd (iso parsing and filesystem driver code)\n" "\n" "Some betatester/support dudes: Belmont, bositman, ChaosCode, CKemu, crushtest," "falcon4ever, GeneralPlot, jegHegy, parotaku, Prafull, Razorblade, Rudy_X, Seta-san") }; static struct { char *name; u32 size; } ioprps[]={ {"IOPRP14", 43845}, {"IOPRP142", 48109}, {"IOPRP143", 58317}, {"IOPRP144", 58525}, {"IOPRP15", 82741}, {"IOPRP151", 82917}, {"IOPRP153", 82949}, {"IOPRP16", 91909}, {"IOPRP165", 98901}, {"IOPRP20", 109809}, {"IOPRP202", 110993}, {"IOPRP205", 119797}, {"IOPRP21", 126857}, {"IOPRP211", 129577}, {"IOPRP213", 129577}, {"IOPRP214", 140945}, {"IOPRP22", 199257}, {"IOPRP221", 196937}, {"IOPRP222", 198233}, {"IOPRP224", 201065}, {"IOPRP23", 230329}, {"IOPRP234", 247641}, {"IOPRP24", 251065}, {"IOPRP241", 251049}, {"IOPRP242", 252409}, {"IOPRP243", 253201}, {"IOPRP250", 264897}, {"IOPRP252", 265233}, {"IOPRP253", 267217}, {"IOPRP254", 264449}, {"IOPRP255", 264449}, {"IOPRP260", 248945}, {"IOPRP270", 249121}, {"IOPRP271", 266817}, {"IOPRP280", 269889}, {"IOPRP300", 275345}, {"DNAS280", 272753}, {"DNAS270", 251729}, {"DNAS271", 268977}, {"DNAS300", 278641}, {"DNAS280", 272705}, {"DNAS255", 264945}, {NULL, 0} }; void GetRPCVersion(char *ioprp, char *rpcver){ char *p=ioprp; int i; struct TocEntry te; if (p && (CDVD_findfile(p+strlen("cdromN:"), &te) != -1)){ for (i=0; ioprps[i].size>0; i++) if (te.fileSize==ioprps[i].size) break; if (ioprps[i].size>0) p=ioprps[i].name; } if (p && (p=strstr(p, "IOPRP")+strlen("IOPRP"))){ for (i=0;(i<4) && p && (*p>='0') && (*p<='9');i++, p++) rpcver[i]=*p; for ( ; i<4 ;i++ ) rpcver[i]='0'; } } u32 GetBiosVersion() { unsigned int fileOffset=0; char *ROMVER; char vermaj[8]; char vermin[8]; struct romdir *rd; u32 version; int i; for (i=0; i<512*1024; i++) { rd = (struct romdir*)&psRu8(i); if (strncmp(rd->fileName, "RESET", 5) == 0) break; /* found romdir */ } if (i == 512*1024) return -1; while(strlen(rd->fileName) > 0){ if (strcmp(rd->fileName, "ROMVER") == 0){ // found romver ROMVER = &psRu8(fileOffset); strncpy(vermaj, ROMVER+ 0, 2); vermaj[2] = 0; strncpy(vermin, ROMVER+ 2, 2); vermin[2] = 0; version = strtol(vermaj, (char**)NULL, 0) << 8; version|= strtol(vermin, (char**)NULL, 0); return version; } if ((rd->fileSize % 0x10)==0) fileOffset += rd->fileSize; else fileOffset += (rd->fileSize + 0x10) & 0xfffffff0; rd++; } return -1; } //2002-09-22 (Florin) int IsBIOS(char *filename, char *description){ struct stat buf; char Bios[260], ROMVER[14+1], zone[12+1]; FILE *fp; unsigned int fileOffset=0, found=FALSE; struct romdir rd; strcpy(Bios, Config.BiosDir); strcat(Bios, filename); if (stat(Bios, &buf) == -1) return FALSE; fp = fopen(Bios, "rb"); if (fp == NULL) return FALSE; while ((ftell(fp)<512*1024) && (fread(&rd, DIRENTRY_SIZE, 1, fp)==1)) if (strcmp(rd.fileName, "RESET") == 0) break; /* found romdir */ if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) { fclose(fp); return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img } while(strlen(rd.fileName) > 0){ if (strcmp(rd.fileName, "ROMVER") == 0){ // found romver unsigned int filepos=ftell(fp); fseek(fp, fileOffset, SEEK_SET); if (fread(&ROMVER, 14, 1, fp) == 0) break; fseek(fp, filepos, SEEK_SET);//go back switch(ROMVER[4]){ case 'T':sprintf(zone, "T10K "); break; case 'X':sprintf(zone, "Test ");break; case 'J':sprintf(zone, "Japan "); break; case 'A':sprintf(zone, "USA "); break; case 'E':sprintf(zone, "Europe"); break; case 'H':sprintf(zone, "HK "); break; case 'P':sprintf(zone, "Free "); break; case 'C':sprintf(zone, "China "); break; default: sprintf(zone, "%c ",ROMVER[4]); break;//shoudn't show } sprintf(description, "%s vXX.XX(XX/XX/XXXX) %s", zone, ROMVER[5]=='C'?"Console":ROMVER[5]=='D'?"Devel":""); strncpy(description+ 8, ROMVER+ 0, 2);//ver major strncpy(description+11, ROMVER+ 2, 2);//ver minor strncpy(description+14, ROMVER+12, 2);//day strncpy(description+17, ROMVER+10, 2);//month strncpy(description+20, ROMVER+ 6, 4);//year found = TRUE; } if ((rd.fileSize % 0x10)==0) fileOffset += rd.fileSize; else fileOffset += (rd.fileSize + 0x10) & 0xfffffff0; if (fread(&rd, DIRENTRY_SIZE, 1, fp)==0) break; } fileOffset-=((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; fclose(fp); if (found) { char percent[6]; if (buf.st_size<(int)fileOffset){ sprintf(percent, " %d%%", buf.st_size*100/(int)fileOffset); strcat(description, percent);//we force users to have correct bioses, //not that lame scph10000 of 513KB ;-) } return TRUE; } return FALSE; //fail quietly } // LOAD STUFF #define ISODCL(from, to) (to - from + 1) struct iso_directory_record { char length [ISODCL (1, 1)]; /* 711 */ char ext_attr_length [ISODCL (2, 2)]; /* 711 */ char extent [ISODCL (3, 10)]; /* 733 */ char size [ISODCL (11, 18)]; /* 733 */ char date [ISODCL (19, 25)]; /* 7 by 711 */ char flags [ISODCL (26, 26)]; char file_unit_size [ISODCL (27, 27)]; /* 711 */ char interleave [ISODCL (28, 28)]; /* 711 */ char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ unsigned char name_len [ISODCL (33, 33)]; /* 711 */ char name [1]; }; #define READTRACK(lsn) \ if (CDVDreadTrack(lsn, CDVD_MODE_2352) == -1) return -1; \ buf = CDVDgetBuffer(); if (buf == NULL) return -1; int LoadCdrom() { return 0; } int CheckCdrom() { u8 *buf; READTRACK(16); strncpy(CdromId, buf+52, 10); return 0; } int GetPS2ElfName(char *name){ FILE *fp; int f; char buffer[256];//if a file is longer...it should be shorter :D char *pos; static struct TocEntry tocEntry; int i; CDVDFS_init(); // check if the file exists if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ SysPrintf("SYSTEM.CNF not found\n"); return 0;//could not find; not a PS/PS2 cdvd } f=CDVDFS_open("SYSTEM.CNF;1", 1); CDVDFS_read(f, buffer, 256); CDVDFS_close(f); buffer[tocEntry.fileSize]='\0'; // SysPrintf( // "---------------------SYSTEM.CNF---------------------\n" // "%s" // "----------------------------------------------------\n", buffer); pos=strstr(buffer, "BOOT2"); if (pos==NULL){ pos=strstr(buffer, "BOOT"); if (pos==NULL) { SysPrintf("This is not a PS2 game!\n"); return 0; } return 1; } pos+=strlen("BOOT2"); while (pos && *pos && pos<=&buffer[255] && (*pos<'A' || (*pos>'Z' && *pos<'a') || *pos>'z')) pos++; if (!pos || *pos==0) return 0; sscanf(pos, "%s", name); //SysPrintf("ELF name: '%s'\n", name); if (strncmp("cdrom0:\\", name, 8) == 0) { strncpy(CdromId, name+8, 11); CdromId[11] = 0; } // inifile_read(CdromId); fp = fopen("System.map", "r"); if (fp) { u32 addr; SysPrintf("Loading System.map\n", fp); while (!feof(fp)) { fseek(fp, 8, SEEK_CUR); buffer[0] = '0'; buffer[1] = 'x'; for (i=2; i<10; i++) buffer[i] = fgetc(fp); buffer[i] = 0; addr = strtoul(buffer, (char**)NULL, 0); fseek(fp, 3, SEEK_CUR); for (i=0; i<256; i++) { buffer[i] = fgetc(fp); if (buffer[i] == '\n' || buffer[i] == 0) break; } if (buffer[i] == 0) break; buffer[i] = 0; disR5900AddSym(addr, buffer); } fclose(fp); } return 2; } /*#define PSX_EXE 1 #define CPE_EXE 2 #define COFF_EXE 3 #define INVALID_EXE 4 static int PSXGetFileType(FILE *f) { unsigned long current; unsigned long mybuf[2048]; EXE_HEADER *exe_hdr; FILHDR *coff_hdr; current = ftell(f); fseek(f,0L,SEEK_SET); fread(mybuf,2048,1,f); fseek(f,current,SEEK_SET); exe_hdr = (EXE_HEADER *)mybuf; if (memcmp(exe_hdr->id,"PS-X EXE",8)==0) return PSX_EXE; if (mybuf[0]=='C' && mybuf[1]=='P' && mybuf[2]=='E') return CPE_EXE; coff_hdr = (FILHDR *)mybuf; if (coff_hdr->f_magic == 0x0162) return COFF_EXE; return INVALID_EXE; } int Load(char *ExePath) { FILE *tmpFile; EXE_HEADER tmpHead; int type; strcpy(CdromId, "SLUS_999.99"); tmpFile = fopen(ExePath,"rb"); if (tmpFile == NULL) { SysMessage("Error opening file: %s", ExePath); return 0; } type = PSXGetFileType(tmpFile); switch (type) { case PSX_EXE: fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile); fseek(tmpFile, 0x800, SEEK_SET); fread((void *)PSXM(tmpHead.t_addr), tmpHead.t_size,1,tmpFile); fclose(tmpFile); psxRegs.pc = tmpHead.pc0; psxRegs.GPR.n.gp = tmpHead.gp0; psxRegs.GPR.n.sp = tmpHead.s_addr; if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00; break; case CPE_EXE: SysMessage("Pcsx found that you wanna use a CPE file. CPE files not support yet"); break; case COFF_EXE: SysMessage("Pcsx found that you wanna use a COFF file.COFF files not support yet"); break; case INVALID_EXE: SysMessage("This file is not a psx file"); break; } return 1; } */ u16 logProtocol; u8 logSource; int connected=0; #define SYNC_LOGGING void __Log(char *fmt, ...) { #ifdef EMU_LOG va_list list; static char tmp[2024]; //hm, should be enough va_start(list, fmt); #ifdef __WIN32__ if (connected && logProtocol>=0 && logProtocol<0x10){ vsprintf(tmp, fmt, list); sendTTYP(logProtocol, logSource, tmp); }//else //!!!!! is disabled, so the text goes to ttyp AND log #endif { #ifndef LOG_STDOUT if (varLog & 0x80000000) { vsprintf(tmp, fmt, list); SysPrintf(tmp); } else if( emuLog != NULL ) { vfprintf(emuLog, fmt, list); } #else //i assume that this will not be used (Florin) vsprintf(tmp, fmt, list); SysPrintf(tmp); #endif } va_end(list); #endif } // STATES #define STATE_VERSION "STv6" const char Pcsx2Header[32] = STATE_VERSION " PCSX2 v" PCSX2_VERSION; #define _PS2Esave(type) \ if (type##freeze(FREEZE_SIZE, &fP) == -1) { \ gzclose(f); \ return -1; \ } \ fP.data = malloc(fP.size); \ if (fP.data == NULL) return -1; \ \ if (type##freeze(FREEZE_SAVE, &fP) == -1) { \ gzclose(f); \ return -1; \ } \ \ gzwrite(f, &fP.size, sizeof(fP.size)); \ if (fP.size) { \ gzwrite(f, fP.data, fP.size); \ free(fP.data); \ } #define _PS2Eload(type) \ gzread(f, &fP.size, sizeof(fP.size)); \ if (fP.size) { \ fP.data = (s8*)malloc(fP.size); \ if (fP.data == NULL) return -1; \ gzread(f, fP.data, fP.size); \ } \ if (type##freeze(FREEZE_LOAD, &fP) == -1) { \ if (fP.size) free(fP.data); \ gzclose(f); \ return -1; \ } \ if (fP.size) free(fP.data); extern void gsWaitGS(); extern u32 g_nextBranchCycle, g_psxNextBranchCycle; int SaveState(char *file) { gzFile f; freezeData fP; gsWaitGS(); SysPrintf("SaveState: %s\n", file); f = gzopen(file, "wb"); if (f == NULL) return -1; gzwrite(f, &dwSaveVersion, 4); gzwrite(f, PS2MEM_BASE, 0x02000000); // 32 MB main memory gzwrite(f, PS2MEM_ROM, 0x00400000); // 4 mb rom memory gzwrite(f, PS2MEM_ROM1,0x00040000); // 256kb rom1 memory gzwrite(f, PS2MEM_SCRATCH, 0x00004000); // scratch pad gzwrite(f, PS2MEM_HW, 0x00010000); // hardware memory gzwrite(f, (void*)&cpuRegs, sizeof(cpuRegs)); // cpu regs + COP0 gzwrite(f, (void*)&psxRegs, sizeof(psxRegs)); // iop regs] gzwrite(f, (void*)&fpuRegs, sizeof(fpuRegs)); // fpu regs gzwrite(f, (void*)&tlb, sizeof(tlb)); // tlbs gzwrite(f, &EEsCycle, sizeof(EEsCycle)); gzwrite(f, &EEoCycle, sizeof(EEoCycle)); gzwrite(f, &IOPoCycle, sizeof(IOPoCycle)); gzwrite(f, &g_nextBranchCycle, sizeof(g_nextBranchCycle)); gzwrite(f, &g_psxNextBranchCycle, sizeof(g_psxNextBranchCycle)); gzwrite(f, &s_iLastCOP0Cycle, sizeof(s_iLastCOP0Cycle)); gzwrite(f, &g_psxWriteOk, sizeof(g_psxWriteOk)); //gzwrite(f, (void*)&ipuRegs, sizeof(IPUregisters)); // ipu regs //hope didn't forgot any cpu.... rcntFreeze(f, 1); gsFreeze(f, 1); vu0Freeze(f, 1); vu1Freeze(f, 1); vif0Freeze(f, 1); vif1Freeze(f, 1); sifFreeze(f, 1); ipuFreeze(f, 1); // iop now gzwrite(f, psxM, 0x00200000); // 2 MB main memory //gzwrite(f, psxP, 0x00010000); // pralell memory gzwrite(f, psxH, 0x00010000); // hardware memory //gzwrite(f, psxS, 0x00010000); // sif memory sioFreeze(f, 1); cdrFreeze(f, 1); cdvdFreeze(f, 1); psxRcntFreeze(f, 1); //mdecFreeze(f, 1); sio2Freeze(f, 1); SysPrintf("Saving GS\n"); _PS2Esave(GS); SysPrintf("Saving SPU2\n"); _PS2Esave(SPU2); SysPrintf("Saving DEV9\n"); _PS2Esave(DEV9); SysPrintf("Saving USB\n"); _PS2Esave(USB); SysPrintf("Saving ok\n"); gzclose(f); return 0; } extern u32 dumplog; extern u32 s_vucount; int LoadState(char *file) { gzFile f; freezeData fP; int i; DWORD OldProtect; DWORD dwVer; #ifdef _DEBUG s_vucount = 0; //dumplog |= 2; #endif SysPrintf("LoadState: %s\n", file); f = gzopen(file, "rb"); if (f == NULL) return -1; gzread(f, &dwVer, 4); if( dwVer != dwSaveVersion ) { gzclose(f); MessageBox(NULL, "Save state wrong version", "Error", MB_OK); return 0; } // stop and reset the system first gsWaitGS(); for (i=0; i<48; i++) ClearTLB(i); Cpu->Reset(); recResetVU0(); recResetVU1(); psxCpu->Reset(); SysPrintf("Loading memory\n"); #ifdef WIN32_VIRTUAL_MEM // make sure can write VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READWRITE, &OldProtect); VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READWRITE, &OldProtect); VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READWRITE, &OldProtect); VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READWRITE, &OldProtect); #endif gzread(f, PS2MEM_BASE, 0x02000000); // 32 MB main memory gzread(f, PS2MEM_ROM, 0x00400000); // 4 mb rom memory gzread(f, PS2MEM_ROM1,0x00040000); // 256kb rom1 memory gzread(f, PS2MEM_SCRATCH, 0x00004000); // scratch pad #ifdef WIN32_VIRTUAL_MEM VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READONLY, &OldProtect); VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READONLY, &OldProtect); VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READONLY, &OldProtect); VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READONLY, &OldProtect); #endif gzread(f, PS2MEM_HW, 0x00010000); // hardware memory SysPrintf("Loading structs\n"); gzread(f, (void*)&cpuRegs, sizeof(cpuRegs)); // cpu regs + COP0 gzread(f, (void*)&psxRegs, sizeof(psxRegs)); // iop regs gzread(f, (void*)&fpuRegs, sizeof(fpuRegs)); // fpu regs gzread(f, (void*)&tlb, sizeof(tlb)); // tlbs gzread(f, &EEsCycle, sizeof(EEsCycle)); gzread(f, &EEoCycle, sizeof(EEoCycle)); gzread(f, &IOPoCycle, sizeof(IOPoCycle)); gzread(f, &g_nextBranchCycle, sizeof(g_nextBranchCycle)); gzread(f, &g_psxNextBranchCycle, sizeof(g_psxNextBranchCycle)); gzread(f, &s_iLastCOP0Cycle, sizeof(s_iLastCOP0Cycle)); gzread(f, &g_psxWriteOk, sizeof(g_psxWriteOk)); rcntFreeze(f, 0); gsFreeze(f, 0); vu0Freeze(f, 0); vu1Freeze(f, 0); vif0Freeze(f, 0); vif1Freeze(f, 0); sifFreeze(f, 0); ipuFreeze(f, 0); // iop now SysPrintf("Loading iop mem\n"); gzread(f, psxM, 0x00200000); // 2 MB main memory //gzread(f, psxP, 0x00010000); // pralell memory gzread(f, psxH, 0x00010000); // hardware memory //gzread(f, psxS, 0x00010000); // sif memory SysPrintf("Loading iop stuff\n"); sioFreeze(f, 0); cdrFreeze(f, 0); cdvdFreeze(f, 0); psxRcntFreeze(f, 0); //mdecFreeze(f, 0); sio2Freeze(f, 0); SysPrintf("Loading GS\n"); _PS2Eload(GS); SysPrintf("Loading SPU2\n"); _PS2Eload(SPU2); SysPrintf("Loading DEV9\n"); _PS2Eload(DEV9); SysPrintf("Loading USB\n"); _PS2Eload(USB); SysPrintf("Loading ok\n"); gzclose(f); //dumplog |= 4; WriteCP0Status(cpuRegs.CP0.n.Status.val); for (i=0; i<48; i++) WriteTLB(i); return 0; } int CheckState(char *file) { gzFile f; char header[32]; f = gzopen(file, "rb"); if (f == NULL) return -1; gzread(f, header, 32); gzclose(f); if (strncmp(STATE_VERSION " PCSX2", header, 10)) return -1; return 0; } typedef struct { char id[8]; char name[64]; } LangDef; LangDef sLangs[] = { { "ar_AR", N_("Arabic") }, { "bg_BG", N_("Bulgarian") }, { "ca_CA", N_("Catalan") }, { "du_DU", N_("Dutch") }, { "de_DE", N_("German") }, { "el_EL", N_("Greek") }, { "en_US", N_("English") }, { "fr_FR", N_("French") }, { "hb_HB" , N_("Hebrew") }, { "hu_HU", N_("Hungarian") }, { "it_IT", N_("Italian") }, { "ja_JA", N_("Japanese") }, { "po_PO", N_("Portuguese") }, { "pl_PL" , N_("Polish") }, { "ro_RO", N_("Romanian") }, { "ru_RU", N_("Russian") }, { "es_ES", N_("Spanish") }, { "sh_SH" , N_("S-Chinese") }, { "tc_TC", N_("T-Chinese") }, { "tr_TR", N_("Turkish") }, { "", "" }, }; char *ParseLang(char *id) { int i=0; while (sLangs[i].id[0] != 0) { if (!strcmp(id, sLangs[i].id)) return _(sLangs[i].name); i++; } return id; } void injectIRX(char *filename){ struct stat buf; char path[260], name[260], *p, *q; struct romdir *rd; int iROMDIR=-1, iIOPBTCONF=-1, iBLANK=-1, i, filesize; FILE *fp; strcpy(name, filename); for (i=0; name[i] && name[i]!='.' && i<10; i++) name[i]=toupper(name[i]);name[i]=0; //phase 1: find ROMDIR in bios for (p=PS2MEM_ROM; pq){*((u64*)p)=*((u64*)p-4);*((u64*)p+1)=*((u64*)p-3);p-=DIRENTRY_SIZE;} *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iIOPBTCONF].fileSize+=DIRENTRY_SIZE; q=PS2MEM_ROM;for (i=0; i<=iROMDIR; i++) q+=(rd[i].fileSize+0xF)&(~0xF); while (p >q){*((u64*)p)=*((u64*)p-2);*((u64*)p+1)=*((u64*)p-1);p-=DIRENTRY_SIZE;} *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iROMDIR].fileSize+=DIRENTRY_SIZE; //phase 3: add the name to the end of IOPBTCONF p=PS2MEM_ROM;for (i=0; i