BRK

BRK is an instruction in the 65xx family of processors that triggers a software interrupt designed for debugging. An interrupt is a signal sent to the CPU that tells it to stop whatever it's doing and run a specific routine, determined by what the interrupt was. It may seem a bit unintuitive that an interrupt can be triggered by an operation the CPU performs. At least to me. After all, if an instruction is written to a specific place, it may seem more like an intended subroutine rather than an interrupt, which has a connotation of spontaneity. But, the intended functionality lumps it in pretty well with the other interrupts.

What exactly does an interrupt do?

Thanks, me. I'm glad I asked.

For this, we'll assume we're running our 65c816 in Native mode, rather than 6502 Emulation mode. And actually, we'll assume we're specifically using the SNES's Ricoh 5A22. There are eight 16-bit vectors located at $00:FFE0. A vector is just a pointer to other code. These ones specifically are hardware vectors, used by the CPU after an interrupt. All of these native mode vectors start by doing the same sequence:

  1. The 24-bit address to return to after the interrupt is pushed to stack.
  2. The program status register is pushed to stack.
  3. The decimal mode flag is cleared.
  4. The interrupt disable flag is set.
  5. The program bank (most significant byte) is set to $00.
  6. The appropriate pointer is loaded into the program counter (PC) from the vector table.

Every vector available to the SNES is shown in the table below. Two of these vectors are unused by the architecture itself. The abort vector is unavailable on the SNES. The native mode reset can never occur by design, as any reset of the CPU will put it into emulation mode. Every interrupt is exited by a special instruction: RTI, ReTurn from Interrupt. This instruction pulls the program status register before it pulls the PC from stack.

Hardware vectors as seen by the SNES
Address Vector Trigger
$00:FFE0 Unused N/A
$00:FFE2 Unused N/A
$00:FFE4 Co-processor COP
$00:FFE6 Software Break BRK
$00:FFE8 Abort N/A
$00:FFEA Non-Maskable Interrupt SNES hardware (60Hz)
$00:FFEC Unused reset N/A
$00:FFEE General Interrupt Request SNES hardware

Moving on

The function of each interrupt isn't necessarily important, because right now, we are focused on the software break interrupt. And this one is up to the developer. This one, as discussed, is triggered by the BRK instruction, which has a very purposely and purposefully chosen opcode of $00. As you might guess, this is a very common value, especially if the developers chose to initialize their ROM that way.

Since this is entirely up to the developers, let's look at a few game's to see what they do.

The Legend of Zelda: A Link to the Past

Hitting a BRK is pretty easy in this game. Many flavors of transition corruption can result in an illegal submodule, causing the game to execute erroneous code or data as code in who-even-knows-where? Most illegal ancillae end up breaking, many of them immediately. Sprite ID 3, which points to $0000 causes the infamous tree warp crash, and going out-of-bounds in the single-entrance underworld more often than not loads an invalid room effect that eventuallys runs a $00. These examples aren't exhaustive, but they should give you an idea of just how easy it is to literally break the game.

The break vector here points to $FFFF in all versions of the game. Whatever they might have been using it for has been erased when production ROMs were produced. This vector is pointing to the high byte of the emulation mode's IRQ/BRK vector, which, in this game, is $82. That's the opcode for the BRL instruction. The next 2 bytes form the operand, which is a relative offset to jump to. So, for example, if the operand were $0004, we would add 4 to the program counter, which is currently sitting at the next instruction, which is $0002. Thus, after this branch is executed, our PC would be at $0006.

You might be wondering whether this operand is read from the next bank or if it wraps around, but it doesn't matter! Both answers would give the same result, because both of these addresses are mirrors of the same address: $7E:0000! Although, for the record, it wraps around.

Since the operand is pulled from extremely volatile memory, the results are, at least to mortals, unpredictable. But, like anything software, they're completely deterministic. The effects of this can and have been used for Tool-Assisted Speedruns. But even then, it sometimes doesn't play nice.

BRK loops

The most devastating effect we can experience is what I will call a BRK loop. This is when that operand becomes an address that points to another $00. When that happens, we will be stuck for a bit executing the same BRK over and over until the stack obliterates us. At this point, all hope is lost. While we can make as many guesses as we want as to what the operand may become at this point, it's all for naught. Our futile pontifications won't save us from the demise we have already experienced.

It's a metaphor for life, really.

Shin Megami Tensei

This vector points to a routine that updates a given character's sword power stat, and it enters right after the PHP instruction. So, actually, this one will exit fairly cleanly! PLP followed by RTL will accomplish almost the same thing as an RTI. The difference between the two instructions is that RTI returns to an exact address pulled from the stack, while RTL uses 1 less than an address. However, this is nothing a few NOPs can't fix. I'm not sure if all this is intentional, but, if it is, it's some fascinating insight into the last pieces of code the developers were working on.

Of course, this only works properly when we're looking at a properly placed BRK. This routine expects the X register to already be loaded with a value corresponding to the desired character's stat offset in memory. Anything else and we're likely looking at some corruption.

Kirby Super Star

HAHA! What fools! This reset vector points to $5FFF, a location in open bus. Due to how open bus operates, this is guaranteed to be an EOR long,X instruction. Following that is memory mirrored from the SA-1's on-board RAM. In any case, a BRK appears to spell certain doom for Kirby.

Crayon Shin-chan - Arashi wo yobu Enji

Ah, dang. Those clever guys at Bandai. These rascals have repurposed those 2 unused vectors at $00:FFE0 for some code: JMP $8000. This forces the game to reset and reinitialize, as if the console were just powered on.

What a shame. I guess as time went on, some people wanted less garbage on screen when things hit and broke the fan.

Whizz

These guys tried, but it doesn't do much. This break vector points to code that jumps to an RTI elsewhere. So a software break will immediately return to where it was. This prevents break loops from destroying the stack, thus increasing the chances that proper code is eventually executed, but it doesn't save the end user from much else. But why expect it to? Pretty much every developer is hoping people won't ever be glitching their game that badly.

Super Mario World

There's a whole host of different break vectors for this game, depending on which version you're using. Hitting one isn't too difficult with some of the game's more powerful glitches, such as item swapping, brown platform loogies, or sprite stunning.

The Japanese version is arguably the worst of the bunch, as it points to open bus at $50B2. How careless. The high byte puts the opcode for BVC in the bus, which will keep us branching ahead 80 bytes at a time until we hit ROM code.

The US version points to $FFFF, and the byte there just so happens to be the same $82 that ALttP has, producing a similar result with break loop potential.

The 1.0 European version points directly to the reset vector, the same decision we saw for Shin-chan.

The Super System version points to $0000, which will execute RAM as code only slightly differently from the BRLs we saw in ALttP and the US version. The biggest difference is that those branches had strong potential to lead anywhere else in the bank, wheras executing $0000 is a bit more likely to stay where it is.

And for some reason, the 1.1 European version points to $0000 as well. What gives? The reset vector is a fairly solid decision as a last ditch recovery if we consider a break a fatal problem. What made them change it back to something that's just going to crash and burn?

Family Dog

Unfortunately, this vector is as boring as the game. It points directly to an RTI.

SNES Test ROM

Another one pointing to open bus, this time to $4000. Interestingly, $40 is the opcode for RTI, and since the top byte will be in the A bus, this vector will behave more like Whizz than Kirby Super Star.