is RTI used to return from BRK? wrong return address?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
is RTI used to return from BRK? wrong return address?
by on (#60704)
is RTI used to return from BRK?

Because BRK pushes PC pointing to the 2nd byte of the instruction following the BRK.

And RTI pulls the PC without changing it.

So if RTI is used to return from a BRK call, then the immediately following byte after the BRK instruction would be ignored.

I guess I'm either wrong about what address is pushed by BRK or about RTI returning grom BRK, but which one?

by on (#60706)
Yes, RTI can be used to return from a BRK handler, and doing so causes the byte after th BRK opcode to be skipped. I'm sure this is documented in any decent 6502 reference.
Re: is RTI used to return from BRK? wrong return address?
by on (#60707)
Petruza wrote:
So if RTI is used to return from a BRK call, then the immediately following byte after the BRK instruction would be ignored.

Yes, which is why the Apple IIGS monitor disassembles BRK as if it took an 8-bit argument: "BRK $00" through "BRK $FF". You might think that would be useful for a syscall mechanism, but the performance isn't there.

by on (#60708)
Well yes, the docs and emu sources I read, implied this byte skipping, but none of them explicitly stated that BRK's following byte was skipped and why.
I suspected it was some kind of error or that I wasn't understanding it.

by on (#60710)
Petruza wrote:
Well yes, the docs and emu sources I read, implied this byte skipping, but none of them explicitly stated that BRK's following byte was skipped and why.


It's classified as a signature byte. This is mentioned in some 65C02 and 65816 books -- for example, Programming the 65816 Including the 6502, 65C02, and 65802 by David Eyes and Ron Lichty. I can provide an exact quote from their book if you want.

I don't understand why so many people have trouble understanding BRK and what the operand byte is for; it's probably because so much 6502 documentation states it's a 1-byte instruction and never points the reader to the fact that the PC is incremented by 2 when encountering BRK. It amuses me when I see disassemblers doing things like turning bytes $00 $C7 into "BRK" then "???", rather than "BRK $C7".

by on (#60712)
koitsu wrote:
I don't understand why so many people have trouble understanding BRK and what the operand byte is for


Maybe it's because $00 is the single opcode that causes the 6502 to completely ignore a prefectly good byte of executable code, which doesn't seem logical, and the fact that, at least the documentation I read, says nothing about this, only a "pc + 2" without any explanation in an uncommented pseudocode.

by on (#60714)
Petruza wrote:
koitsu wrote:
I don't understand why so many people have trouble understanding BRK and what the operand byte is for


Maybe it's because $00 is the single opcode that causes the 6502 to completely ignore a prefectly good byte of executable code, which doesn't seem logical, and the fact that, at least the documentation I read, says nothing about this, only a "pc + 2" without any explanation in an uncommented pseudocode.


Then the documentation you've been reading is sub-par (authors didn't bother to take the time to write something that covered such), same with the source code you've been reading (lack of comments for unintuitive things == trouble).

BRK's behaviour, and signature byte (specifically PC+2), is covered in most 65xxx books I own. It's not your fault if what you've read isn't decent quality.

by on (#60715)
Well, it is my responsibillity to get good documentation, so any help would be appreciated.

So far I'm using http://www.obelisk.demon.co.uk/6502/ , "6502 Microprocessor Revision 1.02 by _Bnu." which I think I got from nesdev, but can't find the link, and the Commodore 64 Programmer's reference guide.

I've finished coding addressing modes and instruction exectuing (big switch for each) but there surely are some errors, I didn't test it yet.

by on (#60718)
Petruza wrote:
Well yes, the docs and emu sources I read, implied this byte skipping, but none of them explicitly stated that BRK's following byte was skipped and why.

Technically, BRK doesn't skip anything. When the CPU executes the BRK opcode, it pushes the address of the opcode+2 on the stack, then pushes the current flags ORed with $30 on the stack, then jumps to the address contained in $FFFE-$FFFF. It's up to the IRQ/BRK handler what to do next, and how to return to the interrupted code.

For good documentation, get a book. I've been reading the 6502/65816 book koitsu just mentioned and it's the best by far of all those I've evaluated recently (I just love that the library still has these!).

by on (#60719)
Petruza wrote:
$00 is the single opcode that causes the 6502 to completely ignore a prefectly good byte of executable code

It appears you've never worked with the unofficial instructions such as the two-byte NOPs. You'll need a few unofficial instructions to get Puzznic and Lolo 3 to run.

by on (#60720)
tepples wrote:
It appears you've never worked with the unofficial instructions such as the two-byte NOPs. You'll need a few unofficial instructions to get Puzznic and Lolo 3 to run.


Damn, thanks. Do you have a doc about that to point me to?

by on (#60722)
@Petruza: This is illegal, you know. Look up "DOP". Though the document is about Atari 8-bit computers, the unofficial instructions are the same on all classic 6502 CPUs, including second-source ones that have the decimal mode circuitry dummied out.

by on (#60735)
Ok, color me uneducated, but why is there an extra byte after BRK? As in, why is BRK a two-byte opcode, where the parameter it takes has no apparent use?

I have no problem accepting the fact that there is an extra, seemingly unused byte after the BRK, but what was the design choice that lead to having BRK skip an extra byte?

by on (#60736)
Quote:
Ok, color me uneducated, but why is there an extra byte after BRK?

.... because the 6502 pushes return adress + 2 on the stack. There is really no other reason. I guess the byte can be used as an "argument" to the BRK opcode, to tell the IRQ handler which type of IRQ you're simluating.
The BRK opcode is completely useless IMO and I never ever used it. I don't see the point to call the IRQ routine in the middle of code.

by on (#60737)
Bregalad wrote:
Quote:
Ok, color me uneducated, but why is there an extra byte after BRK?

.... because the 6502 pushes return adress + 2 on the stack. There is really no other reason. I guess the byte can be used as an "argument" to the BRK opcode, to tell the IRQ handler which type of IRQ you're simluating.
The BRK opcode is completely useless IMO and I never ever used it. I don't see the point to call the IRQ routine in the middle of code.

I understand that PC+2 is pushed onto the stack, which causes the skipped byte, but I'm wondering if there was some kind of reasoning behind pushing PC+2 onto the stack, as opposed to PC+1.

Maybe I got confused, but it sounded like there was a use for (or otherwise, a reason to have) the argument that nobody was explaining. :P

by on (#60739)
Drag wrote:
Ok, color me uneducated, but why is there an extra byte after BRK? As in, why is BRK a two-byte opcode, where the parameter it takes has no apparent use?


This is pure speculation, but as you know the 6502 does dummy memory reads, and writes, and some illegal opcodes like 2-byte NOPs do memory addressing with no apparent reason, all this, including the BRK byte-skipping, make me think that there are internal workings of the chip that may make it do this apparently useless things for no reason.
Maybe the BRK operation needs for some reason to further increment the PC, and the 6502 designers thought that skipping a byte was not so serious.
Or maybe they designed it with an argument to jump to different subroutines whose vectors were to be stored somewhere but then dropped the idea, but didn't correct the instruction's byte length.

by on (#60741)
They wanted BRK to be a "Oh cool, you can pass in an argument to the interrupt handler like this!" instruction. Sorta like SWI on the ARM, or SYSCALL on other processors.

by on (#60742)
The question is, the assemblers used to build NES commercial games in the 80s would add an extra byte for BRK mnemonics?
Or did programmers have to do something like:
Code:
BRK
.byte 00

(or)

BRK
NOP

It's very unlikely, but what if some programmer forgot to pad the BRK (and didn't do anything to correct the returning address) and entered an actual instruction after BRK and somehow the game still worked despite skipping that instruction's opcode? That would be really hard as the interpreting of instructions from that point would be off by one byte.

by on (#60743)
What would be really hard? The 6502 should have no trouble, and neither should an emulator. Usually it will "correct" itself fairly quickly, since it's less likely that the intended instructions just happen to also be interpretable at an offset as a separate stream that never intersects. It's more likely that one of these alternate instructions is of a different length than the instruction it's embedded in, causing the two streams to merge. You can experiment yourself with a disassembler that handles unofficial instructions, and try disassembling some code from various offsets.

If your assembler treats BRK as a one-byte instruction, you can always just have your BRK handler return to the stacked address less one. Or define a Brk macro which accepts a one-byte operand. It might have been that it saved a few transistors to have BRK push PC+2 on the stack. After all, BRK is always presented as a debugging aid, where you don't really care the specifics of its operation since you can compensate in the IRQ/BRK handler.

by on (#60746)
Somewhat on-topic: "Final Fight 3" for the SNES has an ASCII error message stored after every BRK in the code. Presumably, their development system would grab the address the BRK occurred at and print whatever message was stored there. Kinda nifty.

Unfortunately, there's no interesting code at the BRK vector, just an infinite loop. :(

by on (#60749)
This is speculation, but I think BRK pushes PC+2 because the underlying hardware shares circuitry between BRK and JSR.

by on (#63169)
nice info...... thnx for this :)