14 May 2019, 12:58 | #1 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Amiga and multiple IRQs at the same time.
There is a related application note by Motorola (AN1012 - A discussion of Interrupts for the MC68000) about the topic.
An Interrupt Process Flowchart explain how the hardware signals act. There are also a couple of examples regarding multiple interrupts and the maximum latency for code execution (very interesting). However, the Amiga system is peculiar: Paula completely governs IRQ management (apart from IRQ7). This is fortunate because at least you can have predictable behavior. Some IRQs are 'internal' (5->floppy/serial, 4->audio, 1->floppy/serial) some 'external' (6,3,2). An user from the NXP community monitored the exact 'software' sequence during an interupt (probably of common knowledge). The exact timing for an interrupt acknowledge cycle looks like this: 1. Finish executing current instruction 2. Stack PCL at SSP-2 3. Interrupt acknowledge cycle 4. Stack SR at SSP-6 5. Stack PCH at SSP-4 6. Read interrupt vector low word 7. Read interrupt vector high word 8. Execute first instruction from ISR Apart from the strange sequence of the parameters saving (which can only be interesting in the case of a perfect hardware emulation) the important thing is that the pointer in the interrupt vector is read last and therefore the whole sequence listed must necessarily be atomic for guarantee a coherent point of return. Now comes the focal point and let's go back to the amiga world. Suppose we have a low level IRQ (IRQ1) made of fast and simple code that I want it executed immediately, which is triggered at the same o near time as another higher level (take it as IRQ3/VBI but can be any) which has a very long (and disturbing) execution time. If IRQ3 is slightly earlier or contemporary it is not a problem, the fetch is made from Level3 vector: just put as a first instruction MOVE.W #$20,INTREQ, MOVE #$2000,SRand any other lower level IRQ is executed immediately. The same if Level1 is executed slightly before, just put MOVE #$2700,SRand temporarily block the higher level ones. But if the vector pointer has already been fetched for Level1 and the Level 3 in the meantime has arrived, what happens? In that case I already have a point of return to save in the stack, but I haven't run MOVE #$ 2700,SR yet and so I didn't block the long execution time of IRQ3. Also, hasn't Paula yet received the acknowledgment for the IRQ1 so ther IRQ re-trigger? (i've lowered IRQ priority in IRQ3 code, so IRQ1 execute, then normal IRQ3 code execute and the previous one IRQ1 is on stack and pending?) Or much more simply, at least one instruction of the IRQ1 (the MOVE #$2700,SR) is executed and no problem arise? I'm sorry for the long prologue and bizarre question, but depending on this there may be situations in which the code would behave very differently (yes, this is an extreme situation, and yes lowering I bits in IRQ is a bad behavior). |
14 May 2019, 13:20 | #2 | |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
|
If I understand you correctly, you're wondering about the way the processor handles interrupts during interrupts. Adding to this, you're wondering how Paula interacts with this all.
Now, I can't answer the last question - I don't know if Paula retriggers interrupts. If I'd have to guess, I'd say it probably doesn't, but I don't know for sure. Edit: on the other hand, not clearing the correct interrupt bit in INTREQ will cause an interrupt to retrigger immediately, so perhaps this is not correct. As for the first question, AFAIK interrupt handling on the 68k is atomic. Meaning that the individual steps of the interrupt either all happen or all don't happen prior to executing any individual instruction. If this is correct (I can't guarantee not making a mistake but I'm pretty certain the internal IRQ handling of the 68k ought to be atomic), I'd say that there will not be a case in which the IRQ lets an instruction execute 'half way'. The long and short of this is that my expectation would be that Quote:
Do note that (given my edit) this doesn't mean weird stuff can't happen. It merely means that the sequence is always correct. It's still possible that Paula keeps the interrupt of the processor 'set' until acknowledge has occurred. Edit (2): a final thought. Perhaps this can be solved without using the SR at all. It's a bit of a hack I suppose, but you could push a desired return location into the stack and simply have your level 3 interrupt acknowledge and end 'correctly', but with the level 3 handler as a return point. This way you only need to set/clear the Paula interrupt register and can still force the CPU to run code that is triggered by an interrupt, but itself isn't an interrupt. Hopefully this makes some sense, it's a bit of a brain dump Last edited by roondar; 14 May 2019 at 13:30. |
|
14 May 2019, 13:40 | #3 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Thanks roondar.
If my statement in bold is right then yes, there is sure no problems at all. But too many guesses from our posts The only obscure point remains for the following (special) case: - IRQ1 trigger - start of interrupt acknowledge cycle.. - ..up to the vector fetch - IRQ3 trigger - is the first ISR1 instruction executed before or after the first ISR3 instruction? Because there is no inconsistency even if the first ISR1 statement is not executed, but if the code is as I wrote in the first post the final behavior is very different! |
14 May 2019, 13:59 | #4 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
|
The main problem is that I normally only use Paula interrupts on the Amiga, so my knowledge of how the 68k and Paula interrupt systems interact is limited to what I need for those cases.
I'm still pretty certain that an interrupt triggering during another interrupt will either happen entirely before or entirely after the current/next instruction is completed. My primary question here would be what happens if the trigger of an interrupt happens 'during' or just ahead of the move #$2700,SR. Will the 68k then ignore the interrupt based on the now changed SR status or not? I'm not sure. |
14 May 2019, 15:04 | #5 | ||
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Quote:
Quote:
|
||
14 May 2019, 16:44 | #6 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
I could not resist and tried to see how WinUAE behaves and the result is VERY interesting (and who knows if the real machines behave like this).
Code (A500 quickstart, CE): Code:
SECTION irq_test,CODE_C lea $dff000,a6 move.w #$7fff,d0 move.w d0,($9a,a6) move.w d0,($96,a6) move.w d0,($9c,a6) lea (.copper,pc),a0 move.l a0,($80,a6) lea (.irq1,pc),a0 move.l a0,$64.w lea (.irq3,pc),a0 move.l a0,$6c.w .wv moveq #$20,d0 and.w ($1e,a6),d0 beq.b .wv move.w #$8280,($96,a6) move.w #$c014,($9a,a6) .lc move.l (4,a6),d0 lsr.l #1,d0 cmpi.w #$4000,d0 bls.b .lc dcb.w 256,$4e71 bra.w .lc .irq1 move #$2700,sr move.w #$4,$dff09c rte .irq3 move.w #$10,$dff09c move #$2000,sr rte .copper dc.w $8021,$fffe dc.w $009c,$8004 dc.w $009c,$8010 dc.w $ffff,$fffe Code:
0 00014C6A e288 LSR.L #$01,D0 0 00014C6C 0c40 4000 CMP.W #$4000,D0 0 00014C70 63f4 BLS.B #$f4 == $00014c66 (F) 0 00014C72 4e71 NOP 0 00014C74 4e71 NOP 0 00014C76 4e71 NOP 0 00014C78 4e71 NOP 3 00014E84 33fc 0010 00df f09c MOVE.W #$0010,$00dff09c <-- IRQ3 (before IRQ1 even if IRQ1 called first by copper), clear it 3 00014E8C 46fc 2000 MOVE.W #$2000,SR <-- lower IRQ IPL, so.. 1 00014E76 46fc 2700 MOVE.W #$2700,SR <-- ..IRQ1 trigger, block the others 7 00014E7A 33fc 0004 00df f09c MOVE.W #$0004,$00dff09c <-- clear IRQ1 7 00014E82 4e73 RTE <-- exit from IRQ1 -1 00014E90 4e73 RTE <-- exit from IRQ3 1 00014E76 46fc 2700 MOVE.W #$2700,SR <-- IRQ1 re-trigger! 7 00014E7A 33fc 0004 00df f09c MOVE.W #$0004,$00dff09c 7 00014E82 4e73 RTE 0 00014C7A 4e71 NOP 0 00014C7C 4e71 NOP 0 00014C7E 4e71 NOP A comment by Toni is welcome |
14 May 2019, 19:12 | #7 | |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
|
I analyzed all 68000 exception cycle-sequences probably over 10 years ago but it isn't important except for cycle-accuracy (for example if supervisor stack is in chip ram)
68060 is a special case ("The MC68060 is unique from earlier members of the family in that if an interrupt is pending during exception processing, the exception processing for that interrupt is deferred until the first instruction of the exception handler of the current exception is executed. ") All other models can start new interrupt immediately after previous interrupt has finished stack push operations (which can't be interrupted, except by bus error but thats unrecoverable anyway) Technically there is no "re-triggering", condition is simple: if SR interrupt mask is lower than current level of IPL signals (coming from Paula): start interrupt processing. Quote:
|
|
14 May 2019, 20:35 | #8 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Quote:
Practically is: - IRQ1 trigger and a full CPU interrupt acknowledge cycle is executed (there is a vector fetch and all) - if in the following ~44 cycles (I've inserted some CNOP to delay and checked) an higher level IRQ arrives no single IRQ1 ISR instruction is executed BUT.. - ..the new higher level IRQ3 trigger (a full CPU interrupt acknowledge cycle is executed) and the previous context is saved on stack - I clear INTREQ IRQ3 and lower the IPL bits in SR, so actualy Paula immediately (and rightly) call for an IRQ1 - CPU execute IRQ1 ISR, clear INTREQ and RTE - CPU return to IRQ3 ISR (that actually is with IPL=0 in SR due to previous setup) and RTE - CPU return to the (unexecuted) first IRQ1 ISR, clear INTREQ (superfluous because already performed previously), and RTE to usercode. Did I get it right? Ok, not technically a re-trigger but in practice as if it were a failure to clean INTREQ (so an unwanted re-executing ). Lowering IPLs is dangerous, I have to think of a way to handle such a situation. |
|
14 May 2019, 20:52 | #9 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
|
Yeah and I don't care how it appear, what exactly happens is always more important
I guess you could set interrupt level to 7, check "I am already running" variable, if set, jump directly to end (if not set, restore SR). At the end set interrupt level to 7 again (to make following code atomic), clear the variable. No need to restore SR manually because RTE does it automatically. |
14 May 2019, 21:32 | #10 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Quote:
|
|
15 May 2019, 14:50 | #11 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Just for the records, this is a solution that I adopted and that works very well.
It's generic enough, doesn't use additional variables and you can adapt it to different levels of IRQs (three on this example). Code:
.irq1 move #$2700,sr move.w #$4,$dff09c move.w #$4,$dff09c rte .irq2 move #$2700,sr move.w #$8,$dff09c move.w #$8,$dff09c rte .fi move.w #$2700,(sp) rte .irq3 ; move.l a0,-(sp) ; lea (.irq1,pc),a0 ; pc relative ; cmp.l a0,(2+4,sp) ; movea.l (sp)+,a0 ; beq.b .fi cmpi.l #.irq2,2(sp) ; or not.. beq.b .fi cmpi.l #.irq1,2(sp) beq.b .fi .dp move.w #$10,$dff09c move.w #$10,$dff09c move #$2000,sr rte .copper dc.w $8021,$fffe dc.w $009c,$8004 dc.w $009c,$8008 dc.w $009c,$8010 dc.w $ffff,$fffe It is also on a real machine? (yes this is an EXTREME situation and probability is near zero.. ) |
15 May 2019, 16:05 | #12 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
|
Why wouldn't it work like that if rule is (and CPU isn't 68060) "when interrupt's first instruction is about to start, CPU can immediately start new interrupt processing if IPL is higher than SR interrupt mask? And why limit of 2?
Trigger interrupt level 1, then level 2. Wait (using copper) until second interrupt's stack processsing starts, then trigger level 3 and so on. In theory you should be able to stack all 6 levels |
15 May 2019, 16:48 | #13 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Quote:
Code:
.copper dc.w $8021,$fffe dc.w $009c,$8004 dc.w $009c,$8008 dc.w $01fe,0 dc.w $01fe,0 dc.w $01fe,0 dc.w $01fe,0 dc.w $01fe,0 dc.w $01fe,0 dc.w $01fe,0 dc.w $009c,$8010 dc.w $ffff,$fffe Code:
.irq2 .irq1 .user0007FFEE 2210 0001 7A72 2110 0001 7A5C 0010 0001 7876 But I don't understand why first two IRQs in copper list can be consecutive and the third delayed.. In this situation: Code:
.copper dc.w $8021,$fffe dc.w $009c,$8004 dc.w $009c,$8008 dc.w $009c,$8010 dc.w $ffff,$fffe In practice .irq3 is executed, in the stack there is only .irq1 (which I find and execute) then it continues with .irq3, I lower the level and only at that point system stack .irq2 context and execute it, then it ends also .irq3. Actually this is not a problem at all, everything is really fast and executed as I want, but the different behaviour it is not clear to me. Probably because I did not understand enough of what you wrote to me, be patient |
|
15 May 2019, 17:02 | #14 | |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
|
Quote:
- First interrupt starts interrupt processing (level 1). - During level 1 interrupt startup IPL gets increased to level 3 (only important bit is that level is higher than 1) - When CPU is about to start execution of level 1 handler's first instruction, it notices IPL is higher than SR interrupt mask. - interrupt processing starts again, this time level 3. No code from level 1 handler was executed (not yet but after RTE). In other words, if Paula interrupt level (=CPU IPL pin) becomes higher during previous lower level interrupt startup processing, new interrupt processing starts without executing any instructions (unless 68060 which always executes one instruction). Matching this sequence to debugger output can get confusing because interrupt processing is not visible in debugger. Perhaps it should be stored too.. |
|
15 May 2019, 17:31 | #15 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
|
Quote:
I didn't realize that there is practically a 'sampling' (near the handler's first instruction), so all inbetween can be 'skipped'. Thanks! PS: but I have a strange behavior from my code so I have to investigate, sure a bug of mine... EDIT: Yes, the bug is that I've touched the keyboard and obviously I caught an IRQ storm Ok, so the code is right. Last edited by ross; 15 May 2019 at 17:55. |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Want to use multiple drives in amiga 1200 | Mstone | support.Hardware | 22 | 18 October 2018 05:33 |
Amiga joystick on pc for xyz time, but this time with adapter? :) | Srksi | support.WinUAE | 3 | 24 May 2018 03:57 |
Having a hard time mapping multiple Xbox One gamepads in WinUAE | ReL0aDed | support.WinUAE | 4 | 26 July 2016 17:26 |
App to update Amiga System time from web time?? | DDNI | request.Apps | 2 | 31 December 2007 07:21 |
IRQs | Big-Byte | support.Hardware | 5 | 01 June 2002 20:42 |
|
|