Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
19 years ago

interupt disabled in ISR

In the Nios II Software developer's handbook:

"the HAL system library disables interupts when it dispatches an ISR".

I've examine the file alt_irq_entry.S and alt_irq_handler.c but no presence of interupts disabling.

Could anybody tell me where are disabled interupts?

thank u in advance.

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    When an exception is generated, the processor performs the following

    steps automatically:

    ■ Copies the contents of the status register (ctl0) to the estatus

    register (ctl1), saving the pre-exception status of the processor

    ■ Clears the PIE bit of the status register, disabling further hardware

    interrupts

    ■ Stores the address of the instruction after the exception to the ea

    register (r29), providing the return address for the exception

    handler to return to

    ■ Vectors to the exception address
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    thank u for the answer David_Cai.

    This is the code of alt_irq_entry.S:

    /*

    * This is the interrupt exception entry point code, which saves all the

    * registers and calls the interrupt handler. It should be pulled in using

    * a .globl from alt_irq_register.c. This scheme is used so that if an

    * interrupt is never registered, then this code will not appear in the

    * generated executable, thereby improving code footprint.

    */

    /*

    * Explicitly allow the use of r1 (the assembler temporary register)

    * within this code. This register is normally reserved for the use of

    * the compiler.

    */

    .set noat

    /*

    * Pull in the exception handler register save code.

    */

    .globl alt_exception

    .globl alt_irq_entry

    .section .exceptions.entry.label, "xa"

    alt_irq_entry:

    /*

    * Section .exceptions.entry is in alt_exception_entry.S

    * This saves all the caller saved registers and reads estatus into r5

    */

    .section .exceptions.irqtest, "xa"

    # ifdef ALT_CI_EXCEPTION_VECTOR_N

    /*

    * Use the exception vector custom instruction if present to accelerate

    * this code.

    * If the exception vector custom instruction returns a negative

    * value, there are no interrupts active (estatus.pie is 0

    * or ipending is 0) so assume it is a software exception.

    */

    custom ALT_CI_EXCEPTION_VECTOR_N, et, r0, r0

    blt et, r0, .Lnot_irq# else

    /*

    * Test to see if the exception was a software exception or caused

    * by an external interrupt, and vector accordingly.

    */

    rdctl r4, ipending

    andi r2, r5, 1

    beq r2, zero, .Lnot_irq

    beq r4, zero, .Lnot_irq# endif /* ALT_CI_EXCEPTION_VECTOR_N */

    .section .exceptions.irqhandler, "xa"

    /*

    * Now that all necessary registers have been preserved, call

    * alt_irq_handler() to process the interrupts.

    */

    call alt_irq_handler

    .section .exceptions.irqreturn, "xa"

    br .Lexception_exit

    .section .exceptions.notirq.label, "xa"

    .Lnot_irq:

    /*

    * Section .exceptions.exit is in alt_exception_entry.S

    * This restores all the caller saved registers

    */

    .section .exceptions.exit.label

    .Lexception_exit:

    Which are the instruction that save registers and clears PIE bit?

    Probably I miss something.

    Thank u
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    originally posted by soin@Sep 13 2006, 02:21 AM

    which are the instruction that save registers and clears pie bit?

    probably i miss something.

    thank u

    <div align='right'><{post_snapback}> (index.php?act=findpost&pid=18247)

    --- quote end ---

    --- Quote End ---

    As David Cai wrote this is automatically done by the processor, not the software. If you want nested interrupts you have to explicitly re-enable interrupts in your ISR.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    and just to be crystal clear, presumably all that needs to be done is something like the following:

    #include <io.h># include <system.h># include "sys/alt_irq.h"
    // ----------------------------------------------------------------------------
    alt_irq_context IRQ_ALLOW_ESSENTIAL_START (alt_u32 id,  alt_u32* pActive)
    {
      alt_irq_context Ctrl0;
      alt_u32 irq_mask;
      
    //mask out own IRQ and all others having lower priority level
        irq_mask = ~(0x0FFFFFFFF << id);
    // alternatively, mask out self and IRQs 32-29, 28-26
        irq_mask = (~(1 << id)) & 0x01FFFFFFF;
        *pActive = alt_irq_active;
        alt_irq_active &= irq_mask;
        NIOS2_WRITE_IENABLE (alt_irq_active);
    /*  alternatively......
      alt_irq_disable (id);                    //Prevent re-entry
      alt_irq_disable (<a lower priority interrupt that can wait>);
      alt_irq_disable (<another lower priority interrupt that can wait>);
      alt_irq_disable (<yet another lower priority interrupt that can wait>);
    */
        NIOS2_READ_STATUS (Ctrl0);
        Ctrl0 |= NIOS2_STATUS_PIE_MSK;
        NIOS2_WRITE_STATUS (Ctrl0);
        return (Ctrl0);
    }
    // ----------------------------------------------------------------------------
    void IRQ_ALLOW_ESSENTIAL_FINISH (alt_irq_context Ctrl0,  alt_u32 id,  alt_u32 Active)
    {
        Ctrl0 &= ~NIOS2_STATUS_PIE_MSK;
        NIOS2_WRITE_STATUS (Ctrl0);
    /*
      alt_irq_enable (<yet another lower priority interrupt that can wait>);
      alt_irq_enable (<another lower priority interrupt that can wait>);
      alt_irq_enable (<a lower priority interrupt that can wait>);
      alt_irq_enable (id);
    */
        alt_irq_active = Active;
        NIOS2_WRITE_IENABLE (Active);
    }
    // ----------------------------------------------------------------------------
    static void MyInterruptibleISR (void* context, alt_u32 id)
    {
      alt_irq_context Ctrl0;
      alt_u32 Active;
    <time-critical section, e.g. reading registers>
      Ctrl0 = IRQ_ALLOW_ESSENTIAL_START (id, &Active);
    <non-time-critical section, e.g. stuffing in buffers>
      IRQ_ALLOW_ESSENTIAL_FINISH (Ctrl0, id, Active);
    }
    // ----------------------------------------------------------------------------