Crashing Tetris! The Logic Behind the Madness - Behind the Code Leveled Up
HTML-код
- Опубликовано: 6 мар 2024
- Technical pursuit of the code that leads to a crash on the NES for Tetris.
If you would like to support this channel, here is a link to the Displaced Gamers Patreon page - / displacedgamers
Twitter: / displacedgamers
Facebook: / displacedgamers
Instagram: / displacedgamers
Music by:
/ hariboosx
/ @wolfandraven
#NES #Programming #Tetris - Игры
Hope you enjoyed this one! It took longer to make than the others. Tetris is really enjoying a boom in popularity right now, and I find this particular quirk to be fascinating.
Correction: I made an error in Photoshop layers at the 16:50 mark. The logic beginning at address $8045 should be PLA, TAY, PLA, TAX, PLA. The code in the ROM is correct.
Some resources:
mass:werk's article about 6502 opcodes - www.masswerk.at/nowgobang/2021/6502-illegal-opcodes
Meatfigher's Tetris a.i. script - meatfighter.com/nintendotetrisai/#Try_It_Yourself
Note the a.i. script I used is an older version. It was revisited here - meatfighter.com/tetrisairevisited/
You may need to modify the scripts to run them in Mesen. The original was designed for FCEUX.
"Have you ever given much thought to how we count? Probably not."
Programmers screaming right now
Somehow we release videos about the same topic within 24 hours of each other, and they complement each other wonderfully! Awesome work!
both of you do amazing videos!
OMG, RGME!
I enjoyed your video yesterday and was thinking to myself "gee, Displaced Gamers should also do a video on this." And lo and behold!!
It's a rather nice coincidence, to be sure. Both are great videos!
I actually thought it was Displaced Gamers because forgot that I hit the bell on RGME as well
RGME and Displaced Gamers covering Tetris a day apart? Hell ya.
Yep
Thought the same thing. Is there like a Tetris thing in March that I’m not aware of? Just sort of a weird crossover that isn’t a crossover.
@@RobertoVillegas-vincent404A world record for the NES version was broken recently
@@RobertoVillegas-vincent404 Recently a tetris kill screen was hit by a human.
Unfortunate timing but I'll do it again.
"I'M a programmer, not a Tetris master." Best line ever!!!!
As a non-programmer I always appreciate how you visually depict what's happening in game code.
Thanks!
@@DisplacedGamershell, as a programmer I also appreciate the wonderful visualizations. They're brilliantly done.
I checked explanations by: Meetfighter, Agamescout, Hydrant Dude, Fractal, Eric, Wiirambo, RGME, Kirjava and others... and I think I slowly start to understand the topic.
It is a fascinating and fun topic.
just read about stack smashing because that's what happening in the core :P But indeed, Displaced does amazing job with his disassemblies and visual explanations. Till this day i knew that stack's getting damaged but never knew actually why.
20:37 glad you managed to catch some things RGE didn't in their videos, like RAM storing tacos
Displaced Gamers nestris video ayooo??
Loved this video. The explanation of why BCD is needed was the best I've seen, just so clear and direct. And the event viewer visualization of the scoring loop taking over was so good. Looking forward to the next one.
Just for fun, here's a few bits of trivia (might update this later):
- There's actually a second BCD lookup table inside the game code that actually goes all the way up to like 50, which is used on the level select screen. As a result, it's possible to temporarily fix the bugged level indicator with just a couple of game genie codes.
- It may seem counterintuitive that singles are the first line clear to crash the game, since adding smaller numbers seems like it would take less work. However, what this means is that the number of carries increases, which is really what matters for measuring runtime. You can try this yourself: using the standard elementary-school right-to-left method of adding numbers, try computing 999999 + 40 on paper, and then try 999999 + 1200; you probably do more "work" for the first one!
- It's actually (somewhat) possible to control the value of the corrupted address in the dynamic jump routine that causes the crash. In NMI, the last values written to $00 and $01 are the inputs of the player 3/player 4 joypads through the "famicom expansion port" (so since people don't really use these controllers, the values are typically 0). Thus, if we hold down certain button combinations, we can essentially cause the jump routine to go wherever we want (with subtle restrictions ofc). This means that, to some extent, the crash can be fixed by forcing the corrupted address to be correct!
Thanks!
I cut maybe 2500 words from this script during development because it was getting WAY too long (and the video still ended up being super long versus my typical target), but I did think that arbitrary code execution would be a fun topic. I assume using the Famicom expansion port to direct a jump after having "written code" inside the high score table is a possibility. I think some people are already working on attempting something like this.
surprisingly, it's barely possible to achieve ACE without the expansion ports! that said, humans with access to this additional hardware could use it to make it easier to rollover the level counter (or maaaaaybe even do ACE without a TAS, but that seems very unlikely at the moment)
Is there any plan to use controller 3 and 4 for level 255 attempts?
@@MrCheeze I think only fractal has the hardware for it, and he's a little bit interested, but afaik not planning on it anytime soon
I was thinking it was a coincidence that both Retro Game Mechanics Explained and Displaced Gamers made videos related to Tetris. Guess with the popularity jump that's not the case, lol.
Behind the Code day is always a good day!
I love that the NEStris community finally reaching the "true kill screen" has shined more light on the classic game and its fun little quirks. It was very cool getting to see the different ways you and Retro Games Mechanics Explained tackled the same topic, and a very fun coincidence that you both finished your videos so close to each other. I especially appreciated the way you visualized the infinite loop logic.
The $x2 opcodes (except $82, $A2, $C2, $E2) on 6502 do stop the CPU and it gets stuck until a RESET - a write-up called "How MOS 6502 Illegal Opcodes really work" explains why this happens, although it requires you to understand quite a bit about how the 6502 works internally.
The short version is that the CPU decodes each instruction into smaller operations and the last operation is "load the next instruction". Invalid x2 instructions, when decoded, do not contain that operation, so the CPU never stops executing them.
I think I found my new favorite phrase, "An absolutely amazing cataclysm of unfortunate events." 😅
Illegal opcodes is the bread and butter of C64 demoscene coders =P
that's why most of them got arrested at some point.... for executing illegal ... opcodes...
maybe undocumented or unintended opcodes is a better word.
@@Alibaba-id4dw Yeah but that doesn't sound as sexy and exciting. And "Illegal" has an established meaning in computer science context
@@antivanti Hm. Actually I almost never hear "illegal", but I hear "undefined behavior" all the time.
@@Alibaba-id4dw You have "Illegal characters" and "Illegal request" etc. It's a thing.
I recently learned that the NES's CPU is an exact clone of another chip just with part of it cut out to avoid copyright infringement.
The part that got cut out? It would do native binary coded decimal, which would let them just add 0x09 + 0x01 = 0x10 directly.
So this video suggests that this issue is indirectly caused by the NES using a cheaper clone chip.
I love that this brings so much more detail to the recent news event of Willis Gibson beating Tetris. Bravo to him-- he had to progress in the game past a point that the designers didn't prepare for anyone reaching. Thank you so much for this video. It was great to watch!
ETA: And yes, I was laughing once I caught on to the impending code disaster.
I kinda want to see some of these old games with messy code get rebuilt under the hood.
I believe some in the ROM hacking community have put together a tuned-up version of Tetris that allows for better calculation of scoring, a proper level/line display, and more.
It always make my day watching a new video of the series, thanks!
I always admire your dedication to the small quirks and details in this historic pieces. Well done, again!
Your production quality is top notch, as is your way of making extremely complex things simple(r). Great job!
17:29 ackchually, it's PHA for PusH Accumulator to the stack, and PLA for PulL Accumulator :) and TXAand TYA are exchanged fotr TAX and TAY, but rest is accurate.
Yes, i don't have much friends
Alright then! Just for that - next video I am going to mix 68k and x86 assembly terminology into the explanation. Ha!
@@DisplacedGamers horrifying. reminds me of how the no$ emulators use x86 style assembly for every type of cpu architecture
@3:44 interesting fact: storing 0x12 to equal "12" is called BCD (binary coded decimal).. the 6502 actually has built-in support for it.. but the NES doesn't include the full 6502 so they have to do those corrections by hand.
@5:15, a great video that covers this already is, Bugs & Glitches of High-Level NES Tetris, by Retro Game Mechanics Explained. Though he skims over the code and a more in depth look would be a wonderful addition to Behind the Code Leveled Up. Possibly a collaboration?
Star Trek and Star Wars reference spotted. Very nice. Great video as always!
Initially I've been studying C++ for amateur programming but recently decided to study assembly code, specifically 6502 assembly, to get a better direct understanding of what goes on "under the hood" as it were. Now I'm understanding the code you present in your videos. Even though I could understand the concepts to an abstract degree they're all starting make sense now.
These BTC videos really are such a treat, cheers.
thanks for the upload!
Awesome video. I'd love to see a continuation of the Tetris stuff - that outro felt like a teaser of what is yet to come!
Working on a follow-up right now that uses the tools built in this first episode.
These videos are awesome.
Impressive, as always. Though I am familiar with all the topics you cover, it is still a pleasure to watch you cover them
Thank you!
Thank you, fascinating and entertaining as always
Thanks, my friend!
You and RGME are so damn good, i watched both videos. Great presentation
What's rgme
@@AboveEmAllProduction retro game mechanics explained
I love knowing way more than I comprehend about things I barely understand thanks!
Love this
Hello Chris! Subscribed
Ok !! Ready for a new video now !!!
Ever since a 13-year-old player has crashed _Tetris_ (Nintendo R&D1) on NES, the videos on RGME and Displaced Gamers were released about dissecting the game's code and studying the cause of that crash and this really makes _Tetris_ seem like the least competently coded first-party developed NES game.
The moment when the game's programmers only accounted for 31 levels of 256 possible levelvalues...and only made sure 29 of these actually display the correct levelnumber. And even ducked up behavior beyond that.(That is why levelselects exist btw, so people can test levels that no one at the playtesting can naturally get to)
Displaced Gamers in the HOuse!!🔥🔥🔥
I'd like to thank you for adding properly formatted subtitles. Just want you to know that people notice!
Always appreciate words of affirmation for this.
RGME's and your video have fullfilled my gestalt.
"Some would consider crashing a victory"
Me as a teen when I delete update data in Hyrule Warriors Legends(Legal behavior on the 3DS system btw) and hunt for odd behavior when putting an updated savefile into 1.0:
@20:37: wait, you just said the NES only has 2 kB of RAM! "Tacos" has to be a two-terabit asset at least. 😄
Great video! It got me thinking about how people (including me) talk about how software was so much more lightweight in elder days, and while there's an argument to be made there, a lot of the savings was down to using this kind of hack. It works, and on a sufficiently primitive platform it may be the only option, but it'll catch up with you down the road. (See also: Y2K problem, interlaced video, all the character-set disasters . . .)
I’ve been playing Tetris lately!
These videos are so interesting and well made! Have you ever considered looking into “Gimmick!”?
"BOOM... the number 10 is born..." 😂
Heh
Huh, two separate retro game channels covering the same topic within 24 hours.
Yep. Tetris is super popular right now.
I'm pretty sure there's an error at 16:45, the return code does not do what is described. As shown in the video, the return code is "Push A to Stack", "Transfer X to A", "Push A to Stack", "Transfer Y to A", "Push A to Stack", "Push A to Stack", "Return from Interrupt". The correct instructions here should be PLA, TAY, PLA, TAX, PLA, RTI: "Pull A from Stack", "Transfer A to Y", "Pull A from Stack", "Transfer A to X", "Pull A from Stack", "Return from Interrupt".
@@Xaymar Sorry. That is a photoshop error on my part. I wish I could correct it, but it is too late now.
18:20 I find it interesting that the earliest signs of trouble are... "music routine", "music logic", "sound routine". Audio glitches.
I am totally here for Absolutely Amazing Cataclysms of Unfortunate Events.
My philosophy has always been to provide internal variables to all "threads" of an NES program, so Main, NMI and IRQ all have locations they can use to talk to each other but other than that NMI and IRQ have their own internal variables including this "temporary workbench" / "register extension" area of zero page so that no such clobbering can occur as in the video. Also it might be helpful if you are trying to make your interrupt handlers faster to not use the stack and just save the A, X, Y registers to designated per-interrupt zero page locations instead that do nothing else but store your registers during the interrupt. It is a few cycles faster than using the stack.
I'm guessing this is also why Dr. Mario can do weird things and/or crash completely if you perform a very large combo that clears a lot of viruses. The game probably ends up taking too long to add up all of the points that the player scores, and then the code gets interrupted at a critical point.
Two cakes!
Ok, I'm happy to see Displaced Gamer talking about this, but I'm still waiting for Thor "I'm the NWC and the first person to document getting past level 29" to comment on where competitive tetris is now.
A better approach to managing the score would have been to use base 100 encoding, where bytes are confined between 0~99 ($00~$63) when doing arithmetic. Then, a 100-byte lookup table can be used to do the BCD conversion. From what I looked at in the disassembly for Tetris, there are more than enough bytes in RAM to keep track of an internal score and a displayed score up to 999999 (even for 2 players). I may try implementing this along with other bugfixes for this game.
13:03 you might say, unforeseen consequences...
Thank you for your work! This is a much better explanation of this phenomenon than I had seen other places.
The one thing I don't understand, though, is why does scoring a double at that point require so much less processing time than adding the score for a single?
All scoring above a single (a double, triple, or Tetris) does not have a value in the tens place. Because of this, the logic for converting the tens place from hexadecimal to decimal never needs to execute. This saves cycles and shortens scoring time.
Love this channel! Hope you can touch on some Z80 stuff one day with a few Sega Master System games.
Rewatching this video, I really wonder why the developers didn't just like store a lookup table to make the multiplication process faster lol
Looks like we got an Antz/Bug's Life situation in our hands xD
OMG MASS WERK I REMEMBER PLAYING THEIR HTML GAMES ON MY 3DS WHEN I WAS YOUNGER OMG LOL
Headlines: "A 13-year-old is the first human to *_officially_* 'beat' Tetris, by crashing it."
Displaced Gamers: "It's possible to roll over to level 0."
I also crash violently when someone foolishly attempts to execute the contents of my taco storage.
Wooooaaahhh dejavu!
I love it when Tetris stores tacos in RAM 🌮
You're describing packed decimal in the beginning, which is funny because the 6502 normally supports it natively, but the NES disabled those instructions.
edit: might be technically called binary coded decimal. When I was an assembly programmer, we just called it packed decimal, but there's apparently something else called densely packed decimal which is different.
2nd edit: IBM calls it packed decimal
And to think, all of this could've been avoided if they just spent 18 more cycles (or less, if they set a flag somewhere) at the beginning of the scoring loop to check if it was maxed out
The NES never ceases to amaze me. Sure modern computers are orders of magnitude more complex and powerful to the point where wasteful poor programming can still be executed reasonably fast, but the NES for what it was had some neat tricks and a generation of programmers who were on a whole different level.
Nintendo: No one will ever get past level 29 so our work here is done
Pro Tetris players: Bruh we can get into the 150s and up what are you talking about?1
Fun fact: Because of the fact that tournament matches were taking a long time to finish (due to a technique called "Rolling") the organizers of the CTWC (Classic Tetris World Championship) implemented something into the game so that the Tournament carts would speed up again at level 39 because otherwise the games would just go...and go...and go. Originally the idea of a "Line Cap" was brought up but the speed mod is what they settled on
It's definitely gonna be interesting to see what part of Tetris gets covered next because while I know about WHAT happens with some of the things that will eventually get covered its the actual HOW in the rom that actually fascinates me more so I'll be ready and waiting for the next one of these
13:04 That's my desktop wallpaper now.
I was actually also expecting some moddification of the code to prevent certain crash,but maybe next time😁
Tacos!
3:26 Yay!
I'm halfway through and you didn't mention WHY the Tetris developers didn't think anyone would get to a high enough level for this to be a problem. Simply put, the game speeds up so much after 20-something levels that regular play is impossible. Using normal controller posture you can't push the d-pad rapidly enough to move a piece over to the side wall before it lands, so you'll never be able to progress any further in the game and you'll quickly get Game Over. High-level Tetris players eventually figured out a technique called Hypertapping, and another one called Rolling, that allows extremely rapid button pushes to overcome this barrier.
The Tetris developers couldn't have foreseen how long it would become possible to play Tetris, so it's frankly amazing that the game doesn't crash until 100 levels *past* their theorised maximum level.
15:55: Nice reference, you made. Yes. Hm.
I think you are the first person that got this. Restored, my faith is.
Explains why, about that supposed kid broke the world record by crash.
Tetris fans eating good tonight
speedrunners: "what's a race condition?"
@DisplacedGamers
1. Great Video
2. What did you modify to play the game with an AI script?
It does movements which are impossible on the unmodded ROM.
I used an earlier version of the meatfighter script. There is a later script that uses moves that are more realistic. I thought about moving to the revision at one point, but it would have required additional work to make it compatible with Mesen - the emulator that I use.
Whoever told me that I could hide my subs really destroyed my free time. I watch more from my subs feed than the recommendation panel, but with nearly 600 subs now, I'm always behind. Oh well, I am still working on my two biggest projects, but it may be a while yet before I release either.
Hope you can cover one of these days, how the Last Ninja on C64 manages to load the screens with that incredible effect. Great research as always
Am I the first to realize that they just had to add score[lines] with base_score[lines] when changing level and they'd have the right score to apply without having to emulate multiplication with multiple adds when some line is cleared ?
Tacos etc.
the player crashes: the game won
the game crashes: the player won
Tacos
Same story on same topic in two days. Nice.
0:28 is this the setup for a Kool Aid ad?
It sure is! I only thought about Kool-Aid Man as art for that screen a bit too late.
Does the 6502 processor have native taco handling instructions?
21:41 How did the 6502 get past all the brk instructions to get to ISC?
(3:11) I believe you're missing an "INC Score_Mid_Byte_54" instruction at the bottom of the left column here.
I'm sorry. Sadly, it isn't the only Photoshop error in this video.
So well programed, better resets to 0 instead of breaks the game.
Szanuję jak poyebany! 😎🍻
who put tacos in my NES ram? bring me to your manager!!
I too like to store my tacos in RAM
Time to make some tacos
Nice
nice, just watched a similar vid yesterday...been curious about this ever since that kid "beat" the game....always thought the NES verison = Famicom version, interesting to see that isn't the case...so we essentially had 3 versions of the game
what about the 2 other Tetras versions ? Are they programed that poorly like this one ?
how would the NES change if it used a Harvard architecture vs a von Neumann architecture?
and could and emulator be made to fake a Harvard architecture for the 6507?
i always find it ironic when NES games use BCD because they're forced to do it in software as the 6502 variant used in the NES had it's BCD functionality removed (because nintendo sucks and they didn't wanted to pay MOS any royalties)
Can you please stop a video on why double dragon 3 won't execute the spin kick so often??
17:01 typo in pulls, you wrote pushes instead.
oi oi oi now hold just a sec i just saw this same video by retro game mechanics what the hell
Can we just be thankful the NES didn't have to try and calculate the score for a decahexatris?