Ninja Gaiden (USA)
Ninja Gaiden (USA) is on a MMC1 board with 131,072 bytes of program. A crawl of 8,000 steps from power-on kept 142 paths that found new code. Played back over 304,842 frames, they executed 12,425 bytes of it, 9 percent.
What the rules named
- The poll: 1
- The wait for the frame: 3
- The jump engine: 2
- The handler kept in memory: 4
- The bank switch: 14
- The picture writer: 1
- The palette writers: 1
- The sprite writers: 10
- The scroll writer: 1
- The split: 3
- The sound driver: 1
- The random byte: 1
- Where two things are compared: 6
The 177 routines the runs entered
Every place the game's code was entered, by a call, an interrupt or a jump through a table. The ones a rule named come first, with what the rule saw, and their names in the listing say what they are: a poll, an engine, a drain.
| at | its name in the listing | entered by | times | what it is, and the evidence |
|---|---|---|---|---|
| $80F4 (bank 3) | b3_sound_80F4 | a call | 261,747 | The sound driver: frames it ran in 65,968, writes 745,908 |
| $C028 (bank 7) | b7_bank_C028 | a call | 196,540 | The bank switch: writes 982,017, in the blank 0, while drawing 982,017 |
| $E819 (bank 7) | b7_poll_E819 | a call | 182,984 | The poll: port $4016, reads a frame 15, strobes a frame 3 |
| $80A8 (bank 5) | b5_engine_80A8 | a call | 97,924 | The jump engine: tables 3, jumps through them 97,924 |
| $C02A (bank 7) | b7_bank_C02A | a call | 97,872 | The bank switch: writes 489,200, in the blank 0, while drawing 489,200 |
| $F91A (bank 7) | b7_nmi | each frame (NMI) | 91,492 | The bank switch: writes 2,053,599, in the blank 1,710,668, while drawing 342,931 The palette writers: frames it ran in 91,762, writes 518,962 The scroll writer: frames it ran in 91,762, writes in the blank 182,961 The picture writer: frames it ran in 91,762, writes 766,930, in the blank 766,930, while drawing 0 |
| $823B (bank 4) | b4_wait_823B | a call | 47,404 | The wait for the frame: waits on the byte at $001F, times entered 47,402, turns 78,034,703, writes of it under the frame interrupt 91,358, frames in all 92,742 |
| $8181 (bank 4) | b4_sprites_8181 | a call | 47,382 | The sprite writers: frames it ran in 47,382, writes to the sprite page 2,772,141 |
| $F104 (bank 7) | b7_wait_F104 | a call | 42,884 | The wait for the frame: waits on the byte at $001F, times entered 42,971, turns 123,471,937, writes of it under the frame interrupt 91,358, frames in all 92,742 |
| $F5A2 (bank 7) | b7_split_F5A2 | a call | 42,291 | The bank switch: writes 422,419, in the blank 0, while drawing 422,419 The split: frames it ran in 42,289, scroll writes while drawing 84,544, status reads while drawing 30,007,392 |
| $F77C (bank 7) | b7_sprites_F77C | a call | 28,346 | The sprite writers: frames it ran in 15,396, writes to the sprite page 441,661 |
| $837A (bank 3) | b3_handlers_837A | a call | 27,258 | The handler kept in memory: jumps 27,258, places it landed 15, address copied from $0627 |
| $8013 (bank 5) | b5_sprites_8013 | a call | 26,117 | The sprite writers: frames it ran in 22,355, writes to the sprite page 846,976 |
| $F768 (bank 7) | b7_sprites_F768 | a call | 25,850 | The sprite writers: frames it ran in 25,850, writes to the sprite page 1,627,170 |
| $F0A7 (bank 7) | b7_sprites_F0A7 | a call | 25,730 | The sprite writers: frames it ran in 25,730, writes to the sprite page 418,394 |
| $D8D5 (bank 7) | b7_bank_D8D5 | a call | 25,337 | The bank switch: writes 126,639, in the blank 0, while drawing 126,639 |
| $EB7B (bank 7) | b7_handlers_EB7B | a call | 25,337 | The handler kept in memory: jumps 18,804, places it landed 5, address copied from $0000,$006F,$0438 |
| $F1AC (bank 7) | b7_bank_F1AC | a call | 25,337 | The bank switch: writes 940, in the blank 0, while drawing 940 |
| $F7E4 (bank 7) | b7_handlers_F7E4 | a call | 24,985 | The handler kept in memory: jumps 24,985, places it landed 6, address copied from $005F,$0086,$00A3 |
| $E243 (bank 7) | b7_handlers_E243 | a call | 20,143 | The handler kept in memory: jumps 20,143, places it landed 11, address copied from $0051,$0061 |
| $E144 (bank 7) | b7_compare_E144 | a call | 12,873 | Where two things are compared: instructions 2, pairs of bytes 14, bytes in all 16, times compared 15,934, X positions at $0086,$0454,$0457,$0462,$0463,$0464,$0465,$0466,$0467, Y positions at $008A,$0474,$0477,$0482,$0485,$0486,$0487 |
| $DAA2 (bank 7) | b7_compare_DAA2 | a call | 7,763 | Where two things are compared: instructions 2, pairs of bytes 1, bytes in all 2, times compared 7, X positions at $0086,$04D9 |
| $C014 (bank 7) | b7_bank_C014 | a call | 6,767 | The bank switch: writes 33,824, in the blank 0, while drawing 33,824 |
| $F47E (bank 7) | b7_bank_F47E | a call | 2,377 | The bank switch: writes 23,770, in the blank 0, while drawing 23,770 |
| $F5EA (bank 7) | b7_bank_F5EA | a call | 1,225 | The bank switch: writes 6,125, in the blank 0, while drawing 6,125 |
| $8301 (bank 4) | b4_wait_8301 | a call | 1,084 | The wait for the frame: waits on the byte at $001F, times entered 1,084, turns 3,018,154, writes of it under the frame interrupt 91,358, frames in all 92,742 |
| $818E (bank 6) | b6_engine_818E | a call | 969 | The jump engine: tables 1, jumps through them 969 |
| $81E9 (bank 4) | b4_bank_81E9 | a call | 795 | The bank switch: writes 3,975, in the blank 0, while drawing 3,975 |
| $86D2 (bank 4) | b4_sprites_86D2 | a call | 557 | The sprite writers: frames it ran in 557, writes to the sprite page 557 |
| $817D (bank 4) | b4_sprites_817D | a call | 523 | The sprite writers: frames it ran in 523, writes to the sprite page 32,949 |
| $8328 (bank 4) | b4_sprites_8328 | a call | 401 | The sprite writers: frames it ran in 401, writes to the sprite page 1,604 |
| $880F (bank 4) | b4_random_880F | a call | 246 | The random byte: frames it ran in 246, bytes $001D, rotates 2, exclusive-ors 1 |
| $FFDA (bank 7) | b7_reset | power-on | 142 | The bank switch: writes 994, in the blank 994, while drawing 0 The sprite writers: frames it ran in 426, writes to the sprite page 36,352 |
| $DE2B (bank 7) | b7_compare_DE2B | a call | 129 | Where two things are compared: instructions 1, pairs of bytes 6, bytes in all 7, times compared 129, X positions at $0086,$0462,$0463,$0464,$0465,$0466,$0467 |
| $DE5A (bank 7) | b7_compare_DE5A | a call | 129 | Where two things are compared: instructions 1, pairs of bytes 6, bytes in all 7, times compared 129, X positions at $0086,$0462,$0463,$0464,$0465,$0466,$0467 |
| $E902 (bank 7) | b7_bank_E902 | a call | 120 | The bank switch: writes 1,150, in the blank 0, while drawing 1,150 |
| $EAC1 (bank 7) | b7_split_EAC1 | a call | 120 | The bank switch: writes 1,200, in the blank 0, while drawing 1,200 The split: frames it ran in 480, scroll writes while drawing 240, status reads while drawing 88,080 The sprite writers: frames it ran in 480, writes to the sprite page 480 |
| $F8F0 (bank 7) | b7_split_F8F0 | a call | 120 | The bank switch: writes 1,200, in the blank 0, while drawing 1,200 The split: frames it ran in 240, scroll writes while drawing 240, status reads while drawing 82,440 |
| $DE40 (bank 7) | b7_compare_DE40 | a call | 21 | Where two things are compared: instructions 1, pairs of bytes 2, bytes in all 3, times compared 21, X positions at $0086,$0465,$0466 |
| $DECF (bank 7) | b7_compare_DECF | a call | 21 | Where two things are compared: instructions 3, pairs of bytes 5, bytes in all 7, times compared 25, X positions at $0086,$0465,$0466,$0467, Y positions at $008A,$0486,$0487 |
| $8161 (bank 3) | a call | 282,760 | ||
| $E792 (bank 7) | a call | 184,855 | ||
| $BF98 (bank 4) | a call | 97,872 | ||
| $BFB3 (bank 5) | a call | 96,903 | ||
| $8000 (bank 3) | a call | 91,483 | ||
| $82B9 (bank 3) | a call | 55,371 | ||
| $8003 (bank 5) | a table | 47,382 | ||
| $8006 (bank 5) | a table | 47,382 | ||
| $83A9 (bank 4) | a call | 47,382 | ||
| $83B5 (bank 4) | a call | 47,382 | ||
| $DFD3 (bank 7) | a call | 32,672 | ||
| $82E0 (bank 4) | a call | 28,267 | ||
| $81D7 (bank 6) | a call | 28,219 | ||
| $81C8 (bank 6) | a call | 27,250 | ||
| $8193 (bank 5) | a call | 26,117 | ||
| $80D6 (bank 5) | a call | 25,986 | ||
| $D85D (bank 7) | a call | 25,730 | ||
| $DC88 (bank 7) | a call | 25,730 | ||
| $EB64 (bank 7) | a call | 25,730 | ||
| $F10D (bank 7) | a call | 25,730 | ||
| $D710 (bank 7) | a call | 25,337 | ||
| $D9E4 (bank 7) | a call | 25,337 | ||
| $E625 (bank 7) | a call | 25,337 | ||
| $E677 (bank 7) | a call | 25,337 | ||
| $EFF1 (bank 7) | a call | 25,337 | ||
| $DD32 (bank 7) | a call | 24,985 | ||
| $E560 (bank 7) | a call | 24,985 | ||
| $81A4 (bank 6) | a call | 23,210 | ||
| $81B5 (bank 6) | a call | 23,210 | ||
| $81E5 (bank 6) | a call | 23,210 | ||
| $DD6C (bank 7) | a call | 20,173 | ||
| $DFE9 (bank 7) | a call | 20,143 | ||
| $E024 (bank 7) | a call | 20,143 | ||
| $E054 (bank 7) | a call | 19,545 | ||
| $E07B (bank 7) | a call | 18,353 | ||
| $F53E (bank 7) | a call | 14,826 | ||
| $F568 (bank 7) | a call | 14,826 | ||
| $C3E1 (bank 7) | a table | 14,580 | ||
| $DF87 (bank 7) | a call | 14,580 | ||
| $867F (bank 4) | a call | 14,256 | ||
| $EC7B (bank 7) | a table | 9,980 | ||
| $ED0D (bank 7) | a table | 7,431 | ||
| $87A0 (bank 4) | a call | 7,276 | ||
| $84F2 (bank 3) | a table | 6,188 | ||
| $84D7 (bank 3) | a table | 5,282 | ||
| $8535 (bank 3) | a table | 4,910 | ||
| $8225 (bank 3) | a table | 4,730 | ||
| $820A (bank 3) | a table | 4,700 | ||
| $EEE7 (bank 7) | a call | 4,634 | ||
| $81F0 (bank 3) | a table | 4,530 | ||
| $F85D (bank 7) | a table | 4,217 | ||
| $F86F (bank 7) | a table | 4,188 | ||
| $F850 (bank 7) | a table | 4,171 | ||
| $F86A (bank 7) | a table | 4,148 | ||
| $F83E (bank 7) | a table | 4,140 | ||
| $F831 (bank 7) | a table | 4,121 | ||
| $8471 (bank 3) | a table | 3,713 | ||
| $822F (bank 4) | a call | 2,632 | ||
| $F62D (bank 7) | a call | 2,421 | ||
| $83E6 (bank 3) | a table | 2,374 | ||
| $823A (bank 3) | a table | 2,301 | ||
| $8205 (bank 3) | a table | 2,265 | ||
| $83CB (bank 3) | a table | 2,192 | ||
| $8009 (bank 5) | a table | 2,131 | ||
| $F2DD (bank 7) | a call | 2,119 | ||
| $81AA (bank 4) | a call | 1,888 | ||
| $D5B2 (bank 7) | a table | 1,790 | ||
| $815D (bank 5) | a call | 1,688 | ||
| $C431 (bank 7) | a table | 1,515 | ||
| $C487 (bank 7) | a table | 1,286 | ||
| $EDB1 (bank 7) | a table | 1,269 | ||
| $8340 (bank 4) | a call | 1,191 | ||
| $8398 (bank 4) | a call | 1,191 | ||
| $8243 (bank 3) | a call | 1,128 | ||
| $E5B3 (bank 7) | a call | 1,024 | ||
| $8000 (bank 6) | a table | 969 | ||
| $8157 (bank 6) | a call | 969 | ||
| $8166 (bank 6) | a call | 969 | ||
| $BFB3 (bank 6) | a call | 969 | ||
| $83A3 (bank 5) | a call | 965 | ||
| $8192 (bank 4) | a call | 944 | ||
| $81CF (bank 4) | a call | 944 | ||
| $81DE (bank 4) | a call | 944 | ||
| $E2C3 (bank 7) | a call | 923 | ||
| $F745 (bank 7) | a call | 920 | ||
| $80DD (bank 5) | a call | 844 | ||
| $8210 (bank 5) | a table | 823 | ||
| $8448 (bank 3) | a table | 817 | ||
| $81FD (bank 4) | a call | 815 | ||
| $8396 (bank 5) | a call | 809 | ||
| $84C3 (bank 3) | a table | 631 | ||
| $85EB (bank 4) | a call | 564 | ||
| $80BE (bank 4) | a call | 401 | ||
| $860A (bank 4) | a call | 347 | ||
| $8407 (bank 3) | a table | 346 | ||
| $C6B3 (bank 7) | a table | 308 | ||
| $C466 (bank 7) | a table | 297 | ||
| $E132 (bank 7) | a call | 293 | ||
| $868D (bank 4) | a call | 289 | ||
| $C4BE (bank 7) | a table | 270 | ||
| $8500 (bank 3) | a table | 176 | ||
| $850D (bank 3) | a table | 165 | ||
| $8327 (bank 5) | a table | 156 | ||
| $E254 (bank 7) | a call | 151 | ||
| $8000 (bank 4) | a call | 142 | ||
| $E526 (bank 7) | a call | 142 | ||
| $8431 (bank 3) | a table | 133 | ||
| $83FA (bank 3) | a table | 125 | ||
| $E7DC (bank 7) | a call | 120 | ||
| $E7E7 (bank 7) | a call | 120 | ||
| $F0F3 (bank 7) | a call | 120 | ||
| $E233 (bank 7) | a call | 116 | ||
| $D97C (bank 7) | a call | 115 | ||
| $E30A (bank 7) | a call | 115 | ||
| $F653 (bank 7) | a call | 115 | ||
| $F6B5 (bank 7) | a call | 115 | ||
| $851C (bank 3) | a table | 109 | ||
| $E2AF (bank 7) | a call | 106 | ||
| $8516 (bank 3) | a table | 97 | ||
| $E285 (bank 7) | a call | 85 | ||
| $C3BD (bank 7) | a table | 81 | ||
| $EE55 (bank 7) | a table | 62 | ||
| $EE99 (bank 7) | a table | 62 | ||
| $8296 (bank 5) | a table | 22 | ||
| $CB37 (bank 7) | a call | 21 | ||
| $E28F (bank 7) | a call | 17 | ||
| $C41B (bank 7) | a table | 12 | ||
| $800C (bank 5) | a table | 8 | ||
| $8270 (bank 5) | a table | 8 | ||
| $82B0 (bank 5) | a table | 6 | ||
| $830D (bank 5) | a table | 6 | ||
| $D98E (bank 7) | a call | 5 | ||
| $D989 (bank 7) | a call | 4 | ||
| $E1BD (bank 7) | a call | 3 | ||
| $86C1 (bank 4) | a call | 2 | ||
| $C402 (bank 7) | a table | 2 | ||
| $C67F (bank 7) | a table | 2 |
The tables it jumps through
A table of addresses the game picks one from. Some sit right after a call to a jump engine; others are anywhere in the cartridge, and we find them by where the address the game jumped through was loaded from. Some games jump by pushing an address and returning to it, and some keep a table as two, the low bytes of its addresses in one place and the high bytes in another; both are found the same way. An entry is counted as far as the runs saw one taken; the true table may be longer. The last column is the byte of memory whose value picked the entry, where we could follow it: the game's mode, or what one of its objects is doing.
| at | reached | entries | taken | chosen by the byte at |
|---|---|---|---|---|
| $81E0 (bank 3) | through a pointer | 8 | 5 | $00F8 |
| $838B (bank 3) | through a pointer | 32 | 15 | $066C, $067C |
| $820C (bank 5) | after a call | 2 | 2 | $0319 |
| $8221 (bank 5) | after a call | 8 | 4 | |
| $BFB6 (bank 5) | after a call | 5 | 4 | |
| $BFB6 (bank 6) | after a call | 1 | 1 | |
| $F087 (bank 7) | through a pointer | 9 | 5 | $0028, $0094, $043F, $006F |
| $F8E4 (bank 7) | through a pointer | 6 | 6 | $003E, $0086, $00A3, $005F |
The memory its routines share
599 bytes of memory were written by one routine and read by another, and 83 places were reached through an index, which is what a table or a set of object slots in memory looks like.
Reaches through an index: those that hold positions, then the longest
| from | bytes reached | instructions | positions it holds |
|---|---|---|---|
| $0460 | 8 | 17 | 6 across |
| $0450 | 8 | 13 | 2 across |
| $0480 | 8 | 13 | 4 down |
| $0470 | 8 | 6 | 2 down |
| $04D9 | 4 | 6 | 1 across |
| $0300 | 256 | 2 | |
| $0200 | 253 | 4 | |
| $0203 | 253 | 3 | |
| $0201 | 253 | 2 | |
| $0202 | 253 | 2 | |
| $0627 | 113 | 1 | |
| $0628 | 113 | 1 |
What travels with a position
Arrays that at least two routines step through together with an array of positions, across the same range. That is what a table of the things on the screen looks like in memory: one array for each property, one slot for each thing. We can say which arrays hold positions, which of the others get added into them, which is what a speed does, which pick the way through a jump table, which is what a state or a kind does, and which are only ever counted down, which is what a timer does. What the rest hold is not named yet.
| slots | arrays | routines | positions across | positions down | added into them | choosing a jump | counted down | travelling with them |
|---|---|---|---|---|---|---|---|---|
| 8 | 15 | 24 | $0450, $0460 | $0470, $0480 | $0468 | $0410, $0438 | $0400, $0410, $0438, $0440, $0448, $0458, $0468, $0488, $0490, $0498, $04B0 | |
| 4 | 4 | 3 | $04D9 | $04D1, $04D5, $04E1 |
The 24 busiest shared bytes
| byte | reads and writes | routines writing | routines reading |
|---|---|---|---|
| $00F0 | 4,924,733 | 3 | 6 |
| $0028 | 4,816,640 | 4 | 6 |
| $00F3 | 4,420,211 | 2 | 6 |
| $00F2 | 4,111,340 | 2 | 5 |
| $0000 | 3,631,052 | 6 | 6 |
| $00F1 | 3,494,079 | 3 | 6 |
| $0001 | 2,904,631 | 6 | 6 |
| $0002 | 1,509,708 | 6 | 6 |
| $0031 | 688,895 | 4 | 4 |
| $0030 | 688,891 | 4 | 4 |
| $00F4 | 479,803 | 6 | 6 |
| $0073 | 469,217 | 6 | 6 |
| $00F5 | 453,191 | 6 | 6 |
| $0034 | 448,103 | 4 | 3 |
| $033F | 434,803 | 5 | 6 |
| $0003 | 415,527 | 4 | 5 |
| $0380 | 408,553 | 4 | 5 |
| $004E | 393,403 | 2 | 4 |
| $005C | 386,135 | 3 | 3 |
| $001C | 284,594 | 6 | 6 |
| $008C | 282,229 | 4 | 5 |
| $0004 | 268,967 | 6 | 6 |
| $0033 | 264,296 | 4 | 4 |
| $0032 | 264,276 | 4 | 4 |
This page shows none of the game's bytes. The listing these figures were read from stays with the cartridge.