MIPS Assembly programming for the N64

The N64 was Nintendo's first steps into 3D... Built from the technology from the SGI workstations, the N64 gave home users some of the first 3D graphics.

While limited compared to modern systems, the N64 was revolutionary for it's day, and gives us an capable system for learning MIPS!
Cpu 93.75mh NEC VR4300 MIPS III
Ram 4MB Rambus RDRAM
(8mb upgradable)
Video SGI RCP  (Reality Co-Processor)
Resolution 320x240 / 640x480


Memory Map

KUSEG KSEG0
(Cached)
KSEG1
(Uncached)
KSSEG
(TLB-mapped)
Size Purpose
0x00000000  
0x80000000  
0xA0000000  
0xC0000000 2048K RDRAM 0
0x00200000 0x80200000 0xA0200000 0xC0200000 2048K RDRAM 1
0x00400000 0x80400000 0xA0400000 0xC0400000 2048K DisKDrive RDRAM 2
0x00600000 0x80600000 0xA0600000 0xC0600000 2048K DisKDrive RDRAM 3
0x00800000 0x80800000 0xA0800000 0xC0800000 55MB Reserved
0x03F00000 0x83F00000 0xA3F00000 0xC3F00000 1024K RDRAM regs
0x04000000 0x84000000 0xA4000000 0xC4000000 16MB RCP
0x05000000 0x85000000 0xA5000000 0xC5000000 48MB DiskDrive
0x08000000 0x88000000 0xA8000000 0xC8000000 128MB Reserved
0x10000000 0x90000000 0xB0000000 0xD0000000 253MB N64 Cartridge


Screen Memory

Each pixel is represented by one BIG ENDIAN word, in the format %RRRRRGGGGGBBBBBB-

Endian

The N64 is BIG ENDIAN
the PSX is LITTLE ENDIAN


Reading the joystick

The N64 controllers are connected via the so called 'PIF' chip (Peripheral Interface?)
The base of the PIF registers is at address 0xBFC007C0

To initialize things we first write 0x8 to the status register at 0xBFC007FC
We're going to use the serial interface (SI)  to send data to the PIF,
This is basically a DMA copy, which sends a block of data.

We need to prepare a 96 byte block of data to send to the PIF to initialize things.

We also define 8 bytes to get back the results when we do a read!
OK we need to use the SI to Send the INIT code to the PIF
The SI registers are at 0xA4800000+

We need to calculate our source address (PIF_Init) - but we need the true 'hardware address' we can get this by ANDing with 0x1FFFFFFF
We send the source address to 0xA4800000 (SI_DRAM_ADDR_REG)

We want to transfer to the PIF ram at 0xBFC007C0 (PIF_RAM_START) - we also AND this with 0x1FFFFFFF
We write the destination to the write register at 0xA4800010 (SI_PIF_ADDR_WR64B_REG) - this write also starts the transfer
OK Let's actually get the keypresses from the joypads!
This time we use the SI to READ from the PIF.

We need to calculate our destination address (PIF_JoyState) - but we need the true 'hardware address' we can get this by ANDing with 0x1FFFFFFF
We send the destination address to 0xA4800000 (SI_DRAM_ADDR_REG) - this is the same as the address for writing

This time we want to transfer FROM to the PIF ram at 0xBFC007C0 (PIF_RAM_START) - we also AND this with 0x1FFFFFFF
We write the source to the read register 0xA4800004 (SI_PIF_ADDR_RD64B_REG) - this write also starts the transfer
As a test we dump with our memdump sub

There are 8 bytes returned, the first 4 are status, the next 4 are directions and buttons in the format:

%ABZSUDLR --LRUDLR XXXXXXXX YYYYYYYY

AB - A/B Buttons
ZLR  - Shoulder buttons / Triggers
UDLR - Digital Directions
UDLR - C Pad
XXXXXXXX YYYYYYYY - Analog stick
S - Start