We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Notes:Mario Kart 64

From The Cutting Room Floor
Jump to navigation Jump to search

This page contains notes for the game Mario Kart 64.

A deposit of the now defunct 64.vg/w/.


Native functions

/* 0x800936B8 */ extern void mk64_draw_text ( int x, int y, char * s, float xscale, float yscale, int u );

/* 0x80057710 */ extern void mk64_debug_text_preface ( void );

/* 0x800577A4 */ extern void mk64_draw_debug_text ( int x, int y, char * );

/* 0x80098DF8 */ extern void mk64_draw_square ( void *, int up_x, int up_y, int low_x, int low_y, u8, u8, u8, u8 );

/* 0x800400D0 */ extern void mk64_mio0_decode ( void * input, void * output );


0x800046AC { osViExtendVStart }

 Auxiliary symbols for `osViExtendVStart`:
   0x80162D5C = __additional_scanline

0x80028F5C { osSyncPrintf, rmonPrintf }

0x8005994C { leoInitUnit_atten }

 Auxiliary symbols for `leoInitUnit_atten`:

0x8005C654 { alSynDelete }

0x800CE130 0x800D2B80 { __osViGetCurrentContext, __osViGetNextContext, osPiGetDeviceType, __osGetActiveQueue, __osGetCurrFaultedThread, leoChkUnit_atten }

 Auxiliary symbols for `__osViGetCurrentContext`:
   0x800EB3AC = __osViCurr
 Auxiliary symbols for `__osViGetNextContext`:
   0x800EB3AC = __osViNext
 Auxiliary symbols for `osPiGetDeviceType`:
   0x800EB3AC = osRomType
 Auxiliary symbols for `__osGetActiveQueue`:
   0x800EB3AC = __osActiveQueue
 Auxiliary symbols for `__osGetCurrFaultedThread`:
   0x800EB3AC = __osFaultedThread
 Auxiliary symbols for `leoChkUnit_atten`:

0x800D2A10 { osGetThreadPri }

 Auxiliary symbols for `osGetThreadPri`:
   0x800EB3B0 = __osRunningThread


A rudimentary extractor which picks out MIO0 blocks and infers their length via the compression format can be found here. You can also download the Windows binary


Mario Kart 64 doesn't have a single unified filesystem. A search for "MIO0\x00\x00\x10\x00" confirms this. Files are either loaded via distinct tables or through direct lui/addiu operations. This does not dismiss the possibility of being able to change the compression algorithm the ROM uses, however. A hash table could be employed with the original offsets of the file being used as the key. Thus, a DMA function could be intercepted and the proper file loaded regardless of new location.

(Source: MBR)

Map Data

The code that processes the DMA and decompression of map files is dynamically loaded. 0x802AA918: sll t6,a0,2

0x802AA91C: subu t6,t6,a0

0x802AA920: lui t7,0x802c

0x802AA924: addiu t7,t7,-29312

0x802AA928: sll t6,t6,4

0x802AA92C: addu v0,t6,t7

0x802AA930: addiu $sp,$sp,-96

0x802AA934: lui v1,0x800e

0x802AA938: lw v1,-15092(v1)

0x802AA93C: lw t8,0(v0)

0x802AA940: lw t9,4(v0)

0x802AA944: lw t0,8(v0)

0x802AA948: lw t1,12(v0)

0x802AA94C: lw t2,40(v0)

0x802AA950: lw t3,24(v0)

0x802AA954: lw t4,32(v0)

0x802AA958: lw t5,28(v0)

0x802AA95C: lw t6,36(v0)

0x802AA960: lhu t7,44(v0)

0x802AA964: li $at,5

0x802AA968: sw $ra,20($sp)

0x802AA96C: lw a2,16(v0)

0x802AA970: lw a1,20(v0)

0x802AA974: sw t8,72($sp)

0x802AA978: sw t9,68($sp)

0x802AA97C: sw t0,64($sp)

0x802AA980: sw t1,60($sp)

0x802AA984: sw t2,48($sp)

0x802AA988: sw t3,44($sp)

0x802AA98C: sw t4,40($sp)

0x802AA990: sw t5,36($sp)

0x802AA994: sw t6,32($sp)

0x802AA998: beq v1,$at,0x802AA9AC

0x802AA99C: sw t7,28($sp)

0x802AA9A0: li $at,9

0x802AA9A4: bne v1,$at,0x802AA9BC

0x802AA9A8: lui t9,0x8028

0x802AA9AC: lui t8,0x8028

0x802AA9B0: lui $at,0x8016

0x802AA9B4: b 0x802AA9C8

0x802AA9B8: sw t8,-2260($at)

0x802AA9BC: ori t9,t9,0xdf00

0x802AA9C0: lui $at,0x8016

0x802AA9C4: sw t9,-2260($at)

0x802AA9C8: jal 0x802A7D70

0x802AA9CC: or a0,a2,$zero

0x802AA9D0: li a0,9

0x802AA9D4: jal 0x802A7B94

0x802AA9D8: or a1,v0,$zero

0x802AA9DC: lui t0,0x800e

0x802AA9E0: lw t0,-15092(t0)

0x802AA9E4: li $at,5

0x802AA9E8: lw a0,72($sp)

0x802AA9EC: beq t0,$at,0x802AAA08

0x802AA9F0: nop

0x802AA9F4: jal 0x802AA88C /* Map is decompressed further down the line here */

0x802AA9F8: lw a1,68($sp)

0x802AA9FC: li a0,6

Stack trace hereto: (m64p) bt Stack trace for thread 5 (0x801589D0):

  1. 00 0x800400D0 SRC:0x802AA8E8 ARG:{0x802899C0,0x801CCF10,0x00000001,0x802BA360}
   $sp:0x8015AA90  size: 48b
  1. 01 0x802AA88C SRC:0x802AA9F4 ARG:{0x0084E8E0,0x00852E20,0x00000001,0x802BA360}
   $sp:0x8015AAC0  size: 96b
  1. 02 0x802AA918 SRC:0x80002AF4 ARG:{0x00000008,0x0002C470,0x00000001,0x802BA360}
   $sp:0x8015AB20  size: 24b
  1. 03 0x80002A18 SRC:0x8000271C ARG:{0x8028DF00,0x0002C470,0x00000001,0x802BA360}
   $sp:0x8015AB38  size: 24b
  1. 04 0x80002684 SRC:0x80002884 ARG:{0x00000001,0x00006D6E,0x00000000,0x00000000}
   $sp:0x8015AB50  size: ?

For the record, I loaded the first track of the first series.


The map data array begins at 0x802B8D80. The records are 48 bytes each. The structure appears to follow this format:

struct mk64_map_data_t
    unsigned rom_start;
    unsigned rom_end;