I was just thinking about BRK (00) instructions today. When the 6502 encounters a BRK, it jumps to the address written at fffe-ffff. I always assumed that this would happen by accident (if the blank portion of the rom was filled with 0's).
But, could you do this on purpose? Let's say, as a way to save bytes, since BRK takes fewer bytes than jsr someaddress.
Has any game ever used BRK as a special subroutine?
If you're using BRK $nn as a syscall, it takes a long time to safely distinguish it from an IRQ. We
discussed this possibility before and concluded that it'd be impractical. The only game I'm aware of that had any sort of special handling for BRK was Galaxian, and that might just have been a generic 6502 support library that its programmer used.
I mean, the fffe-ffff could point to a code that does something like this...(For example)
Asl a
Asl a
Asl a
Asl a
Rti
Therefore, anytime you need to do that, you just insert BRK, and it will perform this for you, saving 3 bytes each time. (Or some other more frequently used bit of code).
tepples wrote:
The only game I'm aware of that had any sort of special handling for BRK was Galaxian, and that might just have been a generic 6502 support library that its programmer used.
The only thing Galaxian does with the B flag is trigger a cold boot.
Or, perhaps this would be a more frequently used bit of code the BRK could point to...
WaitForVBlank:
BIT $2002
BPL WaitForVBlank
RTI
That's 5 bytes that can be replaced by 1 (BRK). If used 10 times in a game, that could give you an extra...maybe 35 bytes. And it wouldn't slow down the game since this bit takes a bunch of time anyway, looping around.
(I'm expecting someone to chime in any minute now and explain why this is a terrible idea)
BRK advances PC by two bytes. Therefore it'd save only one byte over a JSR.
You could adjust the return address.
Which means you're giving up a buttload of cycles to save a few bytes over JSR.
In my project I used
BRK as a crash diagnostic, since I wasn't using IRQ for anything. Comes in handy sometimes.
Hiryu no Ken Special uses BRK for inter-bank function calls. The two bytes after the BRK are a bank index and a vector index (multiply by 2, add #$8000 and jump to that indirect address). This makes disassembling a bit tricky since not many 6502 disassemblers know how to disassemble BRK as a three-byte instruction.
As far-call methods go, using BRK this way is pretty much the extreme of compactness at the expense of cycle overhead (it also largely precludes using hardware IRQs, but Hiryu no Ken Special is an MMC1 cartridge and doesn't use them) You could squeeze out one more byte per call at the expense of space in your fixed bank by putting the banks and offsets of all functions that are ever called from another bank into a big lookup table. This is what Final Fantasy Legend 3 on the GB does (using RST $18 as the BRK analogue)
Bionic Commando uses the BRK instruction - this happens after destroying the "Main System" at the end of the first level.
According to certain stories, people used to use BRK as a way of patching code on PROMs. Bits could be set to 0, but not set back to 1, so you could replace an instruction with BRK, then add some new code to your BRK handler.
BRK can also be recognized in an underhanded way by setting a global variable right before the BRK is issued.
Alternatively if you know exactly your possible sources of IRQs (there aren't that many), you can manage with IRQ and BRK.