• AVR Freaks

Hot!XC32 free version limitations

Author
henkebenke
Starting Member
  • Total Posts : 49
  • Reward points : 0
  • Joined: 2008/09/27 23:55:51
  • Location: 0
  • Status: offline
2020/01/18 07:32:23 (permalink)
2 (1)

XC32 free version limitations

Hi, I have just begun migration of a project from dsPIC to XC32.
 
I noticed just that the compiler ignores when I define an ISR with the attribute ipl1SRS.  That is, using the shadow registers. It still performs a massive context saving that takes a lot of CPU.
 
I suspect this is a limitation in the free XC32. Is that right? If so, it is bad news, really. The point with a PIC32 is speed.
 
After I wrote this post, I checked again and found that the SRS option actually works. But there is a lot of other context saving, more than backing up registers.  What is the purpose of that? I think there are at least some 20 lines of code, in addition to the saving of the registers.
Perhaps someone can give me some advise on how to minimize the ISR lag?
 
Here is what it looks like:
37: void __ISR(_TIMER_3_VECTOR, ipl1SOFT) TIMER_3_Handler (void)
38: {
9D002BE8 415DE800 RDPGPR SP, SP
9D002BEC 401A7000 MFC0 K0, EPC
9D002BF0 401B6000 MFC0 K1, Status
9D002BF4 27BDFFE0 ADDIU SP, SP, -32
9D002BF8 AFBA001C SW K0, 28(SP)
9D002BFC 401A6002 MFC0 K0, SRSCtl
9D002C00 AFBB0018 SW K1, 24(SP)
9D002C04 AFBA0014 SW K0, 20(SP)
9D002C08 7C1B7844 INS K1, ZERO, 1, 15
9D002C0C 377B0400 ORI K1, K1, 1024
9D002C10 409B6000 MTC0 K1, Status
9D002C14 AFA4000C SW A0, 12(SP)
9D002C18 AFA30008 SW V1, 8(SP)
9D002C1C AFA20004 SW V0, 4(SP)
39: IFS0bits.T3IF = 1;
 
It's just the three last instructions that actually backs up registers. What does the rest of the code do?
 
Regards
post edited by henkebenke - 2020/01/18 08:11:03
#1

9 Replies Related Threads

    NKurzman
    A Guy on the Net
    • Total Posts : 18255
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: XC32 free version limitations 2020/01/18 08:07:51 (permalink)
    +1 (1)
    Which PIC32?
    #2
    andersm
    Super Member
    • Total Posts : 2740
    • Reward points : 0
    • Joined: 2012/10/07 14:57:44
    • Location: 0
    • Status: offline
    Re: XC32 free version limitations 2020/01/18 08:28:19 (permalink)
    +5 (5)
    It's a limitation of the MIPS architecture. Shadow registers bank only the general-purpose registers, but there's still some context that needs to be saved, and setup needed for nested interrupts. See eg. this post for an explanation of the ISR prologue/epilogue. If you have a time-critical interrupt, you can raise its priority to 7, in which case the compiler will omit code needed for nested interrupts.
     
    Also, never use bit fields to write to self-modifying registers.
    #3
    henkebenke
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2008/09/27 23:55:51
    • Location: 0
    • Status: offline
    Re: XC32 free version limitations 2020/01/20 15:22:21 (permalink)
    +1 (1)
    Andersm, I tried setting the priority to 7, and it didn't help. Still a lot of code.
     
    And the AUTO setting didn't help. I had to use ipl7SRS. But still some 15 lines of context saving, or whatever it is.
    #4
    simong123
    Lab Member No. 003
    • Total Posts : 1357
    • Reward points : 0
    • Joined: 2012/02/07 18:21:03
    • Location: Future Gadget Lab (UK Branch)
    • Status: offline
    Re: XC32 free version limitations 2020/01/20 16:06:36 (permalink)
    +2 (2)
    You still haven't said which PIC.
    The code generated for the prologue at SRS7 should be something like
        rdpgpr    $sp,$sp     ;read SP from previous register set
        mfc0    $27,$12       ;read Status register
        addiu    $sp,$sp,-16  ;create stack frame
        mfc0    $26,$12,2     ;read EPC register
        sw    $27,8($sp)      ;push Status to stack
        sw    $26,4($sp)      ;push EPC to stack
        ins    $27,$0,1,15    ;clear bits 1-15 in status copy
        ori    $27,$27,0x1c00 ;set bits 10-12 (interrupt mask = 7)
        mtc0    $27,$12       ;set Status to new value

    Which is pretty much the minimum required for an MM/MX. There are options available on MZ and MK's to reduce this, however they require the use of assembly as the ASE extensions used are not supported by the compiler.
    #5
    henkebenke
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2008/09/27 23:55:51
    • Location: 0
    • Status: offline
    Re: XC32 free version limitations 2020/01/22 13:49:17 (permalink)
    0
    OK, it's a MZ device, and my code looks like Simon listed.  Two things, first a detail - the SP is read from previous shadow set, but if so the actual SP will be discarded - strange.
     
    Then I thought about making an assembly ISR, where the IPL is set to 7.  Wouldn't this work:
     
      ADDIU SP, SP, -4
      SW  t0, 0(SP)
     
     Do something with t0
     
      LW t0, 0(SP)
      ADDIU SP, SP, 4
      ERET
     
      If this ISR has the highest priority, then there will be no need (?) for communicating with CP0, etc.
     
     I have calculated that the latency will "eat up" around 5% of available CPU-power in the project I'm dealing with. That's not too much, but slightly too much, so to speak.
      
    #6
    andersm
    Super Member
    • Total Posts : 2740
    • Reward points : 0
    • Joined: 2012/10/07 14:57:44
    • Location: 0
    • Status: offline
    Re: XC32 free version limitations 2020/01/22 14:28:56 (permalink)
    +1 (1)
    Unless you're using separate stacks for each register set, the current value of the stack pointer has to be read from the previous set. Devices that implement the MIPS MCU extension can be configured to perform this step automatically. Your assembly code would work, but t0 is one of the registers that doesn't need to be saved if shadow registers are used. Also, for full compatibility with the MIPS ABI, the stack pointer should be kept aligned to 8 bytes. Not really an issue for an uninterruptible handler written in assembly, but something to keep in mind.
    #7
    simong123
    Lab Member No. 003
    • Total Posts : 1357
    • Reward points : 0
    • Joined: 2012/02/07 18:21:03
    • Location: Future Gadget Lab (UK Branch)
    • Status: offline
    Re: XC32 free version limitations 2020/01/22 14:31:45 (permalink)
    +1 (1)
    henkebenke
    OK, it's a MZ device, and my code looks like Simon listed.  Two things, first a detail - the SP is read from previous shadow set, but if so the actual SP will be discarded - strange.
     

    There are only 2 'special' registers in the MIPS architecture, $0 (zero) and $31 (RA - return address). It is possible to use any other register as the stack, $29 as SP is only a convention. So to find out where tha actual SP is pointing you have to read it from where it was last in use. It is not maintained across shadow sets automatically.
     

    Then I thought about making an assembly ISR, where the IPL is set to 7.  Wouldn't this work:
     
      ADDIU SP, SP, -4   >>Where does SP get it's value???<<
      SW  t0, 0(SP)
     
     Do something with t0
     
      LW t0, 0(SP)
      ADDIU SP, SP, 4
      ERET
     
      If this ISR has the highest priority, then there will be no need (?) for communicating with CP0, etc.

    Interrupts are not the only exceptions. Whether you need to account for other exceptions depends on your application. You also need to read the current value of $SP as previously mentioned.
     
    As you are using an 'MZ and are willing to write your interrupt in assembler (or at least an entry stub), you can try enabling ASE extensions.
    typedef union
    {
        struct{
        unsigned :5;
        unsigned VS:5;
        unsigned :3;
        unsigned UseKStk:1;
        unsigned APE:1;
        unsigned ClrEXL:1;
        unsigned StkDec:5;
        unsigned ICE:1;
        unsigned PF:1;
        unsigned IPFDC:3;
        unsigned IPPCI:3;
        unsigned IPTI:3;
        };
        unsigned w;
    } INTCTL_T;

        // Configure ASE extensions
        INTCTL_T IntCtl;
        IntCtl.w=_mfc0(12,1);
        IntCtl.PF=1;            // Enable vector pre-fetch
        IntCtl.StkDec=0x4;        // 4 * 4byte words from stack
        IntCtl.ClrEXL=1;        // Clear EXL,ERL,KSU flags
        IntCtl.APE=1;            // Enable auto prologue
        IntCtl.UseKStk=0;        // Use single stack
        IntCtl.ICE=1;            // Interrupt chaining enabled
        _mtc0(12,1,IntCtl.w);

        //Enable multi-vectored interrupts
        INTCONbits.MVEC=1;

    These take care of keeping SP aligned across shadow sets, allocating a stack frame, and automatically push EPC and maintain Status, in parallel with fetching the interrupt vector etc. This can reduce the interrupt latency to ~10 clocks.
    Minimal interrupt code (clears IFS & toggles a pin):
        .section    .vector_4,code    # TIMER_1_VECTOR
        .align    4
        .globl    TMR1Int                # Match declaration in main.c
    .LFB2 = .
        .cfi_startproc
        .set    nomips16
        .set    nomicromips
        .ent    TMR1Int
        .type    TMR1Int, @function
    TMR1Int:
        .frame    $sp,0,$31        # vars= 0, regs= 0/0, args= 0, gp= 0
        .mask    0x00000000,0
        .fmask    0x00000000,0
        .set    noat

    # Clear IFS Flag
        li        $26,16                # 0x10
        lui        $27,%hi(IFS0CLR)
        sw        $26,%lo(IFS0CLR)($27)    # IFS0CLR=BIT(4)

    # Toggle Pin RF3
        li        $3,8                        # 0x08
        lui        $2,%hi(LATFINV)
        sw        $3,%lo(LATFINV)($2)            # LATFINV=BIT(3)

    #NOTE IRET not ERET
        iret            # Return from exception

        .set    at
        .end    TMR1Int
        .cfi_endproc

    Note: it is also possible to 'pre-load' registers in the shadow set (some simple inline assembly in your startup code) to reduce latency further (e.g. pre-load address of IFS0)
        // OPTIONAL
        // As kt0 and kt1 are not used when ASE extensions are enabled, we can use
        // them to store some values instead of calculating them every interrupt and
        // save a small amount of latency (2 instr)
        // In this case used to store the address and mask values of the interrupt flag IFS0.T1IF
        {
            register unsigned a0 asm ("a0");
            register unsigned a1 asm ("a1");

            asm volatile    (".set noreorder");
            //Set previous shadow set to 5 (Tmr1 Interrupt Priority/Shadow Set) to allow writing
            asm volatile    ("mfc0 %0,$12,2"        :"=r"(a0));
            asm volatile    ("ori %0,$0,5"            :"=r"(a1));
            asm volatile    ("ins %0,%1,6,4"        :"=r"(a0)    :"r"(a1));
            asm volatile    ("mtc0 %0,$12,2"        :            :"r"(a0));

            //pre-set reg's k0 and k1 in selected shadow set ($26 & $27)
            asm volatile    ("ori %0,$0,0x10"        :"=r"(a0));                // SRS#5 $26 kt0 = 0x10 (TMR1INT flag bit)
            asm volatile    ("WRPGPR $26,%0"        :            :"r"(a0));    //
            asm volatile    ("lui %0,%%hi(IFS0CLR)"    :"=r"(a0));                // SRS#5 $27 Kt1 = %hi(IFS0CLR)
            asm volatile    ("WRPGPR $27,%0"        :            :"r"(a0));    //
            asm volatile    (".set reorder");
        }

    #8
    Mysil
    Super Member
    • Total Posts : 3634
    • Reward points : 0
    • Joined: 2012/07/01 04:19:50
    • Location: Norway
    • Status: offline
    Re: XC32 free version limitations 2020/01/22 14:49:00 (permalink)
    +1 (1)
    Hi,
    When a ISR is entered, in interrupt Shadow set enabled,
    then Hardware have already performed the switch to the Alternate shadow set to be used in Interrupt processing.
    So the Correct Stack Pointer is the one in the Register set of the code that was running when interrupt happened.
    Either main program stack pointer, or stack pointer of the Interrupt code that was preempted.
    That is the significance of Previous shadow set index.
     
    The SP in the current shadow set is a stale value from previous execution of interrupt code,
    until SP is updated from previous shadow set.
     
    You may get away with simplifications, if interrupt make no use of Stack storage,
    or if you arrange for separate stack memory for each interrupt priority level.
     
        Mysil
    #9
    henkebenke
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2008/09/27 23:55:51
    • Location: 0
    • Status: offline
    Re: XC32 free version limitations 2020/01/23 00:01:37 (permalink)
    0
    OK, the amount of info about the mips architecture is so vast, that it's quite hard to find specific details. But I'm learning, slowly but surely.
    So, if I have an assembly ISR that has IPL 7, then, since shadow sets are enabled, it's just to start coding, perhaps if I would need a stack, I will have to copy SP from the previous shadows.
    So, if shadows are enabled, every time an ISR hits, a new set of shadows will be activated.  And the strange preamble with CP0, etc, is there to accommodate ISR functionality when a higher priority ISR hits. And also to decide whether the shadow registers will be used or not.  So if I write an assembly ISR for IPL7, there wont be any need for that.
    The reason why the compiler still uses this entry code ( on IPL7 ISR) may be to see to that possible traps ( that has a higher priority )will execute?
    So, if I expect no traps my approach probably will work? 
    #10
    Jump to:
    © 2020 APG vNext Commercial Version 4.5