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 > Force a queded IRQ
2017-05-27 08:12
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?
2017-05-27 08:33
TWW

Registered: Jul 2009
Posts: 545
I perhaps do not understand what you are trying to achieve but the Interrupt flag let's you control IRQs so whenever the flag is set, no IRQ's will trigger and when clear, they will.

This should allow you to control when they are triggering from a NMI or in general.

If you need timed (delayed with a certain amount of cycles) you could use the CIA and allow the IRQ to trigger just to set a flag and return which you in then could monitor in the NMI.

Can you elaborate a bit on what you are trying to do?
2017-05-27 09:15
oziphantom

Registered: Oct 2014
Posts: 490
A software interrupt.
However it can if needed rely on the fact it is in a NMI.

I doubt its possible, but you never know there might be some fancy trick to get it ;)
2017-05-27 10:09
TWW

Registered: Jul 2009
Posts: 545
You can trigger a SW interrupt whenever you want by using BRK or SEI/CLI in combination with a timer or raster IRQ which always is set to trigger.

I think I still don't get what you are trying to do ;-)
2017-05-27 10:33
oziphantom

Registered: Oct 2014
Posts: 490
BRK won't force an interrupt, as it will invoke the break handler right then and there, even if you are in an NMI.

So the ideal path is

Enter NMI
Do stuff
Optionally Queue IRQ
Do other stuff
Exit NMI
IRQ triggers when it can, if queued.
2017-05-27 10:46
Oswald

Registered: Apr 2002
Posts: 5094
how about setting up a raster irq (outside of available raster range), and using d019 to artifically fire a raster irq ? not sure if d019 can be used in this way tho.

similar thing could be achieved via timer interrupts too.
2017-05-27 11:46
Flavioweb

Registered: Nov 2011
Posts: 463
If you do a CLI as first instruction of your irq code, when another irq happens it will be triggered as well...
If it's what you mean...
2017-05-27 13:22
Mixer

Registered: Apr 2008
Posts: 452
If you wish to exit NMI directly to irq handler, you have to push the irq handler address to stack so that RTI fetches it correctly.

The irq handler then runs, but there is no flagged interrupt going on, so this execution can be interrupted, unless masked.

If you want some certain interrupt to take place, then set the conditions for that interrupt(VIC/CIA) etc.
2017-05-27 14:04
chatGPZ

Registered: Dec 2001
Posts: 11386
Quote:
BRK won't force an interrupt

in fact that is _exactly_ what a BRK does.
2017-05-27 17:04
White Flame

Registered: Sep 2002
Posts: 136
It's faster to just tail-call right into the IRQ, than it is to exit the NMI and then fake entering the IRQ handler via stack munging.

Neither the stack nor the interrupted program see any difference whether or not it was interrupted via NMI or IRQ, or if it were interrupted twice (NMI falling into IRQ after RTI) instead of once. If the prologues of both interrupt handlers match (which normally would be pushing regs to stack, instead of STA'ing them), you can do a "real" tail call:

nmi:
  prologue
  process
  test
  JMP irq_noprologue
  epilogue

irq:
  prologue
irq_noprologue:
  process
  epilogue


If the prologue/epilogue don't match, then you should do a simple test & compare after restoring saved registers. Since the processor status flags are restored as part of RTI, you don't have to worry about them, so a BCS or a BIT+BNE can perform the test right before the RTI instruction of the NMI handler, depending on how you saved the result of the decision to branch to IRQ.
2017-05-28 06:29
oziphantom

Registered: Oct 2014
Posts: 490
Quoting Groepaz
Quote:
BRK won't force an interrupt

in fact that is _exactly_ what a BRK does.


Fair I was loose with my terminology.
BRK won't force an IRQ.
It will force a jump to the FFFE/FFFF vector, but not under the rules of an IRQ.
2017-05-28 06:39
Flavioweb

Registered: Nov 2011
Posts: 463
Quote: BRK won't force an interrupt, as it will invoke the break handler right then and there, even if you are in an NMI.

So the ideal path is

Enter NMI
Do stuff
Optionally Queue IRQ
Do other stuff
Exit NMI
IRQ triggers when it can, if queued.


Isn't this the normal behaviour of a maskable irq triggered during a NMI?
2017-05-28 07:20
Bitbreaker

Registered: Oct 2002
Posts: 508
Quoting oziphantom

So the ideal path is

Enter NMI
Do stuff
Optionally Queue IRQ
Do other stuff
Exit NMI
IRQ triggers when it can, if queued.


But then it is sufficient to just push the address (+ bogus flags) on the stack to queeue in another task. Then the rti at the end of the NMI handler pulls that stuff form stack again and sets the PC to said address. Then, when th queued irq is also finished with rti, the stuff before entering the nmi is continued. Take care of the registers though and in case also push/pull them from stack.

Other ways are to never acknowledge some irq (lda $dd0d) to make it happen just again and again when you need it, or stop it from happening again by acknowledging.
2017-05-28 08:32
TWW

Registered: Jul 2009
Posts: 545
Quoting oziphantom

So the ideal path is

Enter NMI
Do stuff
Optionally Queue IRQ
Do other stuff
Exit NMI
IRQ triggers when it can, if queued.


Isn't this normal NMI/IRQ behaviour? Let's say you are playing samples, the sample-player will trigger at the set frequency (by a CIA #2 timer) while any triggered IRQ (typically raster) is executed once the NMI is exited (RTI - clearing the IRQ flag).
2017-05-28 09:24
oziphantom

Registered: Oct 2014
Posts: 490
Yes 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."

I could push fake status, then address where address is the IRQ routine + bytes to skip its entry, the issues with it is I need to store 2 address ( 1 normal entry and then 1 NMI entry) and possibly set them in multiple places, which could be mitigated by storing my own NMI entry vector and the code look its up Or all IRQs have a fixed length entry and thus the NMI takes IRQ address + constant then store. I could also do read d012 add 2 with care to make sure its not out of range, then set D012 again and enable to interrupt flag, if I had a free CIA IRQ timer I could use it.

However all the balancing acts, double vectors management etc goes away if you can just trick the 6502 into thinking it has a pending IRQ it needs to do. Hence I'm asking to see if there is any way to do such a thing.
2017-05-28 10:42
soci

Registered: Sep 2003
Posts: 480
I think this is what WF meant:
nmi		;...
		bcs do_queued_irq
		rti
do_queued_irq	jmp ($fffe)

Looks simple to me. But if there's a real IRQ waiting it's not really queued any more.
2017-05-28 11:12
TWW

Registered: Jul 2009
Posts: 545
The only way to initiate a SW controlled IRQ is by doing a BRK instruction, clearing the I-flag when you know (or have deliberately forced) an IRQ condition or mimic the interrupt handler behaviour (push PC, SR and do a JMP (IRQCODE) which I believe is what WF and Soci is pointing at)

The IRQ line is checked between instructions and as you know trigger the IRQ handler if it is high. The BRK does not pull the line high but triggers the handler anyway (and set's the BRK flag so you have control if the IRQ was launched by a voltage (Cartridge port IRQ line, CIA or VIC) or by SW).

At least this is how I understand it.
2017-05-28 11:24
Hein

Registered: Apr 2004
Posts: 954
Maybe you want to interrupt an NMI?
2017-05-28 15:36
Oswald

Registered: Apr 2002
Posts: 5094
I think the issue at hand could be solved with a more sane aproach.
2017-05-28 15:55
chatGPZ

Registered: Dec 2001
Posts: 11386
Quote:
BRK won't force an IRQ

in fact a IRQ will put a BRK into the instruction decoder....
2017-05-28 16:40
soci

Registered: Sep 2003
Posts: 480
Quote: Quote:
BRK won't force an IRQ

in fact a IRQ will put a BRK into the instruction decoder....


On the schematics it looks like it pulls the data lines low in front of the instruction register to make the next instruction a BRK. Not that it's important ;)
2017-05-28 16:42
chatGPZ

Registered: Dec 2001
Posts: 11386
lol. yes. (there was some other subtle difference ... i forgot =P)
2017-05-28 18:05
Oswald

Registered: Apr 2002
Posts: 5094
soci, thats a nice detial, now we know why its 00 :)
2017-05-28 20:19
lft

Registered: Jul 2007
Posts: 369
Quoting Oswald
I think the issue at hand could be solved with a more sane aproach.


This.

Oziphantom, what is the ultimate goal hidden behind your question?
2017-05-29 05:29
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?
2017-05-29 06:45
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 oziphantom
Yes 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.
2017-05-29 07:40
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.
2017-05-29 07:53
oziphantom

Registered: Oct 2014
Posts: 490
Quoting lft
Quoting Oswald
I 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.
2017-05-29 08:11
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.
2017-05-29 08:21
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 ;)
2017-05-29 10:05
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...)
2017-05-29 14:39
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.
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
E$G/HF ⭐ 7
Mason/Unicess
Smasher/F4CG
algorithm
acrouzet/G★P
csabanw
Guests online: 102
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.6)
5 Edge of Disgrace  (9.6)
6 What Is The Matrix 2  (9.6)
7 The Demo Coder  (9.6)
8 Uncensored  (9.6)
9 Comaland 100%  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 No Listen  (9.6)
3 Cubic Dream  (9.6)
4 Party Elk 2  (9.6)
5 Copper Booze  (9.6)
6 Dawnfall V1.1  (9.5)
7 Rainbow Connection  (9.5)
8 Onscreen 5k  (9.5)
9 Morph  (9.5)
10 Libertongo  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Triad  (9.3)
5 Censor Design  (9.3)
Top Swappers
1 Derbyshire Ram  (10)
2 Jerry  (9.8)
3 Violator  (9.7)
4 Acidchild  (9.7)
5 Cash  (9.6)

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