English Amiga Board


Go Back   English Amiga Board > Coders > Coders. General

 
 
Thread Tools
Old 24 September 2019, 18:39   #1
deimos
Registered User

 
Join Date: Jul 2018
Location: Londonish / UK
Posts: 440
Interrupts, doing it low level, but properly.

I'm trying to set up some interrupt handlers, starting with some borrowed code. What I have works, but is limited to Vertical Blank interrupts only. How do I detect and process different kinds of (same level) interrupts, namely Blitter Finished?

So far, I have an interrupt handler:

Code:
static __attribute__((interrupt)) void InterruptHandler(void) {
	custom->intreq = (1 << INTB_VERTB); custom->intreq = (1 << INTB_VERTB); // reset vbl req. twice for A4000 bug

    display->updateDisplay(display);
}
Which I've set using the following:

Code:
void SetInterruptHandler(APTR interrupt) {
    * (volatile APTR *) (((UBYTE *) VBR) + 0x6c) = interrupt;
}
I've then enabled only vertical blank interrupts:

Code:
	custom->intena = (1 << INTB_SETCLR) | (1 << INTB_INTEN) | (1 << INTB_VERTB);
	custom->intreq = 1 << INTB_VERTB; // reset vbl req
While I get what each individual bit of code does, I don't fully get how they work as a whole. For instance, what's that last line, custom->intreq = 1 << INTB_VERTB, about?

And is this code "complete" enough, or is there more that I need to do inside the interrupt handler, for instance?
deimos is offline  
Old 24 September 2019, 19:16   #2
Photon
Moderator

Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 4,772
As a rough minimum,
  1. Wait for the Blitter to finish
  2. Wait for the end of the current frame
  3. Save the old INTENAR and INTREQR, then immediately disable all interrupts that should not be running, at the very least the ones you want to take over, and Copper DMA in DMACON, unless you want to show the OS screen
  4. Save the old int vector and set a new one
  5. Set any new Copper pointer, enable the DMA you want to use, and enable the ints you use

This should be done after the Blitter has finished, and at the end of frame because otherwise, running DMA could potentially thrash memory.

On exit, you do the same thing, but restoring instead of saving.

To turn on only the interrupts you use, you must first clear the other bits. This is done the same way that you clear the INTREQ bit in your interrupt.

Last edited by Photon; 24 September 2019 at 19:24.
Photon is offline  
Old 24 September 2019, 20:23   #3
deimos
Registered User

 
Join Date: Jul 2018
Location: Londonish / UK
Posts: 440
Quote:
Originally Posted by Photon View Post
you clear the INTREQ bit in your interrupt
This. I can see the code, but what does it really mean?
deimos is offline  
Old 24 September 2019, 21:41   #4
Photon
Moderator

Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 4,772
It clears the interrupt request bit for that level (by setting the SET/CLR bit to 0 = CLR, and setting the bit for VBLANK to 1). (It does this twice to be compatible with Amiga 4000, which has a hardware bug.)

The hardware sets this bit when it triggers an interrupt call. You can also read this (from INTREQR) to find out which of the interrupts on the same level as VBLANK that was triggered. They all use this vector. But if only the VBLANK interrupt is enabled, you don't have to check it.
Photon is offline  
Old 24 September 2019, 22:00   #5
deimos
Registered User

 
Join Date: Jul 2018
Location: Londonish / UK
Posts: 440
Quote:
Originally Posted by Photon View Post
You can also read this (from INTREQR) to find out which of the interrupts on the same level as VBLANK that was triggered. They all use this vector.
Ok, so I'll need to do this. Googling INTREQR tells me

Quote:
This register contains interrupt request bits (or flags). These bits may be polled by the processor; if enabled by the bits listed in the above register, they may cause processor interrupts. Both a set and clear operation are required to load arbitrary data into this register. These status bits are not automatically reset when the interrupt is serviced, and must be reset when desired by writing to this address.
Which fills in a gap or two. In my case I'll need to check whether bit 5 (VERTB) or 6 (BLIT) is set (or both?). I don't see a need to enable 4 / COPER.

And I need to clear whichever bit is set. I guess I do that straight away so I can exit from my handler whenever I want.

Anything else I'm missing?

Last edited by deimos; 25 September 2019 at 09:23.
deimos is offline  
Old 25 September 2019, 15:06   #6
Photon
Moderator

Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 4,772
You should only check for the bit that corresponds to the interrupt you are handling, and at the very end of that handling you poll (clear) only that bit.

If several interrupt levels use the same vector call address, you must put a check (if statement) for each level that you have enabled.

If a level is enabled that you have no code to handle, you can normally not pass it on to the OS interrupt handler. So under some circumstances, if you use a vector that has more than one level, you must disable the interrupts on that level that you don't handle, or the user must be OK with some interrupts not being handled.

Last edited by Photon; 25 September 2019 at 15:14.
Photon is offline  
Old 25 September 2019, 15:19   #7
deimos
Registered User

 
Join Date: Jul 2018
Location: Londonish / UK
Posts: 440
So:

Code:
    UWORD intreqr = custom->intreqr;

    if (intreqr & INTF_COPER) {
        processCopperInterrupt();
        custom->intreq = (UWORD) INTF_COPER; custom->intreq = (UWORD) INTF_COPER;
    } else if (intreqr & INTF_VERTB) {
        processVerticalBlankInterrupt();
        custom->intreq = (UWORD) INTF_VERTB; custom->intreq = (UWORD) INTF_VERTB;
    } else if (intreqr & INTF_BLIT) {
        processBlitterInterrupt();
        custom->intreq = (UWORD) INTF_BLIT; custom->intreq = (UWORD) INTF_BLIT;
    }
rather than:

Code:
    UWORD intreqr = custom->intreqr;

    if (intreqr & INTF_COPER) {
        processCopperInterrupt();
        custom->intreq = (UWORD) INTF_COPER; custom->intreq = (UWORD) INTF_COPER;
    }
    
    if (intreqr & INTF_VERTB) {
        processVerticalBlankInterrupt();
        custom->intreq = (UWORD) INTF_VERTB; custom->intreq = (UWORD) INTF_VERTB;
    }
    
    if (intreqr & INTF_BLIT) {
        processBlitterInterrupt();
        custom->intreq = (UWORD) INTF_BLIT; custom->intreq = (UWORD) INTF_BLIT;
    }
?
deimos is offline  
Old 25 September 2019, 20:45   #8
phx
Natteravn

phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 1,479
The last one is correct.
I wouldn't exclude the possibility that multiple interrupt sources may trigger at the same time.
phx 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
Low-level workings of Paula absence Coders. General 75 11 November 2013 18:53
USB Flash Disk Low-Level Format prowler support.Hardware 53 03 August 2012 22:39
Low level format utility for the A1200 Fabie support.Hardware 20 11 January 2010 20:13
When to low level format Galaxy support.Hardware 6 30 January 2007 13:39
Low Level Format??? Djay support.Hardware 4 01 March 2003 21:58

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 01:26.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.
Page generated in 0.08472 seconds with 16 queries