| |
oziphantom
Registered: Oct 2014 Posts: 490 |
Force a queded IRQ
Is there a way to pogrammatically ( without the CIAs ) to en-queue an IRQ from within an NMI?
BRK will interrupt an NMI.But is there some other trick, maybe some stack fiddling? |
|
... 21 posts hidden. Click here to view all posts.... |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
soci, thats a nice detial, now we know why its 00 :) |
| |
lft
Registered: Jul 2007 Posts: 369 |
Quoting OswaldI think the issue at hand could be solved with a more sane aproach.
This.
Oziphantom, what is the ultimate goal hidden behind your question? |
| |
Karmic
Registered: Apr 2015 Posts: 66 |
Yep, I've been trying to wrap my head around this question.
WHY do you need it to behave exactly like a normal IRQ? WHY can't you just jump to your IRQ handler, or use BRK? |
| |
White Flame
Registered: Sep 2002 Posts: 136 |
TWW: The IRQ line is actually active low, so it trips an interrupt when it's grounded, not high. Most C64 signals work like this, with a pull-up resistor defaulting lines to 5V, with any number of chips optionally asserting ground, so no conflict between multiple chips asserting a signal will let out the magic smoke.
Quoting oziphantomYes that is Standard IRQ behaviour, which is what I'm looking for. I'm pointing out the standard IRQ behaviour to show why you can't just use BBK.
The custom behaviour I'm asking about is "Is there a way to achieve an IRQ in software, such that it behaves in the standard way."
You really need to define what "standard behavior" is and why you want it. The only "proper" standard behavior would be to tell another chip to hold /IRQ low. Again, the interrupted code won't perceive anything no matter which option you take, besides the passage of time. You need to list what effects you want to happen. Are you using the stack droppings left over from the interrupt? Do you want it as fast as possible? Those are about the only 2 scenarios I can think of where any of this matters. And a simple software jump will be the fastest route, leaving the NMI's return information on the stack to use to exit the IRQ. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Quoting lft
Oziphantom, what is the ultimate goal hidden behind your question?
Yes, this is sounding a lot like an XY problem to me. |
| |
oziphantom
Registered: Oct 2014 Posts: 490 |
Quoting lftQuoting OswaldI think the issue at hand could be solved with a more sane aproach.
This.
Oziphantom, what is the ultimate goal hidden behind your question?
Its a way of cheating another thread.
So you have the case where some logic is do be done in the "Main loop", you have some other logic that eats CPU - decompression for example, and you have NMIs
So while you have the main loop, you also want to decompress stuff, this means you need to make your decompression routines ( of which I have a few) be state aware, in that each of their internal loops needs to check ( has nmi told me I need to do a thing ) and then break out, do the thing, come back and carry on decompressing.
Once they have finished decompressing, the main loop resorts back to "wait for nmi to tell me do a thing".
The way to simplify and clean up all of this logic is to re-purpose the IRQ to "do the thing". So when you are decompressing you tell the NMI to handle "do the thing", when you are not decompressing you don't tell the NMI to do it and let the main loop take care of it. When I'm in the case that neither the main loop nor the NMIs are doing the thing duty, then the decompression system can trigger the thing.
to which the logic now looks like thanks to Soci
[nmi handler]
LDA NMIDoThing
LSR
PLA
TAY
PLA
TAX
PLA
BCS _queueIRQ
RTI
_queueIRQ
JMP ($FFFE)
inside the decompression routine
LDA DecompressDoThing
BEQ +
BRK
+
Main Loop
- LDA DoThing
BNE -
BRK
JMP -
Thus the NMI is unchanged, it still happens exactly as it was before with its tight timings, the "fragment" or "thread code" is now written in one way, it saves and restore its registers and ends in an RTI, and its updated from a single Vector location, without any management of special cases, allowing the NMI, decompression, VIC or mainloop logic to be generic and used in all cases, with simple control of who is responsible for doing what. Giving me an effective thread that I can have strict timing control, or loose timing control over as needed, and can be passed around very easily allowing me to make any combination needed for the user experience desired. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
"So while you have the main loop, you also want to decompress stuff"
this is usually solved in demos with re-entrant irqs. The main effect is jumped to from an irq, which immediately sets a flag saying not to jump here again in next frame from the irq, and then also a CLI, so upcoming irqs will be served. (all irqs must use stack properly and save registers on stack).
the 'main' cpu thread is used by the loader in the remaining frame fragment when all irqs have been returned. that is the main effect finished running, and there's still some time left until the raster irq starts, that initiates it.
a more primitive way I was doing simply adding a byte counter to the loader, and having it rts after every xth byte. or setting a flag if finished.
I also did multitasking, 2 raster irqs exchanged contents of stack. but better virtually halving the stack and only change stack pointer when changing context. |
| |
oziphantom
Registered: Oct 2014 Posts: 490 |
The BRK/NMI/IRQ are three faces of the same coin
type interupt NMI interupt IRQ Vector needs to exit with RTI
JMP No No whichever you call No
IRQ No No FFFE/F Yes
NMI Yes Yes FFFA/B Yes
BRK Yes Yes FFFE/F Yes So the Standard behaviour I want is the IRQ case. In that is the standard behaviour of the IRQs execution not the Standard behaviour of the IRQ inception.
So outside of an NMI, BRK is a fine substitute for doing an IRQ. Inside an NMI it doesn't substitute for an IRQ.
I'm looking for a way to get the IRQ operation, which is basically to "en-queue" the IRQ on the CPUS "things to do" in a neater way . i.e it gets to the of the NMI and goes "oh yeah I have an IRQ to do as well" *goes and does IRQ*
But I'm not looking for the solution, I'm asking if there is a neater solution.
To which Soci found at this point what I'm going to call the neatest. In that the can use the C flag to "chain" the IRQ onto the end of the NMI. As a PLA will modify N and Z but not C. Any modification of C is restored by the RTI which will do the PLP for you. Thus the C is safe to modify before the stack pulls, and react to it after them. This allows you to transparently and safely jump straight into the IRQ handler, as the stack has now been restored to its "first clock of interrupt state". So no extra handling is needed to handle this "queued interrupt".
And I'm sure the crackers will appreciate such madness being well documented here for them ;) |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
* = $080D
LDA #$7F
STA $DC0D
LDA $DC0D
LDA #$35
STA $01
LDA #<NMI_IRQ
STA $FFFA
LDA #>NMI_IRQ
STA $FFFB
;-------------------
MAIN_LOOP
LDA QUEUED_FLAG
EOR #$01
STA QUEUED_FLAG
JMP MAIN_LOOP
;-------------------
NMI_IRQ
STA RESTORE_A
QUEUED_FLAG = *+$0001
LDA #$01
BEQ NMI_NO_QUEUE
LDA #>QUEUED_IRQ
PHA
LDA #<QUEUED_IRQ
PHA
PHP
NMI_NO_QUEUE
INC $D020
LDA $DD0D
RESTORE_A = *+$0001
LDA #$00
RTI
;-------------------
QUEUED_IRQ
SEI
INC $D021
RTI
;---------------------------------------
The "QUEUED_IRQ" code act as a "normal" IRQ and is queued to a NMI but can be interrupted by a NMI but not by another maskable IRQ...
The QUEUED code will be executed accordingly to "QUEUED_FLAG" value.
Should be something like this?
(Edit: press RESTORE key to fire the NMI...) |
| |
oziphantom
Registered: Oct 2014 Posts: 490 |
If you don't need to push the A,X,Y etc in your handler than you can do it that way. |
Previous - 1 | 2 | 3 | 4 - Next |