IPL3, the boot code
The 4032 bytes at ROM $0040–$0FFF are a program, the third stage of the console’s
boot (IPL1 and IPL2 are in the PIF chip’s ROM). IPL2 copies it into the RSP’s data memory at
$A4000040 (physical $04000040) and runs it; the mupen64plus emulator’s PIF boot code does exactly that
(pifbootrom.c copies $FC0 bytes from ROM $40 to the RSP memory). IPL3 checks the header’s check code,
then copies the program and jumps to it. The explorer disassembles it as the first code region.
It is one of a few known programs, because each is paired with a security chip in the cartridge, the CIC, which talks to the console’s PIF chip over a challenge and a seed byte. The pairing decides two things the file shows: how the check code is computed and, for two chips, the address the program really starts at.
The known variants
A boot code is named by two fingerprints of its 4032 bytes: the standard CRC-32, and the sum of its 1008 big-endian 32-bit words as a
64-bit number. They come from two different sources, so a variant seen in both has been identified twice. The CRC-32 values are from the
cargo-n64 source (src/ipl3.rs); the sums are from the mupen64plus source (src/si/cic.c).
| Chip | CRC-32 of $40–$FFF | Word sum | Check code algorithm | Notes |
|---|---|---|---|---|
| 6101 | 6170A4A1 | $D0027FDF31 or $CFFB631223 | as 6102 | Close to 6102; mupen64plus lists two sums for it. |
| 6102 (PAL: 7101) | 90BB6CB5 | $D057C85244 | as 6102 | The commonest; the boot code of the five test ROMs on this site’s emulator. |
| 7102 | 009E9EA3 | not listed | as 6102 (cargo-n64 treats it so) | N64brew: the entry point is fixed at $80000480. |
| 6103 (PAL: 7103) | 0B050EE0 | $D6497E414B | 6103 | The program starts at the header’s boot address minus $100000. |
| 6105 (PAL: 7105) | 98BC2C86 | $11A49F60E96 | 6105 | The challenge-response chip; its check code mixes in a table inside IPL3. |
| 6106 (PAL: 7106) | ACC8580A | $D6D5BE5580 | 6106 | The program starts at the header’s boot address minus $200000. |
| 5167 | not listed | $1053BC19870 | not found | N64brew: a 64DD ROM conversion, not a physical chip. |
| 8303 | not listed | $D2E53EF008 | not found | N64brew: the 64DD IPL, retail, Japan. |
| “USDD” | not listed | $D2E53E5DDA | not found | A 64DD boot code; the name is mupen64plus’s. |
| “DVDD” | not listed | $D2E53EF39F | not found | A 64DD boot code; the name is mupen64plus’s. |
Where the list ends. The NTSC and PAL chips of a pair (6102 and 7101, 6103 and 7103, 6105 and 7105, 6106 and 7106) share one boot code (N64brew), so the file cannot tell them apart. The Aleck 64 chip 5101 is named on the N64brew page, but no fingerprint of its boot code was found; 8401 and 8501 (64DD IPL, development and retail) are named there too, with none either. A boot code in neither list is shown as “not in the list”, and the header’s check code is then tried under every algorithm below.
The check code ($10–$17)
Read the 1 MiB from ROM $1000 as big-endian 32-bit words w. Six 32-bit registers t1 to t6 all start at a seed.
For each word:
- r = w rotated left by (w AND 31)
- if t6 + w overflows 32 bits, add 1 to t4; then t6 = t6 + w
- t3 = t3 XOR w
- t5 = t5 + r
- if t2 > w then t2 = t2 XOR r, otherwise t2 = t2 XOR t6 XOR w
- t1 = t1 + (t5 XOR w); for the 6105, t1 = t1 + (x XOR w), where x is the word of the ROM at
$0750+ (the word’s offset AND$FF): a table of 64 words inside IPL3
| Algorithm | Seed | CRC1 (at $10) | CRC2 (at $14) |
|---|---|---|---|
| 6101, 6102, 7101, 7102 | $F8CA4DDC | t6 XOR t4 XOR t3 | t5 XOR t2 XOR t1 |
| 6103, 7103 | $A3886759 | (t6 XOR t4) + t3 | (t5 XOR t2) + t1 |
| 6105, 7105 | $DF26F436 | t6 XOR t4 XOR t3 | t5 XOR t2 XOR t1 |
| 6106, 7106 | $1FEA617A | t6 × t4 + t3 | t5 × t2 + t1 |
All arithmetic is modulo 232. The seeds, the registers and the combinations are from the cargo-n64 source’s description of the algorithm
(the work of Parasyte’s n64sums, which the N64brew page does not describe). A ROM shorter than 1 MiB past $1000 counts the missing words as zero.
The boot process
- The PIF boot ROM (IPL1 and IPL2) starts the console, takes the bus timing from the first word of the header and copies IPL3 into RSP data memory at
$A4000040. - IPL3 verifies the header’s check code, then copies the first 1 MiB from ROM
$1000to RDRAM at the boot address. - IPL3 jumps to the boot address. The 6103 chip subtracts
$100000and the 6106 chip$200000from the header’s value first (N64brew); that the copy goes to the same adjusted address is an inference, since the page states only the jump. The 7102 chip jumps to$80000480. - The program reads the rest of the ROM itself, through DMA on the peripheral interface (
PI_CART_ADDRandPI_DRAM_ADDR, registers).
How this page was checked
The check code was computed on five real homebrew ROMs (the ones on this site’s Nintendo 64 emulator, all with the 6102 boot code) and equals the header’s
values in every one; both fingerprints of their boot code name the 6102. The byte-order handling and the word sum were compared with a C program
that contains mupen64plus’s swap_rom function (statement for statement) and its summing loop, run on the same files and on their
.v64 and .n64 conversions: the swapped files read as the .z64 in every field. The algorithms of the 6103, 6105
and 6106 chips were not checked on a real ROM (none is on this machine): they were run on built ROMs against a second implementation written from the
same description, which shows the two agree and nothing more.
Not described
Known, not yet covered
- Reference: the check code of the 64DD chips (5167, 8303 and the others) and of the Aleck 64 chip 5101; what each IPL3 does instruction by instruction; the CIC’s own challenge protocol.
- Viewer: a boot code that is not in the list is not named; the viewer then reports which of the four algorithms, if any, matches the header.
Links
Reference
- CIC-NUS – N64brew wiki: the chip variants and their entry points
- IPL3 – N64brew wiki: the boot code stage
- cargo-n64 ipl3.rs – the boot code CRC-32 values, the seeds and the check code algorithm