1  /* { dg-do run } */
       2  
       3  #ifdef __MSP430X__
       4  #include "isr-push-pop-isr-430x.c"
       5  #include "isr-push-pop-leaf-isr-430x.c"
       6  #else
       7  #include "isr-push-pop-isr-430.c"
       8  #include "isr-push-pop-leaf-isr-430.c"
       9  #endif
      10  
      11  /* Test that ISRs which call other functions do not save extraneous registers.
      12     They only need to save the caller-saved regs R11->R15.
      13     We use a lot of asm statements to hide what is going on from the compiler to
      14     more accurately simulate an interrupt.  */
      15  
      16  /* Store the register number in each general register R4->R15, so they can be
      17     later checked their value has been kept.  */
      18  #define SETUP_REGS		\
      19    __asm__ ("mov #4, r4");	\
      20    __asm__ ("mov #5, r5");	\
      21    __asm__ ("mov #6, r6");	\
      22    __asm__ ("mov #7, r7");	\
      23    __asm__ ("mov #8, r8");	\
      24    __asm__ ("mov #9, r9");	\
      25    __asm__ ("mov #10, r10");	\
      26    __asm__ ("mov #11, r11");	\
      27    __asm__ ("mov #12, r12");	\
      28    __asm__ ("mov #13, r13");	\
      29    __asm__ ("mov #14, r14");	\
      30    __asm__ ("mov #15, r15");
      31  
      32  /* Write an arbitrary value to all general regs.  */
      33  #define TRASH_REGS				\
      34    __asm__ ("mov #0xFFFF, r4" : : : "R4");	\
      35    __asm__ ("mov #0xFFFF, r5" : : : "R5");	\
      36    __asm__ ("mov #0xFFFF, r6" : : : "R6");	\
      37    __asm__ ("mov #0xFFFF, r7" : : : "R7");	\
      38    __asm__ ("mov #0xFFFF, r8" : : : "R8");	\
      39    __asm__ ("mov #0xFFFF, r9" : : : "R9");	\
      40    __asm__ ("mov #0xFFFF, r10" : : : "R10");	\
      41    __asm__ ("mov #0xFFFF, r11" : : : "R11");	\
      42    __asm__ ("mov #0xFFFF, r12" : : : "R12");	\
      43    __asm__ ("mov #0xFFFF, r13" : : : "R13");	\
      44    __asm__ ("mov #0xFFFF, r14" : : : "R14");	\
      45    __asm__ ("mov #0xFFFF, r15" : : : "R15");
      46  
      47  /* Check the value in all general registers is the same as that set in
      48     SETUP_REGS.  */
      49  #define CHECK_REGS			\
      50    __asm__ ("cmp #4,  r4 { jne ABORT");	\
      51    __asm__ ("cmp #5,  r5 { jne ABORT");	\
      52    __asm__ ("cmp #6,  r6 { jne ABORT");	\
      53    __asm__ ("cmp #7,  r7 { jne ABORT");	\
      54    __asm__ ("cmp #8,  r8 { jne ABORT");	\
      55    __asm__ ("cmp #9,  r9 { jne ABORT");	\
      56    __asm__ ("cmp #10, r10 { jne ABORT");	\
      57    __asm__ ("cmp #11, r11 { jne ABORT");	\
      58    __asm__ ("cmp #12, r12 { jne ABORT");	\
      59    __asm__ ("cmp #13, r13 { jne ABORT");	\
      60    __asm__ ("cmp #14, r14 { jne ABORT");	\
      61    __asm__ ("cmp #15, r15 { jne ABORT");
      62  
      63  void __attribute__((noinline))
      64  callee (void)
      65  {
      66    /* Here were modify all the regs, but tell the compiler that we are since
      67       this is just a way to simulate a function that happens to modify all the
      68       registers.  */
      69    TRASH_REGS
      70  }
      71  int 
      72  #ifdef __MSP430X_LARGE__ 
      73  __attribute__((lower))
      74  #endif
      75  main (void)
      76  {
      77    SETUP_REGS
      78  
      79    /* A surprise branch to the ISR that the compiler cannot prepare for.
      80       We must first simulate the interrupt acceptance procedure that the
      81       hardware would normally take care of.
      82       So push the desired PC return address, and then the SR (R2).
      83       MSP430X expects the high bits 19:16 of the PC return address to be stored
      84       in bits 12:15 of the SR stack slot.  This is hard to handle in hand-rolled
      85       assembly code, so we always place main() in lower memory so the return
      86       address is 16-bits.  */
      87    __asm__ ("push #CHECK1");
      88    __asm__ ("push r2");
      89    __asm__ ("br #isr");
      90  
      91    __asm__ ("CHECK1:");
      92    /* If any of the regs R4->R15 don't match their original value, this will
      93       jump to ABORT.  */
      94    CHECK_REGS
      95  
      96    /* Now test that an interrupt function that is a leaf also works
      97       correctly.  */
      98    __asm__ ("push #CHECK2");
      99    __asm__ ("push r2");
     100    __asm__ ("br #isr_leaf");
     101  
     102    __asm__ ("CHECK2:");
     103    CHECK_REGS
     104  
     105    /* The values in R4->R15 were successfully checked, now jump to FINISH to run
     106       the prologue generated by the compiler.  */
     107    __asm__ ("jmp FINISH");
     108  
     109    /* CHECK_REGS will branch here if a register holds the wrong value.  */
     110    __asm__ ("ABORT:");
     111  #ifdef __MSP430X_LARGE__ 
     112    __asm__ ("calla #abort");
     113  #else
     114    __asm__ ("call #abort");
     115  #endif
     116  
     117    __asm__ ("FINISH:");
     118    return 0;
     119  }
     120