https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104701

            Bug ID: 104701
           Summary: MIPS: Nested interrupts won't work with 2 or more
                    shadow register sets
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: reimu at sudomaker dot com
  Target Milestone: ---

GCC version: 12.0
System type: MIPS32 M5150, little endian
Hardware: Microchip PIC32MZ


The PIC32MZ device has EIC and 7 shadow register sets. If 2 different
interrupts with different assigned shadow register sets are coming nested
(second over first), the normal non-interrupt code will end up using first
interrupt's shadow set when all of them are finished.

Example code:

// ISR #1: Timer1
void __attribute__ ((interrupt, use_shadow_register_set,
__section__(".vectors"))) ISR_Timer1() {
        // do something

        IFS0CLR = _IFS0_T1IF_MASK;
}

// ISR #2: External 0
void __attribute__ ((interrupt, use_shadow_register_set,
__section__(".vectors"))) ISR_EXT0() {
        // do something

        IFS0CLR = _IFS0_INT0IF_MASK;
}

void setup_interrupts() {
        uint32_t val;

        // Set the CP0 cause IV bit high
        asm volatile("mfc0   %0,$13" : "=r"(val));
        val |= 0x00800000;
        asm volatile("mtc0   %0,$13" : "+r"(val));

        // Enable multi-vectored mode
        INTCONSET = _INTCON_MVEC_MASK;

        // Assign a different SR set for each priority
        PRISS = 0x76543210;

        asm("ei");

        // Enable Timer1 interrupt with priority 3
        IPC1bits.T1IP = 3;
        IPC1bits.T1IS = 0;

        IFS0CLR = _IFS0_T1IF_MASK;
        IEC0SET = _IEC0_T1IE_MASK;

        // Enable Timer1 interrupt with priority 4
        IPC0bits.INT0IP = 4;
        IPC0bits.INT0IS = 0;

        IFS0CLR = _IFS0_INT0IF_MASK;
        IEC0SET = _IEC0_INT0IE_MASK;
}


int main() {
        // some bootstrap code...

        setup_interrupts();

        while (1) {
                // doing some work, CP0.SRSCtl.CSS is 0, CP0.SRSCtl.PSS is 0
                // Timer1 interrupt comes, CP0.SRSCtl.CSS is 3, CP0.SRSCtl.PSS
is 0
                // External0 interrupt comes, CP0.SRSCtl.CSS is 4,
CP0.SRSCtl.PSS is 3
                // External0 interrupt ends, CP0.SRSCtl.CSS is 3,
CP0.SRSCtl.PSS is 3
                // Timer1 interrupt ends, CP0.SRSCtl.CSS is 3, CP0.SRSCtl.PSS
is 3
                // The program is screwed, since CP0.SRSCtl.CSS is NO LONGER 0
        }
}

Reply via email to