Commodore 64 · 1982 · Commodore

About this page

Footprint

Every byte of the C64's 64 KB, one pixel each, 512 to a row. Lit pixels are what this game is: its code, graphics, level data, sound, text, tables and variables, exactly where they sit in memory. Dim areas are screen and working memory; dark is unused.

WhatBytesOf 64 KB
Program8,65813.2 %
Code4,9227.5 %
Graphics2,1173.2 %
Level data4650.7 %
Sound1480.2 %
Text1900.3 %
Tables7311.1 %
Variables850.1 %
Screen, bitmap, colour, stack, I/O5,3768.2 %
Unused51,50278.6 %

Status

Tiergold
Coverage100 % of the bytes the game uses have a description
Build analysedCOMMODORE V.02
Copyagent-draft
Toolsemulator: VICE x64sc with vice-mcp, disassembler: regenerator2000 0.9.20
Modelclaude-opus-4-1 and claude-fable-5-1 (Claude Code)
Kit version0.0.1

Contributors

Other places to love this game

What the game does, and where we found it

Technical facts live in facts.md; reusable method in ../../docs/c64-re-playbook.md; agent rules in ../../CLAUDE.md.

Read this before annotating code. It is the list of things the game is known to do, from external documentation (c64-wiki) and from the game's own title screen, with our verification status against the V.02 binary.

Treat any documented feature you cannot find in the binary as an open question, never as absent. This game stores text in two alphabets and names a player ability in a control legend, so a feature can be present and still invisible to a naive search.

Status words: confirmed = traced in the code; live = also observed in the emulator; differs = the code does something other than the documentation says.

The cast

The wiki calls the player and the chasers mice. The game's own text says RAT (MOVE RAT, BONUS RAT) and the artwork cannot tell a rat from a mouse, so everywhere else in this project they are the rat (the player) and the red rats (the chasers).

Wiki nameWhat the code doesOur binding
Blue mousethe player; the game's own text calls it the RATplayer_x/player_y ($92/$93); tiles $40$4F in blue
Red mice3–7 chasers; contact kills the playerred_rat_x/red_rat_y ($22/$2A), count−1 in $81; the same tiles in red
Black cats8 or 16 static cats, shown only in the maze view; contact kills the player and stuns a red ratcat_x_table/cat_y_table ($C2/$D2); tile $58$5B

Features

FeatureStatus
F1 starts the gameconfirmedattract_wait_for_f1 polls it at $F000; joystick-1 fire shares the bit
P / ; / . / L = up / right / down / leftconfirmedread_controls ($ED8D), joystick first, keyboard only when the stick is idle
S (or joystick fire) releases the Star Screenconfirmed — a burst of 3 stars, dropped one cell behind the player, one per cell, each costing a unit of TIME
Star Screen temporarily disables followersconfirmed — a red rat landing on a star is stunned for 15 of its moves, then carries on
Collect all cheese to finish the roundconfirmed — 10 cheese; the round ends when the 9 ordinary ones and the 2x one are gone
Cheese scores 100, then 200, rising per sliceconfirmed — n-th cheese of a life scores n×100, the 10th 1,000; NEXT MEAL shows the next value; resets when a life is lost
"2×" cheese doublesconfirmed — meal slot 0 has a red "2x" corner; from it onwards every cheese scores double until the life ends, and X2 flashes on the HUD
Remaining time converts to points at round endconfirmedtime_bonus ($F190), 60 points per unit of TIME left
Extra life for 20,000 pointsconfirmed — once per game (bonus_life_latch); the title screen's own wording, BONUS RAT FOR 20000 PTS, doesn't promise more
Constant background melodyconfirmed — Three Blind Mice, music_tick ($EA2B)
SPEED RUN bonus stageconfirmed — rounds 3, 7, 11 and 15 of every 15-round cycle: intro banner, 16 cats, frozen red rats until TIME runs out, no stars, faster player
GAME OVER bannerconfirmedgame_over_banner ($F328), str_game_over ($FD2B)
Sound effects for cheese, crash, level complete, Star Screenconfirmed — every cue mapped to its trigger (see the sound table in facts.md)
Rounds add more red ratsconfirmed — 3 → 7 across the 15-round table; red rats also get faster from round 8
Rounds add more cheesediffers — always 10
Black cats only delaydiffers, live — in V.02 a cat kills the player (player_collision_check, $F344, treats cats and red rats identically); only red rats are delayed by cats. Placing the player on a cat during a SPEED RUN (red rats frozen elsewhere) cost a life and ended the SPEED RUN
Black cats hide behind cornersconfirmed in effect — cats are never drawn on the radar, only in the 9×9-cell maze view
Radarconfirmed, live — cheese as character blips; the player and red rats as hardware sprites 0–7

Beyond the documentation

Found in the code, not in the manual or wiki:

Open questions

  1. Does a black cat kill the player in real play? The code is unambiguous; a live confirmation is still wanted.
  2. What the two filler bytes $08 at $FF7D and $F1 at $FF7F are. Nothing reads them.

Answered: the first round after loading has the same layout every time. It depends only on prng_hi ($0219), which the game never initialises, and two independent boots in VICE (the saved snapshot and a fresh process) produced byte-identical cheese and cat tables.

How the analysed state was reached

work/Radar Rat Race.d64 — single file on disk: radar rat race (34 blocks, 8450-byte PRG once extracted to work/radarrat.prg). Disk label is a "c64.com" preservation re-release, not an original retail disk, but the program itself is unmodified Commodore code — title screen confirms (C) 1982 COMMODORE ELECTRONICS LTD.

Load sequence

Standard autostart: LOAD"*",8,1RUN → BASIC line 1983 SYS2061.

SYS 2061 ($080D) enters a small loader/relocator, disassembled live at that breakpoint:

$080D: SEI                  ; disable interrupts
$080E: LDY #$00
$0810: STY $02 / STY $04 / STY $06      ; low bytes of 3 zero-page pointers = 0
$0816: LDA #$28 / STA $03   ; ptr1 (source)      = $2800
$081A: LDA #$3F / STA $05   ; ptr2 (dest A)       = $3F00
$081E: LDA #$FF / STA $07   ; ptr3 (dest B)       = $FF00
$0822: LDX #$20             ; 32 pages (8KB) to move
$0824: LDA ($02),Y          ; copy loop: read from ptr1
$0826: STA ($04),Y          ;   write to ptr2 (dest A)
$0828: STA ($06),Y          ;   write to ptr3 (dest B)  -- same byte, two destinations
$082A: INY / BNE $0824
$082D: DEC $03 / DEC $05 / DEC $07      ; all 3 pointers march down one page
$0833: DEX / BNE $0824
$0836: LDA $0870,Y / STA $8000,Y ...    ; final block copied to $8000

So: it duplicates the just-loaded 8KB image (source pages $28→$08, i.e. the program's own load region $0800–$2800) into two places at once — pages $3F→$1F and $FF→$DF — then separately relocates a block from $0870 to $8000. Earlier in the same stub (not re-disassembled here, seen in the raw PRG bytes) there's LDA #$35 / STA $01 — the standard 6510 I/O-port trick to bank BASIC ROM out and get full RAM underneath, which is why this duplication into $8000/$C000-ish territory is possible at all. Reads as a classic early-80s trick to get code/graphics data into every memory configuration the game will bank-switch between at runtime (RAM under BASIC, RAM under KERNAL, etc.) without reloading from disk each time.

Verification note: confirmed live — checkpoint at $080D fired with hit_count: 1 (correctly rare, matches expectations for a one-shot SYS entry point), and by the time the ~1-frame overshoot let it settle, the zero-page pointers ($03/$05/$07) had each decremented by exactly 3 — i.e. 3 full 256-byte passes had completed, consistent with the loop structure above.

Confirmed working end-to-end

vice_disk_attachvice_autostart → checkpoint on the SYS target → vice_disassemblevice_display_screenshot. Boots correctly to the title/attract screen: TIME bar, HI-SCORE/SCORE, "PUSH 'F1' TO RUN", NEXT MEAL bonus, ROUND 1. Reference screenshots of the title screen, play, the time bonus and a SPEED RUN are in reference/.

Next steps, if we go further

The symbol map for this game is symbols.json; the listing behind the Source tab is listing.json. Write-ups, facts and symbol maps are CC BY-SA 4.0. The game itself is not hosted here.