English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 14 May 2019, 13:58   #1
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
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,SR
and any other lower level IRQ is executed immediately.
The same if Level1 is executed slightly before, just put
MOVE #$2700,SR
and 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).
ross is offline  
Old 14 May 2019, 14:20   #2
roondar
Registered User

 
Join Date: Jul 2015
Location: The Netherlands
Posts: 1,477
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:
Or much more simply, at least one instruction of the IRQ1 (the MOVE #$2700,SR) is executed and no problem arise?
is correct.

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 14:30.
roondar is offline  
Old 14 May 2019, 14:40   #3
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
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!
ross is offline  
Old 14 May 2019, 14:59   #4
roondar
Registered User

 
Join Date: Jul 2015
Location: The Netherlands
Posts: 1,477
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.
roondar is offline  
Old 14 May 2019, 16:04   #5
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
Quote:
Originally Posted by roondar View Post
My primary question here would be what happens if the trigger of an interrupt happens 'during' or just ahead of the move #$2700,SR.
Yes, this is the main question: if an higher IRQ can happens immediately, even before the first instruction in a lower priority ISR, BUT after the CPU interrupt acknowledge cycle (so with a already defined return point from IRQ3 to IRQ1).

Quote:
Will the 68k then ignore the interrupt based on the now changed SR status or not?

I'm not sure.
There is no doubt here: 68k immediately ignore the request from Paula until the RTE.
ross is offline  
Old 14 May 2019, 17:44   #6
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
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
Sequence of instructions executed on line 80 (always repeatable thanks to the synchronization made with the copper):
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
So there is a IRQ1 re-trigger.
A comment by Toni is welcome
ross is offline  
Old 14 May 2019, 20:12   #7
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 44
Posts: 23,503
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:
So there is a IRQ1 re-trigger.
There is no re-trigger. Check the stack contents when first interrupt starts
Toni Wilen is online now  
Old 14 May 2019, 21:35   #8
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
Quote:
Originally Posted by Toni Wilen View Post
There is no re-trigger. Check the stack contents when first interrupt starts
Yes, stack checked, and there is the condition (inconvenient) that which I hypothesized in the first message..

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.
ross is offline  
Old 14 May 2019, 21:52   #9
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 44
Posts: 23,503
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.
Toni Wilen is online now  
Old 14 May 2019, 22:32   #10
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
Quote:
Originally Posted by Toni Wilen View Post
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.
Thanks Toni!

ross is offline  
Old 15 May 2019, 15:50   #11
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
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
@Toni: this routine works anyway, but I've noticed that WinUAE stack the previous context for only a double simultaneous IRQ.
It is also on a real machine? (yes this is an EXTREME situation and probability is near zero.. )
ross is offline  
Old 15 May 2019, 17:05   #12
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 44
Posts: 23,503
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
Toni Wilen is online now  
Old 15 May 2019, 17:48   #13
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
Quote:
Originally Posted by Toni Wilen View Post
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
Yah!
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
Stack from .irq3 perspective:
Code:
               .irq2            .irq1          .user
0007FFEE 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
IRQ2 trigger (and context on stack) only when I lower IPL (the move #$2000 during IRQ3).. before there is no trace on stack.

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
ross is offline  
Old 15 May 2019, 18:02   #14
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 44
Posts: 23,503
Quote:
Originally Posted by ross View Post
But I don't understand why first two IRQs in copper list can be consecutive and the third delayed..
It should be quite obvious. Sequence is:

- 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..
Toni Wilen is online now  
Old 15 May 2019, 18:31   #15
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,348
Quote:
Originally Posted by Toni Wilen View Post
It should be quite obvious. Sequence is:

- 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..
OK, this time I got it (and yes, now is obvious)

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 18:55.
ross is offline  
 


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 06:33
Amiga joystick on pc for xyz time, but this time with adapter? :) Srksi support.WinUAE 3 24 May 2018 04:57
Having a hard time mapping multiple Xbox One gamepads in WinUAE ReL0aDed support.WinUAE 4 26 July 2016 18:26
App to update Amiga System time from web time?? DDNI request.Apps 2 31 December 2007 08:21
IRQs Big-Byte support.Hardware 5 01 June 2002 21:42

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 14:14.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.
Page generated in 0.14178 seconds with 13 queries