RLX Credits Warp Technical Explanation
Apr 9th, 2016
- RLX Credits Warp Technical Explanation
- by SethBling
- This is a technical explanation of how the arbitrary code execution works in the RLX credits warp (so-called because you hold RLX during the item swap).
- SNES instruction set: http://wiki.superfamicom.org/snes/show/65816+Reference
- SMW Ram map: http://www.smwcentral.net/?p=map&type=ram
- Performing the item swap with the chargin' chuck causes Yoshi to eat the chuck, which is normally disallowed. As a result, processor execution jumps to 014A13. This is in a region of the address space called open bus, which is not mapped to any device, so all reads will just return the contents of MDR (memory data register), which will contain whatever memory value was last written/read.
- Since the data bank of the JMP was the last byte read, the MDR contains $01, so the instruction is ORA ($01,x). The x register is determined by the sprite slot of the chargin' chuck, which is 9. So the indirect lookup uses the address at $01+9=$0A. $0A was most recently set as the high byte of Yoshi's x-coordinate and $0B as the high byte of his y-coordinate. In this case, $0A=$0107. So the instruction will OR the "a" register with the contents of memory address $0107. This RAM address contains $17. OR a with $17. Now the MDR contains $17.
- The next instruction is ORA [$17],y. Direct page addresses $17 and $18 are controller registers for axlr----, $17 is the current frame, and $18 is for first-frame presses. By holding down RLX, $17 is $50, and $18 is $00, because none of the presses are first-frame. $19 is $00 because Mario has no powerup. Because y contains $74, the instruction ORs a with the contents of $000050+74=$0000E4. $E4 is the low byte of the x-coordinate for sprite slot 0, which was the shell on the ground at the beginning of the level. It was spit out for a value of $FC, so the MDR is now $FC.
- The next instruction looks like it should be JSR ($FCFC,x) (jump to subroutine). JSR interacts strangely with open bus:
- * First, the instruction is read as $FC (JSR)
- * The low byte of the destination is also read as $FC
- * Then, the high byte of the return address is pushed to the stack ($4A)
- * Then, the low byte of the return address is pushed to the stack ($19). The MDR is now $19.
- * Finally, the high byte of the destination is read ($19)
- So the instruction is actually JSR ($19FC,x). x is still 9, so we JSR to the address contained at $1A05. $1A05 is in a part of memory responsible for keeping track of collected coins and used ?-boxes. $1A05 is always $00 in YI2, because there aren't any item boxes or coins in that part of the level. The Yoshi box is tracked by the $02 bit of $1A06, it becomes 1 when you hit it. By duping that Yoshi block to the right, we also set the $01 bit of $1A06, so that $1A06 becomes $03. That means we JSR to $0300, which is the middle of the OAM table.
- The OAM table is responsible for drawing tiles to the screen. Different entries of the OAM table are used for certain types of tiles. $0300 is used for drawing Yoshi swallowing an item, and also for Mario when he turns around while carrying an item. Since we turned around while holding a shell near the end of the level, $0300 is set by the x coordinate of the turn-around animation, which was last seen as $80. $0301 is set by the y coordinate of the tile, which is set to $F0 (off-screen) after the animation is done. The next instruction is BRA $F0, which branches backwards $10 bytes (after moving forward 2 for executing the instruction). We land at $02F2.
- $02F0-$02F7 are used for white "splat" tiles whenever you kill or hit an enemy. $02F2 is $7C (the splat tile identifier), which is JMP (addr,x). $02F3 is $20 (the splat tile attributes). $02F4 is the x-coordinate of one of the splat tiles, whenever it was last seen, which is when we kicked the shell off the left side of the screen, and set to $18. So the instruction is JMP ($1820,x). x is still 9, so it's JMP ($1829), we'll end up at the address that's contained by $1829.
- $1829 is inside the minor extended sprite y-velocity table. Some minor extended sprites, such as coins don't use this table. But Yoshi egg fragments do. $1829 is the top right fragment, and $182A is the bottom left fragment. We let the bottom left fragment despawn naturally for a value of $42. The top right fragment gets despawned early by our screen scroll at a y-velocity of $1A (can also be $18). The instruction ends up being JMP $421A (or potentially $4218).
- $4218 are the multitap registers. We have three controllers plugged in. Port 1 slot 1 is the main controller, and has RLX pressed. The bit format for $4218 is axlr----, so the value is $70, which is BVS. The next byte will be the operand for BVS, and since no other buttons are being pressed on the controller, the value is $00, so it'll branch forward 0, or do nothing, leaving us at $421A.
- $421A is port 2 slot 1, which is pressing A, L, Left and Select. $421A is axlr----, so $A0, which is LDY. $421B is byetUDLR, so $22. LDY #$22, y is now 22.
- $421C is port 1 slot 2, which is pressing L, Select, Y, B, Down and Right, so $421C is $20 and $421D is $E5. Since there's nothing plugged in to port 2 slot 2, $421E is $00. So JSR $00E5.
- We're now at $00E5, which is inside the sprite x-coordinate low byte table at slot #1 (remember, it's 0-indexed). We've spat out shells at x coordinates for slots #1-#5: $94, $F7, $4C, $87, $EF, which is STY ($F7,x); JMP $EF87. Since x is STILL 9, we store y to memory address $0100, which is where the game mode is stored, setting the game mode to $22. Then we jump to $EF87 in bank 1 of the ROM, which is the middle of a graphical function, which ends up pulling 4 bytes off the stack (we did two JSRs and don't want the game returning to open bus) and doing an RTS, and returning control back to the game. The game is now in game mode $22, so it stops trying to run a level, and rolls the first enemy screen of the credits.
- Non-multitap Route:
- For the non-multitap route, everything is the same until the processor reaches $421A. $421A now has the controller that $421C had in the multitap route, so we JSR $00E5, pushing $421C onto the stack as the return address. The low byte of that return address will become important later.
- $E5 contains different shell code in this route. It's now $A2, $28, $4C, $14, $DB, or LDX #$28; JMP $DB14. The low byte of the JMP destination can actually take a few different values here. This is the middle of another ROM function that pulls 4 values off the stack, with one very important difference. The first pull instruction it runs is PLA, which takes the low byte of the multitap JSR return address off the stack, which was $1C. Then it runs STA $D8,x. Since we changed x to $28 in the shell code, this stores $1C to $100, which corresponds to the beginning of the Yoshi's house cutscene in the credits.
Please, Sign In to add comment