PIF-NUS: Difference between revisions

From N64brew Wiki
Jump to navigation Jump to search
Line 201: Line 201:
|Terminate boot process
|Terminate boot process
|This command is sent by VR4300 when the boot process is done. PIF expects this command before 5 seconds from boot, otherwise it freezes itself and the whole console.
|This command must be sent by VR4300 when the boot process is done. PIF expects this command before 5 seconds from boot, otherwise it freezes itself and the whole console.
Notice that no official IPL3 do this, so this must be done by the application itself (eg: [https://github.com/DragonMinded/libdragon/blob/0efbe60fd7bb04065c4603de02b74738bc9d605a/src/entrypoint.S#L37-L38 libdragon code]).

Revision as of 09:58, 4 May 2022

The PIF-NUS (or PIF, or PIF(P)-NUS on PAL) manages multiple critical functions of the N64 console. It is a physical microchip found on the console's motherboard, which is based on the Sharp SM5 Microcontroller. It is not clear whether SGI or Nintendo intended this to stand for "Peripheral InterFace" or not. While the naming is unintuitive, the Peripheral (or Parallel) Interface is used to read/write to the game ROM and devices like the 64DD; whereas, the PIF handles the following:

  • Console startup and piracy protections
    • Stores the first 2 stages of the Initial Program Load (IPL) that is executed by the VR4300 CPU
  • Console reset button to avoid corrupting save game data
  • Controller and EEPROM read/write via JoyBus protocol


PIF Decapped with Pins numbered
PIF Decapped with Pins numbered
PIF Pinout (28 Pin SOP Package)
N64 Function SM5 Function Pin Pin SM5 Fuction N64 Function Direction
PIF Clock Pin 1 Pin 28 VDD VDD Power
RC Cold Pin 2 Pin 27 Reset Button Input
CIC D Out Pin 3 Pin 26 N/C (No Connect)
RC Rand Pin 4 Pin 25 INT 2 VR4300 CPU Output
CIC D In Pin 5 Pin 24 EEPROM Data I/O
/Cold Pin 6 Pin 23 EEPROM Data I/O
NMI VR4300 CPU Pin 7 Pin 22 Player 4 Controller Input
Power Good Pin 8 Pin 21 Player 4 Enable I/O
PIF CLK Input from RCP Pin 9 Pin 20 Player 3 Controller Input
Input Test 0 ?? Pin 10 Pin 19 Player 3 Enable I/O
PIF ADR from RCP Pin 11 Pin 18 Player 2 Controller Input
Input Test 1 ?? Pin 12 Pin 17 Player 2 Enable I/O
PIF DATA from RCP Pin 13 Pin 16 Player 1 Controller Input
Power GND GND Pin 14 Pin 15 Player 1 Enable I/O

Internal ROMs and RAM

Since PIF is based on the Sharp SM5 which is a programmable microcontroller, its logic is executed by a program that is burnt into an internal ROM, called PIF-SM5-ROM. This program is written for the SM5 4-bit core, and has been dumped via chip decapping. The jago85/UltraPIF_MCUproject on GitHub is a compatible implementation based on the STM32 architecture that can be inspected for further studying what PIF does in details. Everything described in this page is implemented by the means of this internal program.

Moreover, PIF contains a second internal ROM (1984 bytes) and a small RAM (64 bytes). These memories are usually referred to as PIF-ROM and PIF-RAM, but it is important not confuse this PIF-ROM with the previous PIF-SM5-ROM. Both PIF-ROM and PIF-RAM are memory mapped to the VR4300 address space via the SI interface in RCP (so each access actually requires a serial bus transmission and is thus quite slow).

The PIF-ROM contains the first two stages of code for the VR4300 boot process (IPL1 and IPL2) and is only memory mapped to VR4300 during the boot. After the boot process is finished, before jumping into the game code, the PIF locks the PIF-ROM for security reason, so that it cannot be accessed by VR4300 anymore. The PIF-ROM is slightly different between PAL and NTSC console: it actually hardcodes the region and communicate it to VR4300 during the boot via the PIF-RAM.

Dumping the PIF-ROM can be done via software thanks to a loophole: it is in fact possible to boot the console once, setup a hardware breakpoint at BFC0 0000 via the MIPS COP0 Watch register, and then soft-reset the console; as soon as the boot resumes, the interrupt will trigger; a registered handler for that interrupt would then be able to read the contents of PIF-ROM that are now unlocked, and dump them somewhere (eg: into SRAM). Check the hcs64/pif_rom_dumper project on GitHub for an example of implementing this technique.

The PIF-RAM is always available to be accessed by VR4300 and is used to perform communication with the PIF. Normally, it is used as part of the Joybus protocol to communicate with controllers and EEPROMs.

RAM-based communication protocol

Communication between VR4300 and PIF happens using the 64-byte PIF-RAM. The last byte of PIF-RAM (offset 0x3F) is called the "command byte" and is interpreted as a bit mask: each bit corresponds to a different command that VR4300 asks the PIF to perform. While PIF is running, it is constantly monitor PIF-RAM and soon as it sees a bit going to 1 in the command byte, it performs the requested function and then turns off the bit. It is possible for the VR4300 to set more than one bit at the same time, but in general they are not fully orthogonal with each other. The rest of the PIF-RAM is used to provide the arguments for the requested command.

Description of PIF commands
Bit Command Description Arguments Results
0x01 Run Joybus protocol This is the most used command during normal game run. It is used to poll the controllers and accessory PAKs. See below for more information. A sequence of joybus commands must be provided in PIF-RAM starting at 0. The results are written in PIF-RAM, overwriting each Joybus command.
0x02 Challenge / response for protection (CIC-NUS-6105) The CIC-NUS-6105 implements a challenge/response security protocol that was used as anti-piracy measure. The VR4300 can execute this protection protocol any time it wants to verify that an authentic CIC-NUS-6105 is present in the cartridge: a random challenge string is provided by VR4300, sent to CIC, and the response is sent back. 15 challenge bytes at offset 0x30 in PIF-RAM. 15 response bytes at offset 0x30 in PIF-RAM.
0x04 Unknown
0x08 Terminate boot process This command must be sent by VR4300 when the boot process is done. PIF expects this command before 5 seconds from boot, otherwise it freezes itself and the whole console.

Notice that no official IPL3 do this, so this must be done by the application itself (eg: libdragon code).

None? None?
0x10 ROM lockout This command asks the PIF to lock the PIF-ROM. It is part of the sequence to terminate the boot. After this command is received, PIF makes sure that the PIF-ROM is not exposed anymore via the serial bus (and thus accessible by VR4300) for security purposes. None None
0x20 IPL3 Checksum verification This commands tells PIF to verify whether the provided checksum matches the expected one for IPL3. PIF reads the expected checksum from CIC and compares it: if it matches, it sets bit 0x80 in command byte (this is the only command that uses the command byte itself as a result). 8 byte checksum at offset 0x32 in PIF-RAM Bit 0x80 of command byte is set if the checksum is correct.
0x40 Clear PIF RAM This command simply fills the whole PIF RAM with 0. None PIF-RAM filled with 0.
0x80 Unused This bit is used as response bit for command 0x20, and is not handled by PIF as a command. None None

Console startup

  1. PIF holds all of the console components in reset mode
  2. PIF starts communicating with the CIC inside the cartridge
    1. CIC sends 4 bits (nibble) including region encoding
    2. CIC sends 4 bit encrypted seed value
    3. CIC sends 4 bit checksum
  3. PIF checks that these are the expected values
    1. If the values don't match, the PIF stops the boot (same scenario if no cartridge is inserted)
      1. The user would generally reset using the button or power off
      2. Remove/Re-insert cartridge (or change games)
      3. Power on (go to step #1)
  4. PIF writes the encrypted seed value to the PIF-RAM at offset 0x24 (mapped at 0xBFC0 07E4)
  5. PIF releases the reset pin for the whole console
    1. The PIF (console) and CIC (cartridge) communication continues as long as the console is powered on
    2. If there is ever a failure in the data exchange the console will be reset.
  6. VR4300 starts running code from address 0xBFC0 0000 which is mapped to PIF ROM via SI interface
  7. IPL1 is now executed directly fetching opcodes from PIF-ROM.
    1. These instructions are executed in this very slow manner.
    2. Thankfully IPL1 is only 52 instructions + some looping.
    3. It performs some really basic hardware initialization.
    4. It then copy the rest of the PIF-ROM (IPL2) to the RSP IMEM. Notice that at this point RDRAM is not initialized yet, so it cannot be used. RSP IMEM is instead available without any initialization and is much faster than PIF ROM thanks to the parallel bus.
    5. Jump to RSP IMEM to execute IPL2
  8. IPL2 is executed by the VR4300 reading the instructions from RSP IMEM
    1. More general hardware initialization
    2. If it's determined to be a 64DD disk, it will jump to 0xA600 0000
    3. Load IPL3 from the cartridge ROM into the RSP DMEM
    4. Calculate the checksum of IPL3, using the checksum seed provided by CIC at the beginning.
    5. VR4300 asks PIF to verify that the checksum is correct (PIF command 0x20).
    6. VR4300 tells the PIF that the PIF-ROM can now be locked (PIF command 0x10).
    7. Jump to RSP DMEM to execute IPL3
  9. IPL3 is executed by the VR4300 reading the instructions from the RSP DMEM.
    1. Initialize RDRAM
    2. Depending on reset type
      1. Power On: Invalidate VR4300 ICache & DCache
      2. Reset : Writeback VR4300 ICache & DCache
    3. Move IPL3 execution from DMEM to RDRAM
    4. DMA 1 MB of Game code to RDRAM
    5. Authenticate 1 MB of Game Program
    6. Reset RSP
    7. Clear Interrupts
    8. Clear IPL3 from DMEM
    9. Clear IPL2 from IMEM
    10. Jump to Game code in RDRAM

Console Reset

The reset process is driven by the PIF, which is connected to the physical reset button. The actual reset is done via a NMI to VR4300 which resets it by starting again the full boot process, but it is important to notice that RCP is not reset in any way. The boot code expects the RCP to be idle when the boot is initiated and is not guaranteed to work if the RCP is active in any way (DMAs in progress, RDP drawing triangles, RSP executing code, etc.), which means that it is up to the VR300 to stop issuing commands to the RCP and putting it in idle state before the reset is executed. To do so, VR4300 is given a forewarn that a reset is incoming via an interrupt (aptly called "pre-NMI") and is given grace time of 500ms before the actual NMI arrives.

This is the full sequence:

  1. User presses Console Reset button
  2. PIF reads the button state
  3. PIF toggles VR4300 Interrupt 2 (INT2) also known as "pre-NMI".
    1. This is the time and opportunity for the game to finish saving game data and stop issuing commands to RCP to avoid graphics/audio corruption and/or a hard freeze.
  4. PIF sends the RESET command to CIC (command 0b11)
  5. CIC waits for 500ms (grace time)
  6. CIC acknowledges the RESET command to PIF by writing a 0 bit.
  7. PIF toggles VR4300 Non-Maskable Interrupt (NMI) which resets it.
    1. PIF also unlocks the internal PIF ROM so that the boot process can start executing IPL1.

Controller and EEPROM communication

This is the main task of PIF while the game is running. All communication with connected hardware like controllers and accessory PAKs is made through the PIF, using the Joybus protocol.

The VR4300 writes a Joybus packet into PIF-RAM and then triggers a handshake (by modifying the last byte of PIF-RAM which acts as "command" byte). PIF will execute the commands in the packet and provide the results into PIF-RAM. VR4300 would then read there results from there. (TODO: better document this process).