A couple weeks ago, I streamed myself playing Nintendo Entertainment System games on Twitch while using a peculiar emulator script. This script, which I wrote using the Lua language, can be applied to any NES ROM, allowing the game to be played as normal. However, every time the ‘A’ button is pressed, more and more glitches start to appear…
Take a look below to see some of my experiences using it with the original Super Mario Bros.
Some of the glitches put the game in a soft-lock, requiring you to restart the game. But some actually allow you to progress. Still, it can be a challenge to even get past level 2!
I saw Goombas flying through the air. I saw unbreakable blocks. I saw levels consisting of different parts of other levels all thrown together. Sometimes, pipes that would normally lead to bonus areas ended up leading to different levels, or even bonus areas that I didn’t know existed.
So how is this script able to generate so many glitches? Well, let’s take a look at the code.
You can also try it out for yourself using the FCEUX emulator and any NES ROM file.
emu.print("Starting") local held = false local lastheld = false local pressed = false while true do -- Check if player 1 has pressed the A button this frame lastheld1 = held1 held1 = joypad.readimmediate(1).A pressed1 = held1 and not lastheld1 -- Check if player 1 has pressed the A button this frame lastheld2 = held2 held2 = joypad.readimmediate(2).A pressed2 = held2 and not lastheld2 -- Glitch it up if pressed1 or pressed2 then for i = 1, 3, 1 do addr = math.random(0x000, 0x7FF) value = math.random(0x00, 0xFF) memory.writebyte(addr, value) emu.print("Glitch at $" .. string.format("%04x", addr) .. " (#$" .. string.format("%02x", value) .. ")") end end emu.frameadvance() end
How the NES Works
So how does this script work? Let’s start by looking at how the NES (or NES emulator) runs games.
NES cartridges contain game information stored on ROM chips. You may be familiar with the term “ROM” from using various retro game emulators. A “ROM” file that you might load into an emulator is merely a copy of what the cartridge ROM chips store for a given game. This includes game logic, graphics information, and other code that determines how a game is played and what appears on screen.
Unlike modern computers, which load programs from persistent storage (like a hard drive) into RAM, the NES CPU (a modified version of the trusty MOS 6502) has direct access to code and other information stored in ROM. The RAM on a NES is reserved for variables that are modified by the game’s code.
What is Mario’s location on the screen? What enemies are on screen? What level are we playing? These are all determined by variables stored in RAM.
By modifying some of these variables, we can change the current state of the game! Sometimes, a player can use this to his/her advantage. For example, by using a Game Genie, the player can intercept and change values in the NES’s RAM to some desired effect like having extra lives, or invincibility. But if the wrong RAM variables are messed with, you often end up with… glitches!
Now, a NES emulator attempts to imitate the NES’s hardware, creating artificial RAM and loading game information from a ROM file. Using FCEUX’s Lua engine, we can load our own code that will run alongside the ROM code. We even have access to the information stored in emulated RAM.
So let’s break down our script’s code.
emu.print("Starting") local held = false local lastheld = false local pressed = false
This section of code just prints “Starting” to the FCEUX console to notify the player that our script is running. After that, we set up a few new variables that will be used later.
while true do
This line starts an endless loop. We need this in order to constantly check the state of the game and joypads.
lastheld1 = held1 held1 = joypad.readimmediate(1).A pressed1 = held1 and not lastheld1
Here, we check if player 1 has pressed the ‘A’ button during the current frame. Reading the joypad information directly only tells us whether the ‘A’ button is currently held down. Using temporary variables and a little bit of logic, we can determine if the ‘A’ button has just been pressed this frame. This lets us generate glitches only once per press of the ‘A’ button, and not on subsequent frames.
Some similar lines of code are put in to read the ‘A’ button from player 2.
if pressed1 or pressed2 then for i = 1, 3, 1 do
Here, we check if either player has just pressed the ‘A’ button. If they have, we start a loop that will run 3 times (each ‘A’ button press results in 3 glitches being produced).
addr = math.random(0x000, 0x7FF) value = math.random(0x00, 0xFF)
These lines generate some random values for us. One will be used as the RAM address (or variable) for the glitch, and the other is used as the replacement value. For the address, we use a random replacement value between 0 and 2047 (in hexadecimal, 0 to 7FF), which covers the entire range of the NES’s internal RAM, 2 Kilobytes. For the value, we use a random value between 0 and 255 (0 to FF in hexadecimal). Since the NES is an 8-bit system, each RAM variable can hold a maximum value of 255.
memory.writebyte(addr, value) emu.print("Glitch at $" .. string.format("%04x", addr) .. " (#$" .. string.format("%02x", value) .. ")")
Now here’s the good stuff! We write a byte of information to the emulated NES RAM. Both the address in RAM and the value we are inserting there are random. This is what causes our glitches. Replacing random variables in RAM with random values cause a lot of weird effects. We could end up replacing the variable containing Mario’s location, or the graphics information determining what an enemy looks like.
After this, we simply display where the glitch occurred and what value was inserted on the FCEUX console.
Finally, we progress the game’s frame every iteration of our endless loop. This keeps the game moving like normal.
So now that you know a little about how this glitch script works, try it out for yourself! Monkey around with some of the Lua code and see just how glitchy you can get your NES games.
Until next time, happy glitching!