As the hero of this game, Link just doesn't understand why his name isn't in the title of the game. Who is this mysterious Zelda person? Even after beating the game, he is as clueless as ever...

Game objectives

  • Emulator used: FCEUX 2.2.2
  • Arbitrary Code Execution
  • Heavy glitch abuse
  • Luck Manipulation
  • Uses damage to save time
  • Uses game restart sequence

Comments

Shortly after the previous movie was submitted, sockfolder found a way to use the names of the 3 game files to acquire ACE. The 8-byte long filenames are conveniently stored right after each other starting at $0638, $0640 and $0648 (which was also pointed out by pirohiko). Even though the values of the characters only range from 0x00 to 0x64 (meaning we can only use less than half of the opcodes available), sockfolder found a way to poll values from the input data and slowly, bit by bit, writing (shifting) code into arbitrary locations (chosen by input). You can read his full post here.

The glitch that triggers it all

When the game tries to spawn a new sprite, it will check for a free slot (0x00) and puts the new value (the value of the sprite) in the free slot. In the FDS version of this game, if you fill up all slots and play the whistle to spawn a new sprite (for example when the whistle reveals a new exit), the game tries to find free slot but it overflows (it actually counts backwards and underflows) and puts the value in a dangerous location.
This dangerous location can be the state of a sprite, making the code for that sprite use the wrong value for indexing and the game jumps to $0602. This location is where the game stores a lot of the music data. The code manages to get through that (additionally pressing A at the same frame you activate the whistle with B makes it a bit safer) and eventually gets to the filenames at $0638... which hold the values for ZELDA, because we had to start the 2nd quest. Fortunately, we can use the remaining 3 characters directly after ZELDA for our code while still starting the 2nd quest. And we're also in luck that the code ZELDA does nothing dangerous when being executed.

Filenames

 23 0E 15 0D 0A 0E 4B 06
 20 4B 06 0A 10 02 33 02
 4C 40 06 36 2F 64 24 24
The first 5 bytes are ZELDA and the last 2 are left blank (0x24), which means that the important code starts at:
 $063D: 0E 4B 06  ASL $064B
which effectively changes the 4th letter in the 3rd filename from 0x36 to 0x6C (which is necessary, because the characters only ranged from 0x00 to 0x64). Then, the main loop starts:
 $0640: 20 4B 06  JSR $064B
 $0643: 0A        ASL
 $0644: 10 02     BPL $0648
 $0646: 33 02     RLA ($02),Y
 $0648: 4C 40 06  JMP $0640
 -
 $064B: 6C 2F 64  JMP ($642F)
$0640: So the main loop starts by making a subroutine call to $064B.
$064B: This jumps to whatever is inside $642F, which is $EA1F and happens to be the routine that deals with the input. After returning, A holds only the newly pressed buttons and Y holds all the buttons.
$0643: An Arithmetic Shift Left is done so that the Carry is 1 if A was just pressed, else the Carry is 0.
$0644: This will branch forward if B was not just pressed (since B is now the MSB), but if B was indeed just pressed this frame then we go to:
$0646: Opcode 0x33 is actually an illegal opcode but the microprocessor still does something according to the bits in the opcode. The important part is, that this instruction shifts a byte in memory one bit to the left. Which byte is shifted is given by whatever address is in $0002, which is $0602 because that is where the address was stored when the glitch started (remember how the glitch started by jumping to $0602?). Y is being added to the $0602 to give the final address that is being shifted. It will shift the Carry into the LSB, which was previously set at $0643.
$0648: Jump to the start of the main loop.

The code itself

Writing the code

The small problem with this way of writing code is that it is really slow. You write the code by shifting bits, and you have to repress the buttons. In FCEUX this means you effectively write with a speed of 1 bit per 2 frames, which is 3.75 bytes per second (REALLY SLOW)... (well it's not really 3.75 bytes per second because of clever ways of writing code, which I explain later)
I say in FCEUX because this emulator only lets you input once per frame, even when it is polled multiple times. This also had the effect that sometimes some buttons were lost (because of unfortunate timing) and I had to wait a frame.
The whole memory where we want to write stuff is filled with 0x00's. This, and the fact that we are shifting from the right means that the lower the bytes are, the faster we can write them. For example a 0x00 takes no time at all, because we can just skip it. A 0x01 just takes 1 bit, 0x02 and 0x03 take 2 bits and so on. All bytes from 0x80 to 0xFF take all 8 bits and so I tried to avoid them as much as possible.
To shift in 1 bits, the Carry has to be set, so we have to newly press A for that frame (see $0643), and remember that we had to also newly press B (see $0644) to actually make the shift. Holding both A and B means that Y is at least 0xC0. Since Y is added to the address (which is $0602), we can write code starting at $06C2.
A way to actually execute the code is to corrupt the filename code. By shifting a 0 to $064B, changing it from 0x6C to 0xD8, we can escape from the loop. It will fail at the 0x22 at $0654, so we change that to a 0x44. Then the code will execute to our code, only that $06C2 is part of the BRK (the 0x00 instruction) at $06C1, so we don't start our code at $06C2, but $06C3.

Requirements

So, the credits are loaded with Level 9, which means we have to actually load it. This can be done by setting $0010 to 0x09 (level 9), $0011 to 0x00 (do something) and $0012 to 0x02 (load the bank).
After the level is loaded, we have to finish the game somehow. This is done by setting $0011 to 0x00 (do something) and $0012 to 0x13 (credits routine).

Let's go

Starting at $06C3:
 29 02 20 4C 84 09 09 85 10 6E 00 20 A5 3C D0 FC 09 13 20 4C 84 20 7B 63
Cool, huh? Let's see...
 $06C3: 29 02     AND #$02
 $06C5: 20 4C 84  JSR $844C
We are in luck and A is 0xCA which means we can change it to 0x02 by ANDing, which is faster than LDA #$02, because that would be A9 02 and remember that writing A9 is slower than writing 29. Jumping to $844C does quite a bit setup for us. It sets $0012 to whatever is in A (which is 0x02), it sets $0011 to 0x00 and it returns with A being 0x00.
 $06C8: 09 09     ORA #$09
 $06CA: 85 10     STA $0010
Because A returned as 0x00, we can use ORA to set A to 0x09, which again, is faster than using the slow LDA. Then we set $0010 to 0x09 and we finished our first requirement. Only the problem now is that where do we return to? How do we continue the game? How do we continue the code after Level 9 loaded?
 $06CC: 6E 00 20  ROR $2000
 $06CF: A5 3C     LDA $003C
 $06D1: D0 FC     BNE $06CF
NMI is disabled by the game to avoid interrupts (updating the screen) before the game is done calculating the frame. We manually activate it by shifting the Carry (which is thankfully set) into the NMI enable bit in $2000. Then we start our own "infinite loop" which continues until $003C holds 0x00. $003C is basically a timer that counts down until we can move in the dungeon. So the code continues when the level is loaded and we can basically move.
 $06D3: 09 13     ORA #$13
 $06D5: 20 4C 84  JSR $844C
Since $003C should be 0x00 by now, A is also 0x00 (because of the LDA $003C), which means we can, again, change it to 0x13 by using the fast ORA. Then we, again, call $844C which does the same thing as before, only with a different A. $0012 is set to 0x13 and $0011 is set to 0x00. At this point we could write a quick infinite loop to show the credits and so on, but that would result in a crash as soon as you press something after the credits. To avoid that, the last piece of code is this:
 $06D8: 20 7B 63  JSR $637B
$637B is the infinite loop the game uses, so the game is back to normal now and starts the credits routine.

Special Thanks to

  • RAT926 for finding the item glitch and finding slight improvements in the route.
  • pirohiko for pointing out errors in the submission text. :D
(Seriously though, who is Zelda?)

Nach: I don't know what's going on. I can't make any sense of this. Consider yourself as glitching out the judge☺ابوSنصرO محمدT بEنV محEمد فا Россия²راYبی‎(T)נ"ך. Accepting as new run for this game.
Spikestuff: Publishing!


TASVideoAgent
They/Them
Moderator
Joined: 8/3/2004
Posts: 15582
Location: 127.0.0.1
Post subject: lonk from pennsylvania
Experienced player (690)
Joined: 11/23/2013
Posts: 2233
Location: Guatemala
Lonk: "who is zorldo?". This is fantastic, but I have one question... Does this corrupts memory? The submission text doesn't make that clear... for me.
Here, my YouTube channel: http://www.youtube.com/user/dekutony
Editor, Player (69)
Joined: 1/18/2008
Posts: 663
What was the thing holdering the trifarce?
true on twitch - lsnes windows builds 20230425 - the date this site is buried
d-feather
He/Him
Joined: 2/12/2015
Posts: 152
Location: Everett, WA
The ending made even less sense than last time, and I love it! Yes vote.
:shrug: I'm more active on Twitter nowadays: @HunterCoates5
Twisted_Eye
He/Him
Active player (398)
Joined: 10/17/2005
Posts: 632
Location: Seattle, WA
True wrote:
What was the thing holdering the trifarce?
boobs or two off-palette body pieces of a Moldorm either/or
ALAKTORN
He/Him
Former player
Joined: 10/19/2009
Posts: 2527
Location: Italy
Pirohiko link in OP text is broken. Edit: “I say in FCEUX because this emulator only lets you input once per frame, even when it is polled multiple times. This also had the effect that sometimes some buttons were lost (because of unfortunate timing) and I had to wait a frame.” So does this mean it would be faster on a better emulator? 7/8.8
Samsara
She/They
Senior Judge, Site Admin, Expert player (2238)
Joined: 11/13/2006
Posts: 2822
Location: Northern California
Finally, a TAS that plays out like one of my nightmares
TASvideos Admin and acting Senior Judge 💙 Currently unable to dedicate a lot of time to the site, taking care of family. Now infrequently posting on Bluesky
warmCabin wrote:
You shouldn't need a degree in computer science to get into this hobby.
Experienced player (584)
Joined: 2/23/2008
Posts: 266
Location: CA, USA
That ending... holy...
Editor, Skilled player (1439)
Joined: 3/31/2010
Posts: 2108
Nice improvement. Yes vote, natch. Edit: One thing I'd like to know in general is what happens in the screen wrap-around glitch. Why does it work and how is it done? If anyone could tell me, that'd be much appreciated.
Skilled player (1741)
Joined: 9/17/2009
Posts: 4981
Location: ̶C̶a̶n̶a̶d̶a̶ "Kanatah"
The delayed ending was oddly fitting considering how slow the game seems to load. :P
Player (13)
Joined: 6/17/2006
Posts: 508
Game: YOU HAVE AN AMAZING WISDOM AND POWER. Me: I agree. Reading the submission comments though, I feel that emulators for TASing should have an option to record input at any given CPU cycle. I'm surprised this is still a problem.
Skilled player (1785)
Joined: 5/7/2008
Posts: 187
Location: Japan
Improvement of the ACE and the improvement of the movement are interesting both. The insertion of the code which is real time in NES is very epoch-making.
Player (107)
Joined: 8/4/2013
Posts: 84
Location: Japan
Nice Run and Nice ACE Running test movie Legend of zelda Ver1.1 to ACE OK(FDS Zelda no densetu Ver1.1)
Editor, Experienced player (570)
Joined: 11/8/2010
Posts: 4036
What an ending! Yes vote.
Post subject: Re: #4709: TASeditor & Masterjun & sockfolder's FDS Legend of Zelda "2nd quest, game end glitch" in 03:06.46
Skilled player (1785)
Joined: 5/7/2008
Posts: 187
Location: Japan
TASVideoAgent wrote:
$0643: An Arithmetic Shift Left is done so that the Carry is 1 if B was held, else the Carry is 0. $0644: This will branch forward if A was not held (since A is now the MSB), but if A was held then we go to:
Because the order of the key is "RLDUTSBA", I suppose that the explanation of $ 0643 and $ 0644 became alternate. When A=0x80 was pushed, ASL turns on a carry flag. When B=0x40 was pushed, ASL turns on a negative flag.
Editor, Player (69)
Joined: 1/18/2008
Posts: 663
ALAKTORN wrote:
Pirohiko link in OP text is broken. Edit: “I say in FCEUX because this emulator only lets you input once per frame, even when it is polled multiple times. This also had the effect that sometimes some buttons were lost (because of unfortunate timing) and I had to wait a frame.” So does this mean it would be faster on a better emulator? 7/8.8
We need a better emulator for NES anyway, period.
true on twitch - lsnes windows builds 20230425 - the date this site is buried
Synahel
She/Her
Former player
Joined: 1/19/2011
Posts: 260
Location: France
Amazing.
Techokami
He/Him
Joined: 6/23/2008
Posts: 160
Good gravy, that was nuts! Yes vote!
ALAKTORN
He/Him
Former player
Joined: 10/19/2009
Posts: 2527
Location: Italy
True wrote:
We need a better emulator for NES anyway, period.
I thought BizHawk did NES? Am I wrong or is that also not up to par?
Spikestuff
They/Them
Editor, Publisher, Expert player (2642)
Joined: 10/12/2011
Posts: 6438
Location: The land down under.
ALAKTORN wrote:
I thought BizHawk did NES? Am I wrong or is that also not up to par?
http://tasvideos.org/EmulatorResources/NESAccuracyTests.html
WebNations/Sabih wrote:
+fsvgm777 never censoring anything.
Disables Comments and Ratings for the YouTube account. Something better for yourself and also others.
Joined: 5/8/2010
Posts: 177
Location: Entropy
Link didn't bother with Ganon, the glitch boss was enough to win the game.
ALAKTORN
He/Him
Former player
Joined: 10/19/2009
Posts: 2527
Location: Italy
Spikestuff wrote:
ALAKTORN wrote:
I thought BizHawk did NES? Am I wrong or is that also not up to par?
http://tasvideos.org/EmulatorResources/NESAccuracyTests.html
Thanks. Bizhawk 26 52 13 33 5 3 132 83.5% The 3 should be bolded if I’m understanding it right. Edit: Mixing puNES and BizHawk would give 100%, so wouldn’t that be good/feasable? Edit: Nvm wouldn’t be 100% still.
Joined: 6/5/2005
Posts: 139
Very accurate depiction of what happens when you play a flute in a graveyard. Yes vote.
I like stuff...
Editor
Joined: 3/31/2010
Posts: 1466
Location: Not playing Puyo Tetris
So our hero, went to a graveyard, played an instrument, then he entered into a strange place where there was no logic. A fire spoke to our hero. Then the fire changed into something and held up a triangle. The hero did the same. The day was saved. Somehow...
When TAS does Quake 1, SDA will declare war. The Prince doth arrive he doth please.
Warepire
He/Him
Editor
Joined: 3/2/2010
Posts: 2178
Location: A little to the left of nowhere (Sweden)
That was even more amazing than last time. Absolute yes vote.