PS2 PAL TO NTSC VIDEO MODE CHANGER WITH Y-FIX
PS2 PAL TO NTSC VIDEO MODE CHANGER WITH Y-FIX
URL: www.geocities.com/jayteemaster2003
V1.03 BETA - 23 February, 2004
Coding by JayteeMaster
Hello, PS2 users:
I write this program to allow you to play your PAL games in color and with the screen centered!
Some programs, like ADR patcher, already allowed you to patch your game from PAL from NTSC. But the screen was not centered!
Most of the times you had to search for a specific patch.
No any more, I hope!
But if you find one like from ps2chimps i recommend you to use it instead.
Some PAL games have already built in screen centering. If you know this is advance you may skip this pacther and use instead the ADR patcher for converting only from PAL to NTSC. But remember that sometimes the maximum screen offset is to small for you to shift up the picture. So you might enjoy to use this patcher.
The patching engine is based on my PS2 NTSC TO PAL VIDEO MODE CHANGER WITH Y-FIX which has a very high successful patching rate.
Support ISO and BIN CD/DVD PS2 images and single ELF files as well.
!!!!!!!! NEW: Now you have the option to build a P/N Selector !!!!!!!!!
Attention:
- Case 1) This program will modify the ELF file. BACKUP THE ELF FILE FIRST, PLEASE.
- Case 2) For CD/DVD PS2 images the ELF file is backuped automatically.
USAGE:
- Click on 'Browse' and then choose an ELF file or a CD/DVD PS2 image.
- Select the amount of offset to shift the screen up.
- Check the 'MAKE PN SELECTOR' Box for building a P/N selector. Otherwise, uncheck it.
- Click on 'Patch File' and read the text output.
The program will first try to change the video mode from PAL to NTSC.
It will indicate you if found any locations to patch, if the ELF is already patched and the number of locations to patch.
Then it will try to patch the screen Y position. It will indicate you if
can not find any patch locations or if can not patch the locations found.
If you checked the 'MAKE PN SELECTOR' box the program will try to build a P/N selector for you.
In this situation, when loading the game in your PS2 you have the option to choose between NTSC with Y-FIX, NTSC or PAL video mode. A preview of the selector screen is included in the zip.
NEW: the selector includes 3 boot modes. If the game does not boot you may try one of the others by pressing the triangle button in the pad. PLEASE DO NOT ASK ME WHAT EACH MODE DOES EXACTLY BECAUSE I DO NOT KNOW THE DETAILS. The Iop Reboot 0 does nothing but Iop Reboot 1 and 2 reboots the IOP. If the game does not boot with the default just try the others and report.
IF YOUR ELF FILE IS RELEASED BY PARADOX OR KALISTO THIS PROGRAM MAY HAVE NO EFECT! - usually those games have a intro screen or a P/N selector (The original game code usually is compressed) - if not, they probably are not compressed.
BUT DO NOT WORRY! THE PROGRAM AUTODETECTS COMPRESSED ELF FILES.
Please report any bugs or suggestions to jayteemaster2003@yahoo.com.br
Also, I would appreciate if you send me some fast FTPs with PS2 rips.
Enjoy your games,
JayteeMaster.
Important
This info relates to the amount of Y-FIX OFFSET to use.
VERY IMPORTANT: you will never see the complete picture on your TV when patching from PAL to NTSC. This is because PAL has more height resolution (more lines) than NTSC. If the PAL game is not fullscreen (has 2 small black bars at top and bottom) then it may be possible to watch the whole picture in NTSC. Usually you will lose some part of the bottom picture. With the correct Y-FIX offset you can minimize this problem. I think also that with the proper amount of Y-FIX OFFSET you can split the lost lines between the top and the bottom of screen.
If you choose an OFFSET to high the game may not work or be unplayable.
** For starting i recommend you to use 32. **
When you get more experience (like watching for the screen position on
your TV and guessing how much could you increase the OFFSET to shift the screen UP) you can try to increase the Y-FIX OFFSET.
For your information my PS2 NSTC TO PAL VIDEO MODE CHANGER WITH Y-FIX
uses the default of 48 to shift the screen DOWN.
** Then you may try to use 48 or 40. **
Values greater than 48 will probably make the game not work or unplayable.
Also i do not know if there is a relation between the amount of Y-FIX offset and the progressive/interlaced screen mode. For your reference, an even number of y-fix patched positions may mean interlaced mode and
an odd number of y-fix patched positions may mean progressive mode.
Maybee someone could maintain a list with the game name, patching results, Y-FIX OFFSET used and some info (like 'a bit more OFFSET will center the screen better', 'i still see a black bar at top','screen centering perfect', ...) for helping other users.
Source code
/* ps2_pal2ntsc_yfix - PS2 PAL TO NTSC VIDEO MODE CHANGER WITH Y-FIX
* Copyright (C) 2003-2004 Jayteemaster <jayteemaster2003@yahoo.com.br>
* URL: www.geocities.com/jayteemaster2003
*
* 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 <afxwin.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <memory.h>
#include <stdarg.h>
#include "regs.h"
#include "Elfheader.h"
#ifdef GUI
extern CEdit *p_m_edit;
void SysPrintf(char *fmt, ...) {
va_list list;
char msg[512];
va_start(list,fmt);
vsprintf(msg,fmt,list);
va_end(list);
p_m_edit->ReplaceSel(msg);
}
#define Exit(code) return
#else
void SysPrintf(char *fmt, ...) {
va_list list;
char msg[512];
va_start(list,fmt);
vsprintf(msg,fmt,list);
va_end(list);
printf(msg);
}
#define Exit(code) exit(code)
#endif
unsigned int next2power(unsigned int n);
unsigned int calledby(FILE *fid, unsigned int offset);
unsigned int fcalls[12][2];
typedef struct {
unsigned int offset;
unsigned int address;
unsigned int saved_reg; //reg1
unsigned int base_reg;
unsigned int instr[3];
unsigned int spare_reg; //reg2
int can_use_jr;
int has2return;
int has2return2;
int has2jump;
int no_nop;
int has2flip;
int ei;
int do2;
int nofix;
} FIX_RECORD;
FIX_RECORD Y_fixes[16];
int n2fix;
extern int yfix_offset;
unsigned int sub1[16] = // without spare_reg and can not use jr ra
//daddiu saved_reg,saved_reg,xxxx; ...; daddiu saved_reg,saved_reg,0000; instr[0]; j address+8; nop
{0x64008000,0x64008000,0x64008000,0x64008000,0x64008000,0x64008000,0x64000000,0x64000000,0x00000000,0x08000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};
unsigned int sub2[16] = // without spare_reg and can use jr ra
//daddiu saved_reg,saved_reg,xxxx; ...; daddiu saved_reg,saved_reg,0000; instr[0]; jr ra; nop
{0x64008000,0x64008000,0x64008000,0x64008000,0x64008000,0x64008000,0x64000000,0x64000000,0x00000000,0x03E00008,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};
unsigned int sub3[8] = // with spare_reg and can not use jr ra
//lui reg2,3; subu reg1,reg1,reg2; daddiu reg1,reg1,0; instr[0]; instr[1]; j address+8; nop
{0x3C000003, 0x0000002F, 0x64000000, 0x00000000, 0x00000000, 0x08000000, 0x00000000, 0x00000000};
unsigned int sub4[8] = // with spare_reg and can use jr ra
//lui reg2,3; subu reg1,reg1,reg2; daddiu reg1,reg1,0; instr[0]; instr[1]; jr ra; nop
{0x3C000003, 0x0000002F, 0x64000000, 0x00000000, 0x00000000, 0x03E00008, 0x00000000, 0x00000000};
unsigned int set_v2NTSC[4] = {0x24030002,0x0000000C,0x03E00008,0x00000000};
unsigned int set_v2PAL[4] = {0x34050002,0x24030002,0x0000000C,0x03E00008};
/////////////////
// selector
/////////////////
unsigned int u_vmode[4];
int u_posv;
unsigned int u_yfix[16*3];
extern int pn_selector;
unsigned int original_filesize;
//
// syscall
#ifdef PS2LOADV7
extern unsigned int u_syscall[2], u_posys;
unsigned int Syscall6[4] = {0x24030006,0x0000000C,0x03E00008,0x00000000};
unsigned int Syscall6f2[4] = {0x34030006,0x0000000C,0x03E00008,0x00000000};
#endif
unsigned int SIGNATURE = 0x5459414A;
unsigned int buf[1024], nextval, prevval;
unsigned char buf_2[4*1024];
int please_inform;
int wasmodified=0;
#ifdef GUI
void main_(int argc, char *argv[])
#else
void main(int argc, char *argv[])
#endif
{
FILE *fid;
unsigned int offset, count, i, j;
unsigned int reg_values[32], reg, reg2, spare_reg, value;
int enable_jr = 0, enable_sd = 0;
int posfnd = 0, posfnd2=0;
int have2reset=0;
int sm1=0, sm2=0, sm3=0;
unsigned int vmN[10], vmP[10], nN=0, nP=0;
unsigned int space_av, space_nd, use_short_sub=0;
unsigned int Sub[16];
int phnum=-1;
int shnum=-1;
unsigned int wbytes=0;
unsigned int p_align;
unsigned int num2read, addr1;
int found;
int FvF=-1;
char keycode; int user_option_1;
unsigned int filesize, spare_space, extra_space;
int rd_pos, wt_pos;
unsigned int address;
unsigned int store_last;
int dupofs;
unsigned int fxreg;
int sfchange=0,nofix=0;
SysPrintf("PS2 PAL 2 NTSC VIDEO MODE CHANGER WITH Y-FIX\r\n");
SysPrintf("Patching Engine V1.09 - 24 May, 2004\r\n");
SysPrintf("By Jaytee\r\n");
SysPrintf("\r\n");
SysPrintf("Please report any bugs or suggestions to jayteemaster2003@yahoo.com.br\r\n");
SysPrintf("Also, I would appreciate if you send me some fast FTPs with PS2 rips.\r\n");
SysPrintf("\r\n");
// Y Fix Offset
for (i=0;i<8;i++)
{
sub1[i]=0x64008000;
sub2[i]=0x64008000;
}
for (i=0;i<8-(yfix_offset/8);i++)
{
sub1[i]=0x64000000;
sub2[i]=0x64000000;
}
sub3[0]=0x3C000000 | ((unsigned int)yfix_offset/16);
sub4[0]=sub3[0];
if ((yfix_offset%16)==0)
{
sub3[2]=0x64000000;
sub4[2]=sub3[2];
}
else
{
sub3[2]=0x64008000;
sub4[2]=sub3[2];
}
//
wasmodified=0;
/////////////////
// selector
/////////////////
u_posv=0;
memset(u_vmode, 0, sizeof(unsigned int)*4);
memset(u_yfix, 0, sizeof(unsigned int)*16*3);
//
#ifdef PS2LOADV7
u_posys=0;
memset(u_syscall, 0, sizeof(unsigned int)*2);
#endif
if (argc<2)
{
SysPrintf("Usage: ps2_pal2ntsc_yfix <elf file>\r\n");
Exit(0);
}
ClearHeaders();
loadElfFile(argv[1]);
fid = fopen(argv[1], "rb");
if (fid==NULL)
{
SysPrintf("File %s not found.\r\n", argv[1]);
Exit(1);
}
fseek(fid, 0, SEEK_END);
original_filesize = filesize = ftell(fid);
fseek(fid, 0, SEEK_SET);
n2fix = 0;
memset(Y_fixes, 0, sizeof(FIX_RECORD)*16);
memset(reg_values, 0, sizeof(unsigned int)*32);
offset = 0;
while (!feof(fid))
{
count = fread(buf, 4, 1024, fid);
for (i=0;i<count;i++)
{
// search for SetGsCrt
if (buf[i] == set_v2NTSC[sm1])
{
sm1++;
if (sm1 == 4)
{
sm1 = 0;
vmN[nN++] = (offset+i-3)*4;
}
}
else
sm1=0;
if (buf[i] == set_v2PAL[sm2])
{
sm2++;
if (sm2 == 4)
{
sm2 = 0;
vmP[nP++] = (offset+i-3)*4;
}
}
else
sm2=0;
// selector syscall
#ifdef PS2LOADV7
if ((buf[i] == Syscall6[sm3])||(buf[i] == Syscall6f2[sm3]))
{
sm3++;
if (sm3 == 4)
{
if (u_posys<2)
{
sm3 = 0;
u_syscall[u_posys++] = (offset+i-3)*4;
}
}
}
else
sm3=0;
#endif
// end selector
// search lui reg,$1200
// if ((buf[i]&0xFFE0FFFF) == 0x3C001200)
// search lui reg,$xxxx
if ((buf[i]&0xFFE00000) == 0x3C000000)
{
reg = (buf[i]>>16) & 31;
// reg_values[reg] = 0x12000000;
reg_values[reg] = (buf[i]&0x0000FFFF)<<16;
//SysPrintf("lui %d,12000 at offset %d\r\n", reg, (offset+i)*4);
//getchar();
}
// search ori reg,reg2,$0080
// search ori reg,reg2,$00A0
// if (((buf[i]&0xFC00FFFF) == 0x34000080) || ((buf[i]&0xFC00FFFF) == 0x340000A0) )
// search ori reg,reg2,$xxxx
if ((buf[i]&0xFC000000) == 0x34000000)
{
reg = (buf[i]>>16) & 31;
reg2 = (buf[i]>>21) & 31;
value = buf[i] & 0xFFFF;
reg_values[reg] = reg_values[reg2] | value;
if ((reg_values[reg] == 0x12000080) || (reg_values[reg] == 0x120000A0))
{
//SysPrintf("Found Y fix at offset %x\r\n", offset+i);
enable_sd = 1;
}
}
// search sd reg2, $0000(reg)
// search sd reg2, $xxxx(reg) ***** NEW *******
//if ((enable_sd) & ((buf[i]&0xFC00FFFF) == 0xFC000000))
if ((buf[i]>>26)==0x3F)
{
unsigned int ofs;
reg = (buf[i]>>21) & 31;
reg2 = (buf[i]>>16) & 31;
ofs = buf[i] & 0xFFFF;
if ((((reg_values[reg]+ofs) == 0x12000080) || ((reg_values[reg]+ofs) == 0x120000A0)) && (reg2!=0))
{
//SysPrintf("Found Y fix at offset %x\r\n", offset+i);
Y_fixes[n2fix].address = 0x00000000; // ?
Y_fixes[n2fix].base_reg = reg;
Y_fixes[n2fix].can_use_jr = 0;
Y_fixes[n2fix].instr[0] = buf[i];
Y_fixes[n2fix].offset = (offset+i)*4;
Y_fixes[n2fix].saved_reg = reg2;
Y_fixes[n2fix].spare_reg = 0;
Y_fixes[n2fix].has2return = 0;
Y_fixes[n2fix].has2return2 = 0;
Y_fixes[n2fix].has2jump = 0;
Y_fixes[n2fix].no_nop = 0;
Y_fixes[n2fix].has2flip=0;
Y_fixes[n2fix].ei=0;
Y_fixes[n2fix].do2=0;
Y_fixes[n2fix].nofix=0;
//
if ((n2fix>0) && (Y_fixes[n2fix].saved_reg==Y_fixes[n2fix-1].saved_reg) && (nofix==1))
Y_fixes[n2fix].nofix=1;
fxreg=reg2;
sfchange=6;
nofix=0;
//
if (have2reset==1)
{
Y_fixes[n2fix].has2return = 1; // MotoGP3
//MessageBox(0,"aaa","gagaag",MB_OK);
}
// prev instruction
if (i==0)
{
prevval = store_last;
}
else
prevval = buf[i-1];
Y_fixes[n2fix].instr[2] = prevval;
// check if prev instruction is beq zero,zero,0xXXXXXXXX: Prince of Persia
if ((prevval>>26)==4)
{
if ((((prevval>>16) & 31)!=0) || (((prevval>>21) & 31)!=0))
Y_fixes[n2fix].nofix=1;
else
{
Y_fixes[n2fix].has2jump = prevval & 0xFFFF;
Y_fixes[n2fix].has2flip = 1; // FOR NOW
}
}
// check if follows a ld reg, $xxxx(reg2)
if ((i+1)==count)
{
fread(&nextval, 4, 1, fid);
fseek(fid, -4, SEEK_CUR);
}
else
nextval = buf[i+1];
Y_fixes[n2fix].instr[1] = nextval;
// this save follows the previous
if ((n2fix>0) && ((Y_fixes[n2fix].offset-Y_fixes[n2fix-1].offset)==4))
{
Y_fixes[n2fix-1].do2=1;
Y_fixes[n2fix].do2=2;
}
if (Y_fixes[n2fix].has2return ==0)
{
// ALTERAR AQUI PARA MAIS INSTRUCOES DE LOAD
if ( ((nextval&0xFC000000) == 0xDC000000) // ld
|| ((nextval&0xFC000000) == 0x8C000000) // lw
|| ((nextval&0xFC000000) == 0x9C000000) // lwu
|| ((nextval&0xFC000000) == 0x80000000) // lb
|| ((nextval&0xFC000000) == 0x90000000) ) // lbu
{
spare_reg = (nextval>>16) & 31;
if ((spare_reg>0) && (spare_reg<26) && (((nextval>>21) & 31)!=spare_reg))
{
//SysPrintf("Can use reg %d\r\n", spare_reg);
Y_fixes[n2fix].instr[1] = nextval;
Y_fixes[n2fix].spare_reg = spare_reg;
}
}
// segue-se jr ra
if (nextval == 0x03e00008)
Y_fixes[n2fix].has2return2 = 1;
// segue-se j ou jal, sync, beq ou bne
if ( ((nextval>>26)==2) || ((nextval>>26)==3) || (nextval==0xF) || ((nextval>>26)==4) || ((nextval>>26)==5))
{
Y_fixes[n2fix].has2flip = 1;
// this save follows the previous
if ((n2fix>0) && ((Y_fixes[n2fix].offset-Y_fixes[n2fix-1].offset)==8))
{
Y_fixes[n2fix-1].do2=1;
Y_fixes[n2fix].do2=2;
}
}
}
//
n2fix++;
posfnd++;
posfnd2++;
}
}
// search for a repeated use of the saved reg
if (sfchange)
{
if ((buf[i]>>16) == ((0x19<<10)|(fxreg<<5)|fxreg)) //daddiu saved_reg, saved_reg, 0xXXXX
{
nofix=1;
}
if ((((buf[i]&0x7FF)==0x2F)&&((buf[i]>>26)==0)) //dsubu saved_reg, saved_reg, reg
||(((buf[i]&0x7FF)==0x2D)&&((buf[i]>>26)==0))) //daddu saved_reg, saved_reg, reg
{
if ((((buf[i]>>11)&31)==fxreg)&&(((buf[i]>>21)&31)==fxreg))
nofix=1;
}
sfchange--;
}
/////////////////////////////////////
// track modifications of registers
if ( (buf[i]&0xFC000000) == 0x24000000) // addiu reg, reg2, $xxxx
{
reg = (buf[i]>>16) & 31;
reg2 = (buf[i]>>21) & 31;
value = buf[i] & 0xFFFF;
reg_values[reg] = reg_values[reg2] + value;
}
// search lw reg2, $xxxx(reg)
// search ld reg2, $xxxx(reg)
if (((buf[i]>>26)==0x23)||((buf[i]>>26)==0x37))
{
reg2 = (buf[i]>>16) & 31;
reg_values[reg2] = 0; // set it to zero
}
// ... (more to add)
//
/////////////////////////////////////
// search ld ra, $xxxx(reg)
if ( ((buf[i]&0xFC1F0000) == 0xDC1F0000) // ld ra, $xxxx(reg)
|| ((buf[i]&0xFC1F0000) == 0x781F0000) ) // lq ra, $xxxx(reg)
{
enable_jr = 1;
for (;posfnd>0;posfnd--)
{
Y_fixes[n2fix-posfnd].can_use_jr = 1;
}
posfnd=0;
}
// search ei
if (buf[i] == 0x42000038)
{
for (;posfnd2>0;posfnd2--)
{
Y_fixes[n2fix-posfnd2].ei = 1;
}
posfnd2=0;
}
// reset
if (have2reset==1)
{
have2reset=0;
memset(reg_values, 0, 32*4);
enable_jr = 0;
enable_sd = 0;
posfnd = 0;
posfnd2 = 0;
sfchange=0;
}
// search jr ra
// search addiu sp,sp,0xXXXX
if ((buf[i] == 0x03e00008) || ((buf[i]&0xFFFF0000) == 0x27BD0000))
{
have2reset=1;
/*
memset(reg_values, 0, 32*4);
enable_jr = 0;
enable_sd = 0;
posfnd = 0;
posfnd2 = 0;
*/
}
}
store_last = buf[count-1];
offset += count;
}
fclose(fid);
//Exit(0);
fid = fopen(argv[1], "r+b");
if (fid == NULL)
{
SysPrintf("File %s is read only.\r\n", argv[1]);
Exit(1);
}
if (nN == 0)
{
if (nP>0)
SysPrintf("PAL 2 NTSC: already patched.\r\n");
else
SysPrintf("PAL 2 NTSC: could not find any patch locations.\r\n");
}
else
{
SysPrintf("PAL 2 NTSC: found %d patch locations.\r\n", nN);
if (nP > 0)
SysPrintf(" Also found %d locations already patched.\r\n", nP);
for (i=0;i<nN;i++)
{
SysPrintf("Patching...");
fseek(fid, vmN[i], SEEK_SET);
fwrite(set_v2PAL, 4, 4, fid);
SysPrintf(" Done.\r\n");
}
wasmodified=1;
}
for (i=0;i<elfHeader.e_phnum;i++)
{
if (elfProgH[i].p_type == 0x1)
{
unsigned int offs1=elfProgH[i].p_offset, offs2=elfProgH[i].p_offset+elfProgH[i].p_filesz;
if ((n2fix>0)&&(offs1<=Y_fixes[0].offset)&&(offs2>=Y_fixes[n2fix-1].offset))
{
if (nN>0)
{
if ((offs1<=vmN[0])&&(offs2>=vmN[nN-1]))
{
phnum=i;
break;
}
}
else if (nP>0)
{
if ((offs1<=vmP[0])&&(offs2>=vmP[nP-1]))
{
phnum=i;
break;
}
}
else
{
phnum=i;
break;
}
}
}
}
if ((n2fix>0)&&((elfHeader.e_phnum == 0)||(phnum==-1)))
{
SysPrintf("Elf program header not found.\r\n");
SysPrintf("Aborting.\r\n");
fclose(fid);
Exit(0);
}
/////////////////
// selector
/////////////////
for (i=0;i<nN;i++)
{
u_vmode[u_posv] = vmN[i];
u_posv++;
}
for (i=0;i<nP;i++)
{
u_vmode[u_posv] = vmP[i];
u_posv++;
}
for (i=0;i<u_posv;i++)
u_vmode[i] = u_vmode[i]-elfProgH[phnum].p_offset+elfProgH[phnum].p_vaddr;
//
for (i=0;i<n2fix;i++)
{
u_yfix[i*3+0] = Y_fixes[i].offset-elfProgH[phnum].p_offset+elfProgH[phnum].p_vaddr;
u_yfix[i*3+1]=Y_fixes[i].instr[0];
u_yfix[i*3+2]=Y_fixes[i].instr[1];
}
//
#ifdef PS2LOADV7
for (i=0;i<u_posys;i++)
u_syscall[i] = u_syscall[i]-elfProgH[phnum].p_offset+elfProgH[phnum].p_vaddr;
#endif
//
if (n2fix == 0)
{
SysPrintf("Y FIX: could not find any patch locations.\r\n");
fclose(fid);
}
else
{
SysPrintf("\r\n");
SysPrintf("Y FIX: found %d patch locations.\r\n", n2fix);
user_option_1 = 1;
////////////////////////////////////
// DETECT BRANCHES TO THE NEXT INSTRUCTION (THE ONE FOLLOWING SD)
fclose(fid);
fid=fopen(argv[1], "rb");
for (i=0;i<n2fix;i++)
{
address = Y_fixes[i].offset-elfProgH[phnum].p_offset+elfProgH[phnum].p_vaddr;
address+=4;
fseek(fid, Y_fixes[i].offset-512*4, SEEK_SET);
count=fread(buf, 4, 1024, fid);
for (j=0;j<count;j++)
{
value=(buf[j]>>26);
if ((value==4)||(value==20)||(value==5)||(value==21)) // search beq,beql,bne,bnel
{
if ((buf[j]&0xFFFF)==(512-j))
{
Y_fixes[i].no_nop=1;
Y_fixes[i].has2flip=1; // poderia esolher a de cima
// embora ela nao esteja ainda implementada
//MessageBox(0, "arafaf","gfagaga",MB_OK);
if ((i>0) && ((Y_fixes[i].offset-Y_fixes[i-1].offset)==8))
{
Y_fixes[i-1].do2=1;
Y_fixes[i].do2=2;
}
}
}
}
}
fclose(fid);
fid=fopen(argv[1], "r+b");
//////////////////////////////////////
space_av = elfProgH[phnum].p_offset-(elfHeader.e_phoff + elfHeader.e_phnum * elfHeader.e_phentsize);
space_nd = 0;
for (i=0;i<n2fix;i++)
{
if ((Y_fixes[i].spare_reg == 0)||(Y_fixes[i].spare_reg == Y_fixes[i].saved_reg)||(Y_fixes[i].spare_reg == Y_fixes[i].base_reg)||(Y_fixes[i].has2return == 1)||(Y_fixes[i].has2return2 == 1)||(Y_fixes[i].has2flip == 1)||(Y_fixes[i].has2jump != 0))
space_nd += 16;
else
space_nd += 8;
}
// Start file offset must be a power of two ?
////////space_nd = next2power(space_nd);
if (space_av<(space_nd*4))
{
spare_space=(filesize/2048+1)*2048-filesize;
if (spare_space==2048)
spare_space=0;
space_av=space_av-(space_av%16);
please_inform=0;
if (((space_av+spare_space)>=(space_nd*4)) || (pn_selector))
{
//MessageBox(0,"ILLEGAL FILE TYPE", "PS2 PAL 2 NTSC W/ YFIX", MB_OK|MB_ICONINFORMATION);
please_inform=1;
extra_space=space_nd*4-space_av;
elfHeader.e_shoff += extra_space;
for (i=0;i<elfHeader.e_phnum;i++)
{
if (elfProgH[i].p_offset!=0)
elfProgH[i].p_offset += extra_space;
if (elfProgH[i].p_align>1)
{
while ((elfProgH[i].p_offset%elfProgH[i].p_align)!=0)
elfProgH[i].p_align = elfProgH[i].p_align/2;
if (elfProgH[i].p_align==1)
elfProgH[i].p_align=0;
}
}
for (i=0;i<elfHeader.e_shnum;i++)
{
if (elfSectH[i].sh_offset!=0)
elfSectH[i].sh_offset += extra_space;
if (elfSectH[i].sh_addralign>1)
{
while ((elfSectH[i].sh_offset%elfSectH[i].sh_addralign)!=0)
elfSectH[i].sh_addralign = elfSectH[i].sh_addralign/2;
if (elfSectH[i].sh_addralign==1)
elfSectH[i].sh_addralign=0;
}
}
for (i=0;i<n2fix;i++)
{
Y_fixes[i].offset += extra_space;
}
memset(buf_2, 0, extra_space);
fclose(fid);
fid=fopen(argv[1], "ab");
fwrite(buf_2, 1, extra_space, fid);
fclose(fid);
fid=fopen(argv[1], "r+b");
rd_pos=filesize;
wt_pos=filesize+extra_space;
while (rd_pos>0)
{
rd_pos-=4*1024;
wt_pos-=4*1024;
num2read=4*1024;
if (rd_pos<0)
{
num2read=4*1024+rd_pos;
rd_pos=0;
wt_pos=extra_space;
}
fseek(fid, rd_pos, SEEK_SET);
fread(buf_2, 1, num2read, fid);
fseek(fid, wt_pos, SEEK_SET);
fwrite(buf_2, 1, num2read, fid);
}
fclose(fid);
fid=fopen(argv[1], "r+b");
space_av=space_nd*4;
}
else
{
SysPrintf("Unable to patch Y pos.\r\n");
SysPrintf("Wait for the next program release or contact the author.\r\n");
SysPrintf("Aborting.\r\n");
fclose(fid);
Exit(0);
}
}
use_short_sub = 1;
if (space_av>=(n2fix*16*4))
use_short_sub = 0;
for (i=0;i<n2fix;i++)
{
/*
if (Y_fixes[i].ei==1)
{
SysPrintf("Unable to patch.\r\n");
continue;
}
*/
if (Y_fixes[i].nofix==1)
{
SysPrintf("Skipped.\r\n");
continue;
}
if (Y_fixes[i].do2==1)
SysPrintf("Patching 2...");
else if (Y_fixes[i].do2!=2)
SysPrintf("Patching...");
Y_fixes[i].address = Y_fixes[i].offset-elfProgH[phnum].p_offset+elfProgH[phnum].p_vaddr;
/**********/if ((use_short_sub||(user_option_1==2)) && (Y_fixes[i].spare_reg > 0) && (Y_fixes[i].spare_reg != Y_fixes[i].saved_reg) && (Y_fixes[i].spare_reg != Y_fixes[i].base_reg) && (Y_fixes[i].has2return == 0) && (Y_fixes[i].has2return2 == 0) && (Y_fixes[i].has2flip == 0) && (Y_fixes[i].has2jump == 0))
value = (elfProgH[phnum].p_vaddr-8*4-wbytes)>>2;
else
value = (elfProgH[phnum].p_vaddr-16*4-wbytes)>>2;
//
if (Y_fixes[i].do2==2)
{
unsigned int tempdo2;
fseek(fid, dupofs, SEEK_SET);
tempdo2=0x08000000|value;
fwrite(&tempdo2, 4, 1, fid);
}
//
fseek(fid, Y_fixes[i].offset, SEEK_SET);
if ((Y_fixes[i].has2return==1) || ((Y_fixes[i].has2return2==1)&&(Y_fixes[i].has2flip==0)))
{
value |= 0x08000000; //j
memcpy(Sub, sub2, 16*4);
}
else if ((Y_fixes[i].can_use_jr) && (Y_fixes[i].has2jump == 0))
{
value |= 0x0C000000; //jal
/**************/if ((use_short_sub||(user_option_1==2)) && (Y_fixes[i].spare_reg > 0) && (Y_fixes[i].spare_reg != Y_fixes[i].saved_reg) && (Y_fixes[i].spare_reg != Y_fixes[i].base_reg) && (Y_fixes[i].has2flip==0))
memcpy(Sub, sub4, 8*4);
else
memcpy(Sub, sub2, 16*4);
}
else
{
value |= 0x08000000; //j
/**************/if ((use_short_sub||(user_option_1==2)) && (Y_fixes[i].spare_reg > 0) && (Y_fixes[i].spare_reg != Y_fixes[i].saved_reg) && (Y_fixes[i].spare_reg != Y_fixes[i].base_reg) && (Y_fixes[i].has2flip==0) && (Y_fixes[i].has2jump == 0))
{
memcpy(Sub, sub3, 8*4);
Sub[5] |= (Y_fixes[i].address+8)>>2;
}
else
{
memcpy(Sub, sub1, 16*4);
if (Y_fixes[i].has2jump != 0)
{
if (Y_fixes[i].has2jump >= 0x8000 )
Sub[9] |= (Y_fixes[i].address-((0xFFFF-Y_fixes[i].has2jump)<<2))>>2;
else
Sub[9] |= (Y_fixes[i].address+(Y_fixes[i].has2jump<<2)+0)>>2;
}
else if (Y_fixes[i].has2flip==0)
Sub[9] |= (Y_fixes[i].address+8)>>2;
else
Sub[9] |= (Y_fixes[i].address+4)>>2;
}
}
if (Y_fixes[i].do2==2) goto nextstep;
if (Y_fixes[i].has2return==1)
{
fseek(fid, Y_fixes[i].offset-4, SEEK_SET);
fwrite(&value, 4, 1, fid);
fseek(fid, Y_fixes[i].offset, SEEK_SET);
value=0;
fwrite(&value, 4, 1, fid);
/////////////////
// selector
/////////////////
u_yfix[i*3+0] -= 4;
u_yfix[i*3+1]=Y_fixes[i].instr[2];
u_yfix[i*3+2]=Y_fixes[i].instr[0];
}
else if (Y_fixes[i].has2flip==1)
{
unsigned int tempo;
fseek(fid, Y_fixes[i].offset-4, SEEK_SET);
fread(&tempo, 4, 1, fid);
fseek(fid, Y_fixes[i].offset, SEEK_SET);
if (Y_fixes[i].has2jump != 0)
tempo=0;
fwrite(&tempo, 4, 1, fid);
fseek(fid, Y_fixes[i].offset-4, SEEK_SET);
fwrite(&value, 4, 1, fid);
/////////////////
// selector
/////////////////
u_yfix[i*3+0] -= 4;
u_yfix[i*3+1]=Y_fixes[i].instr[2];
u_yfix[i*3+2]=Y_fixes[i].instr[0];
}
else if (Y_fixes[i].has2return2==1)
{
fwrite(&value, 4, 1, fid);
fseek(fid, Y_fixes[i].offset+4, SEEK_SET);
value=0;
fwrite(&value, 4, 1, fid);
}
else
{
fwrite(&value, 4, 1, fid);
//if (Y_fixes[i].spare_reg == Y_fixes[i].saved_reg)
{
fseek(fid, Y_fixes[i].offset+4, SEEK_SET);
value=0;
fwrite(&value, 4, 1, fid);
}
}
//
// I do not know if it will be needed
/*
if (Y_fixes[i].do2==1)
{
fseek(fid, Y_fixes[i].offset+4, SEEK_SET);
value=0;
fwrite(&value, 4, 1, fid);
}
*/
nextstep:
/**********/if ((use_short_sub||(user_option_1==2)) && (Y_fixes[i].spare_reg > 0) && (Y_fixes[i].spare_reg != Y_fixes[i].saved_reg) && (Y_fixes[i].spare_reg != Y_fixes[i].base_reg) && (Y_fixes[i].has2return == 0) && (Y_fixes[i].has2return2 == 0) && (Y_fixes[i].has2flip == 0))
{
if (user_option_1==2)
{
Sub[0] = 0x3C000005;
Sub[0] |= (Y_fixes[i].spare_reg)<<16;
}
else
Sub[0] |= (Y_fixes[i].spare_reg)<<16;
value = ((Y_fixes[i].saved_reg)<<10) | ((Y_fixes[i].spare_reg)<<5) | (Y_fixes[i].saved_reg);
Sub[1] |= value<<11;
value = ((Y_fixes[i].saved_reg)<<5) | (Y_fixes[i].saved_reg);
if (user_option_1==2)
{
Sub[2] |= (value<<16) | 0x801C;
}
else
Sub[2] |= (value<<16);// | 0x14; // X-FIX
Sub[3] = Y_fixes[i].instr[0];
if (Y_fixes[i].do2!=1)
Sub[4] = Y_fixes[i].instr[1];
//
if (Y_fixes[i].do2==1)
dupofs=elfProgH[phnum].p_offset-8*4-wbytes+5*4;
//
fseek(fid, elfProgH[phnum].p_offset-8*4-wbytes, SEEK_SET);
fwrite(Sub, 4, 8, fid);
wbytes += 8*4;
}
else
{
value = ((Y_fixes[i].saved_reg)<<5) | (Y_fixes[i].saved_reg);
Sub[0] |= value<<16;
Sub[1] |= value<<16;
Sub[2] |= value<<16;
Sub[3] |= value<<16;
Sub[4] |= value<<16;
Sub[5] |= value<<16;
Sub[6] |= value<<16;
Sub[7] |= (value<<16);// | 0x14; // X-FIX
Sub[8] = Y_fixes[i].instr[0];
//if (Y_fixes[i].spare_reg == Y_fixes[i].saved_reg)
if ((Y_fixes[i].has2return != 1) && (Y_fixes[i].has2return2 != 1) && (Y_fixes[i].has2flip != 1) && (Y_fixes[i].do2!=1))
Sub[10] = Y_fixes[i].instr[1];
//
if (Y_fixes[i].do2==1)
dupofs=elfProgH[phnum].p_offset-16*4-wbytes+9*4;
//
fseek(fid, elfProgH[phnum].p_offset-16*4-wbytes, SEEK_SET);
fwrite(Sub, 4, 16, fid);
wbytes += 16*4;
}
/**********/if ( (user_option_1==2) && (Y_fixes[i].spare_reg == 0) )
SysPrintf(" WARNING: had to use small offset. ");
if (Y_fixes[i].do2==1)
SysPrintf(" Done.");
else
SysPrintf(" Done.\r\n");
}
fclose(fid);
// Change Elf Program Header
elfProgH[phnum].p_offset -= wbytes;
elfProgH[phnum].p_vaddr -= wbytes;
if (elfProgH[phnum].p_paddr>0)
elfProgH[phnum].p_paddr -= wbytes;
elfProgH[phnum].p_filesz += wbytes;
elfProgH[phnum].p_memsz += wbytes;
value = elfProgH[phnum].p_vaddr;
p_align=1;
while ((value%2)==0)
{
value = value/2;
p_align *= 2;
}
if (p_align==1)
p_align=0;
if ((p_align<elfProgH[phnum].p_align)||((p_align%elfProgH[phnum].p_align)!=0))
elfProgH[phnum].p_align = p_align;
// Change Elf Section Header
for (i=0;i<elfHeader.e_shnum;i++)
{
if (elfSectH[i].sh_flags & 0x2)
{
unsigned int offs1=elfSectH[i].sh_offset, offs2=elfSectH[i].sh_offset+elfSectH[i].sh_size;
if ((offs1<=Y_fixes[0].offset)&&(offs2>=Y_fixes[n2fix-1].offset))
{
if (nN>0)
{
if ((offs1<=vmN[0])&(offs2>=vmN[nN-1]))
{
shnum=i;
break;
}
}
else
{
shnum=i;
break;
}
}
}
}
if (elfHeader.e_shnum==0)
SysPrintf("Warning: No section headers.\r\n");
else if (shnum==-1)
SysPrintf("Warning: Elf section header not found.\r\n");
else
{
//SysPrintf("%s\r\n",sections_names);
//if (strncmp(§ions_names[elfSectH[shnum].sh_name],".text",5)!=0)
// SysPrintf("Warning: Expected .text section.\r\n");
elfSectH[shnum].sh_addr -= wbytes;
elfSectH[shnum].sh_offset -= wbytes;
elfSectH[shnum].sh_size += wbytes;
value = elfSectH[shnum].sh_addr;
p_align=1;
while ((value%2)==0)
{
value = value/2;
p_align *= 2;
}
if (p_align==1)
p_align=0;
if ((p_align<elfSectH[shnum].sh_addralign)||((p_align%elfSectH[shnum].sh_addralign)!=0))
elfSectH[shnum].sh_addralign = p_align;
}
saveElfFile(argv[1]);
SysPrintf("\r\nAll done.\r\n");
wasmodified=1;
}
}
unsigned int next2power(unsigned int n)
{
unsigned int p;
p=1;
while (p<n)
p=p*2;
return p;
}
// search for the begin of the function where the call is made
unsigned int calledby(FILE *fid, unsigned int offset)
{
unsigned int i, num2read, count;
// fill buffer
if (offset >= 4*1024)
{
num2read = 4*1024;
fseek(fid, offset-4*1024, SEEK_SET);
count = fread(buf, 4, 1024, fid);
//num2read=ftell(fid);
}
else
{
num2read = offset;
fseek(fid, 0, SEEK_SET);
count = fread(buf, 0, offset>>2, fid);
}
for (i=0;i<count;i++)
{
if (((buf[count-i-1]>>16) == 0x27BD) && // ADDIU sp, sp, xxxx
((buf[count-i-1]&0xFFFF) >= 0x8000) )
{
offset = offset-4*(i+1);
break;
}
}
return offset;
}
// returns:
// -1: error
// 0: file not compressed
// 1: file compressed
int check_compressed(char *filename)
{
FILE *fid;
unsigned int i, numread, conta[256], filesize, sum, bz;
//unsigned int max_val, max_pos, max_prob;
fid = fopen(filename, "rb");
if (fid==NULL)
return -1;
fseek(fid, 0, SEEK_END);
filesize = ftell(fid);
fseek(fid, 0, SEEK_SET);
for (i=0;i<256;i++)
conta[i]=0;
bz=0;
while (!feof(fid))
{
numread = fread(buf_2, 1, 4*1024, fid);
for (i=0;i<numread;i++)
conta[buf_2[i]]++;
sum=0;
for (i=0;i<numread;i++)
sum+=buf_2[i];
//if (numread==4*1024)
{
if (sum==0)
bz++;
else
bz=0;
}
}
fclose(fid);
/*
max_pos=1;
max_val=conta[1];
for (i=2;i<256;i++)
{
if (conta[i]>max_val)
{
max_val=conta[i];
max_pos=i;
}
}
max_prob = (double)(filesize-conta[0])/255+1;
*/
//if ((bz>0)||(max_val<max_prob))
if (bz>1)
return 1;
return 0;
}