Claim set · data/claims/smb1-demo.yaml

Super Mario Bros. title-screen demo (doppelganger's SMBDIS via Xkeeper0/smb1)

Game: Super Mario Bros..

Super Mario Bros.' demo is a script of 21 controller bytes in DemoActionData, each held for the number of frames at the same place in DemoTimingData; DemoEngine moves to the next byte when the count runs out. The 21 counts add up to 1,119 frames (computed), about 18.6 seconds at the NES's 60.1 frames a second (computed). smb1-demo/script

About: Super Mario Bros. Demo playback

Value
[
 [
  1,
  155
 ],
 [
  128,
  16
 ],
 [
  2,
  24
 ],
 [
  129,
  5
 ],
 [
  65,
  44
 ],
 [
  128,
  32
 ],
 [
  1,
  36
 ],
 [
  66,
  21
 ],
 [
  194,
  90
 ],
 [
  2,
  16
 ],
 [
  128,
  32
 ],
 [
  65,
  40
 ],
 [
  193,
  48
 ],
 [
  65,
  32
 ],
 [
  193,
  16
 ],
 [
  1,
  128
 ],
 [
  193,
  32
 ],
 [
  1,
  48
 ],
 [
  2,
  48
 ],
 [
  128,
  1
 ],
 [
  0,
  255
 ]
]
Codesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L459-L467DemoActionData: .db $01, $80, $02, $81, $41, $80, $01 .db $42, $c2, $02, $80, $41, $c1, $41, $c1 .db $01, $c1, $01, $02, $80, $00 DemoTimingData: .db $9b, $10, $18, $05, $2c, $20, $24 .db $15, $5a, $10, $20, $28, $30, $20, $10 .db $80, $20, $30, $30, $01, $ff, $00smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L469-L485LDX DemoAction ; load current demo action LDA DemoActionTimer ; load current action timer BNE DoAction ; if timer still counting down, skip INX INC DemoAction ; if expired, increment action, X, and … LDA DemoTimingData-1,x ; get next timer STA DemoActionTimer ; store as current timer … LDA DemoActionData-1,x ; get and perform action (current or next) STA SavedJoypad1Bits DEC DemoActionTimer ; decrement action timersmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/defs.asm#L104-L111A_Button = %10000000 B_Button = %01000000 … Left_Dir = %00000010 Right_Dir = %00000001Checked by claude, 2026-10-22 — read DemoEngine and both tables at the pinned commit; the first call with a timer of 0 loads a count and applies the byte once, so each byte is applied for its full count; summed the 21 counts before the final $00 (1,119); the frame rate (60.0988 Hz NTSC) is outside the source and only scales the computed seconds

Cited by: Demo playback

The demo writes each byte into SavedJoypad1Bits, the byte the interrupt routine fills from controller 1 every frame, and then calls GameCoreRoutine, the same engine a game in play runs, so Mario moves by the ordinary player code. smb1-demo/input-path

About: Super Mario Bros. Demo playback

Codesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L74NonMaskableInterrupt:smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L116JSR ReadJoypads ; read joypadssmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L1895STA SavedJoypadBits,x ; save controller status here alwayssmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L480-L481LDA DemoActionData-1,x ; get and perform action (current or next) STA SavedJoypad1Bitssmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L343-L348LDX DemoTimer ; otherwise check demo timer BNE ChkWorldSel ; if demo timer not expired, branch to check world selection STA SelectTimer ; set controller bits here if running demo JSR DemoEngine ; run through the demo actions BCS ResetTitle ; if carry flag set, demo over, thus branch JMP RunDemo ; otherwise, run game engine for demosmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L390-L391RunDemo: JSR GameCoreRoutine ; run game enginesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/ram.asm#L31-L32SavedJoypadBits = $06fc SavedJoypad1Bits = $06fcChecked by claude, 2026-10-22 — read the NMI's ReadJoypads call, ReadPortBits' store, GameMenuRoutine's demo branch, and RunDemo at the pinned commit; SavedJoypadBits,x with x = 0 is SavedJoypad1Bits

Cited by: Demo playback

Each time the title screen starts, InitializeGame sets DemoTimer to $18 (24). It is one of the interval timers, which the interrupt routine counts down once every 21 frames, so the demo starts about 500 frames after the title appears (computed: 24 × 21 = 504, less up to 20 for the first tick). Pressing Select, or B once world select is enabled, puts the timer back to $18. smb1-demo/start

About: Super Mario Bros. Demo playback

Value
{
 "ticks": 24,
 "framesPerTick": 21
}
Codesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L316-L323TitleScreenMode: LDA OperMode_Task JSR JumpEngine .dw InitializeGamesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L2131-L2132LDA #$18 ; set demo timer STA DemoTimersmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L74NonMaskableInterrupt:smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L126-L140LDX #$14 ; load end offset for end of frame timers DEC IntervalTimerControl ; decrement interval timer control, BPL DecTimersLoop ; if not expired, only frame timers will decrement LDA #$14 STA IntervalTimerControl ; if control for interval timers expired, LDX #$23 ; interval timers will decrement along with frame timers … DEC Timers,x ; otherwise decrement the current timersmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/ram.asm#L60-L82Timers = $0780 … DemoTimer = $07a2smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L355-L359LDA DemoTimer ; if select or B pressed, check demo timer one last time BEQ ResetTitle ; if demo timer expired, branch to reset title screen mode LDA #$18 ; otherwise reset demo timer STA DemoTimersmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L348-L354ChkWorldSel: LDX WorldSelectEnableFlag ; check to see if world selection has been enabled BEQ NullJoypad CMP #B_Button ; if so, check to see if the B button was pressedChecked by claude, 2026-10-22 — DemoTimer at $07A2 is offset $22 of Timers, inside the interval range (X = $23) and outside the frame range (X = $14); IntervalTimerControl reloads $14 when it goes negative, so the interval timers tick every 21st frame; read the select/B branch at the pinned commit

Cited by: Demo playback

The demo ends, and the title screen restarts from InitializeGame, in three ways: the script reaches its closing count of 0; the engine reaches its lose-life routine (GameEngineSubroutine 6); or a player presses Start (alone or with A) or Select on either controller; B, which the title screen checks for world select, isn't tested while the demo runs. smb1-demo/end

About: Super Mario Bros. Demo playback

Codesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L474-L478INC DemoAction ; if expired, increment action, X, and SEC ; set carry by default for demo over LDA DemoTimingData-1,x ; get next timer STA DemoActionTimer ; store as current timer BEQ DemoOver ; if timer already at zero, skipsmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L390-L400JSR GameCoreRoutine ; run game engine LDA GameEngineSubroutine ; check to see if we're running lose life routine CMP #$06 BNE ExitMenu ; if not, do not do all the resetting below ResetTitle: LDA #$00 ; reset game modes, disable STA OperMode ; sprite 0 check and disable STA OperMode_Task ; screen outputsmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L4266-L4276GameRoutines: … .dw PlayerLoseLifesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L330-L342LDA SavedJoypad1Bits ; check to see if either player pressed ORA SavedJoypad2Bits ; only the start button (either joypad) CMP #Start_Button BEQ StartGame CMP #A_Button+Start_Button ; check to see if A + start was pressed … CMP #Select_Button ; check to see if the select button was pressed BEQ SelectBLogic ; if so, branch reset demo timersmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L343-L344LDX DemoTimer ; otherwise check demo timer BNE ChkWorldSel ; if demo timer not expired, branch to check world selectionsmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L348-L357ChkWorldSel: LDX WorldSelectEnableFlag ; check to see if world selection has been enabled … CMP #B_Button ; if so, check to see if the B button was pressed … SelectBLogic: LDA DemoTimer ; if select or B pressed, check demo timer one last time BEQ ResetTitle ; if demo timer expired, branch to reset title screen modesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L402-L404ChkContinue: LDY DemoTimer ; if timer for demo has expired, reset modes BEQ ResetTitleChecked by claude, 2026-10-22 — read DemoEngine's end branch, RunDemo's lose-life test (entry 6 of GameRoutines is PlayerLoseLife), and GameMenuRoutine's Start, A+Start, and Select tests, which run before the demo branch and reach ResetTitle while DemoTimer is 0; ResetTitle sets OperMode_Task to 0, TitleScreenMode's first task, InitializeGame; ChkWorldSel's B test is reached only while DemoTimer is not 0

Cited by: Demo playback

The demo doesn't reseed the random generator. PseudoRandomBitReg at $07A7 gets its seed $A5 only at reset, and the interrupt routine shifts it every frame; InitializeGame clears memory only up to $076F. The generator's state when the demo starts therefore depends on the number of frames since reset. smb1-demo/rng-not-reset

About: Super Mario Bros. Demo playback

Codesmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L29-L35ColdBoot: JSR InitializeMemory ; clear memory using pointer in Y … LDA #$a5 ; set warm boot flag STA WarmBootValidation STA PseudoRandomBitReg ; set seed for pseudorandom registersmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L74NonMaskableInterrupt:smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L142-L158PauseSkip: … LDA PseudoRandomBitReg ; get first memory location of LSFR bytes … ROR PseudoRandomBitReg,x ; rotate carry into d7, and rotate last bit into carrysmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/prg.asm#L2124-L2125LDY #$6f ; clear all memory as in initialization procedure, JSR InitializeMemory ; but this time, clear only as far as $076fsmb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1) · src/ram.asm#L237PseudoRandomBitReg = $07a7Checked by claude, 2026-10-22 — the only store of a seed into PseudoRandomBitReg is at ColdBoot (grep); PauseSkip follows the pause branch, so the shift runs every NMI; InitializeMemory clears page 7 from Y down to 0, so Y = $6F leaves $0770-$07FF; the statement makes no claim about whether the demo's run uses the generator

Cited by: Demo playback