re PR target/81305 ([avr] avrtiny uses LDS for SREG in ISR routines which is out...
authorGeorg-Johann Lay <avr@gjlay.de>
Wed, 5 Jul 2017 12:34:36 +0000 (12:34 +0000)
committerGeorg-Johann Lay <gjl@gcc.gnu.org>
Wed, 5 Jul 2017 12:34:36 +0000 (12:34 +0000)
gcc/
PR target/81305
* testsuite/gcc.target/avr/isr-test.h: New file.

From-SVN: r249996

gcc/ChangeLog
gcc/testsuite/gcc.target/avr/isr-test.h [new file with mode: 0644]

index 121f6ab441d7e129c78f303bd88a54602a3c8605..b977a6d952b3e625b38dcc933243c711a3bbb541 100644 (file)
@@ -1,3 +1,8 @@
+2017-07-05  Georg-Johann Lay  <avr@gjlay.de>
+
+       PR target/81305
+       * testsuite/gcc.target/avr/isr-test.h: New file.
+
 2017-07-05  Georg-Johann Lay  <avr@gjlay.de>
 
        PR target/81305
diff --git a/gcc/testsuite/gcc.target/avr/isr-test.h b/gcc/testsuite/gcc.target/avr/isr-test.h
new file mode 100644 (file)
index 0000000..2d2babe
--- /dev/null
@@ -0,0 +1,282 @@
+#ifndef ISR_TEST_H
+#define ISR_TEST_H
+
+#include <string.h>
+
+#define ISR(N,...)                                                      \
+__attribute__ ((used, externally_visible , ## __VA_ARGS__))             \
+    void __vector_##N (void);                                           \
+    void __vector_##N (void)
+
+#define SFR(ADDR) (*(unsigned char volatile*) (__AVR_SFR_OFFSET__ + (ADDR)))
+#define CORE_SFRS SFR (0x38)
+#define SREG      SFR (0x3F)
+#define SPL       SFR (0x3D)
+#define EIND      SFR (0x3C)
+#define RAMPZ     SFR (0x3B)
+#define RAMPY     SFR (0x3A)
+#define RAMPX     SFR (0x39)
+#define RAMPD     SFR (0x38)
+
+#ifdef __AVR_HAVE_JMP_CALL__
+#define VEC_SIZE 4
+#else
+#define VEC_SIZE 2
+#endif
+
+#ifdef __AVR_TINY__
+#define FIRST_REG 16
+#else
+#define FIRST_REG 0
+#endif
+
+#define CR "\n\t"
+
+typedef struct
+{
+  unsigned char sfrs[8];
+  unsigned char gprs[32 - FIRST_REG];
+} regs_t;
+
+regs_t reginfo1, reginfo2;
+
+__attribute__((noinline))
+static void clear_reginfo (void)
+{
+  memset (reginfo1.sfrs, 0, sizeof (reginfo1.sfrs));
+  memset (reginfo2.sfrs, 0, sizeof (reginfo2.sfrs));
+}
+
+__attribute__((noinline))
+static void compare_reginfo (unsigned long gpr_ignore)
+{
+  signed char regno;
+  const unsigned char *preg1 = &reginfo1.gprs[0];
+  const unsigned char *preg2 = &reginfo2.gprs[0];
+
+  if (memcmp (&reginfo1, &reginfo2, 8))
+    __builtin_abort();
+
+  gpr_ignore >>= FIRST_REG;
+
+    for (regno = FIRST_REG; regno < 32;
+       regno++, preg1++, preg2++, gpr_ignore >>= 1)
+    {
+      if (gpr_ignore & 1)
+        continue;
+
+      if (*preg1 != *preg2)
+        {
+          static signed char volatile failed_regno;
+          failed_regno = regno;
+          __builtin_abort();
+        }
+    }
+}
+
+/* STore GPR */
+#define ST(regno,M)                                     \
+  CR "sts %[" #M "]+8-%[first]+" #regno ", r" #regno
+
+/* STore SFR */
+#define ST_SFR(sfr, n_sfr, M)                   \
+  CR "in __tmp_reg__,%i[s_" #sfr "]"            \
+  CR "sts %[" #M "]+" #n_sfr ", __tmp_reg__"
+
+/* Named asm OPerand for SFR */
+#define OP_SFR(sfr)                             \
+  , [s_ ## sfr] "n" (&(sfr))
+
+/* Write funny value to SFR */
+#define XX_SFR(sfr)                             \
+  CR "dec r31 $ out %i[s_" #sfr "], r31"
+
+/* Write 0 to SFR */
+#define OO_SFR(sfr)                             \
+  CR "out %i[s_" #sfr "], __zero_reg__"
+
+/* Macros for SREG */
+#define ST_SREG(M) ST_SFR (SREG,0,M)
+#define OP_SREG    OP_SFR (SREG)
+#define XX_SREG    XX_SFR (SREG)
+
+/* Macros for EIND */
+#if defined __AVR_HAVE_EIJMP_EICALL__
+#define ST_EIND(M) ST_SFR (EIND,1,M)
+#define OP_EIND    OP_SFR (EIND)
+#else
+#define ST_EIND(M) /* empty */
+#define OP_EIND    /* empty */
+#endif
+
+/* Macros for RAMPX */
+#if defined (__AVR_HAVE_RAMPX__)
+#define ST_RAMPX(M) ST_SFR (RAMPX,2,M)
+#define OP_RAMPX    OP_SFR (RAMPX)
+#define XX_RAMPX    XX_SFR (RAMPX)
+#define OO_RAMPX    OO_SFR (RAMPX)
+#else
+#define ST_RAMPX(M) /* empty */
+#define OP_RAMPX    /* empty */
+#define XX_RAMPX    /* empty */
+#define OO_RAMPX    /* empty */
+#endif
+
+/* Macros for RAMPY */
+#if defined (__AVR_HAVE_RAMPY__)
+#define ST_RAMPY(M) ST_SFR (RAMPY,3,M)
+#define OP_RAMPY    OP_SFR (RAMPY)
+#define XX_RAMPY    XX_SFR (RAMPY)
+#define OO_RAMPY    OO_SFR (RAMPY)
+#else
+#define ST_RAMPY(M) /* empty */
+#define OP_RAMPY    /* empty */
+#define XX_RAMPY    /* empty */
+#define OO_RAMPY    /* empty */
+#endif
+
+/* Macros for RAMPZ */
+#if defined (__AVR_HAVE_RAMPZ__)
+#define ST_RAMPZ(M) ST_SFR (RAMPZ,4,M)
+#define OP_RAMPZ    OP_SFR (RAMPZ)
+#define XX_RAMPZ    XX_SFR (RAMPZ)
+#define OO_RAMPZ    OO_SFR (RAMPZ)
+#else
+#define ST_RAMPZ(M) /* empty */
+#define OP_RAMPZ    /* empty */
+#define XX_RAMPZ    /* empty */
+#define OO_RAMPZ    /* empty */
+#endif
+
+/* Macros for RAMPD */
+#if defined (__AVR_HAVE_RAMPD__)
+#define ST_RAMPD(M) ST_SFR (RAMPD,5,M)
+#define OP_RAMPD    OP_SFR (RAMPD)
+#else
+#define ST_RAMPD(M) /* empty */
+#define OP_RAMPD    /* empty */
+#endif
+
+/* Macros for all GPRs */
+#if defined __AVR_TINY__
+#define ST_REGS_LO(M) /* empty */
+#else
+#define ST_REGS_LO(M)                           \
+  ST(0,M)   ST(1,M)   ST(2,M)   ST(3,M)         \
+  ST(4,M)   ST(5,M)   ST(6,M)   ST(7,M)         \
+  ST(8,M)   ST(9,M)   ST(10,M)  ST(11,M)        \
+  ST(12,M)  ST(13,M)  ST(14,M)  ST(15,M)
+#endif /* AVR_TINY */
+
+#define ST_REGS_HI(M)                           \
+  ST(16,M)    ST(17,M)    ST(18,M)    ST(19,M)  \
+  ST(20,M)    ST(21,M)    ST(22,M)    ST(23,M)  \
+  ST(24,M)    ST(25,M)    ST(26,M)    ST(27,M)  \
+  ST(28,M)    ST(29,M)    ST(30,M)    ST(31,M)
+
+__attribute__((used,naked,noinline,noclone))
+static void host_store1 (void)
+{
+  __asm __volatile__
+  ("nop"
+   CR ".global do_stores_before"
+   CR ".type   do_stores_before,@function"
+   CR "do_stores_before:"
+   /* Funny values to some SFRs */
+   CR "ldi r31, 1 + 'Z'"
+   XX_RAMPZ
+   XX_RAMPY
+   XX_RAMPX
+   CR "dec __zero_reg__"
+   CR "clr r31"
+   XX_SREG
+   /* Must set I-flag due to RETI of ISR */
+   CR "sei"
+   /* Store core regs before ISR */
+   ST_RAMPX (mem1)
+   ST_RAMPY (mem1)
+   ST_RAMPZ (mem1)
+   ST_RAMPD (mem1)
+   ST_EIND  (mem1)
+   ST_SREG  (mem1)
+   CR "ldi r31, 0xaa"
+   CR "mov __tmp_reg__, r31"
+   CR "ldi r31, 31"
+   ST_REGS_LO (mem1)
+   ST_REGS_HI (mem1)
+   CR "ret"
+   : /* No outputs */
+   : [mem1] "i" (&reginfo1), [first] "n" (FIRST_REG)
+   OP_RAMPX
+   OP_RAMPY
+   OP_RAMPZ
+   OP_RAMPD
+   OP_EIND
+   OP_SREG
+   : "memory", "r31");
+}
+
+__attribute__((used,naked,noinline,noclone))
+static void host_store2 (void)
+{
+  __asm __volatile__
+  ("nop"
+   CR ".global do_stores_after"
+   CR ".type   do_stores_after,@function"
+   CR "do_stores_after:"
+   /* Store core regs after ISR */
+   ST_REGS_LO (mem2)
+   ST_REGS_HI (mem2)
+   ST_RAMPX (mem2)
+   ST_RAMPY (mem2)
+   ST_RAMPZ (mem2)
+   ST_RAMPD (mem2)
+   ST_EIND  (mem2)
+   ST_SREG  (mem2)
+   /* Undo funny values */
+   CR "clr __zero_reg__"
+   OO_RAMPX
+   OO_RAMPY
+   OO_RAMPZ
+   CR "ret"
+   : /* No outputs */
+   : [mem2] "i" (&reginfo2), [first] "n" (FIRST_REG)
+   OP_RAMPX
+   OP_RAMPY
+   OP_RAMPZ
+   OP_RAMPD
+   OP_EIND
+   OP_SREG
+   : "memory");
+}
+
+#define MK_CALL_ISR(vecno)                      \
+  __asm __volatile__                            \
+  (/* Funny values to some SFRs */              \
+   /* Must set I-flag due to RETI of ISR */     \
+   /* Store core regs before ISR */             \
+   CR "%~call do_stores_before"                 \
+   /* Execute ISR */                            \
+   CR "%~call __vectors + %[vect]"              \
+   /* Store core regs after ISR */              \
+   /* Undo funny values */                      \
+   CR "%~call do_stores_after"                  \
+   : /* No outputs */                           \
+   : [vect] "i" (VEC_SIZE * (vecno))            \
+   , "i" (host_store1)                          \
+   , "i" (host_store2)                          \
+   : "memory", "r31")
+
+
+#define MK_RUN_ISR(N, IGMSK)                    \
+                                                \
+__attribute__((noinline,noclone))               \
+void run_isr_ ## N (void)                       \
+{                                               \
+  clear_reginfo();                              \
+  MK_CALL_ISR (N);                              \
+  compare_reginfo (IGMSK);                      \
+}
+
+#endif /* ISR_TEST_H */
+