I've been doing some testing and debugging of the pause glitch, and I seem to have figured out how it works!
The reason it happens is a bit technical, so bear with me:
- Every frame the normal program flow is "interrupted" by the VBlank interrupt, which draws the graphics to the screen. The code that does this is called the VBlank interrupt.
- After the VBlank interrupt, the program normally returns exactly to where it left off.
- Sometimes a bank can be switched during the VBlank interrupt. Normally this isn't a problem, because the VBlank normally only occurs when code in bank 0 (code from 0000-3FFF) is being executed. It looks like normally the game tries to switch back the bank to what it was, but fails sometimes.
- Notably, the bank is always switched from 4 -> 1 during VBlank when the game is paused.
- In certain situations, the game will return to the the wrong bank, and resume execution in the wrong place -- this is how the glitch occurs!
- I haven't quite figured out why this occurs, but it seems to have to do with lag caused by having too many objects on screen.
So in short, some situations, notably pausing, cause the game to switch banks during VBlank. Sometimes, the game will return to the wrong code (this happens when the return address is >=0x4000) and glitches will happen.
I made a Lua script to investigate the glitch. It will constantly spit out information about the VBlank in the debug menu and will pause VBA when the glitch occurs. (Try it on some of the vbm's mugg posted!)
pause_glitch.lua:
http://slexy.org/view/s2aZxMaoKS
I also did a more in-depth analysis of the video MUGG posted where it corrupted the level (
http://dehacked.2y.net/microstorage.php/info/767390219/lightning%2C%20glitched%20up%20row%20inside%20level.vbm):
Using my Lua script, you can see that the glitch occurs when the game should be returning to 4:4067, but returns to 1:4067. The code at 1:4067 just happens to jump to A201 and execute the code there. This is remarkable because A201 is in SRAM and is manipulable by the object duplication glitch! Strangely enough, this isn't even what causes the level to be corrupted - that has to do with the next VBlank, and doesn't really seem important to me. The code that the game actually runs at A201 mostly doesn't do anything and then hits a STOP instruction, which causes it to wait until the next VBlank. This is important because it stops the game from running a bunch of garbage code and crashing.
Sorry if that's all too technical, so let me summarize: We can use the pause glitch to run arbitrary code from an area of RAM we can control! I think a with a little more testing and cleverness we could easily use this to set A2D5.
(One final note: an alternative to setting A2D5 is setting FFB9 to 12,13, or 23 -- this will skip to the credits directly without having to die first. 13 hits the cutscene two frames before 23 and one frame before 12 - although I'm not sure that matters if last input is how movie length is counted.)
Edit: Seems obvious in retrospect, but what's causing the the glitch is a VBlank happening before the previous VBlank is finished. This is probably caused by lag - possibly it trying to draw too many objects and taking too long to finish. In practical terms, this means the only possible return addresses we can exploit are inside VBlank - which is good, because it should make manipulation a bit less of a guessing game.
Summary of return addresses of various glitch executions:
4067 - this runs code at A201 - the holy grail is being able to hit this after manipulating A201 to the code we want to run
5911 - causes a coin to appear
51D5 - freezes game
5916 - causes block to appear
4035 - glitched graphics (may be exploitable?)
Edit 2: New version of the Lua script:
http://slexy.org/view/s2PmJh4Gdv
This one assists in automatically triggering the pause glitch. Simple create a savestate in an area with lots of lag (I use the macro zone - wait just offscreen by the ant until the timer is ~333, and the game will be really laggy when you scroll the rocks on screen), then hold G to trigger the glitch.
Here's some more return addresses I was able to trigger:
4074 - soft reset
51C1,51C5,51D4,51D6,51D7 - freeze
58F7 - soft reset
590E,5914 - coin
5916 - break a block (glitch block appears)
triggered this twicem, only one time a block appeared
7FED,7FEF,7FFC - soft reset
Edit 3:
Unfortunately I didn't record a movie of this, but I was spin jumping while running the Lua script and this happened - I zipped upwards into glitch world, fell back down and the level was corrupted. Note that the pause glitch didn't trigger this. So it looks like the level corruption glitch is actually separate from the pause glitch.