English Amiga Board


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

 
 
Thread Tools
Old 10 April 2022, 05:41   #1
Jobbo
Registered User
 
Jobbo's Avatar
 
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
Jobbo is offline  
Old 10 April 2022, 08:45   #2
bloodline
Registered User
 
bloodline's Avatar
 
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)
bloodline is offline  
Old 10 April 2022, 08:50   #3
Toni Wilen
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.
Toni Wilen is online now  
Old 10 April 2022, 14:27   #4
Jobbo
Registered User
 
Jobbo's Avatar
 
Join Date: Jun 2020
Location: Druidia
Posts: 389
Quote:
Originally Posted by bloodline View Post
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)

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!
Jobbo is offline  
Old 10 April 2022, 14:36   #5
Jobbo
Registered User
 
Jobbo's Avatar
 
Join Date: Jun 2020
Location: Druidia
Posts: 389
Quote:
Originally Posted by Toni Wilen View Post
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.
Thank you!

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.
Jobbo is offline  
Old 10 April 2022, 14:43   #6
bloodline
Registered User
 
bloodline's Avatar
 
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
bloodline is offline  
Old 10 April 2022, 16:15   #7
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
Quote:
Originally Posted by Jobbo View Post
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.
Hi Jobbo, it doesn't.
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).
ross is offline  
Old 10 April 2022, 16:20   #8
Jobbo
Registered User
 
Jobbo's Avatar
 
Join Date: Jun 2020
Location: Druidia
Posts: 389
Quote:
Originally Posted by ross View Post
Hi Jobbo, it doesn't.
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).
But they both do things in the opposite order which seems to be where you have a problem.

Here is the code from LSP:
Code:
move.w    #$2000,$dff09c
btst.b    #0,$bfdd00
beq.s    .skipa
Jobbo is offline  
Old 10 April 2022, 16:26   #9
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
Quote:
Originally Posted by Jobbo View Post
But they both do things in the opposite order which seems to be where you have a problem.

Here is the code from LSP:
Code:
move.w    #$2000,$dff09c
btst.b    #0,$bfdd00
beq.s    .skipa
I hadn't checked LSP, in fact this is wrong (or better, slower)

EDIT: re-checked ptplayer, it seems in the right order

Last edited by ross; 10 April 2022 at 16:33.
ross is offline  
Old 10 April 2022, 16:52   #10
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,427
Quote:
Originally Posted by ross View Post
EDIT: re-checked ptplayer, it seems in the right order
Might be time for me to download a newer version then as the version I've been using definitely clears INTREQ before the CIA.
roondar is offline  
Old 10 April 2022, 17:25   #11
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,517
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.
phx is offline  
Old 10 April 2022, 17:48   #12
ross
Defendit numerus
 
ross's Avatar
 
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
But this usually works properly (every other CIA IRQ6 that doesn't matter is cleaned up and so for PAULA):
Code:
 btst #0,ICR(ciab)
 beq.b .x
...

.x
 move.w #$2000,INTREQ
 rte

Last edited by ross; 10 April 2022 at 18:18.
ross is offline  
Old 10 April 2022, 19:07   #13
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,517
Quote:
Originally Posted by ross View Post
Paula manages the physical CPU' IPL lines, RTE the internal SR' IP mask bits.
It keeps lines active until INTREQ is cleared.
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.
phx is offline  
Old 10 April 2022, 19:11   #14
Jobbo
Registered User
 
Jobbo's Avatar
 
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?
Jobbo is offline  
Old 10 April 2022, 19:46   #15
Jobbo
Registered User
 
Jobbo's Avatar
 
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.
Jobbo is offline  
Old 10 April 2022, 20:01   #16
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
Quote:
Originally Posted by Jobbo View Post
Another issue I'd like to clean up is that my sample will receive an unexpected Alarm interrupt.
Can't you just ignore it?

Quote:
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?
You can read the ICR mask with cia.resource AbleICR()

Quote:
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?
FLAG is for floppy INDEX signal.
ross is offline  
Old 11 April 2022, 04:11   #17
Jobbo
Registered User
 
Jobbo's Avatar
 
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;
And I also thought I could set the Alarm count with this code:

Code:
// Set alarm count to zero.
ciab.ciacrb = CIACRBF_ALARM;
ciab.ciatodhi = 0;
ciab.ciatodmid = 0;
ciab.ciatodlow = 0;
I can also pause the counter with something like:

Code:
// Pause TOD count.
//ciab.ciatodhi = 0;
Leaving out the pause code, it seems that my code isn't actually working to set the alarm count as I'd expect because I will still see an Alarm interrupt at a time that isn't zero?

I must be missing something?
Jobbo is offline  
Old 11 April 2022, 04:31   #18
Jobbo
Registered User
 
Jobbo's Avatar
 
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?
Jobbo is offline  
Old 11 April 2022, 05:16   #19
Jobbo
Registered User
 
Jobbo's Avatar
 
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.
Jobbo is offline  
Old 11 April 2022, 08:55   #20
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 54
Posts: 4,481
Quote:
Originally Posted by Jobbo View Post
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?
Yep, TOD counter is buggy.

When TODMID change from 0x0F to 0x10 it transits temporarily to 0x00.
This of course has unpleasant side effects on ALARM
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
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

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 12:36.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.09788 seconds with 14 queries