10 April 2022, 05:41 | #1 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
CIAB A-timer interrupt confusion?
Hi there
I'm learning how to use the CIA timers for the first time. With help from Roondar over on Discord I've figured out some of what was confusing me. However, I'm still very confused about why I seem to be getting two level 6 interrupt calls instead of just one for my trivial timer. My example is a simple program that installs a level 6 handler to change the background color for a moment. I've then tried to setup a ciab a-timer that will trigger an interrupt a certain time after a wait vbl. The main loop will wait for the vbl and then start the timer. My handler will check if the interrupt came from the a-timer and change the background color to red and then back to black. Otherwise it'll change the color to green and then back to black. What I expected to see was one red short line on screen. Instead I see a red line followed by a green line. I can see in the debugger that the interrupt handler is getting called twice each frame. I can also see that for the second call the pending ciairc interrupt value was zero, which seems like it should be impossible given that I'm getting an int6 interrupt call. I've put my code together in a minimal project and put it up on github. It's in C, sorry assembler only people! The Amiga exe is in the repo if anyone just wants to run the example. If anyone has time and can explain what is going on I'd really appreciate it! Thanks |
10 April 2022, 08:45 | #2 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
I think you should try checking for each specific ICR bit and identify what is generating an INT, at the moment all you know is that the second INT isn’t TA, but it could be TB, TOD, the serial port (which on CIAA is the keyboard), or the disk drive sync (which I think flags on the CIAA ICR)
|
10 April 2022, 08:50 | #3 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,540
|
Read ICR first to clear CIA interrupt, then write to INTREQ to clear Paula interrupt. Writing to INTREQ first does nothing because CIA interrupt is still active.
|
10 April 2022, 14:27 | #4 | |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
Quote:
I did check and for the unexpected interrupt call the ICR returned zero which was confusing. However Toni's explanation is perfect and now I get it! |
|
10 April 2022, 14:36 | #5 | |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
Quote:
When clearing INTREQ the system must immediately re-trigger the EXTER interrupt because the ICR has not been cleared, which explains why I get a second interrupt call. This makes perfect sense now. Interestingly enough the same mistake seems to have been made in all the example code I looked at including PtPlayer and LightSpeedPlayer. If I'm not mistaken then in all those examples the problem is masked because the code checks the A-timer bit and skips through to the end if it's zero. But they are still going to be paying a penalty for the second interrupt. |
|
10 April 2022, 14:43 | #6 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
Your question has actually highlighted incorrect behaviour with my CIA emulation!
When a CIA event occurs which sets a bit in the ICR, an INTREQ flag is set for the correct level…. And an interrupt happens… If the INTREQ flag for the CIA is cleared, but the ICR isn’t clear, no further interrupts will be generated. I’m going to modify my code so that my CIA will keep trying to raise an interrupt until the ICR is clear, as this is more correct behaviour |
10 April 2022, 16:15 | #7 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
|
Quote:
CIAs work differently for acknowledging IRQs, it's just the ICR reading that cleans them up, unlike PAULA which needs explicit writing. This is why if you are interested in more than one CIA IRQ source you have to check all the (buffered) bits sequentially and not wait for the next trigger: otherwise you lose it! So PtPlayer or LightSpeedPlayer don't suffer any penalty: they read ICR (so they clean up the CIA concerned) and then they clean INTREQ (so there is no PAULA retrigger). |
|
10 April 2022, 16:20 | #8 | |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
Quote:
Here is the code from LSP: Code:
move.w #$2000,$dff09c btst.b #0,$bfdd00 beq.s .skipa |
|
10 April 2022, 16:26 | #9 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
|
Quote:
EDIT: re-checked ptplayer, it seems in the right order Last edited by ross; 10 April 2022 at 16:33. |
|
10 April 2022, 16:52 | #10 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,427
|
|
10 April 2022, 17:25 | #11 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,519
|
Now I'm confused. I would say that the order of writing to INTREQ and reading the CIA-ICR is not important, as long as both happens in your interrupt handler routine, with the current IPL still masked in SR.
On lowering the IPL with RTE, Paula and CIA interrupts are both acknowledged and I see no reason why it should retrigger. |
10 April 2022, 17:48 | #12 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
|
Nope.
Paula manages the physical CPU' IPL lines, RTE the internal SR' IP mask bits. It keeps lines active until INTREQ is cleared. But the CIA lines are external lines (IRQ 2 and 6) and therefore must be acknowledged externally, else the relative INTREQ write does nothing (is immediately retriggered by the as yet uncleaned external condition of the CIA). So the right order is always: read ICR (and enslave all interrupts pending), write INTREQ and then RTE (return the mask of the IRQs to be used in the previous condition). EDIT: just to leave no doubts: a btst is a full byte read, so a ICR acknowledge So this is bad (second bit test lose a possible IRQ): Code:
btst #0,ICR(ciax) bne.b .a btst #1,ICR(ciax) bne.b .b Code:
btst #0,ICR(ciab) beq.b .x ... .x move.w #$2000,INTREQ rte Last edited by ross; 10 April 2022 at 18:18. |
10 April 2022, 19:07 | #13 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,519
|
Ahh, now I got it. The key is that I thought the CPU drives the IPL lines. So the still active INT-line from the CIA will immediately reset the interrupt bit in Paula to 1, no matter how often I clear it in INTREQ. Make sense.
|
10 April 2022, 19:11 | #14 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
Another issue I'd like to clean up is that my sample will receive an unexpected Alarm interrupt.
This must be because I'm not turning off the Alarm in my setup code. But I can't figure out how to correctly do that? Also, my setup code might be doing things incorrectly for the timers or it might be doing unnecessary work, so if anyone can have a look at that I'd be grateful. It doesn't seem to be common for people to manage the CIA stuff in their setup. I also see there is a Flag interrupt in the list of possible ICR bits, but I can't seem to find in the HRM what that is for and where it would come from? |
10 April 2022, 19:46 | #15 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
I found the info for Flag. It’s todo with the handshake stuff and not really something I need to think about.
|
10 April 2022, 20:01 | #16 | |||
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
|
Quote:
Quote:
Quote:
|
|||
11 April 2022, 04:11 | #17 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
I could just ignore the alarm flag but I'd like to know how to use the alarm timer for interrupts in which case I'd like to set it up in a clean known state. As it stands I'm confused about using the alarm timer.
It seems pretty straightforward to change the TOD count ahead of time with this code: Code:
// Set TOD count to zero. ciab.ciacrb = 0; ciab.ciatodhi = 0; ciab.ciatodmid = 0; ciab.ciatodlow = 0; Code:
// Set alarm count to zero. ciab.ciacrb = CIACRBF_ALARM; ciab.ciatodhi = 0; ciab.ciatodmid = 0; ciab.ciatodlow = 0; Code:
// Pause TOD count. //ciab.ciatodhi = 0; I must be missing something? |
11 April 2022, 04:31 | #18 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
I seem to be running into a bug. When I set the Alarm to 0x000000 then I get an interrupt at TOD == 0x001000. I see Toni mentioning it in some other thread. Seems weird, am I mistaken?
|
11 April 2022, 05:16 | #19 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 389
|
I’d say I have it all worked out now. But that bug really tripped me up.
|
11 April 2022, 08:55 | #20 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
|
Quote:
When TODMID change from 0x0F to 0x10 it transits temporarily to 0x00. This of course has unpleasant side effects on ALARM |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Blitter interrupt during VERTB interrupt | phx | Coders. Asm / Hardware | 38 | 01 October 2021 19:54 |
timer interrupt to emulate 60Hz | jotd | Coders. Asm / Hardware | 3 | 14 August 2021 21:25 |
Timer instantly causes interrupt | TCH | Coders. Asm / Hardware | 8 | 20 July 2021 15:48 |
example of a CIA timer interrupt in assembler using cia.resource | Apollo | Coders. Asm / Hardware | 3 | 05 July 2013 08:40 |
CIA timer interrupt handler called twice during mod playback | absence | Coders. General | 5 | 16 March 2009 18:55 |
|
|