Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Best practice IRQ recovery
2021-06-10 20:30
Trap

Registered: Jul 2010
Posts: 221
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
2021-06-10 20:54
TheRyk

Registered: Mar 2009
Posts: 2035
F...ing around with $01 reg just to use KERNAL routines is hardly ever worth the trouble if you don't want KERNAL banked in other parts of your code.
Just look into KERNAL ROM routines to see what they do, for example here: http://unusedino.de/ec64/technical/aay/c64/krnromma.htm and then take the few things you need, normally that would be what you find at $EA81 = restoring accumulator and x/y registers and use them somewhere in RAM.
2021-06-10 21:09
Six

Registered: Apr 2002
Posts: 287
Where does it hang, before or after the depacker starts?
2021-06-10 21:34
chatGPZ

Registered: Dec 2001
Posts: 11088
Quote:
What is the correct/proper way to exit from a part and go to the next?

that raises the question what you are doing there... a trackmo? classic "press space" stuff?
2021-06-10 21:46
Trap

Registered: Jul 2010
Posts: 221
It crashes before it gets to the unpacking
2021-06-10 21:53
MagerValp

Registered: Dec 2001
Posts: 1055
Set a breakpoint at unpacker and then step through the code and see where it crashes? There's no one answer here, it makes some assumption about things and you'll have to figure out what it is.
2021-06-10 21:56
chatGPZ

Registered: Dec 2001
Posts: 11088
the first thing that comes to mind is... don't use SEI. disable the irq sources instead. then set the pointers to their defaults.
2021-06-10 21:58
Krill

Registered: Apr 2002
Posts: 2804
Without further information, my bet is on pending interrupts that wreak havoc as soon as the I flag is cleared. =)

Then wrong vectors/memory configuration usually cause crashes, or with the ROM interrupt handler restored, an infinite IRQ-handling loop (as the ROM interrupt handler only acknowledges CIA1 interrupts, but not VIC interrupts).

Bottom line being that properly disabling any interrupt sources (not just executing SEI) is good practice for cleanly exiting a demo part (in a classical spacemo, that is).

Edit: Oh yeah, what Groepaz said. :D
2021-06-10 22:03
Trap

Registered: Jul 2010
Posts: 221
Well, I'm just learning stuff right now :)

ok, I will re-visit setting the IRQ vectors back. What would be the perfect sequence for this?

Should I just modify the running IRQ code to go to the default IRQ handler and then wait a few frames for it to catch it?
2021-06-10 22:12
Krill

Registered: Apr 2002
Posts: 2804
It's common practice to check for space during an interrupt handler that's executed once a video frame. The I flag is usually still set (because you're in an interrupt) and the interrupt itself was triggered by VIC.

When detecting the keypress, just write 0 to $d01a to disable any VIC interrupts, then write $ff to $d019 to acknowledge any pending VIC interrupts. Resetting any interrupt vectors should not be required. Directly exit to whatever code to unpack and run the next part.
2021-06-10 22:21
Trap

Registered: Jul 2010
Posts: 221
So

set IRQ vector to default handler
$d01a=0
$d019=$ff
wait a frame or two
go to unpacker

Is that what you meant?
2021-06-10 22:32
Krill

Registered: Apr 2002
Posts: 2804
Resetting IRQ vectors or waiting shouldn't be required, but should be no harm. It's just unnecessary. :)
2021-06-10 22:39
Oswald

Registered: Apr 2002
Posts: 5007
my guess is that depacker overwrites your irq code, and on the next irq request cpu tries to jump into that. simply set irq vector to a new piece of irq handler which surely is undisturbed.
2021-06-10 22:48
Flavioweb

Registered: Nov 2011
Posts: 442
I guess something overwrite $0314/5 before setting $01 to $36.
Force it back to $EA31 (or $EA81) (and may be better to restore other vectors too) insted of call $FF81.
Clear VIC IRQs enable flags too.
2021-06-10 22:50
TWW

Registered: Jul 2009
Posts: 541
In your IRQ setup, disable CIA Interrupts and ack any pending before setting up your VIC IRQ and IRQ pointers.

Assuming no NMI's, the only thing which should be able to trigger the IRQ handler is the VIC.

If your keyboard detection routine is inside an IRQ, the I-Flag should remain set until you ack it. This means that as long as you don't ack it and the unpacker doesn't ack/cli no IRQ should trigger before your next part start (where you presumably SEI and setup next round of IRQ interrupts).
2021-06-11 11:34
ChristopherJam

Registered: Aug 2004
Posts: 1359
If you disable CIA and VIC interrupts *without* a preceding SEI you don't even need to acknowledge any pending ones - the existing handler will deal with that.


tinycrunch's self extracting mode only wraps the decrunch in SEI/CLI because too many people were having issues with nucrunch's default of just turning off CIA while trying to crunch things that needed the kernal interrupt to still be in place when they started up :-/
2021-06-11 14:04
chatGPZ

Registered: Dec 2001
Posts: 11088
someone gotta write this "SEI considered harmful" rant already :)
2021-06-11 15:37
ChristopherJam

Registered: Aug 2004
Posts: 1359
Quote: someone gotta write this "SEI considered harmful" rant already :)

Well I think it's already been flogged to death over at
TIL: The instruction after SEI can be executed before a pending IRQ is handled and to a lesser extent in C-64 coding cargo cults but it's always been as an offshoot from a broader discussion, so far as I can find.
2021-06-12 06:01
Martin Piper

Registered: Nov 2007
Posts: 629
Tried single stepping using the debugger in Vice?
It will probably show where various IRQs happen after the CLI.


Create, or reuse, consistent IRQ disable and ACK code: https://github.com/martinpiper/C64Public/blob/master/stdlib/std..


I generally always use this to initialise to a known state: https://github.com/martinpiper/C64Public/blob/master/stdlib/Ini..
2021-06-12 08:50
Oswald

Registered: Apr 2002
Posts: 5007
"lda #$7f
sta CIA1InterruptControl
sta CIA2InterruptControl"

I will stick to dc0d dd0d :D letsnamealltheregisters_so_itseasyertocode NOT.
2021-06-12 11:47
Martin Piper

Registered: Nov 2007
Posts: 629
It's easier for me to name registers and sometimes their bitfields.
2021-06-12 13:06
chatGPZ

Registered: Dec 2001
Posts: 11088
Is this "how to make trivial code unreadable 101"? /o\
2021-06-12 13:26
Krill

Registered: Apr 2002
Posts: 2804
Oh come on, the registers have names already in the datasheet.
And not everybody spent years writing and analysing code with a memory monitor before using a proper assembler. =)

I'd stick to concise symbols like "CIA1_ICR", though.

And yes, using symbols instead of raw addresses and bitfields can make code more readable, especially with rarely used registers.
2021-06-12 13:37
Oswald

Registered: Apr 2002
Posts: 5007
Quote: Oh come on, the registers have names already in the datasheet.
And not everybody spent years writing and analysing code with a memory monitor before using a proper assembler. =)

I'd stick to concise symbols like "CIA1_ICR", though.

And yes, using symbols instead of raw addresses and bitfields can make code more readable, especially with rarely used registers.


I'm sorry, for me lda $#7f sta $dc0d is more readable than lda #CIAdisableallinterrupts sta Cia2interruptcontrolregister. anyone who didnt spent years using these registers by hex values raise their hands. nobody? good :)

and btw if you code like this, and then you see your code in monitor, you will have no clue what part of your code you see. same goes for source code thats programmed as a script.
2021-06-12 13:46
TWW

Registered: Jul 2009
Posts: 541
Best of both worlds :)

    // Disable all CIA interrupts
    lda #$7f
    sta $dc0d
    sta $dd0d

    // Acknowlege any pending CIA iterrupts
    lda $dc0d
    lda $dd0d
2021-06-12 13:48
Krill

Registered: Apr 2002
Posts: 2804
Quoting Oswald
anyone who didnt spent years using these registers by hex values raise their hands. nobody? good :)
Some people got into C-64 coding only recently.

Quote:
if you code like this, and then you see your code in monitor, you will have no clue what part of your code you see.
VICEmon symbol files have been invented. \=D/

Quote:
same goes for source code thats programmed as a script.
Please elaborate.
2021-06-12 14:14
chatGPZ

Registered: Dec 2001
Posts: 11088
TWW: there are no pending interrupts after disabling them (or to be precise, they'd still trigger, before you can even ACK, the original handler will take care of them)
2021-06-12 15:09
TWW

Registered: Jul 2009
Posts: 541
GPZ: This is done inside a sei-cli raster IRQ setup to ensure no accidental CIA IRQ triggers after cli'ing which may have activated between the sei and the point you actually disable them.
2021-06-12 15:15
chatGPZ

Registered: Dec 2001
Posts: 11088
so DONT USE SEI/CLI. *sigh*
2021-06-12 15:30
TWW

Registered: Jul 2009
Posts: 541
This was posted in response to the discussion above regarding $dc0d vs CIA1_REG whatever above by Oswald/Krill.

*sight* yourself...
2021-06-12 15:38
chatGPZ

Registered: Dec 2001
Posts: 11088
>_<
2021-06-12 16:05
Frantic

Registered: Mar 2003
Posts: 1626
GPZ: How about writing that SEI/CLI rant at https://codebase64.org/doku.php?id=base:interrupts ? :D
2021-06-12 16:09
chatGPZ

Registered: Dec 2001
Posts: 11088
Should do that, some day. Better yet, trick cjam into doing it :o)
2021-06-12 16:27
Frantic

Registered: Mar 2003
Posts: 1626
@CJam: Groepaz said you had promised to write that anti SEI/CLI rant at https://codebase64.org/doku.php?id=base:interrupts We are waiting.
2021-06-12 16:40
Oswald

Registered: Apr 2002
Posts: 5007
Quote: Best of both worlds :)

    // Disable all CIA interrupts
    lda #$7f
    sta $dc0d
    sta $dd0d

    // Acknowlege any pending CIA iterrupts
    lda $dc0d
    lda $dd0d


winner :)
2021-06-12 16:46
Oswald

Registered: Apr 2002
Posts: 5007
Krill, too much macroing / kickassing when people write a code that spits out sourcecode which gets assembled. and often we get questions here, which shows the guy thinks he writes the code that runs on c64, and not a code that generates src :D anyway, there's no way good of doing it just different tastes, and I like to voice my dislike for some of these. My other point against script src generation, is that often staring at your code in monitor (without label resolving!) gives the best ideas for optimising it, hence finally you see it at "matrix level", and not the assembler shit which is few steps away from what the cpu really sees. Either you have to be the cpu for good optimisation, so see the problem from an extremely low level, my other excersize to finding faster ways is to try to find a simpler solution to solve the problem. NOT always but 10 times out of 9 it will be faster.

the downside is that these two most of time doesnt gives you a better algoritmic solution, just good to shave off a few instructions.

ahyeah I also used to think stuff like "okay how to end up with the same result without having to do this or that" that mostly end up in crazy table shit, and not much win.
2021-06-12 17:02
TWW

Registered: Jul 2009
Posts: 541
Quoting Oswald
My other point against script src generation, is that often staring at your code in monitor (without label resolving!) gives the best ideas for optimising it


This is a good point. I often catch myself doing this especially since I perhaps rely a little much on scripts/macros. If I really need to get down and dirty, the monitor is where it's at.
2021-06-12 20:09
Krill

Registered: Apr 2002
Posts: 2804
Quoting Oswald
Krill, too much macroing / kickassing when people write a code that spits out sourcecode which gets assembled. and often we get questions here, which shows the guy thinks he writes the code that runs on c64, and not a code that generates src :D
I dunno, seems like just overusing the hammer that is Kickass scripting and wanting to make everything a nail. :) Scripting, offline code generation and external tools producing data to .incbin are all good things, when used right.

Quoting Oswald
My other point against script src generation, is that often staring at your code in monitor (without label resolving!) gives the best ideas for optimising it
Source level and machine code level are two different things. I also like to look at the code in the monitor to spot low-level (non-algorithmic) performance or size optimisation opportunities, but translating the solutions back to the source code then results in a higher-level representation to produce the desired output.
2021-06-12 23:05
Copyfault

Registered: Dec 2001
Posts: 466
Quoting TWW
Best of both worlds :)

    // Disable all CIA interrupts
    lda #$7f
    sta $dc0d
    sta $dd0d

    // Acknowlege any pending CIA iterrupts
    lda $dc0d
    lda $dd0d
What about this ;)
ldx #$80
nop $dc8d,x
dex
stx $dc0d
stx $dd0d


Then again, Groepaz is right: once an irq-source is disabled, acknowledging should be in the realm of the irq handler.

And Frantic is even more correct in stating that the SEI considered harmful-article has to be added to codebase asap'st ;)
2021-06-12 23:15
Copyfault

Registered: Dec 2001
Posts: 466
Quoting Krill
[...]
Quoting Oswald
My other point against script src generation, is that often staring at your code in monitor (without label resolving!) gives the best ideas for optimising it
Source level and machine code level are two different things. I also like to look at the code in the monitor to spot low-level (non-algorithmic) performance or size optimisation opportunities, but translating the solutions back to the source code then results in a higher-level representation to produce the desired output.
Exactly what I thought when reading all the comments on "Kickass-scripting". I think you, Oswald, are totally right in stating that most (if not all) golden optimization nuggets will solely be found when looking at the code on a monitor-level (be it via Vice, C64Debugger, on the real deal, whatnot).

But expecially when it comes to data preparation (which I think is the main purpose for the nowadays oh so popular "scripting"), I'm not willing to do this manually nor write everything as 6510-native-code if it can be avoided. But maybe I'm just getting old and lazy, idk...
2021-06-12 23:18
chatGPZ

Registered: Dec 2001
Posts: 11088
Quote:
And Frantic is even more correct in stating that the SEI considered harmful-article has to be added to codebase asap'st ;)

another volunteer!
2021-06-12 23:28
TWW

Registered: Jul 2009
Posts: 541
Quoting Copyfault
acknowledging should be in the realm of the irq handler.


Even if you disable new CIA IRQ's from occurring, existing ones isn't cleared and may trigger a premature interrupt.

Simply put:

// You do not know the state of the CIA here
sei
// a CIA interrupt may activate here
lda #$7f
sta $dc0d
sta $dc0d
// CIA maintain the IRQ signal, but don't generate new ones
lda #100
sta $d012 // This is where you want the IRQ to happen
lda #1
sta $d01a
fffe/ffff vetor = IRQ_Code
cli
// latent CIA IRQ triggers here instead of @ line 100
jmp *
IRQ_Code:
blablabla

Avoided by ack'ing the CIAs prior to cli'ing
2021-06-13 00:56
chatGPZ

Registered: Dec 2001
Posts: 11088
we *really* need this rant :)
// switch off irq sources
lda #$7f
sta $dc0d
sta $dd0d
ldx #0
stx $d01a
// whatever irq was pending triggers here and the old handler handles it
// setup irq sources and change pointers
lda #100
sta $d012
lda #$1b
sta $d011
lda #>handler
sta $ffff
lda #<handler
sta $fffe
// perhaps wait for rasterline here to avoid glitching
// enable irq sources
inx
stx $d01a
2021-06-13 02:59
Copyfault

Registered: Dec 2001
Posts: 466
Quoting Groepaz
we *really* need this rant :)
We do, but I won't volunteer as I'm not worthy enough to tickle this sensitive topic!

Quoting Groepaz

// switch off irq sources
lda #$7f
sta $dc0d
sta $dd0d
ldx #0
stx $d01a
// whatever irq was pending triggers here and the old handler handles it
// setup irq sources and change pointers
lda #100
sta $d012
lda #$1b
sta $d011
lda #>handler
sta $ffff
lda #<handler
sta $fffe
// perhaps wait for rasterline here to avoid glitching
// enable irq sources
inx
stx $d01a
Yes, this is the way to do it. Only detail I'm not sure about is when the potentially still pending IRQs might happen: my guess is that the irq acknowledging will still be in place, i.e. any "old" irq routine might be called at different spots.
// switch off irq sources
lda #$7f
sta $dc0d
         //if an irq condition happens before cycle 3 of this opcode, it will be
         //triggered directly after the STA-opcode has been processed...
sta $dd0d
         //...if not, it will take until this 2nd STA-opcode before the irq is triggered
ldx #0
         //same here: any pending IRQs of CIA2 will happen here the latest
stx $d01a
         // whatever irq was pending triggers here...
// setup irq sources and change pointers
lda #100
         //..or here if the raster IRQ condition occured at cycle 3 or 4 of the STX-opcode
[...]

Is this correct or do I mix things up?
2021-06-13 06:33
Martin Piper

Registered: Nov 2007
Posts: 629
If 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.

So using SEI/CLI is the correct bullet proof way of tackling that issue.
2021-06-13 08:48
TWW

Registered: Jul 2009
Posts: 541
Quote: If 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.

So using SEI/CLI is the correct bullet proof way of tackling that issue.


Yes!

    // Unknown state of VIC/CIA
    sei
    ldx #0
    stx $d01a
    lda #$7f
    sta $dc0d
    sta $dd0d
    cli
    // IRQ May happen here if one was triggered between the SEI and the write to the IRQ reg to diasble them.

    // Unknown state of VIC/CIA
    sei
    lda #0
    sta $d01a
    lda #$7f
    sta $dc0d
    sta $dd0d
    lda $dc0d
    lda $dd0d
    lda #1
    sta $d019
    cli
    // No URQ can trigger now from VIC/CIA.




@ GPZ: "// perhaps wait for rasterline here to avoid glitching"

Instead, just ack any pending IRQ's and you don't have to wait. Don't overthink it.

Edit: Typos
2021-06-13 10:32
ChristopherJam

Registered: Aug 2004
Posts: 1359
so, the following would work, but it's hella overengineered.

Quoting TWW
Yes!
    // Unknown state of VIC/CIA
    sei
    ldx #0
    stx $d01a
    lda #$7f
    sta $dc0d
    sta $dd0d
    cli
    // IRQ May happen here if one was triggered between the SEI and the write to the IRQ reg to diasble them.

Given that you're still allowing the triggered IRQ to go ahead, the only effect of wrapping the above in SEI/CLI is that you're potentially delaying the response to the IRQ to after
the write, hence giving the IRQ handler an opportunity to undo it.

Quote:
    // Unknown state of VIC/CIA
    sei
    lda #0
    sta $d01a
    lda #$7f
    sta $dc0d
    sta $dd0d
    lda $dc0d
    lda $dd0d
    lda #1
    sta $d019
    cli
    // No URQ can trigger now from VIC/CIA.


^the entire sequence of re-disabling CIA interrupts and acknowledging any that occured is only required in this section because you wrapped the first section in SEI/CLI
2021-06-13 10:39
ChristopherJam

Registered: Aug 2004
Posts: 1359
Quote: If 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.

So using SEI/CLI is the correct bullet proof way of tackling that issue.


The sequence doesn't need to be atomic.

Interrupts could occur before you enter the sequence regardless of whether the sequence itself is wrapped, and leaving the I flag clear just allows them to occur as late as just before the instruction performing the write.

Once the write occurs however, as long as you *didn't* execute an SEI, no CIA interrupts will occur afterwards.

And if you're concerned about a VIC interrupt reenabling your CIA interrupt, then wrapping that your code with SEI/CLI will only defer that to the end of the section; it does nothing to protect you against that.
2021-06-13 10:50
ChristopherJam

Registered: Aug 2004
Posts: 1359
argh, 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..
2021-06-13 10:59
Martin Piper

Registered: Nov 2007
Posts: 629
For the cost of two bytes SEI/CLI pair to handle all the hostile cases, I'd say it was reasonable.
I might even switch of the CIA2 source first, then CIA1. To handle NMIs.
2021-06-13 11:31
TWW

Registered: Jul 2009
Posts: 541
Quote: For the cost of two bytes SEI/CLI pair to handle all the hostile cases, I'd say it was reasonable.
I might even switch of the CIA2 source first, then CIA1. To handle NMIs.


Better yet, ground the NMI if you're not using it;

    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


@ CJ: "Given that you're still allowing the triggered IRQ to go ahead, the only effect of wrapping the above in SEI/CLI is that you're potentially delaying the response to the IRQ to after"

If you are fiddling with the IRQ vectors and not having the I-Flag set you're asking for it :)
2021-06-13 12:08
ChristopherJam

Registered: Aug 2004
Posts: 1359
haha, writing to the NMI vector without disabling the pertinent CIA first is just as much asking for it.

SEI is no more effective at disabling otherCIA and VIC than turning off the relevant sources, and if you're *really* concerned about hostile/badly written code I've yet to see anything that would protect against someone using a never-returning once-per-frame NMI that immediately sets up a raster interrupt from scratch before falling into NOPs.

You're still going to be vulnerable right up to the point that you've written to both DC0D and I and there's not much you can do about that.

At some point you need to set some ground rules for the code you're shutting down. So yes, if you want to be tolerant of the preceding part setting enable bits in ISRs, by all means wrap your shutdown code in SEI/CLI. It still won't be ironclad, but it will indeed deal with a few more possibilities.

Alternately, either assume that enabling interrupt sources should only be done at startup, or make it the responsibility of the preceding part to shut down gracefully.
2021-06-13 12:08
Copyfault

Registered: Dec 2001
Posts: 466
Quoting Martin Piper
If 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?
2021-06-13 12:17
ChristopherJam

Registered: Aug 2004
Posts: 1359
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).
2021-06-13 12:23
Copyfault

Registered: Dec 2001
Posts: 466
Quoting ChristopherJam
argh, 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...
2021-06-13 12:27
Copyfault

Registered: Dec 2001
Posts: 466
Quoting ChristopherJam
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).
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 :(
2021-06-13 13:41
chatGPZ

Registered: Dec 2001
Posts: 11088
The resistance to write proper code in favour of some 80s cargocult is impressing =D
2021-06-13 13:59
Krill

Registered: Apr 2002
Posts: 2804
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.
2021-06-13 14:07
chatGPZ

Registered: Dec 2001
Posts: 11088
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.
2021-06-13 14:20
Oswald

Registered: Apr 2002
Posts: 5007
good point with irq's reenabling irqs. I'll keep sei cli and ack cia irqs :)
2021-06-13 15:21
ChristopherJam

Registered: Aug 2004
Posts: 1359
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.
2021-06-13 16:34
TWW

Registered: Jul 2009
Posts: 541
Quoting ChristopherJam
haha, 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).
2021-06-13 17:53
chatGPZ

Registered: Dec 2001
Posts: 11088
you forgot the second SEI
2021-06-13 18:01
Oswald

Registered: Apr 2002
Posts: 5007
2021-06-13 18:20
TWW

Registered: Jul 2009
Posts: 541
Quoting Groepaz
you forgot the second SEI


If a NMI is executed between the SEI and the DD0D disable code, the Processor Status Register (PSR) gets pushed to the stack. When the inevitable RTI is executed the PSR is pulled from stack, the I-flag is restored without the need to set it a second time.
2021-06-13 18:21
Trap

Registered: Jul 2010
Posts: 221
Wow. This sure sparked a discussion :) I read the thread a few times, but I honestly still don't feel I am any bit closer to knowing how I should deal with my problem?

Thank you all for dishing in - truly wonderful and much appreciated though :)
2021-06-13 18:21
chatGPZ

Registered: Dec 2001
Posts: 11088
But what if the NMI handler manipulates the Stack? Are you assuming it doesnt?
2021-06-13 18:35
Trap

Registered: Jul 2010
Posts: 221
I am not using NMI or reading any keyboard presses. Just a normal IRQ running with kernal off ($01=$35).
2021-06-13 18:56
chatGPZ

Registered: Dec 2001
Posts: 11088
To answer your question we'd still need to know what exactly you are trying to do - there is no universal answer :)
2021-06-13 18:57
ChristopherJam

Registered: Aug 2004
Posts: 1359
Quoting Trap
I am not using NMI or reading any keyboard presses. Just a normal IRQ running with kernal off ($01=$35).


Then you can ignore almost all of the last 50 comments, and just
lda #$7f
sta $dc0d
ldx #0
stx $d01a

no SEI/CLI required. (that said, you do still need to ack the interrupt you're responding to if you do this in an ISR instead of in your main)
2021-06-13 18:58
ChristopherJam

Registered: Aug 2004
Posts: 1359
Quoting TWW
When the inevitable RTI is executed


We already covered this - the RTI is not at all inevitable if the interrupt in question is just setting up for another interrupt.
2021-06-13 19:19
TWW

Registered: Jul 2009
Posts: 541
Quote: But what if the NMI handler manipulates the Stack? Are you assuming it doesnt?

If the NMI code messes with the stack, the RTI won't work, and chances are any previously running code prior to this would not have worked either.

@ Trap: If you setup and have control of your interrupts as I posted above, it should be straight forward to handle unpacking and transitions since you only need to handle Raster IRQs (assuming no funky memory banking).

    // space is pressed inside a raster IRQ or whatever
    // I-Flag is set since it's handled inside the IRQ
    ldx #0
    stx $d01a
    inx
    stx $d019
    cli
    // no more (internal) interrupts can happen here
    jmp depack


PS. STACK is messed up at this point, so you cannot have any rti/rts. If the depacker sei/cli or not should not matter as long as it doesn't activate any IRQs. Finally ensure that there is no mem-bank trickery going on which may mess things up.
2021-06-13 19:32
TWW

Registered: Jul 2009
Posts: 541
Quote: Quoting TWW
When the inevitable RTI is executed


We already covered this - the RTI is not at all inevitable if the interrupt in question is just setting up for another interrupt.


If the interrupt in question is just setting up for another interrupt, you do not need to do anything except handle the ongoing *known* interrupt and it's source, assuming you *know* that no other internal interrupts may occur.
2021-06-13 20:27
chatGPZ

Registered: Dec 2001
Posts: 11088
You are assuming quite a bit now - wasnt your code about not assuming anything and work always?

Quote:
If the NMI code messes with the stack, the RTI won't work, and chances are any previously running code prior to this would not have worked either.

no?

nmiend:
  bit flag
  bmi notyet
  plp
  and #~4
  php
notyet:
  rti


(yes the working code looks a bit more elaborate, you get the idea)
2021-06-13 21:03
TWW

Registered: Jul 2009
Posts: 541
Quoting Groepaz
(yes the working code looks a bit more elaborate, you get the idea)


Yes I get the idea. Interesting argument technique, I use it myself sometimes...

So by your reasoning, would the 2nd sei in the code above mean that you consider it 100% safe?

If yes - Are you sure someone couldn't tailor some code to break it anyway if they really wanted to :)
If no - Why did you make the argument, knowing it's pointless?

Edit:
It just occurred that you could move the sei after disabling/ack'ing $dc0d. No need to have one before so you still only need one sei to counter the evil GPZ code above hehe :)
2021-06-13 23:02
Trap

Registered: Jul 2010
Posts: 221
In case somebody has the same question, I'll post what I finally found to work. Thanks a million to all the great input from you guys.

Not 100% what I'm doing here, but it works :)

sei
lda #$36
sta $01
jsr vsync
lda #$0b
sta $d011
lda #$7f
sta $dc0d
sta $dd0d
lda $dc0d
lda $dd0d
lda #$48
sta $fffe
lda #$ff
sta $ffff
ldx #0
stx $d01a
inx
stx $d019
cli
jmp nextthinghappening

Thank you.

Trap
2021-06-13 23:21
chatGPZ

Registered: Dec 2001
Posts: 11088
Quote:
If yes - Are you sure someone couldn't tailor some code to break it anyway if they really wanted to :)
If no - Why did you make the argument, knowing it's pointless?

Oh, its not me who is saying his code is totally safe and makes no assumptions. Step back and look at what you posted in #62 - it will work pretty much exactly the same for all practical purposes, without the sei/cli :) Except when you try hard to break it, which will require exploiting similar uncommon scenarios as the one i posted.

trap: do the vsync (better: wait a frame) after setting d011 to $0b - then you can be sure it will really be blanked (the flag is only checked once per frame ~line f8 or sth)
2021-06-14 00:03
TWW

Registered: Jul 2009
Posts: 541
Quoting Groepaz
its not me who is saying his code is totally safe and makes no assumptions. Step back and look at what you posted in #62


Here is what was actually said in post #62:

"Here is the full code I use to setup a safe raster IRQ without presuming too much"

If you're going to paraphrase, at least do it right.

Besides, it still only took to move one sei to counter your example of destructive code;

    ldx #$7f
    stx $dd0d
    lda $dd0d
    sei
    stx $dc0d
    lda $dc0d

Thanks for contributing to improve it.
2021-06-14 00:21
chatGPZ

Registered: Dec 2001
Posts: 11088
you cant just move it, you must sei first to prevent that an irq triggers right after the stx $dd0d and then enables the NMI again.

Quote:

Here is what was actually said in post #62:

"Here is the full code I use to setup a safe raster IRQ without presuming too much"


Thats a really weak argument. How would anyone know exactly what you mean? Finding out how to do it "without assuming an undefined too much" (whatever it means) is not an interesting question at all. Making it 100% safe is. And if not - then what matters most of the time. And most of the time all those scenarios where one interrupt(source) triggers and enables another interrupt(source) as a result does not matter at all - making sei/cli or even ACKing the sources in the setup code a pointless exercise in most scenarios. Those things are only needed when trying to write code that considers those special edge cases. (And then... not considering all of them is ... a bit lame :=P)
2021-06-14 10:27
Krill

Registered: Apr 2002
Posts: 2804
So... how about guarding a safe interrupt disable routine against a malicious VM running on 6502 itself, so any of the routine's instructions would be made ineffective if an attempt to disable interrupts (SEI, disable bits in an interrupt mask register, etc.) is detected? =)
2021-06-14 10:32
ChristopherJam

Registered: Aug 2004
Posts: 1359
I'm still with groepaz on this one. For 99% of the parts out there, even if they don't shut themselves down properly all wrapping your cleanup code in SEI/CLI does is to add complexity. If I is clear, you can just turn off the sources and you're done - no acks required.

For the remaining 1%, TWW's solutions will work for some and not others - you really need to study the routine in question to see what you need, and honestly any routine with requirements so weird as to need anything more complex really should be responsible for cleaning up its own shit.


edit - and cf Krill's comment for an example of why there really is no such thing as a bulletproof routine :D
2021-06-14 10:47
Krill

Registered: Apr 2002
Posts: 2804
Yeah, repeating myself: if you need to set interrupt masks from within an ISR, you're most likely doing it wrong and asking for trouble. =)
2021-06-14 14:48
JackAsser

Registered: Jun 2002
Posts: 1987
Quote: Yeah, repeating myself: if you need to set interrupt masks from within an ISR, you're most likely doing it wrong and asking for trouble. =)

I enable/disable NMs from raster IRQs by messing with the mask. F.e. have a stable 4 line timer that I just mask/unmask in top / bottom border to enable the $d011 trickery needed.
2021-06-14 14:52
Krill

Registered: Apr 2002
Posts: 2804
Quoting JackAsser
I enable/disable NMs from raster IRQs by messing with the mask. F.e. have a stable 4 line timer that I just mask/unmask in top / bottom border to enable the $d011 trickery needed.
Could the same effect be achieved by enabling/disabling the NMI handler's ack from a non-NMI context? (And acking previous NMI after re-enabling the handler's ack.)

Alternatively, have the 4-line timer not generate interrupts, but the other timer count just 1 underrun of the 4-line timer and generate interrupts. The latter can then be started and stopped from a non-NMI context without losing sync to VIC.
2021-06-14 15:45
chatGPZ

Registered: Dec 2001
Posts: 11088
I also did something like this in Mongobong to play samples in borders using NMI and then have FLI in the display area. Dont remember details, it probably _was_ stupid to do it like i did :)
2021-06-14 15:49
ChristopherJam

Registered: Aug 2004
Posts: 1359
Samples plus FLI? Now that is brave.
2021-06-14 16:16
JackAsser

Registered: Jun 2002
Posts: 1987
Quote: Quoting JackAsser
I enable/disable NMs from raster IRQs by messing with the mask. F.e. have a stable 4 line timer that I just mask/unmask in top / bottom border to enable the $d011 trickery needed.
Could the same effect be achieved by enabling/disabling the NMI handler's ack from a non-NMI context? (And acking previous NMI after re-enabling the handler's ack.)

Alternatively, have the 4-line timer not generate interrupts, but the other timer count just 1 underrun of the 4-line timer and generate interrupts. The latter can then be started and stopped from a non-NMI context without losing sync to VIC.


Ofcourse u can, but less elegant and not really less error prone. A 4th line NMI is 100% predictable when it will trigger anyway.
2021-06-14 16:36
TWW

Registered: Jul 2009
Posts: 541
Quoting Groepaz
you cant just move it, you must sei first to prevent that an irq triggers right after the stx $dd0d and then enables the NMI again.

Enabling NMIs inside an IRQ... Never saw that myself, but not saying it doesn't exist.

Quoting Groepaz
(And then... not considering all of them is ... a bit lame :=P)


Lame yourself :-D
2021-06-14 17:48
Krill

Registered: Apr 2002
Posts: 2804
Quoting JackAsser
Ofcourse u can, but less elegant and not really less error prone. A 4th line NMI is 100% predictable when it will trigger anyway.
Sure, but my point was to avoid setting interrupt masks in ISRs (without drawbacks, except maybe elegance, which is somewhat subjective).
Avoid the main cause for disabling without SEI/ACK/CLI wrapper failing. =)
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Scrap/Genesis Project
iAN CooG/HVSC
stephan-a
Soren/Camelot, MoN, ..
Brittle/Dentifrice^(?)
Dr. Doom/RAD
Nova
Mason/Unicess
Sentinel/Excess/TREX
Airwolf/F4CG
Guests online: 350
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 No Bounds  (9.6)
6 Comaland 100%  (9.6)
7 Uncensored  (9.6)
8 The Ghost  (9.6)
9 Wonderland XIV  (9.6)
10 Bromance  (9.6)
Top onefile Demos
1 Party Elk 2  (9.7)
2 Cubic Dream  (9.6)
3 Copper Booze  (9.5)
4 Rainbow Connection  (9.5)
5 TRSAC, Gabber & Pebe..  (9.5)
6 Onscreen 5k  (9.5)
7 Dawnfall V1.1  (9.5)
8 Quadrants  (9.5)
9 Daah, Those Acid Pil..  (9.5)
10 Birth of a Flower  (9.5)
Top Groups
1 Booze Design  (9.3)
2 Nostalgia  (9.3)
3 Oxyron  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Swappers
1 Derbyshire Ram  (10)
2 Jerry  (9.8)
3 Violator  (9.8)
4 Acidchild  (9.7)
5 Starlight  (9.6)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.186 sec.