Once you RTI from your BRK the BRK is gone... So you would have to run all of your code in the interrupt vector? Or conditionally jump out of it? And if you used JSR you wouldn't be able to check for it... I just... There are tons of better ways to store and check bit. I don't know man. You do you. Good luck.stan423321 wrote: ↑Tue Feb 16, 2021 1:51 pmAn important part about the "bit in the memory" is that it can be a relative hindrance to check B, but one place in the ROM is likely enough. Setting up anything else takes space which would probably be better "wasted" on a whole BSR instead.
BRK masking bug and reliability of B pseudoflag
Moderator: Moderators
- Controllerhead
- Posts: 218
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: BRK masking bug and reliability of B pseudoflag
- rainwarrior
- Posts: 8006
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: BRK masking bug and reliability of B pseudoflag
I think the goal with using BRK is usually to save space, not cycles? All else considered, it's a fantastically concise way to dispatch some kinds of things.Controllerhead wrote: ↑Tue Feb 16, 2021 1:09 pmLook man, just use a bit / byte in memory and save yourself the headaches and the cycles.
The stack manipulation sounds fussy to work with but you only write that part once, and then you use the BRK a hundred times.
Treating it as a 2-byte instruction with 1 parameter, it can be a little bit like the x86 INT instruction, where you have a set of common "system" routines selected via the parameter byte.
Another idiom that I like that can produce very concise code:
Code: Select all
jsr function
.byte param1, param2, param3, param4
function:
; read return address from stack and use it to access parameters
; do function
; add parameter data size to the return address
rts
; macros can make it very convenient too:
.macro FUNCTION p1, p2, p3, p4
jsr function
.byte p1, p2, p3, p4
.endmacro
; everything on one convenient line
FUNCTION 1 2 3 4
-
- Posts: 1080
- Joined: Tue Feb 07, 2017 2:03 am
Re: BRK masking bug and reliability of B pseudoflag
So the official way to do it is ; <from the Commodore KERNALs>
What would be interesting to know is if you can use an NMI/IRQ to abort a RESET. Not really sure how you would set it up possibly some custom hardware on say a Expansion Port that drops RESET then counts 2 Phi 2 clocks and drops NMI and see what happens?
To which I propose the only truly safe measure is
fetch return address from stack
-2
fetch byte and check to see if it is 0
if it is, jmp to BRK handler
Although possibly one could just risk it given you know you don't have DCPM and your game is in "one frame" so you won't have an NMI overlap issue. It depends on the project at hand.
Some assemblers back in the day use to come with BRK based instruction extensions libraries built in.
Code: Select all
.C:ff48 48 PHA
.C:ff49 8A TXA
.C:ff4a 48 PHA
.C:ff4b 98 TYA
.C:ff4c 48 PHA
.C:ff4d BA TSX
.C:ff4e BD 04 01 LDA $0104,X
.C:ff51 29 10 AND #$10
.C:ff53 F0 03 BEQ $FF58
.C:ff55 6C 16 03 JMP ($0316) ; BRK here
.C:ff58 6C 14 03 JMP ($0314) ; IRQ here
Yes in my Duck Hunt port I had to lock my sample frequency to be a perfect multiple of the clocks per line to ensure the IRQ didn't fire over my NMI and cause my NMI to be lost. If they got dropped the whole game would implode on it selfrainwarrior wrote: ↑Mon Feb 15, 2021 10:55 pmWhen an NMI takes over an IRQ, for most types of IRQ devices it's not going to be an issue because with no acknowledge the IRQ will still be asserting when the NMI handler does RTI.Oziphantom wrote: ↑Mon Feb 15, 2021 10:06 pmIt's not just BRK its any interrupt. If an IRQ interrupts a NMI or an NMI interrupts an IRQ you will get lost interrupts.
Can an IRQ actually take over an NMI? I hadn't read about that case, only the other way around... but if this is possible, obviously we can have our update delayed by a frame, but at least for NES purposes it should not cause a crash unless our code cannot handle slowdown / timing variations?

Well yes for detecting the "BRK has been aborted" 4015 is not useful. however it is useful for knowing that one has happened and you do probably need to handle it reasonably fast, i.e at least first to keep the DCPM pumping. Then after servicing the DCPM, check to see if B exists and deal with it accordingly. Although it is not clear to me that the B flag will always be set properly if the BRK is aborted by the IRQ or NMI hitting in the first 2 clocks before the push happens. As it can't restart the sequence nor can it wait for the sequence to finish otherwise you get a spare address and status flags on the stack so when you next to an RTS you're going to crash. So it must steal the sequence to keep the Stack consistent.If you are using BRK for some code that must happen (e.g. game logic), it is different than both of those cases. The stolen BRK needs to be detected and recovered from, or whatever the BRK was supposed to do won't happen.
No, that wouldn't work. If you're using IRQ + BRK, a check for B in the interrupt handler will already do the right thing. The stolen BRK would still do the BRK behaviour first, and the unacknowledged IRQ will still be asserting when it does RTI. If you instead polled the IRQ device, like reading DPCM $4015, the BRK would remain stolen, and only the IRQ would get serviced. The B flag is the only way to know a BRK had been requested, so far as I can tell.Oziphantom wrote: ↑Mon Feb 15, 2021 10:06 pmunless you are doing DCPM or exotic peripherals you wouldn't even need to worry about checking the B flag. If you are using DCPM read 4015 would be easier, faster and more useful.
The NMI conflict is the weirder case, but indeed checking B at the end and using it to dispatch the BRK should be sufficient to correct.
To which I propose the only truly safe measure is
fetch return address from stack
-2
fetch byte and check to see if it is 0
if it is, jmp to BRK handler
Although possibly one could just risk it given you know you don't have DCPM and your game is in "one frame" so you won't have an NMI overlap issue. It depends on the project at hand.
Some assemblers back in the day use to come with BRK based instruction extensions libraries built in.
- rainwarrior
- Posts: 8006
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: BRK masking bug and reliability of B pseudoflag
Sure, checking the IRQ status first before checking B would let you do a more timely IRQ dispatch. I interpreted what you said as suggesting to check it instead of B, which seemed contrary to the OP's question which is really about whether BRK can be serviced reliably. I was mostly thinking that the "naive" case of only checking B would still service both the BRK and the IRQ, but making sure to handle the IRQ first is a good suggestion if your IRQ is timing sensitive.Oziphantom wrote: ↑Tue Feb 16, 2021 10:26 pmWell yes for detecting the "BRK has been aborted" 4015 is not useful. however it is useful for knowing that one has happened and you do probably need to handle it reasonably fast, i.e at least first to keep the DCPM pumping. Then after servicing the DCPM, check to see if B exists and deal with it accordingly.
I'm confused by what this is suggesting to do? Why would you take the return address from the stack? To what are you doing "-2"? What are you checking if is 0? (The B flag is set for a BRK...?)Oziphantom wrote: ↑Tue Feb 16, 2021 10:26 pmTo which I propose the only truly safe measure is
fetch return address from stack
-2
fetch byte and check to see if it is 0
if it is, jmp to BRK handler
The C64 kernal snippet you posted looks like a very good example of how to read the B flag and branch to your BRK handler, and it would fine to do the same process instead at the end of an IRQ or NMI to catch the interrupted BRK.
The Visual6502 article and our Wiki article only mention cases where the NMI interrupting a BRK has the B flag set. Our wiki cites as reference blargg's cpu_interrupts_v2 test, which documents that the B flag is set in the NMI handler when a BRK is interrupted at 5 different timing alignments. My belief was that it's reliable for an interrupted BRK, based on this.Oziphantom wrote: ↑Tue Feb 16, 2021 10:26 pmAlthough it is not clear to me that the B flag will always be set properly if the BRK is aborted by the IRQ or NMI hitting in the first 2 clocks before the push happens.
It might be worth writing a different hardware test to verify its reliability with another means though. The behaviour should be easy to demonstrate. I haven't personally verified it, as I've only actually used BRK for this system-call type of behaviour on Apple II, where the NMI isn't really used normally.
Last edited by rainwarrior on Wed Feb 17, 2021 1:10 am, edited 3 times in total.
-
- Posts: 1080
- Joined: Tue Feb 07, 2017 2:03 am
Re: BRK masking bug and reliability of B pseudoflag
My idea was, look up the byte 2 before and see that it is 00. i.e check for a BRK XX XX command. Now that I'm more awake, there are some cases were you could end up with a 00 2 before that was not actually a BRK and thus this is not fool proof either.rainwarrior wrote: ↑Wed Feb 17, 2021 12:07 amI'm confused by what this is suggesting to do? Why would you take the return address from the stack? To what are you doing "-2"? What are you checking if is 0? (The B flag is set for a BRK...?)Oziphantom wrote: ↑Tue Feb 16, 2021 10:26 pmTo which I propose the only truly safe measure is
fetch return address from stack
-2
fetch byte and check to see if it is 0
if it is, jmp to BRK handler
The C64 kernal snippet you posted looks like a very good example of how to read the B flag and branch to your BRK handler, and it would fine to do the same process instead at the end of an IRQ or NMI to catch the interrupted BRK.
If the B flag as suggest by the article ( the link is broken by the way, it needs a www. at the start it currently get tagged onto the forums address as a relative path ) is dependable then my above idea is mootrainwarrior wrote: ↑Wed Feb 17, 2021 12:07 amThe Visual6502 article and our Wiki article only mention cases where the NMI interrupting a BRK has the B flag set. Our wiki cites as reference blargg's cpu_interrupts_v2 test, which documents that the B flag is set in the NMI handler when a BRK is interrupted at 5 different timing alignments. My belief was that it's reliable for an interrupted BRK, based on this.Oziphantom wrote: ↑Tue Feb 16, 2021 10:26 pmAlthough it is not clear to me that the B flag will always be set properly if the BRK is aborted by the IRQ or NMI hitting in the first 2 clocks before the push happens.
It might be worth writing a different hardware test to verify its reliability with another means though. The behavior should be easy to demonstrate. I haven't personally verified it, as I've only actually used BRK for this system-call type of behaviour on Apple II, where the NMI isn't really used normally.

- rainwarrior
- Posts: 8006
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: BRK masking bug and reliability of B pseudoflag
Ohhh, I understand now. Hmm, yeah I can't think of a way to identify what instruction was interrupted like that.Oziphantom wrote: ↑Wed Feb 17, 2021 1:02 amMy idea was, look up the byte 2 before and see that it is 00. i.e check for a BRK XX XX command. Now that I'm more awake, there are some cases were you could end up with a 00 2 before that was not actually a BRK and thus this is not fool proof either.
-
- Posts: 34
- Joined: Wed Sep 09, 2020 3:08 am
Re: BRK masking bug and reliability of B pseudoflag
It can be technically done, but without some help data in the code it would probably have to be extremely slow. And the whole point here is to save two bytes per call compared to JSRing into the dispatch call, so help data seems counterproductive.
-
- Posts: 1080
- Joined: Tue Feb 07, 2017 2:03 am
Re: BRK masking bug and reliability of B pseudoflag
well it gives you a single dispatch point, so you could for example put all the "handle" code in another bank, then call this from any bank and since it goes via a vector it gives you a the ability to trap and dispatch as needed. It also frees up registers.
ldy #what I want you to do
lda #param1
ldx #param2
jsr fixedAddress
becomes
lda #param2
ldx #param3
ldy #param4
BRK WhatIWantYouToDo param1
so you can encode the operation and 1 param or upto 65536 operations in the instruction with a single dispatch handler
ldy #what I want you to do
lda #param1
ldx #param2
jsr fixedAddress
becomes
lda #param2
ldx #param3
ldy #param4
BRK WhatIWantYouToDo param1
so you can encode the operation and 1 param or upto 65536 operations in the instruction with a single dispatch handler
-
- Posts: 34
- Joined: Wed Sep 09, 2020 3:08 am
Re: BRK masking bug and reliability of B pseudoflag
Oh, banking is a really good point to consider. I guess that saves more ROM than I was thinking.
Still, if we needed, say, two more bytes per call to make BRKs easy to detect, it'd be saner to just jump to the dispatcher directly. So it boils down to the B pseudoflag reliability again.
I'm really interested about the case of NMI being masked. It would of course be advisable to keep IRQ out of NMI's way regardless, but I'm really surprised it would mask it outright. It's supposed to be non-maskable after all. Do you remember any details?
Still, if we needed, say, two more bytes per call to make BRKs easy to detect, it'd be saner to just jump to the dispatcher directly. So it boils down to the B pseudoflag reliability again.
I'm really interested about the case of NMI being masked. It would of course be advisable to keep IRQ out of NMI's way regardless, but I'm really surprised it would mask it outright. It's supposed to be non-maskable after all. Do you remember any details?
-
- Posts: 34
- Joined: Wed Sep 09, 2020 3:08 am
Re: BRK masking bug and reliability of B pseudoflag
Pardon the double post. I may have figured out a workaround in case B doesn't reliably work that only has the JSR cost if there's no post-BRK payload whatsoever, and otherwise can be reduced to a byte, five bits, or further. The trick is to put an otherwise unused opcode as the RTI target. KIL/HLT/JAM/STP seem rather useless to return to, and there's a group of eight of them that shares five bits, so they would be comparatively easy to check for while allowing to distinguish them as well. Different schemes are possible, of course, though there aren't that many completely useless opcodes, but there're a few redundant ones.
Of course, there's more indirection involved, so B would be preferable. Maybe HLT trick (pun entirely intended) would make a test ROM easier? Probably not, that can just index the test BRKs. Oh well.
Of course, there's more indirection involved, so B would be preferable. Maybe HLT trick (pun entirely intended) would make a test ROM easier? Probably not, that can just index the test BRKs. Oh well.
-
- Posts: 1080
- Joined: Tue Feb 07, 2017 2:03 am
Re: BRK masking bug and reliability of B pseudoflag
It was two CIA timers, one IRQ and one NMI. NMI runs the main splits, the IRQ runs the Sample playback. It was on VICE so it could be that VICE allows the NMI to be aborted as well, which the hardware might not. But VICE tends to have done a lot of research into these things, or find the edge case because some demo coders had it happen to them etc.
-
- Posts: 34
- Joined: Wed Sep 09, 2020 3:08 am
Re: BRK masking bug and reliability of B pseudoflag
Ah, okay, should have figured out that wasn't NES you would port Duck Hunt to. I can't say if the VICE is correct about this, but it's less confusing now.
- rainwarrior
- Posts: 8006
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: BRK masking bug and reliability of B pseudoflag
The problem is that after an interrupt you have no idea about the size of the interrupted instruction. How do we tell a 16-bit operand apart from an opcode? E.g.:stan423321 wrote: ↑Wed Feb 17, 2021 8:47 amPardon the double post. I may have figured out a workaround in case B doesn't reliably work that only has the JSR cost if there's no post-BRK payload whatsoever, and otherwise can be reduced to a byte, five bits, or further. The trick is to put an otherwise unused opcode as the RTI target. KIL/HLT/JAM/STP seem rather useless to return to, and there's a group of eight of them that shares five bits, so they would be comparatively easy to check for while allowing to distinguish them as well. Different schemes are possible, of course, though there aren't that many completely useless opcodes, but there're a few redundant ones.
Code: Select all
$8D $00 $80: STA $8000
$00 $80: BRK, .byte $80
-
- Posts: 34
- Joined: Wed Sep 09, 2020 3:08 am
Re: BRK masking bug and reliability of B pseudoflag
It's likely B works, sure, although more testing would help, but if it doesn't, what I meant is that we can do this:rainwarrior wrote: ↑Wed Feb 17, 2021 12:14 pmThe problem is that after an interrupt you have no idea about the size of the interrupted instruction. How do we tell a 16-bit operand apart from an opcode? E.g.:I think Blargg's test is good reason to assume B is reliable though? I might write a different test for it on the weekend.Code: Select all
$8D $00 $80: STA $8000 $00 $80: BRK, .byte $80
Code: Select all
BRK
.byte $80
.byte $12
Code: Select all
STA $8000
.byte $12
- rainwarrior
- Posts: 8006
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: BRK masking bug and reliability of B pseudoflag
Oh, I see. Since we can't really know how many bytes the interrupted instruction was, but we can know what the next opcode is, you're suggesting placing another marker byte after a BRK...
That seems like a valid way to mark it, though it's starting to hurt BRK's main use of being compact. It's about half a byte away from being worse than just doing a JSR... :S (For x86 INT style system routine selection I think JSR is already better than a 3-byte BRK.)
That seems like a valid way to mark it, though it's starting to hurt BRK's main use of being compact. It's about half a byte away from being worse than just doing a JSR... :S (For x86 INT style system routine selection I think JSR is already better than a 3-byte BRK.)