The Legend of Zelda: A Link to the Past
Nintendo's 1991 Super Famicom/SNES Zelda, read through kan's disassembly of the US release.
The Legend of Zelda: A Link to the Past is Nintendo’s 1991 Zelda for the Super Famicom and SNES. The atlas reads it through kan’s (spannerisms’) disassembly of the US release, which he says assembles to that ROM exactly. snesrev’s zelda3, a C reimplementation translated from the same machine code, served as a map to the routines but isn’t cited. Nothing here has been measured in an emulator yet.
#Hearts
Health counts in eighths of a heart. A heart container adds one heart, up to 201. Every fourth Piece of Heart grants a container2. That container and the Sanctuary’s refill Link’s life; a boss’s adds a single heart of life1.
#Getting hit
A monster’s damage class and Link’s mail pick the damage of a touch from a 10 × 3 table3. The touch also pushes Link away at a speed of 24 with a small hop, and he can’t act for at least 19 frames4. A 58-frame timer, counted every frame, keeps further touches from landing5.
#Drops, magic, beams, and keys
A monster with a prize pack, numbered 1 to 7, drops something half the time, or always for pack 4. Each pack steps through its own eight prizes6. Each magic item has three costs, and one byte picks the column for all of them, such as 16, 8, or 4 for the rods7. The sword beam needs the Master Sword or better and less than half a heart missing8. Each dungeon keeps its own count of small keys9.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Health upgrade | Pieces | four Pieces of Heart make a container; up to 20 hearts |
| Damage formula | Defense table | a 10 × 3 table by the monster's damage class and Link's mail |
| Invincibility frames | Frame timer | 58 frames, counted down every frame |
| Knockback | Fixed shove | a speed of 24 away from the monster and a hop, at least 19 frames without control |
| Item drop table | Pack cycle | seven prize packs, each stepping through its own eight prizes |
| Magic meter | Consumption level | a cost per item, from one of three columns that a single byte picks |
| Sword beam | Near full | the Master Sword or better, with less than half a heart missing |
| Keys and locked doors | Per dungeon | each dungeon keeps its own small-key count |
Every claim about this game, by concept (9)
References
- ^ abA heart container adds 8 to Link's life capacity, one heart, up to
$A0, 20 hearts. The one from four pieces refills his life to the new capacity; the one a boss leaves adds a single heart of life.Codespannerisms/usdasmHow we know
13497|08C45A| CMP.b #$26 ; ITEMGET 26 13498|08C45C| BEQ .refill_hp ⋮ 13503|08C462| CMP.b #$3E ; ITEMGET 3E ⋮ 13509|08C46D| CMP.b #$A0 ⋮ 13513|08C472| ADC.b #$08 13514|08C474| STA.l $7EF36C ⋮ 13518|08C47D| ADC.b #$08 13519|08C47F| STA.l $7EF372 ⋮ 13525.refill_hp ⋮ 13538|08C49B| SBC.b $00 13539|08C49D| STA.b $00 ⋮ 13543|08C4A4| ADC.b $00 ⋮
bank_08.asm lines 13496–13544 at bcdd96e · upstream ↗ 13234|08C2DD| dw $FFFF ; FIGHTER SWORD ⋮ 13272|08C329| dw $0158 ; HEART CONTAINER FROM 4/4 - MESSAGE 0158 ⋮ 13296|08C359| dw $FFFF ; BOSS HC
bank_08.asm lines 13233–13297 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Each Piece of Heart adds 1 to a count kept modulo 4; the piece that brings it back to 0 grants item
$26, a heart container.Codespannerisms/usdasmHow we know
20390|05F08A| LDA.l $7EF36B 20391|05F08E| INC A 20392|05F08F| AND.b #$03 20393|05F091| STA.l $7EF36B 20394|05F095| BNE .not_full_set ⋮ 20400|05F09C| LDY.b #$26 ; ITEMGET 26
bank_05.asm lines 20390–20402 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A monster's bump damage class (0–9) and Link's mail (green, blue, or red) pick the damage of a touch from a 10 × 3 table, in eighths of a heart. Class 3 takes 8, 4, or 2; class 9 takes 64, 48, or 24; class 1 takes 4 whatever the mail.Codespannerisms/usdasm
How we know
LDA.w $0CD2,X … AND.b #$0F … ASL A … ADC.b $00 … ADC.l $7EF35B … LDA.w BumpDamageGroups,Y … STA.w $0373
bank_06.asm#L22729-L22740 · upstream ↗ 22775BumpDamageGroups: 22776|06F427| db $02, $01, $01 ; 0x00 22777|06F42A| db $04, $04, $04 ; 0x01 ⋮ 22779|06F430| db $08, $04, $02 ; 0x03 ⋮ 22785|06F442| db $40, $30, $18 ; 0x09
bank_06.asm lines 22775–22785 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A monster's touch sets Link's speed to 24 on the longer axis of the line from the monster to Link, the other axis in proportion, with a hop of vertical speed 12. It also sets a timer to 19 and Link's recoil flag. While the flag is set, his state handler runs the recoil state instead of the code that reads the buttons, and that state counts the timer down each frame, holding it at 1 until Link lands, so the recoil lasts at least 19 frames.Codespannerisms/usdasmrevised
How we know
22720|06F3E3| LDA.b #$13 22721|06F3E5| STA.b $46 ⋮ 22723|06F3E7| LDA.b #$18 22724|06F3E9| JSR ApplyRecoilToLink ⋮ 22726|06F3EC| LDA.b #$01 22727|06F3EE| STA.b $4D
bank_06.asm lines 22720–22727 at bcdd96e · upstream ↗ 23385ApplyRecoilToLink: 23386|06F688| PHA ⋮ 23397|06F695| LSR A 23398|06F696| STA.b $29
bank_06.asm lines 23385–23399 at bcdd96e · upstream ↗ 20385ProjectSpriteSpeedTowardsLink: ⋮ 20438.x_is_bigger ⋮ 20446.next 20447|06E9CC| LDA.b $0B 20448|06E9CE| CLC 20449|06E9CF| ADC.b $0C 20450|06E9D1| CMP.b $0D ⋮ 20459|06E9DB| DEX 20460|06E9DC| BNE .next
bank_06.asm lines 20385–20492 at bcdd96e · upstream ↗ 239|07812C| LDA.b $4D 240|07812E| BEQ .not_recoiling ⋮ 320|078199| LDA.b #$02 ; LINKSTATE 02 321|07819B| STA.b $5D ⋮ 323|07819D| BRL LinkState_Recoil
bank_07.asm lines 239–323 at bcdd96e · upstream ↗ 1450HandleRecoilAndTimer: ⋮ 1457|07871A| DEC.b $46 ⋮ 1459|07871C| LDA.b $46 1460|07871E| BEQ .delay ⋮ 1462.airborne ⋮ 1467.delay 1468|078723| INC A 1469|078724| STA.b $46 ⋮ 1471|078726| LDA.b $24 ⋮ 1476.no_height 1477|07872E| LDA.b $29 1478|078730| BPL .airborne
bank_07.asm lines 1450–1478 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^A monster's touch does nothing while Link's blink timer is above 0. A hit sets it to 58, and Link's sprite routine counts it down once a frame, so the protection lasts 58 frames.Codespannerisms/usdasm
How we know
22715#AttemptDamageToLinkPlusRecoil: 22716|06F3DB| LDA.w $031F 22717|06F3DE| ORA.w $037B 22718|06F3E1| BNE .no_damage
bank_06.asm lines 22715–22718 at bcdd96e · upstream ↗ 146|0780B4| LDA.w $031F 147|0780B7| BNE .have_iframes ⋮ 149|0780B9| LDA.b #$3A 150|0780BB| STA.w $031F
bank_07.asm lines 146–150 at bcdd96e · upstream ↗ 4530|0DAA46| LDA.b $11 4531|0DAA48| BNE .check_stair_visibility ⋮ 4533|0DAA4A| LDA.w $031F 4534|0DAA4D| BEQ .check_stair_visibility ⋮ 4536|0DAA4F| DEC A 4537|0DAA50| STA.w $031F
bank_0D.asm lines 4530–4537 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A defeated monster's prize pack (1–7) gives a drop half the time, and pack 4 always. Each pack keeps its own counter that steps through 8 prizes in order; pack 1's row is heart, heart, heart, heart, green rupee, heart, heart, green rupee.Codespannerisms/usdasm
How we know
24136|06F9B2| JSL GetRandomNumber ⋮ 24138|06F9B6| PLY ⋮ 24140|06F9B7| AND.w PrizePackRarities,Y 24141|06F9BA| BNE .you_dont_get_a_drop ⋮ 24152|06F9C0| ORA.w $0FC7,Y ⋮ 24155|06F9C4| LDA.w $0FC7,Y 24156|06F9C7| INC A 24157|06F9C8| AND.b #$07 24158|06F9CA| STA.w $0FC7,Y ⋮ 24162|06F9CE| LDA.w PrizePackPrizes,Y
bank_06.asm lines 24107–24162 at bcdd96e · upstream ↗ 24276|06FA5C| db $01 ; pack 1 : 50% ⋮ 24279|06FA5F| db $00 ; pack 4 : 100%
bank_06.asm lines 24275–24283 at bcdd96e · upstream ↗ 24307.pack_1 24308|06FA72| db $D8 ; SPRITE D8 - heart ⋮ 24312|06FA76| db $D9 ; SPRITE D9 - green rupee
bank_06.asm lines 24305–24315 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Each magic item's cost comes from a table with three columns, and one byte,
$7EF37B, picks the column for every item. The rods cost 16, 8, or 4; the medallions 32, 16, or 8; the powder 8, 4, or 2; the lamp 4, 2, or 2.Codespannerisms/usdasmrevisedHow we know
9964ItemMagicCost: ⋮ 9967|07B087| db $10, $08, $04 ; rod 9968|07B08A| db $20, $10, $08 ; medallion 9969|07B08D| db $08, $04, $02 ; powder ⋮ 9973|07B099| db $04, $02, $02 ; lamp
bank_07.asm lines 9964–9975 at bcdd96e · upstream ↗ 9990CheckMagicCost: ⋮ 9993|07B0AD| LDA.w ItemMagicCost.offset,X 9994|07B0B0| CLC 9995|07B0B1| ADC.l $7EF37B ⋮ 9998|07B0B6| LDA.w ItemMagicCost.cost,X ⋮ 10001|07B0BB| LDA.l $7EF36E
bank_07.asm lines 9990–10007 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^A Link to the Past fires the sword beam only with the Master Sword or better and less than half a heart missing; The Legend of Zelda fired it with up to half a heart missing and any sword.Codespannerisms/usdasm · aldonunez/zelda1-disassembly · “Legend of Zelda, The (USA) (Rev 1)”
How we know
5895|079C70| LDA.l $7EF36C 5896|079C74| SEC 5897|079C75| SBC.b #$04 5898|079C77| CMP.l $7EF36D 5899|079C7B| BCS .no_make_beam ⋮ 5906|079C86| LDA.l $7EF359 5907|079C8A| CMP.b #$02 5908|079C8C| BCC .no_make_beam
bank_07.asm lines 5895–5908 at bcdd96e · upstream ↗ 4632 ; If full hearts <> (heart containers - 1), return. ⋮ 4645 ; If partial heart is less than half full, return. 4646 LDA HeartPartial 4647 CMP #$80 4648 BCC L1F854_Exit
src/Z_07.asm lines 4632–4648 at 50a1c86 · upstream ↗ In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): bank 7 MakeSwordShot in Rev 1. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Each dungeon keeps its own small-key count. Loading a dungeon copies its count from a per-dungeon array into the current count,
SaveDungeonKeyscopies it back, and the overworld sets the current count to$FF. The Sewers and Hyrule Castle share one slot.Codespannerisms/usdasmrevisedHow we know
394|02825A| LSR A 395|02825B| TAX ⋮ 397|02825C| LDA.l $7EF37C,X
bank_02.asm lines 388–398 at bcdd96e · upstream ↗ 6643|02A1D4| LSR A 6644|02A1D5| TAX ⋮ 6646|02A1D6| LDA.l $7EF36F 6647|02A1DA| STA.l $7EF37C,X
bank_02.asm lines 6638–6648 at bcdd96e · upstream ↗ 666|0283E4| LDA.b #$FF 667|0283E6| STA.l $7EF36F
bank_02.asm lines 666–667 at bcdd96e · upstream ↗ 4154BitMasks: 4155|0098C0| dw $8000 ; Sewers 4156|0098C2| dw $4000 ; Hyrule Castle
bank_00.asm lines 4154–4156 at bcdd96e · upstream ↗ 17099RebuildHUD_Keys: 17100|0DFA68| STA.l $7EF36F
bank_0D.asm lines 17099–17100 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
Sources
Code
- (spannerisms), kan. 2026. “usdasm: A Link to the Past US Disassembly.” Commit bcdd96e. spannerisms/usdasm @ bcdd96e · licence, all uses
- Núñez, Aldo. 2021. “zelda1-disassembly: A complete disassembly of The Legend of Zelda.” Commit 50a1c86. aldonunez/zelda1-disassembly @ 50a1c86 · licence, all uses
- n.d. “Legend of Zelda, The (USA) (Rev 1).” · licence, all uses