# MUSCLE (U) routine purpose notes - Pass 2 # addrpurpose 0x8000 Power-on entry: stack set up, PPU blanked through two vblank waits, APU frame counter silenced, $0300-$032C cleared, then the initial nametable stream is decoded into $0400 and the first stage is started. 0x800E Spin on $2002 until bit 7 is set, so the write to $2000 just before it has taken effect. 0x8019 Second vblank wait, this time before touching $4017/$4010. 0x802C Reset the game-state bytes at $0326/$032B/$032C and zero page $FF, clear $0300-$032C, then decode the compressed nametable pointed at by SourcePointerLo/Hi. 0x8052 Decode the compressed nametable stream at (SourcePointerLo/Hi) into (DestinationPointerLo/Hi). A byte with bit 7 clear is a run of (byte & $7F) copies of the next stream byte; a byte with bit 7 set is a literal, written only when it differs from what is already at the destination. $0346 is set whenever VRAM actually changed. 0x80AC Stage start-up: reset the animation and actor counters, clear the OAM shadow, initialise the sound engine, upload the HUD palette row, and hand control to MainGameLoop. 0x8132 Push or drop the two flash sprites (palette tiles $82) depending on PlayerCount and the fade state. 0x8164 Round initialisation: clear the shadow arrays at zero page $00-$BF, reset the controllers and the OAM shadow, collect the $81/$82 type sprites, set the per-player palette and sprite bases, and start the actors. 0x8226 Main game loop. Waits for the NMI handler to raise $0321, services the two frame timers, reads the controllers, and restarts the stage or updates actor positions. $0321/$0320 form the vblank handshake with the NMI. 0x82AC Restoring binary division of the 8-bit value in A by the constant 20 ($14). Eight steps shift the divisor right, conditionally subtract it from the 16-bit remainder, and roll the quotient bit into $0349. Quotient -> $0349, remainder -> $0347/$0348. 0x82E1 Point sound channels 1 and 3 at the silent sequence at $B1A1/$B1B0 with step 0. 0x82ED Point sound channel 3 at $B1B0 with step 0 (the tail of SilenceSoundChannels1And3). 0x82FA Set the $14-frame transition timer and start the intro music sequence for all four channels. 0x82FF Start a four-channel music sequence from the $B2B9/$B3B2 tables. 0x832A Draw the two score/tally markers at $20BB and $24A6 when their flags at $0338/$0339 are set. 0x8353 Redraw the score row at $20EC and $210C with the three current digits. 0x8372 Write one score digit: blank the cell unless it matches PlayerCount, then stamp the tile. 0x8399 Copy the 32-byte OAM shadow at $9EF4 into $0300 and upload it. 0x83A7 Advance both actors: add the per-actor scroll delta to the position in $0340-$0342, then step the round counter and redraw the tally markers. 0x845C Per-round timer and state update: redraw the score, start the round-change music, and either loop again or advance the round and prepare the transition objects. 0x856C Start the short round-change jingle and wait for the NMI handshake. 0x8596 Compare the actor position in $0340-$0342 against the screen bounds in $0328-$032A and latch the tighter limit. 0x8639 Clear the vblank handshake ($0321, $0320) and re-enable rendering. 0x8644 Force rendering off: PPUCTRL=$10, PPUMASK=0, updating both shadow bytes. 0x8653 Force rendering off and immediately signal the main loop by setting $0321. 0x865D Positive game-state branch of the NMI: update the flash counters and actors, detect a button edge, and bump the frame-skip counter in zero page $FE. 0x8751 Finish the NMI: clear the vblank latch unless $0321 says work is outstanding, poll $2002 to release the PPU address latch, and run the sound frame update. 0x8759 NMI epilogue: poll $2002, update the sound engine, restore Y/X/A, and RTI at $8764. 0x8765 Point sound channel 1 at the $B1EB sequence. 0x877C Main game-state dispatcher. Counts down the transition timer at zero page $8D and runs one of fourteen subsystem updates chosen by that counter. 0x87F2 Advance the screen-flash counter against the $2C-frame limit. 0x8837 Play the player-death sequence: load the palette, upload the sound command, clear the attribute area, and respawn the actors. 0x8848 Test the start/select bits of the raw controller byte. 0x885B Read the controllers and advance the frame counter. 0x887C Signal the main loop that the NMI frame is finished. 0x8882 Read the controllers and test the round-transition flag at $0326. 0x88A4 Build the OAM list for the active player: blank every slot, then emit one sprite per visible actor row. 0x88B0 Emit a single OAM entry built from the actor record. 0x8936 Find the next free OAM slot by scanning the $032E source list for a value matching the running sprite index. 0x8986 Compact the OAM list, dropping entries whose actor has moved off screen. 0x89CE Read the controllers, reset the per-player bookkeeping, and initialise the object list. 0x8A28 Update the stage actors: pick the animation for each player from the palette index pair and hand off to SpawnStageActors. 0x8AE8 Rewrite the attribute table entry at $209C through the compressed stream writer. 0x8B20 Write one tile into the nametable at the address in zero page $10/$11 plus the per-round offset. 0x8B92 Render the HUD digits: set up the palette copy, clear the digit cells, then run each digit descriptor. 0x8BF8 Re-enable rendering: PPUCTRL=$10 with PPUMASK left at zero and the shadow updated. 0x8C05 Advance the animation slot below the current one. 0x8C0E Queue a VRAM descriptor built from the PlayerCount-relative index. 0x8C65 Execute the queued VRAM transfer: copy bytes from (BytecodeStreamPointerLo/Hi) through the destination pointer and the two block counters. 0x8CB8 Push a VRAM descriptor and bump the queue index. 0x9AE8 Bytecode interpreter entry. Reads a token byte through (BytecodeStreamPointerLo/Hi); tokens $C8-$EF are converted to an index and dispatched through the handler table at $9237 into jmp ($001C); anything else is an operand consumed by the current handler. 0x9B05 jmp ($001C) - the handler table and the $9F2B table both land here to re-enter the interpreter at the next token. 0x9B25 Main bytecode program loop: advance the program counter, dispatch the token, and resume. 0x9CBB Reset the per-invocation script state at $034D/$034E and the flags in zero page $4D/$4E. 0x9E7F Queue a nametable write described by a two-byte descriptor and advance the write pointer. 0x9F4B Update actor movement from the object script, dispatching through jmp ($001C). 0x9F54 Move an actor by one opcode: read the displacement, apply it, and redraw. 0xA01D Process one bytecode opcode against the actor record, advancing the script pointer. 0xA17F Run an actor script: set up the source/destination pointers, then walk the descriptor stream. 0xA250 Read one byte of the actor configuration block, scaled by four. 0xA253 Compute the byte offset of an actor configuration record. 0xA4FF Flip the low bit of A, turning a player index into its partner (0<->1, 2<->3). 0xA508 Resolve an object index through the per-player tables at $2A and $26. 0xA512 Walk the object slots looking for one whose countdown at $45 is non-zero. 0xA68E Update the whole object list, then the second half of it. 0xA6F8 Update object collisions and the object scroll test. 0xA8D1 Advance an object animation frame from the table at ($75),y. 0xA949 Update both players' object animations. 0xAA56 Read both controller ports: strobe $4016, shift eight bits per port into zero page $FA/$FB, save the previous byte in $F4/$F5, and derive the face/direction masks in $F6-$F9. 0xAA63 Shift one controller port's eight bits in from $4016/4017 and run the edge-detection post-processing. 0xAACD Enable rendering: PPUMASK=$18, PPUCTRL=$90, both shadows updated. 0xAADC Disable rendering, then clear both nametables to tile $30. 0xAAEF Set the PPU address from A and write $C0/$40 bytes of tile $30. 0xAB68 Load the HUD palette and the per-round object configuration into the $0300 shadow. 0xABB1 Upload the 32-byte palette from $0300 to $3F00, then restore PPUMASK. 0xABE4 Write the latched scroll (PpuScrollX/PpuScrollY) and PpuCtrlShadow to the PPU. 0xABFC Clear the 256-byte OAM shadow at $0200 to $F0. 0xAC0D Select and run the level's VRAM writer from the three-entry table at $AC35, indexed by the level byte at $0326. 0xAC82 Decode one compressed VRAM token: below $B8 is a literal, $B8-$C3 is a run whose fill value comes from the table at $ACBD and whose length is the next stream byte, $C0 additionally skips a byte first, and $C4 or above is a literal. 0xAC88 Advance the compressed-stream source pointer (SourcePointerLo/Hi) by one byte. 0xACF5 Write a block of compressed data to VRAM: the first byte is the block count, then each block supplies a 16-bit PPU address followed by a token run. 0xAD19 Compute the collision bit flags for the active player and store them in zero page $15. 0xAF25 Silence the APU: $4015=0, the enable mask cleared, and all four channels marked finished. 0xAF3B Sound frame update: walk all four channels and update the APU. 0xAF40 Update all four sound channels in turn. 0xAF43 Update one sound channel: restart it from its sequence when finished, otherwise count the note timer down and step the sequence. 0xAFAB Advance a sound channel's sequence pointer by step*2 from its base. 0xAFC5 Compute the envelope mask for a channel from its envelope mode. 0xAFD9 Compute the tone period for a channel from its note table and write the period registers. 0xB03A Read a note's duration from the sequence and store it, doubling it for looped notes. 0xB06C Apply one byte of a sound sequence: below $A0 is ignored, $A0-$AF patches the $4000 control byte, and $B0+ handles note and sustain data. 0xB0C6 Decrement the channel's sustain counter and advance the sequence.0x8644 Set PPUCTRL to $10 and PPUMASK to 0, updating both shadow bytes. Provably unreachable: no word in the image points at it except the jsr at $8654, and $8653 itself is unreferenced. Kept as code because the shape is unambiguous. 0x8653 Call ForceRenderingOff, signal the main loop through SignalVblankComplete, then clear the vblank latch at $0320. Provably unreachable (no word in the image points at $8653). Kept as code because the shape is unambiguous. 0x9CAD Decrement the 16-bit word in Zp14/Zp15 by one. A textbook "dec 16-bit" helper, but Zp14/Zp15 are otherwise scratch, and no word in the image points here. Provably unreachable; kept as code.