The BRK
instruction on the MOS 6502 seems to be one of the more
ill-documented features of the processor. The 1976 preliminary data
sheet from MOS indicates that it's a 1-byte instruction using
the "implied" addressing mode (i.e., it has no operands), as does the
the 1980 CSG data sheet.¹ (Edit: the MCS6500 Microcomputer
Family Programminng Manual does describe the details and
intention of the BRK
instruction in §9.11 pp. 144-146.)
However, unlike an IRQ interrupting any other 1-byte instruction, the
program counter pushed on to the stack when a BRK
is executed does
not point to the byte immediately after the opcode but instead to the
second byte after the opcode. (This is mentioned nowhere in those
two data sheets.²)
Given the lack of documentation about this, I'm guessing that this was
unintentional³ (though evidence otherwise is welcome!), because it
wastes the byte after the BRK
if the interrupt handler does an RTI
to the address pushed by the BRK
after handling it. (If there was no
RTI
, the byte need not be wasted: control would never flow past the
BRK
and so another routine could have an entry point immediately
after it. This was the case on, e.g., the Apple II, where a BRK would
stop whatever program was executing and enter the monitor.⁴)
I'm looking for examples in "real-world" code (as opposed to
demonstration or example code) of how this "spare byte" was used in
systems with IRQ routines that did an RTI
to return to the address
pushed by the BRK
instruction.⁵ This could be use by the IRQ routine
itself (as a parameter, or similar, e.g. as Woz sugested in his
November 1977 BYTE article on Sweet 16) or something else.
Ideally the examples would be from widely distributed software for 6502-based general purpose computers. Again, I'm not too interested in demo code that shows how it could be used in a theoretical real-world program. But if you feel you have an example that has something useful to offer beyond the limited technical details of how to implement this, feel free post an answer about it.
¹Both have a note "See Fig. 1" beside the instruction in the instruction set/opcde table, but none of the figures in either document are numbered, and none seem to be relevant. I welcome clarification of this.
²The ignored byte after the BRK
is kind of implied by the cycle
breakdown of the BRK
instruction on page A-11 of the 1976 MCS6500
Microcomputer Family Hardware Manual, where after the T0
cycle reads the opcode the subsequent T1 cycle puts on the address bus
"PC + 1 (PC on hardware interrupt)" before pushing the PC on to the
stack in T2 and T3. But documenting it as a one-byte instruction or
opcode with no operands, despite the byte after it being skipped,
persists even today in the 2018 WDC W65C02S data sheet.
This post on forum.6502.org does say, "WDC
describes BRK as '...a 2 byte instruction. The NMOS and CMOS devices
simply skips [sic] the second byte (i.e. doesn’t care about the second
byte) by incrementing the program counter twice.'" However, it doesn't
give a source for that quote.
³By "unintentional" I mean that having that unused byte after the
BRK
instruction was not a design goal. In this context, "we've got
an unused byte there but it isn't a problem and that lets us save
transistors (or whatever) elsewhere" does not count as
"intentional."
⁴See the IRQ
routine at $FA86
in the BIOS listing on page 81
(PDF page 84) of the Apple II Reference Manual.
⁵An IRQ routine could use bit 4 of the program status register
value pushed on to the stack to determine it had been invoked by a
BRK
and then use the PC pushed on to the stack to find the spare
byte. Wilson Mines gives details on how to do this.
BRK
handler if the return address were the one right afterBRK
, rather than the one after, just as is done withJSR
. And that seems to me simpler because you don't have to remember to skip a byte before starting your next instruction (e.g., by always putting aNOP
afterBRK
) if you're using a handler that doesn't take parameter data after the instruction.