| |
Trap
Registered: Jul 2010 Posts: 222 |
Best practice IRQ recovery
Hi,
Here's a little newbie question. Sorry, I'm still learning this shit and it's really complicated :(
I have kernel off ($01=$35) and I am running IRQ's using the normal $fffe/$ffff vectors.
I want to exit from this and call a prepacked piece of code (in this case something packed with TinyCrunch).
I tried restoring the IRQ vectors and jump to the packer. However, it just hangs. I tried some other things but all gave the same result. The only thing that worked was when I did this:
sei
lda #$36
sta $01
jsr $ff81
jmp unpacker
The problem of course is that it resets the VIC which isn't really great for my situation.
So, my question:
What is the correct/proper way to exit from a part and go to the next? preferably not using kernal routines :|
Thank you.
Trap |
|
... 78 posts hidden. Click here to view all posts.... |
| |
Copyfault
Registered: Dec 2001 Posts: 466 |
Quoting Martin PiperIf there was code running that used two or more interrupt sources to operate correctly, then using SEI/CLI would be advisable. This is because the code below without SEI/CLI is not atomic:
lda #$7f
sta $dc0d
sta $dd0d
ldx #0
stx $d01a
In other words, there are a few cycles between switching off IRQ source from CIA1, CIA2 and VIC2 where such complex code could misbehave, say for example by enabling the source in the IRQ that you've just switched off. This is what I was pointing at with my last post: an IRQ condition might become fulfilled during the execution of the STORE-opcodes that actually switch off further IRQ triggers by the source the STORE is affecting. The no. of cycles that it'll take to enter the irq routine depends on the cycle this irq condition was fulfilled - and the added comments in the example source code reflect my understanding of this delay.
Quoting Martin Piper]So using SEI/CLI is the correct bullet proof way of tackling that issue. I still don't understand why this should be needed. Switching off an IRQ source does just this; no further IRQs should be triggered after the source has been disabled, with the exception of the ones that got triggered while performing the disabling store opcode (see above).
But reading the other posts, I guess I have to ask: where am I wrong? |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1378 |
Quoting Copyfault I still don't understand why this should be needed. Switching off an IRQ source does just this; no further IRQs should be triggered after the source has been disabled, with the exception of the ones that got triggered while performing the disabling store opcode (see above).
But reading the other posts, I guess I have to ask: where am I wrong?
You're not really wrong. The only edge case this misses is when an interrupt triggered by one source reenables interrupts from another source you've already shut down (eg a VIC interrupt setting up a CIA interrupt). |
| |
Copyfault
Registered: Dec 2001 Posts: 466 |
Quoting ChristopherJamargh, damn it. Give the possibility of "some other coder's VIC interrupt setting up a CIA interrupt or vise versa" I might actually need to reconsider my stance.
How hostile an environment do I want to guard against is the question I guess.. Ah ok, if the irq vecs have been changed already and need to be readjusted to some new routine, this might become tricky without SEI/CLI. Not completely impossible, but needs careful planning when the hi/lo-vecs are set.
In my former posts, I had a basic startup situation with its standard irqs in mind... |
| |
Copyfault
Registered: Dec 2001 Posts: 466 |
Quoting ChristopherJamQuoting Copyfault I still don't understand why this should be needed. Switching off an IRQ source does just this; no further IRQs should be triggered after the source has been disabled, with the exception of the ones that got triggered while performing the disabling store opcode (see above).
But reading the other posts, I guess I have to ask: where am I wrong?
You're not really wrong. The only edge case this misses is when an interrupt triggered by one source reenables interrupts from another source you've already shut down (eg a VIC interrupt setting up a CIA interrupt). Oh yes! So mixtures of IRQ sources have to be forbidden ;) But this'd narrow the possibilities (and thus the creativity) so I fear the revenge of evil SEI/CLI :( |
| |
chatGPZ
Registered: Dec 2001 Posts: 11114 |
The resistance to write proper code in favour of some 80s cargocult is impressing =D |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
As has been demonstrated, it's not cargo cult under certain conditions. (It remains cargo cult when coming from BASIC.)
But then i'd consider setting interrupt masks from interrupt handlers bad practice. There are ways to effectively suspend interrupts without setting an interrupt mask, for both CIA timer and VIC raster interrupts, which would work in a ping-pong setup.
Now, any clean-up code after a demo part should know best how to safely disable all interrupts.
And it's still advisable to clean up things from within an interrupt handler. The I flag is set already, and the last interrupt has been acknowledged already or would have to be acked later anyways if not exiting yet. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11114 |
Quote:it's not cargo cult under certain conditions.
sure, there are some RARE cases where its needed. but certainly not in the general case, or even in most cases. |
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
good point with irq's reenabling irqs. I'll keep sei cli and ack cia irqs :) |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1378 |
Quote: good point with irq's reenabling irqs. I'll keep sei cli and ack cia irqs :)
Don't forget to write to $dd0d before the others then SEI for a second time in case an NMI didn't restore the I bit. |
| |
TWW
Registered: Jul 2009 Posts: 541 |
Quoting ChristopherJamhaha, writing to the NMI vector without disabling the pertinent CIA first is just as much asking for it.
Yes, you should disable/ack CIA#2 interrupts first before grounding it / fiddling with the vectors. Here is the full code I use to setup a safe raster IRQ without presuming too much:
sei
// Disable/ack all CIA interrupts
ldx #$7f
stx $dd0d
lda $dd0d
stx $dc0d
lda $dc0d
// Bank in all available RAM except IO
lda #$35
sta $01
// Ground NMI
lda #<NMI_Lock
sta $fffa
lda #>NMI_Lock
sta $fffb // Set NMI Vector to point to RTI
ldx #$00
stx $dd0e // Stop CIA #2 Timer A
stx $dd04
stx $dd05 // Set CIA #2 Timer A to 0 cycles
inx
stx $dd0d // Enable CIA #2 Timer A as NMI source
lda #$81
sta $dd0e // Start Timer A and trigger NMI
bne *+3
NMI_Lock:
rti
// Set IRQ Vector
lda #<IRQ_Vector.getValue()
sta $fffe
lda #>IRQ_Vector.getValue()
sta $ffff
// Set Raster Interrupt Compare Value
lda #Raster_Compare_Value.getValue()
sta $d012
lda $d011
.if (Raster_Compare_Value.getValue()<256) {
and #%01111111
} else {
ora #$80
}
sta $d011
// Ack any pending Raster Compare IRQs (normally not neccessary)
lda #$01
sta $d019
// Enable Raster IRQs
// lda #$01
sta $d01a
// Allow IRQ's
cli
// async code
async:
jmp async
I consider this as safe as I can make it without making assumptions on what was.
Another important point is that if you are running async. code after the cli (instead of jmp *) you can get straight to that with no hassle and you are sure the VIC IRQ which was setup fires exactly when you told it and not by accident after the cli if some latent CIA IRQ fired (which it may have if you entered from basic). |
Previous - 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 - Next |