One byte chooses the screen, the way Mario's does
A title that waits for Start, the jump lesson’s square to play with, and a pause that freezes it, with Start moving between them. The program is 313 instructions in 701 bytes, built and checked the same way.
Play it here The cartridge, to play anywhere that plays NES cartridges: screens.nes
On the screen
One byte chooses what runs
Super Mario Bros. keeps which screen it is on in one byte of memory and, every frame, calls a routine that takes an address from a table placed right after the call, the entry chosen by that byte. The autopsy names that routine a jump engine. This cartridge does the same with its own byte: 0 is the title, 1 playing, 2 paused. Then we ran the autopsy over our own cartridge, the same tools that went over the games, to see whether they would recognise what we wrote.
| this cartridge | Super Mario Bros. | |
|---|---|---|
| values the screen byte took, in order | 0, 1, 2, 1 | 0, 1, 3, 0 |
| a jump engine found by the autopsy | yes | yes |
| the table chosen by the screen byte: entries, taken in the run | 3, 3 | 4, 3 |
| stretches the run was cut into by which routines ran | 4 | 19 |
| changes of the screen byte where a stretch began | 3 of 3 | 2 of 3 |
| bytes of memory changing a frame: before the pause, while paused | 5, 0 | 41, 9 |
What the autopsy said of it
It found the engine and the table, and the table’s choosing byte was ours. The stretches it cut the run into, knowing nothing of screens, began where the screen byte changed 3 times out of 3. While paused, 0 bytes of memory changed a frame, outside the stack and the sprites’ page: the pause is nothing but the entry that only waits for Start.
As written
The part of the program this lesson is about. The whole program is a plain text file: screens.s
;; What runs this frame, by the screen: the table after the call.
screen:
LDA $40
JSR engine
.word on_title
.word on_play
.word on_pause
;; The jump engine: A is the entry. The call's return address, taken off
;; the stack, is one byte short of the table that follows the call; the
;; entry's two bytes are an address, and the jump goes there. Each entry
;; ends with RTS, which returns past the call to `screen`: the engine
;; took its own return address off the stack, so the one left on top is
;; main's. (Reached from main directly, there would be none, and the RTS
;; would go wherever the stack's next two bytes said.)
engine:
ASL A
TAY
PLA
STA $04
PLA
STA $05
INY
LDA ($04),Y
STA $06
INY
LDA ($04),Y
STA $07
JMP ($06)