Author Topic: I found something about region fixing  (Read 4162 times)

0 Members and 1 Guest are viewing this topic.

Offline sanni

  • Moderator
  • Hero Member
  • *****
  • Posts: 502
I found something about region fixing
« on: January 08, 2011, 06:44:23 PM »
I don't understand it though  ::sm-26.gif::
But maybe someone finds this an interesting read:

Fixing-Doc - Part 1.1

by Hotblack/Dextrose 1999

Uh oh...first doc and immediately wrong :(
I kicked the wrong part about back-copying original code from rom
But since I heard that no one can follow my explanations - who cares anyway :)

The Country-Check

Since I got some questions lately about what PALadin exactly does, I decided to write
this doc (so I don't have to write it again and again ;) )

First thing you should know, is what country-check actually means.

While booting, the bootcode writes the kind of videosystem into a
special address in the N64-Ram:


This address is called osTvType and it's value is defined as follows:

#define   OS_TV_PAL      0
#define   OS_TV_NTSC      1
#define   OS_TV_MPAL      2

That means, if your running a PAL-system, there's 0 (zero) written to $80000300

The country-check just checks this value. If a ntsc-game doesn't finds 1 (OS_TV_NTSC),
it won't start (sometimes displaying a msg about wrong video-system)

Usually a crack means killing all checks, but since there are several methods to read
a value in asm, it takes some time to find them all (they could be encrypted/packed)

A much simpler way to kick the check is writing the expected value to osTvMode
Since this value is written only once in the bootup-procedure, it can be changed
right after that when the execution of the real rom-code starts.

As you should already know (otherwise this whole info wouldn't help you much) the
entry-point in RAM is stored in the header at $b0000008.
The code beginning at $b0001000 (that's in the rom) is copied and execution continues
there, after the boot-procedure is finished.

[The address itself is $1000. If we talk about an address in RAM we need to add $80000000
and if it's the ROM-address we have to add $b0000000]

Now, what does PALadin do?

Let's look into an example. This rom has it's entrypoint at $80161600 and here's the
original code:

$80161600   lui   $t0, 8007
$80161604   addiu   $t0, $t0, 8360
$80161608   addiu   $t1, $zero, 2530

We don't care, what that code does. It's unimportant and we only need it to get the rom
working again after we patched it.

PALadin inserts some code at the very end of the rom (hoping, there's no vital information
stored ;) ) and replaces the code above with the following:

$80161600   lui   $at, b0ff
$80161604   ori   $at, $at, ffd8
$80161608   jr   $at

You see that there are three lines changed

The first 2 instructions move $b0ffffd8 into the register $at
The next instructions jumps to the address stored in $at

$b0ffffd8 is the place, where PALadin has inserted his fixing-code (in this example!)

No let's move on to the code at the end of the rom:

$b0ffffd8   lui   $t0, a000         ; $t1 = a0000000
$b0ffffdc   ori   $t1, $zero, 1         ; $t1 = 1 (1=NTSC, 0=PAL)
$b0ffffe0   sw   $t1, 0300($t0)         ; *a0000300 = $t1

Those 3 lines do the fix. To write to a ram-address we have to use $a0000300 instead of
$80000300, because writing to $8xxxxxxx is always cached and it's not sure, that the cache
is updated to ram when the first check of the address occurs

This example is a PAL-Fix, that means we want the rom to "think" it's running on
a NTSC-system. That's why we write OS_TV_NTSC to osTvType.

$b0ffffe4   lui   $t0, 8007
$b0ffffe8   addiu   $t0, $t0, 8360
$b0ffffec   addiu   $t1, $zero, 2530

Hmm..looks familiar...those are the 3 lines which have been overwritten at the entry of the
rom. It's obvious that those lines have to be executed to get the rom working.
So PALadin just copied them here.

$b0fffff0   lui   $at, 8016
$b0fffff4   ori   $at, $at, 160c
$b0fffff8   jr   $at
$b0fffffc   nop

This is the jump back to the entry-point right after PALadins first 3 instructions
(no, we don't want them to be executed again)

This whole thing has one drawback: If the first 4 instructions of the roentry look like:

$80161600   xxx
$80161604   lui   $t1, 8360
$80161608   jr   $t1
$8016160c   addi   $t1, $t1, fff8

PALadins fix won't work. You surely can find out yourself why not ;)

There's another possibillity, which should always work.
First the entry should be overwritten with 4 instr, the last one a simple NOP
That makes sure, that the jump always sux aeh succeeds

>>>Instead of copying the 4 instr to the end we could just copy them back from the rom to ram
>>>and continue executing at the (now depatched and original) entry of the rom

Of course we can't copy them back from rom, because they're not there ;)
But we could copy them from where we stored it before (if we did)
The advantage would be, that those instructions would be executed exactly where they
would executed in the original rom - that would always work

Hmm...I think that's all
I know it was to confusing :P

Any suggestions, corrections or flames to
(well flames please to ;) )

Hotblack :)

PS: Now you see why such a country-check-removing-only PAL-Fix doesn't help PAL-Only-Users.
Even if the game would have an autodetection of the videomode and WOULD init PAL on PAL-systems,
this fix forces them to NTSC. To make it playable on Non-Multi-TVs we need to patch the
videotables (and sometimes the frequency of the sound) - but that's another story :)

Offline mic_

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 632
Re: I found something about region fixing
« Reply #1 on: January 08, 2011, 08:07:25 PM »
Psuedo-code for this operation:

jump_to_fix = assemble(
"lui $at,b0ff
 ori $at,$at,ffd8
 jr $at"

fix_tv_reg = assemble(
"lui $t0,a000
 ori $t1,$zero,1         // 1 if the target system is NTSC, 0 if PAL
 sw $t1,0300($t0)"

jump_back = assemble(
"lui $at,8016
 ori $at,$at,160c
 jr $at

memcpy(0xb0ffffe4, RAM_ENTRY, sizeof(jump_to_fix))
memcpy(RAM_ENTRY, jump_to_fix, sizeof(jump_to_fix))
memcpy(0xb0ffffd8, fix_tv_reg, sizeof(fix_tv_reg))
memcpy(0xb0fffff0, jump_back, sizeof(jump_back))

Offline Conle

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2203
Re: I found something about region fixing
« Reply #2 on: January 08, 2011, 11:27:38 PM »
I did a little research on this...

First thing:
While booting, the bootcode writes the kind of videosystem into a
special address in the N64-Ram:

If "bootcode" stands for the actual 4K bootcode,then this is incorrect.
The bootcode doesn't seem to do any checks.

Anyway.I don't see anything new except from the os tv type address.

This is the usual static patching using patterns , that most of us are familiar with but with the difference that actual hooks being called.

For example , i've got the Indiana Jones game as reference :

LOC_00042F54: (This seems to be the main check proc (being referenced few times) )
Code: [Select]
00042F54: 3C0B8000 LUI        $t3,8000

00042F58: 3C0D8000 LUI        $t5,8000

00042F5C: AD8B0004 SW         $t3,0004($t4)

00042F60: 8DAD0300 LW         $t5,0300($t5)

00042F64: 15A00007 BNE        $t5,$zero,00042F84

Code: [Select]
t5 = *(vu32*)0x80000300;

if(t5 != 0)
goto LOC_00042F84

LOC_00042F84: //Check for MPAL
Code: [Select]
00042F84: 3C0E8000 LUI        t6,8000
00042F88: 8DCE0300 LW         t6,0300(t6)

00042F8C: 24010002 ADDIU      $at,$zero,0002

00042F90: 15C10007 BNE        t6,$at,00042FB0

00042F94: 00000000 NOP


Code: [Select]
t6 = *(vu32*)0x80000300;
at = 0x00000002;

if(t6 != at)
goto LOC_00042FB0


Code: [Select]
...code code code code code

00042FA8: 10000006 BEQ        $zero,$zero,00042FC4

Code: [Select]
goto 00042FC4


Code: [Select]

...code code code code code

00043014: 0C010AFC JAL        00042BF0

Most games should be doing this , so , we could assume that the following op-patterns could be patched automatically:

Code: [Select]
LUI REG,IMM = $8000
LW REG,MEM(REG) //mem = $0300

So we could replace it with:
Code: [Select]
LW REG,selected_os_tv_type

Another pattern:
Code: [Select]
LW REG,MEM(REG) //mem = $0300

And will be replaced with:
Code: [Select]
LW REG,selected_os_tv_type

So there's no need to add extra code + hooks.

What im trying to say is that those are still hacks , and can always cause big trouble.
Because the game boots and plays in the first few levels , doesn't mean that it won't crash in the next FMV...

As for adding this option to the menu : Maybe,sometime :D
« Last Edit: January 08, 2011, 11:45:27 PM by Conle »

Offline mic_

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 632
Re: I found something about region fixing
« Reply #3 on: January 08, 2011, 11:56:53 PM »
What im trying to say is that those are still hacks , and can always cause big trouble.
Because the game boots and plays in the first few levels , doesn't mean that it won't crash in the next FMV...

I think that's why PALadin took the approach of modifying the value in RAM that contains the TV type, rather than patching all places that reads the value since that might be done in a lot of places and in a lot of different ways.

Offline Conle

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2203
Re: I found something about region fixing
« Reply #4 on: January 09, 2011, 12:00:58 AM »
Hmm  ~sm-72.gif~.gif

A "clean"  ~sm-57.gif~.gif solution might be to let the core do the patching job(It will be writing either 0,1 or 2 to that reserved address) every few cycles...
That way dirty hacks will go away  ~sm-67.gif~.gif

Offline Conle

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2203
Re: I found something about region fixing
« Reply #5 on: January 09, 2011, 12:02:01 AM »
I think that's why PALadin took the approach of modifying the value in RAM that contains the TV type, rather than patching all places that reads the value since that might be done in a lot of places and in a lot of different ways.

Yep , that is correct  8)

Offline ChillyWilly

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1751
  • Just a coding machine.
Re: I found something about region fixing
« Reply #6 on: January 09, 2011, 04:54:27 AM »
From my experience with the menu, the N64 sets the TV value in OS ram based on the country code in the rom header at boot time. It's why I had to make a separate PAL version of the menu. The ONLY difference I've EVER seen between US and PAL versions of N64 games (like Doom) is the country code; a hex difference on the two rom images shows only the country code as different... uh, and the checksum, naturally.

Offline Conle

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2203
Re: I found something about region fixing
« Reply #7 on: January 09, 2011, 04:53:27 PM »
I did a little research on this...

First thing:
If "bootcode" stands for the actual 4K bootcode,then this is incorrect.
The bootcode doesn't seem to do any checks.

To correct myself : Indeed , the bootcode does it!

It was a bug in my bootcode dumper + dissasembly gen using qemu's mips-dis module.

Here's how a bootcode looks like:
Code: [Select]
Dissasembly of bootcode.bin

0x0: mtc0 zero,$13
0x4: mtc0 zero,$9
0x8: mtc0 zero,$11
0xc: lui t0,0xa470
0x10: addiu t0,t0,0
0x14: lw t1,12(t0)
0x18: bnez t1,0x3d0
0x1c: nop
0x20: addiu sp,sp,-24
0x24: sw s3,0(sp)
0x28: sw s4,4(sp)
0x2c: sw s5,8(sp)
0x30: sw s6,12(sp)
0x34: sw s7,16(sp)
0x38: lui t0,0xa470
0x3c: addiu t0,t0,0
0x40: lui t2,0xa3f8
0x44: lui t3,0xa3f0
0x48: lui t4,0xa430
0x4c: addiu t4,t4,0
0x50: li t1,0x40
0x54: sw t1,4(t0)
0x58: li s1,8000
0x5c: nop
0x60: addi s1,s1,-1
0x64: bnez s1,0x5c
0x68: nop
0x6c: sw zero,8(t0)
0x70: li t1,0x14
0x74: sw t1,12(t0)
0x78: sw zero,0(t0)
0x7c: li s1,4
0x80: nop
0x84: addi s1,s1,-1
0x88: bnez s1,0x80
0x8c: nop
0x90: li t1,0xe
0x94: sw t1,0(t0)
0x98: li s1,32
0x9c: addi s1,s1,-1
0xa0: bnez s1,0x9c
0xa4: li t1,0x10f
0xa8: sw t1,0(t4)
0xac: lui t1,0x1808
0xb0: ori t1,t1,0x2838
0xb4: sw t1,8(t2)
0xb8: sw zero,20(t2)
0xbc: lui t1,0x8000
0xc0: sw t1,4(t2)
0xc4: move t5,zero
0xc8: move t6,zero
0xcc: lui t7,0xa3f0
0xd0: move t8,zero
0xd4: lui t9,0xa3f0
0xd8: lui s6,0xa000
0xdc: move s7,zero
0xe0: lui a2,0xa3f0
0xe4: lui a3,0xa000
0xe8: move s2,zero
0xec: lui s4,0xa000
0xf0: addiu sp,sp,-72
0xf4: move s8,sp
0xf8: lui s0,0xa430
0xfc: lw s0,4(s0)
0x100: lui s1,0x101
0x104: addiu s1,s1,257
0x108: bne s0,s1,0x120
0x10c: nop
0x110: li s0,512
0x114: ori s1,t3,0x4000
0x118: b 0x128
0x11c: nop
0x120: li s0,1024
0x124: ori s1,t3,0x8000
0x128: sw t6,4(s1)
0x12c: addiu s5,t7,12
0x130: jal 0x4000778
0x134: nop
0x138: beqz v0,0x21c
0x13c: nop
0x140: sw v0,0(sp)
0x144: li t1,8192
0x148: sw t1,0(t4)
0x14c: lw t3,0(t7)
0x150: lui t0,0xf0ff
0x154: and t3,t3,t0
0x158: sw t3,4(sp)
0x15c: addi sp,sp,8
0x160: li t1,4096
0x164: sw t1,0(t4)
0x168: lui t0,0xb019
0x16c: bne t3,t0,0x1a0
0x170: nop
0x174: lui t0,0x800
0x178: add t8,t8,t0
0x17c: add t9,t9,s0
0x180: add t9,t9,s0
0x184: lui t0,0x20
0x188: add s6,s6,t0
0x18c: add s4,s4,t0
0x190: sll s2,s2,0x1
0x194: addi s2,s2,1
0x198: b 0x1a8
0x19c: nop
0x1a0: lui t0,0x10
0x1a4: add s4,s4,t0
0x1a8: li t0,8192
0x1ac: sw t0,0(t4)
0x1b0: lw t1,36(t7)
0x1b4: lw k0,0(t7)
0x1b8: li t0,4096
0x1bc: sw t0,0(t4)
0x1c0: andi t1,t1,0xffff
0x1c4: li t0,1280
0x1c8: bne t1,t0,0x1f0
0x1cc: nop
0x1d0: lui k1,0x100
0x1d4: and k0,k0,k1
0x1d8: bnez k0,0x1f0
0x1dc: nop
0x1e0: lui t0,0x101c
0x1e4: ori t0,t0,0xa04
0x1e8: sw t0,24(t7)
0x1ec: b 0x1fc
0x1f0: lui t0,0x80c
0x1f4: ori t0,t0,0x1204
0x1f8: sw t0,24(t7)
0x1fc: lui t0,0x800
0x200: add t6,t6,t0
0x204: add t7,t7,s0
0x208: add t7,t7,s0
0x20c: addiu t5,t5,1
0x210: sltiu t0,t5,8
0x214: bnez t0,0x128
0x218: nop
0x21c: lui t0,0xc400
0x220: sw t0,12(t2)
0x224: lui t0,0x8000
0x228: sw t0,4(t2)
0x22c: move sp,s8
0x230: move v1,zero
0x234: lw t1,4(sp)
0x238: lui t0,0xb009
0x23c: bne t1,t0,0x298
0x240: nop
0x244: sw t8,4(s1)
0x248: addiu s5,t9,12
0x24c: lw a0,0(sp)
0x250: addi sp,sp,8
0x254: li a1,1
0x258: jal 0x4000a40
0x25c: nop
0x260: lw t0,0(s6)
0x264: lui t0,0x8
0x268: add t0,t0,s6
0x26c: lw t1,0(t0)
0x270: lw t0,0(s6)
0x274: lui t0,0x8
0x278: add t0,t0,s6
0x27c: lw t1,0(t0)
0x280: lui t0,0x400
0x284: add t6,t6,t0
0x288: add t9,t9,s0
0x28c: lui t0,0x10
0x290: add s6,s6,t0
0x294: b 0x31c
0x298: sw s7,4(s1)
0x29c: addiu s5,a2,12
0x2a0: lw a0,0(sp)
0x2a4: addi sp,sp,8
0x2a8: li a1,1
0x2ac: jal 0x4000a40
0x2b0: nop
0x2b4: lw t0,0(a3)
0x2b8: lui t0,0x8
0x2bc: add t0,t0,a3
0x2c0: lw t1,0(t0)
0x2c4: lui t0,0x10
0x2c8: add t0,t0,a3
0x2cc: lw t1,0(t0)
0x2d0: lui t0,0x18
0x2d4: add t0,t0,a3
0x2d8: lw t1,0(t0)
0x2dc: lw t0,0(a3)
0x2e0: lui t0,0x8
0x2e4: add t0,t0,a3
0x2e8: lw t1,0(t0)
0x2ec: lui t0,0x10
0x2f0: add t0,t0,a3
0x2f4: lw t1,0(t0)
0x2f8: lui t0,0x18
0x2fc: add t0,t0,a3
0x300: lw t1,0(t0)
0x304: lui t0,0x800
0x308: add s7,s7,t0
0x30c: add a2,a2,s0
0x310: add a2,a2,s0
0x314: lui t0,0x20
0x318: add a3,a3,t0
0x31c: addiu v1,v1,1
0x320: slt t0,v1,t5
0x324: bnez t0,0x234
0x328: nop
0x32c: lui t2,0xa470
0x330: sll s2,s2,0x13
0x334: lui t1,0x6
0x338: ori t1,t1,0x3634
0x33c: or t1,t1,s2
0x340: sw t1,16(t2)
0x344: lw t1,16(t2)
0x348: lui t0,0xa000
0x34c: ori t0,t0,0x300
0x350: lui t1,0xfff
0x354: ori t1,t1,0xffff
0x358: and s6,s6,t1
0x35c: sw s6,24(t0)
0x360: move sp,s8
0x364: addiu sp,sp,72
0x368: lw s3,0(sp)
0x36c: lw s4,4(sp)
0x370: lw s5,8(sp)
0x374: lw s6,12(sp)
0x378: lw s7,16(sp)
0x37c: addiu sp,sp,24
0x380: lui t0,0x8000
0x384: addiu t0,t0,0
0x388: addiu t1,t0,16384
0x38c: addiu t1,t1,-32
0x390: mtc0 zero,$28
0x394: mtc0 zero,$29
0x398: cache 0x8,0(t0)
0x39c: sltu at,t0,t1
0x3a0: bnez at,0x398
0x3a4: addiu t0,t0,32
0x3a8: lui t0,0x8000
0x3ac: addiu t0,t0,0
0x3b0: addiu t1,t0,8192
0x3b4: addiu t1,t1,-16
0x3b8: cache 0x9,0(t0)
0x3bc: sltu at,t0,t1
0x3c0: bnez at,0x3b8
0x3c4: addiu t0,t0,16
0x3c8: b 0x418
0x3cc: nop
0x3d0: lui t0,0x8000
0x3d4: addiu t0,t0,0
0x3d8: addiu t1,t0,16384
0x3dc: addiu t1,t1,-32
0x3e0: mtc0 zero,$28
0x3e4: mtc0 zero,$29
0x3e8: cache 0x8,0(t0)
0x3ec: sltu at,t0,t1
0x3f0: bnez at,0x3e8
0x3f4: addiu t0,t0,32
0x3f8: lui t0,0x8000
0x3fc: addiu t0,t0,0
0x400: addiu t1,t0,8192
0x404: addiu t1,t1,-16
0x408: cache 0x1,0(t0)
0x40c: sltu at,t0,t1
0x410: bnez at,0x408
0x414: addiu t0,t0,16
0x418: lui t2,0xa400
0x41c: addiu t2,t2,0
0x420: lui t3,0xfff0
0x424: lui t1,0x10
0x428: and t2,t2,t3
0x42c: lui t0,0xa400
0x430: addiu t1,t1,-1
0x434: lui t3,0xa400
0x438: addiu t0,t0,1216
0x43c: addiu t3,t3,1908
0x440: and t0,t0,t1
0x444: and t3,t3,t1
0x448: lui t1,0xa000
0x44c: or t0,t0,t2
0x450: or t3,t3,t2
0x454: addiu t1,t1,0
0x458: lw t5,0(t0)
0x45c: addiu t0,t0,4
0x460: sltu at,t0,t3
0x464: addiu t1,t1,4
0x468: bnez at,0x458
0x46c: sw t5,-4(t1)
0x470: lui t4,0x8000
0x474: addiu t4,t4,0
0x478: jr t4
0x47c: nop
0x480: lui t3,0xb000
0x484: lw t1,8(t3)
0x488: lui t2,0x1fff
0x48c: ori t2,t2,0xffff
0x490: lui at,0xa460
0x494: and t1,t1,t2
0x498: sw t1,0(at)
0x49c: lui t0,0xa460
0x4a0: lw t0,16(t0)
0x4a4: andi t0,t0,0x2
0x4a8: bnezl t0,0x4a0
0x4ac: lui t0,0xa460
0x4b0: li t0,4096
0x4b4: add t0,t0,t3
0x4b8: and t0,t0,t2
0x4bc: lui at,0xa460
0x4c0: sw t0,4(at)
0x4c4: lui t2,0x10
0x4c8: addiu t2,t2,-1
0x4cc: lui at,0xa460
0x4d0: sw t2,12(at)
0x4d4: nop
0x4d8: nop
0x4dc: nop
0x4e0: nop
0x4e4: nop
0x4e8: nop
0x4ec: nop
0x4f0: nop
0x4f4: nop
0x4f8: nop
0x4fc: nop
0x500: nop
0x504: nop
0x508: nop
0x50c: nop
0x510: nop
0x514: nop
0x518: nop
0x51c: nop
0x520: nop
0x524: nop
0x528: nop
0x52c: nop
0x530: nop
0x534: nop
0x538: nop
0x53c: nop
0x540: nop
0x544: lui t3,0xa460
0x548: lw t3,16(t3)
0x54c: andi t3,t3,0x1
0x550: bnez t3,0x4d4
0x554: nop
0x558: lui t3,0xb000
0x55c: lw a0,8(t3)
0x560: move a1,s6
0x564: lui at,0x5d58
0x568: ori at,at,0x8b65
0x56c: multu a1,at
0x570: addiu sp,sp,-32
0x574: sw ra,28(sp)
0x578: sw s0,20(sp)
0x57c: lui ra,0x10
0x580: move v1,zero
0x584: move t0,zero
0x588: move t1,a0
0x58c: li t5,32
0x590: mflo v0
0x594: addiu v0,v0,1
0x598: move a3,v0
0x59c: move t2,v0
0x5a0: move t3,v0
0x5a4: move s0,v0
0x5a8: move a2,v0
0x5ac: move t4,v0
0x5b0: lw v0,0(t1)
0x5b4: addu v1,a3,v0
0x5b8: sltu at,v1,a3
0x5bc: beqz at,0x5c8
0x5c0: move a1,v1
0x5c4: addiu t2,t2,1
0x5c8: andi v1,v0,0x1f
0x5cc: subu t7,t5,v1
0x5d0: srlv t8,v0,t7
0x5d4: sllv t6,v0,v1
0x5d8: or a0,t6,t8
0x5dc: sltu at,a2,v0
0x5e0: move a3,a1
0x5e4: xor t3,t3,v0
0x5e8: beqz at,0x5fc
0x5ec: addu s0,s0,a0
0x5f0: xor t9,a3,v0
0x5f4: b 0x600
0x5f8: xor a2,t9,a2
0x5fc: xor a2,a2,a0
0x600: addiu t0,t0,4
0x604: xor t7,v0,s0
0x608: addiu t1,t1,4
0x60c: bne t0,ra,0x5b0
0x610: addu t4,t7,t4
0x614: xor t6,a3,t2
0x618: xor a3,t6,t3
0x61c: xor t8,s0,a2
0x620: xor s0,t8,t4
0x624: lui t3,0xb000
0x628: lw t0,16(t3)
0x62c: bne a3,t0,0x648
0x630: nop
0x634: lw t0,20(t3)
0x638: bne s0,t0,0x648
0x63c: nop
0x640: bal 0x650
0x644: nop
0x648: bal 0x648
0x64c: nop
0x650: lui t1,0xa408
0x654: lw t1,0(t1)
0x658: lw s0,20(sp)
0x65c: lw ra,28(sp)
0x660: beqz t1,0x67c
0x664: addiu sp,sp,32
0x668: li t2,65
0x66c: lui at,0xa404
0x670: sw t2,16(at)
0x674: lui at,0xa408
0x678: sw zero,0(at)
0x67c: lui t3,0xaa
0x680: ori t3,t3,0xaaae
0x684: lui at,0xa404
0x688: sw t3,16(at)
0x68c: lui at,0xa430
0x690: li t0,1365
0x694: sw t0,12(at)
0x698: lui at,0xa480
0x69c: sw zero,24(at)
0x6a0: lui at,0xa450
0x6a4: sw zero,12(at)
0x6a8: lui at,0xa430
0x6ac: li t1,2048
0x6b0: sw t1,0(at)
0x6b4: li t1,2
0x6b8: lui at,0xa460
0x6bc: lui t0,0xa000
0x6c0: ori t0,t0,0x300
0x6c4: sw t1,16(at)
0x6c8: sw s7,20(t0)
0x6cc: sw s5,12(t0)
0x6d0: sw s3,4(t0)
0x6d4: beqz s3,0x6e8
0x6d8: sw s4,0(t0)
0x6dc: lui t1,0xa600
0x6e0: b 0x6f0
0x6e4: addiu t1,t1,0
0x6e8: lui t1,0xb000
0x6ec: addiu t1,t1,0
0x6f0: sw t1,8(t0)
0x6f4: lui t0,0xa400
0x6f8: addiu t0,t0,0
0x6fc: addi t1,t0,4096
0x700: addiu t0,t0,4
0x704: bne t0,t1,0x700
0x708: sw zero,-4(t0)
0x70c: lui t0,0xa400
0x710: addiu t0,t0,4096
0x714: addi t1,t0,4096
0x718: addiu t0,t0,4
0x71c: bne t0,t1,0x718
0x720: sw zero,-4(t0)
0x724: lui t3,0xb000
0x728: lw t1,8(t3)
0x72c: jr t1
0x730: nop
0x734: nop
0x738: addiu sp,sp,-160
0x73c: sw s0,64(sp)
0x740: sw s1,68(sp)
0x744: move s1,zero
0x748: move s0,zero
0x74c: sw v0,0(sp)
0x750: sw v1,4(sp)
0x754: sw a0,8(sp)
0x758: sw a1,12(sp)
0x75c: sw a2,16(sp)
0x760: sw a3,20(sp)
0x764: sw t0,24(sp)
0x768: sw t1,28(sp)
0x76c: sw t2,32(sp)
0x770: sw t3,36(sp)
0x774: sw t4,40(sp)
0x778: sw t5,44(sp)
0x77c: sw t6,48(sp)
0x780: sw t7,52(sp)
0x784: sw t8,56(sp)
0x788: sw t9,60(sp)
0x78c: sw s2,72(sp)
0x790: sw s3,76(sp)
0x794: sw s4,80(sp)
0x798: sw s5,84(sp)
0x79c: sw s6,88(sp)
0x7a0: sw s7,92(sp)
0x7a4: sw s8,96(sp)
0x7a8: sw ra,100(sp)
0x7ac: jal 0x4000880
0x7b0: nop
0x7b4: addiu s0,s0,1
0x7b8: slti t1,s0,4
0x7bc: bnez t1,0x7ac
0x7c0: addu s1,s1,v0
0x7c4: srl a0,s1,0x2
0x7c8: jal 0x4000a40
0x7cc: li a1,1
0x7d0: lw ra,100(sp)
0x7d4: srl v0,s1,0x2
0x7d8: lw s1,68(sp)
0x7dc: lw v1,4(sp)
0x7e0: lw a0,8(sp)
0x7e4: lw a1,12(sp)
0x7e8: lw a2,16(sp)
0x7ec: lw a3,20(sp)
0x7f0: lw t0,24(sp)
0x7f4: lw t1,28(sp)
0x7f8: lw t2,32(sp)
0x7fc: lw t3,36(sp)
0x800: lw t4,40(sp)
0x804: lw t5,44(sp)
0x808: lw t6,48(sp)
0x80c: lw t7,52(sp)
0x810: lw t8,56(sp)
0x814: lw t9,60(sp)
0x818: lw s0,64(sp)
0x81c: lw s2,72(sp)
0x820: lw s3,76(sp)
0x824: lw s4,80(sp)
0x828: lw s5,84(sp)
0x82c: lw s6,88(sp)
0x830: lw s7,92(sp)
0x834: lw s8,96(sp)
0x838: jr ra
0x83c: addiu sp,sp,160
0x840: addiu sp,sp,-32
0x844: sw ra,28(sp)
0x848: move t1,zero
0x84c: move t3,zero
0x850: move t4,zero
0x854: slti k0,t4,64
0x858: beqzl k0,0x8bc
0x85c: move v0,zero
0x860: jal 0x400090c
0x864: move a0,t4
0x868: blezl v0,0x88c
0x86c: slti k0,t1,80
0x870: subu k0,v0,t1
0x874: multu k0,t4
0x878: move t1,v0
0x87c: mflo k0
0x880: addu t3,t3,k0
0x884: nop
0x888: slti k0,t1,80
0x88c: bnez k0,0x854
0x890: addiu t4,t4,1
0x894: sll a0,t3,0x2
0x898: subu a0,a0,t3
0x89c: sll a0,a0,0x2
0x8a0: subu a0,a0,t3
0x8a4: sll a0,a0,0x1
0x8a8: jal 0x4000980
0x8ac: addiu a0,a0,-880
0x8b0: b 0x8c0
0x8b4: lw ra,28(sp)
0x8b8: move v0,zero
0x8bc: lw ra,28(sp)
0x8c0: addiu sp,sp,32
0x8c4: jr ra
0x8c8: nop
0x8cc: addiu sp,sp,-40
0x8d0: sw ra,28(sp)
0x8d4: move v0,zero
0x8d8: jal 0x4000a40
0x8dc: li a1,2
0x8e0: move s8,zero
0x8e4: li k0,-1
0x8e8: sw k0,4(s4)
0x8ec: lw v1,4(s4)
0x8f0: sw k0,0(s4)
0x8f4: sw k0,0(s4)
0x8f8: move gp,zero
0x8fc: srl v1,v1,0x10
0x900: andi k0,v1,0x1
0x904: beqzl k0,0x914
0x908: addiu gp,gp,1
0x90c: addiu v0,v0,1
0x910: addiu gp,gp,1
0x914: slti k0,gp,8
0x918: bnez k0,0x900
0x91c: srl v1,v1,0x1
0x920: addiu s8,s8,1
0x924: slti k0,s8,10
0x928: bnezl k0,0x8e8
0x92c: li k0,-1
0x930: lw ra,28(sp)
0x934: addiu sp,sp,40
0x938: jr ra
0x93c: nop
0x940: addiu sp,sp,-40
0x944: sw ra,28(sp)
0x948: sw a0,32(sp)
0x94c: sb zero,39(sp)
0x950: move t0,zero
0x954: move t2,zero
0x958: li t5,0xc800
0x95c: move t6,zero
0x960: slti k0,t6,64
0x964: bnezl k0,0x978
0x968: move a0,t6
0x96c: b 0x9f0
0x970: move v0,zero
0x974: move a0,t6
0x978: jal 0x4000a40
0x97c: li a1,1
0x980: jal 0x4000ad0
0x984: addiu a0,sp,39
0x988: jal 0x4000ad0
0x98c: addiu a0,sp,39
0x990: lbu k0,39(sp)
0x994: li k1,800
0x998: lw a0,32(sp)
0x99c: multu k0,k1
0x9a0: mflo t0
0x9a4: subu k0,t0,a0
0x9a8: bgezl k0,0x9b8
0x9ac: slt k1,k0,t5
0x9b0: subu k0,a0,t0
0x9b4: slt k1,k0,t5
0x9b8: beqzl k1,0x9cc
0x9bc: lw a0,32(sp)
0x9c0: move t5,k0
0x9c4: move t2,t6
0x9c8: lw a0,32(sp)
0x9cc: slt k1,t0,a0
0x9d0: beqzl k1,0x9ec
0x9d4: addu v0,t2,t6
0x9d8: addiu t6,t6,1
0x9dc: slti k1,t6,65
0x9e0: bnezl k1,0x964
0x9e4: slti k0,t6,64
0x9e8: addu v0,t2,t6
0x9ec: srl v0,v0,0x1
0x9f0: lw ra,28(sp)
0x9f4: addiu sp,sp,40
0x9f8: jr ra
0x9fc: nop
0xa00: addiu sp,sp,-40
0xa04: andi a0,a0,0xff
0xa08: li k1,1
0xa0c: xori a0,a0,0x3f
0xa10: sw ra,28(sp)
0xa14: bne a1,k1,0xa24
0xa18: lui t7,0x4600
0xa1c: lui k0,0x8000
0xa20: or t7,t7,k0
0xa24: andi k0,a0,0x1
0xa28: sll k0,k0,0x6
0xa2c: or t7,t7,k0
0xa30: andi k0,a0,0x2
0xa34: sll k0,k0,0xd
0xa38: or t7,t7,k0
0xa3c: andi k0,a0,0x4
0xa40: sll k0,k0,0x14
0xa44: or t7,t7,k0
0xa48: andi k0,a0,0x8
0xa4c: sll k0,k0,0x4
0xa50: or t7,t7,k0
0xa54: andi k0,a0,0x10
0xa58: sll k0,k0,0xb
0xa5c: or t7,t7,k0
0xa60: andi k0,a0,0x20
0xa64: sll k0,k0,0x12
0xa68: or t7,t7,k0
0xa6c: li k1,1
0xa70: bne a1,k1,0xa80
0xa74: sw t7,0(s5)
0xa78: lui k0,0xa430
0xa7c: sw zero,0(k0)
0xa80: lw ra,28(sp)
0xa84: addiu sp,sp,40
0xa88: jr ra
0xa8c: nop
0xa90: addiu sp,sp,-40
0xa94: sw ra,28(sp)
0xa98: li k0,8192
0xa9c: lui k1,0xa430
0xaa0: sw k0,0(k1)
0xaa4: move s8,zero
0xaa8: lw s8,0(s5)
0xaac: li k0,4096
0xab0: sw k0,0(k1)
0xab4: li k1,64
0xab8: and k1,k1,s8
0xabc: srl k1,k1,0x6
0xac0: move k0,zero
0xac4: or k0,k0,k1
0xac8: li k1,16384
0xacc: and k1,k1,s8
0xad0: srl k1,k1,0xd
0xad4: or k0,k0,k1
0xad8: lui k1,0x40
0xadc: and k1,k1,s8
0xae0: srl k1,k1,0x14
0xae4: or k0,k0,k1
0xae8: li k1,128
0xaec: and k1,k1,s8
0xaf0: srl k1,k1,0x4
0xaf4: or k0,k0,k1
0xaf8: li k1,0x8000
0xafc: and k1,k1,s8
0xb00: srl k1,k1,0xb
0xb04: or k0,k0,k1
0xb08: lui k1,0x80
0xb0c: and k1,k1,s8
0xb10: srl k1,k1,0x12
0xb14: or k0,k0,k1
0xb18: sb k0,0(a0)
0xb1c: lw ra,28(sp)
0xb20: addiu sp,sp,40
0xb24: jr ra
0xb28: nop
0xb2c: nop
0xb30: movf v0,s0,$fcc0
0xb34: 0x400a0088
0xb38: bltz v0,0x9344
0xb3c: j 0x4107fc
0xb40: j 0x210110
0xb44: 0x120087f
0xb48: 0x2041010
0xb4c: lb a0,1056(a0)
0xb50: 0x41fe0808
0xb54: 0x40220110
0xb58: j 0x2011010
0xb5c: 0x3fc00700
0xb60: lwc1 $f8,2176(s0)
0xb64: li at,16386
0xb68: sll zero,s0,0x2
0xb6c: sllv s2,zero,s0
0xb70: 0x40418c03
0xb74: lb s8,524(v1)
0xb78: beq zero,s0,0xfffffffffffe0c8c
0xb7c: 0x2200900
0xb80: srl.ob $f0,$f8,$f2[0]
0xb84: 0x1100880
0xb88: lh t8,16128(zero)
0xb8c: addu.qb zero,ra,v0
0xb90: 0x800400
0xb94: addi at,zero,-248
0xb98: 0x400200
0xb9c: b 0xfffffffffffe0bb0
0xba0: 0x3ff07f
0xba4: sc zero,4096(s0)
0xba8: lb a0,32(zero)
0xbac: 0x1ff0800
0xbb0: 0x40020010
0xbb4: 0x800400
0xbb8: addi zero,zero,1792
0xbbc: lwc1 $f8,2176(s0)
0xbc0: li at,16386
0xbc4: sra zero,s0,0x2
0xbc8: scd zero,-28668(s0)
0xbcc: 0x40618d03
0xbd0: lwl zero,4608(v0)
0xbd4: lbu a0,-32732(zero)
0xbd8: 0x12009ff
0xbdc: lwc2 $2,16402(zero)
0xbe0: 0x900480
0xbe4: li at,8200
0xbe8: bltz t8,0x4bec
0xbec: lb a0,32(zero)
0xbf0: 0x1000800
0xbf4: 0x40020010
0xbf8: 0x800400
0xbfc: addi v1,zero,-32768
0xc00: 0x40020010
0xc04: 0x800400
0xc08: addi at,zero,8
0xc0c: 0x420210
0xc10: beqz a0,0xfffffffffffe1434
0xc14: jal 0xe010088
0xc18: 0x2102082
0xc1c: bltz at,0x9424
0xc20: addi t2,zero,-32670
0xc24: add v0,s0,t0
0xc28: lb a0,544(a0)
0xc2c: j 0x1000800
0xc30: b 0xfffffffffffe0c44
0xc34: 0x200100
0xc38: j 0x10008
0xc3c: sll zero,s0,0x2
0xc40: bltz zero,0x10c04
0xc44: lb t4,112(zero)
0xc48: bltz k0,0x17454
0xc4c: lwc2 $6,16689(at)
0xc50: beq t4,t0,0xfffffffffffe3cf4
0xc54: daddi v1,t2,1048
0xc58: addi zero,a2,1088
0xc5c: addi at,t8,5128
0xc60: sb a0,-32222(v0)
0xc64: beq t0,s0,0xfffffffffffe2d78
0xc68: c0 0x220910
0xc6c: slti at,a0,17414
0xc70: addi s0,zero,3841
0xc74: lh s0,2176(s0)
0xc78: sub.ob $f0,$f8,$f1[0]
0xc7c: 0x500280
0xc80: bnez zero,0xfffffffffffe4ca4
0xc84: lb v1,3079(v0)
0xc88: lb ra,-32254(v1)
0xc8c: beq zero,t0,0xfffffffffffe0da0
0xc90: 0x2201101
0xc94: jal 0xfc10008
0xc98: sll zero,s0,0x2
0xc9c: bltz zero,0x8ca0
0xca0: jal 0xc061840
0xca4: j 0x2012004
0xca8: 0x400a0050
0xcac: 0x2801410
0xcb0: lbu t0,-32445(v0)
0xcb4: jal 0x1e41fc
0xcb8: lb v0,4104(s0)
0xcbc: lb a0,544(v0)
0xcc0: addi s8,t7,2080
0xcc4: 0x40820410
0xcc8: beqz a0,0xfffffffffffe1cd4
0xccc: addi s0,zero,8065
0xcd0: 0x2100880
0xcd4: mfc1 zero,$f2
0xcd8: madd t6,zero,zero
0xcdc: 0x40011008
0xce0: lb v0,1039(v0)
0xce4: ll ra,-4080(v1)
0xce8: 0x800400
0xcec: addi at,zero,8
0xcf0: 0x400200
0xcf4: b 0xfffffffffffe0d08
0xcf8: 0x200100
0xcfc: 0x40220110
0xd00: j 0x2011008
0xd04: addi s1,zero,136
0xd08: bltz v0,0x9510
0xd0c: j 0x410204
0xd10: j 0x1e0100
0xd14: beqz s0,0xfffffffffffe2d38
0xd18: 0x40420208
0xd1c: addi at,v0,272
0xd20: j 0x2011004
0xd24: 0x400a0020
0xd28: syscall 0x40208
0xd2c: beqz v1,0xfffffffffffe1758
0xd30: addiu s1,v0,8841
0xd34: bne v0,a1,0x5dd8
0xd38: sb a1,2600(t2)
0xd3c: addi at,a0,1032
0xd40: addi zero,v0,4353
0xd44: bltzal zero,0x8f48
0xd48: lwl v0,-32760(zero)
0xd4c: 0x400500
0xd50: 0x44041020
0xd54: lb v0,8200(s0)
0xd58: 0x40110108
0xd5c: j 0x820220
0xd60: bltz v0,0x5d64
0xd64: 0x40020010
0xd68: 0x800400
0xd6c: addi at,zero,127
0xd70: sc at,16(zero)
0xd74: 0x1000800
0xd78: lb t0,128(zero)
0xd7c: j 0x20010
0xd80: 0x400400
0xd84: 0x3ff00f80
0xd88: lb t0,2112(s0)
0xd8c: c0 0x21010
0xd90: lb a0,1056(a0)
0xd94: addi at,t0,2056
0xd98: 0x40410407
0xd9c: ll v0,48(zero)
0xda0: 0x2800400
0xda4: addi at,zero,8
0xda8: 0x400200
0xdac: b 0xfffffffffffe0dc0
0xdb0: 0x200100
0xdb4: jal 0xc021020
0xdb8: beqz v0,0xfffffffffffe0dcc
0xdbc: 0x200200
0xdc0: addi v0,zero,32
0xdc4: 0x2002002
0xdc8: 0x1fe00f
0xdcc: 0x840810
0xdd0: 0x40800400
0xdd4: 0x401c0010
0xdd8: 0x400208
0xddc: beqz v0,0xfffffffffffe1200
0xde0: bltz gp,0x11e4
0xde4: blez zero,0xffffffffffff0e10
0xde8: 0x900480
0xdec: 0x44042021
0xdf0: 0x2081ff8
0xdf4: 0x2001000
0xdf8: lb ra,-32512(zero)
0xdfc: j 0x10008
0xe00: srl s0,s7,0x3
0xe04: tgei zero,64
0xe08: 0x2081040
0xe0c: lb t0,1920(t0)
0xe10: jal 0xc021020
0xe14: beqz v0,0xfffffffffffe1618
0xe18: b 0xfffffffffffefe34
0xe1c: beqz at,0x11228
0xe20: j 0x410204
0xe24: j 0x1e00fc
0xe28: ll v0,32(zero)
0xe2c: 0x1001000
0xe30: lb a0,64(zero)
0xe34: movf v0,s0,$fcc0
0xe38: sll zero,t0,0x1
0xe3c: 0x2000f00
0xe40: lh t0,4160(zero)
0xe44: lb a0,2112(s0)
0xe48: lui v0,0x1020
0xe4c: mftr at,v0,0,0,1
0xe50: mtc0 at,$1,7
0xe54: lb t7,132(zero)
0xe58: j 0x410208
0xe5c: bltzal zero,0x8f6c
0xe60: 0x1e80040
0xe64: 0x2081040
0xe68: lb t0,1920(t0)
0xe6c: 0x2001000
0xe70: lb a0,32(zero)
0xe74: 0x1000800
0xe78: 0x40020010
0xe7c: nop
0xe80: addi at,zero,216
0xe84: bltz s6,0x568c
0xe88: addi zero,zero,0
0xe8c: nop
0xe90: nop
0xe94: nop
0xe98: sll zero,zero,0x11
0xe9c: addi at,s0,4104
0xea0: lh ra,1088(ra)
0xea4: addi at,s0,4104
0xea8: lb ra,-31680(ra)
0xeac: addi at,s0,4104
0xeb0: lb zero,1536(a2)
0xeb4: beq zero,at,0xeb8
0xeb8: nop
0xebc: nop
0xec0: nop
0xec4: nop
0xec8: nop
0xecc: lb a0,16676(v0)
0xed0: bltz t2,0x7ed4
0xed4: 0x40070054
0xed8: bltzal a0,0x11fdc
0xedc: addi zero,zero,0
0xee0: sll zero,zero,0x2
0xee4: bltz zero,0x8eec
0xee8: dsrl32 at,t0,0x1f
0xeec: 0x2001000
0xef0: lb a0,32(zero)
0xef4: nop
0xef8: nop
0xefc: nop
0xf00: nop
0xf04: movf a2,zero,$fcc0
0xf08: lb a0,64(zero)
0xf0c: nop
0xf10: nop
0xf14: nop
0xf18: jal 0xff80000
0xf1c: nop
0xf20: nop
0xf24: nop
0xf28: nop
0xf2c: nop
0xf30: nop
0xf34: andi at,zero,0x8000
0xf38: nop
0xf3c: sllv t0,zero,zero
0xf40: 0x400400
0xf44: 0x40040040
0xf48: bltz zero,0x10f5c
0xf4c: 0x400400
0xf50: mfc0 zero,$0
0xf54: syscall
0xf58: 0x600000
0xf5c: nop
0xf60: sll zero,zero,0x6
0xf64: jal 0x0
0xf68: nop
0xf6c: nop
0xf70: 0x3ff800
0xf74: sra zero,zero,0x0
0xf78: sd zero,0(gp)
0xf7c: nop
0xf80: bltz t8,0x11f94
0xf84: beqz at,0xfffffffffffe0f98
0xf88: 0x400400
0xf8c: 0x40020010
0xf90: nop
0xf94: addi at,zero,7
0xf98: 0xc60808
0xf9c: lb a0,12610(at)
0xfa0: c2 0x225122
0xfa4: lwl v0,13840(t1)
0xfa8: 0x2402186
0xfac: 0x3c00000
0xfb0: nop
0xfb4: nop
0xfb8: nop
0xfbc: nop

The BC also writes to the non-cached address compared to what most games do : read from cached area + cache sync.

I'm attaching here the source of my tools(note : libbfd-dev is required) in case someone want's to 'play' with them.
« Last Edit: January 09, 2011, 05:45:27 PM by Conle »

Offline Dr.neo

  • Administrator
  • Hero Member
  • *****
  • Posts: 3826
Re: I found something about region fixing
« Reply #8 on: January 10, 2011, 11:41:35 PM »
i think you can't change this region bit so easy, because the N64 will check the BL crc every time when you power on, if this region bit was changed, it'll cause the crc different and can't make N64 power on.  ~sm-58.gif~.gif
In my world,have 0 and 1 only ......Matrix World......

Offline Conle

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2203
Re: I found something about region fixing
« Reply #9 on: January 11, 2011, 12:40:50 AM »
because the N64 will check the BL crc every time when you power on

The crc is the last thing to worry about. I've already got a crc patching module for the SD menu somewhere in my source code base  8)
But i think you're talking about the "boot code's crc...
Well , you don't have to patch the bootloader.All you have to do is to write to that ram offset the selected region code.

But of course if the n64 core could do this for us , there's no need at all for crc patching , since the core will be writing to an adress in ram every few seconds or simply
allow to write the entry point address to a myth core register , then when the core does the decoding , check if PC == EntryPoint and write to that ram address the region code passed in the region id register.
(~sm-82.gif~.gif )

« Last Edit: January 11, 2011, 12:45:20 AM by Conle »

Offline ChillyWilly

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1751
  • Just a coding machine.
Re: I found something about region fixing
« Reply #10 on: January 11, 2011, 04:23:43 AM »
I think those old methods of patching the rom were because they didn't know how the N64 set the TV mode; so they patch where the game looks for the TV mode. When you run these games from the menu, the TV mode will be set according to the country code used by the menu. It seems to me that patching the loaded rom to match the menu should be the easiest way to make games run in the same mode as the menu. Just set the code in the loaded rom to be the same as the menu, then recalculate the CRC.

Offline Conle

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2203
Re: I found something about region fixing
« Reply #11 on: January 11, 2011, 12:17:06 PM »
This patching method can only be useful for 3 reasons :

1.Fix syncing issues --for example the audio playback is messed up-- (The only game i've seen so far that does this ,  is WR64 ...and the native versions for each region work fine anyway  ~sm-82.gif~.gif)
2.Some games support hires display , so its nice to experiment with.
3.PAL systems to be able to run NTSC games at 60hz without glitches ( and vise versa )
(Most NTSC/PAL games are region free anyway and they run at 50hz/60hz on PAL/NTSC systems. )

That's all  ::sm-18.gif::
« Last Edit: January 11, 2011, 12:52:36 PM by Conle »