1  #ifndef ISR_TEST_H
       2  #define ISR_TEST_H
       3  
       4  #include <string.h>
       5  
       6  #define ISR(N,...)                                                      \
       7  __attribute__ ((used, externally_visible , ## __VA_ARGS__))             \
       8      void __vector_##N (void);                                           \
       9      void __vector_##N (void)
      10  
      11  #define SFR(ADDR) (*(unsigned char volatile*) (__AVR_SFR_OFFSET__ + (ADDR)))
      12  #define CORE_SFRS SFR (0x38)
      13  #define SREG      SFR (0x3F)
      14  #define SPL       SFR (0x3D)
      15  #define EIND      SFR (0x3C)
      16  #define RAMPZ     SFR (0x3B)
      17  #define RAMPY     SFR (0x3A)
      18  #define RAMPX     SFR (0x39)
      19  #define RAMPD     SFR (0x38)
      20  
      21  #ifdef __AVR_HAVE_JMP_CALL__
      22  #define VEC_SIZE 4
      23  #else
      24  #define VEC_SIZE 2
      25  #endif
      26  
      27  #ifdef __AVR_TINY__
      28  #define FIRST_REG 16
      29  #else
      30  #define FIRST_REG 0
      31  #endif
      32  
      33  #define CR "\n\t"
      34  
      35  typedef struct
      36  {
      37    unsigned char sfrs[8];
      38    unsigned char gprs[32 - FIRST_REG];
      39  } regs_t;
      40  
      41  regs_t reginfo1, reginfo2;
      42  
      43  __attribute__((noinline,unused))
      44  static void clear_reginfo (void)
      45  {
      46    memset (reginfo1.sfrs, 0, sizeof (reginfo1.sfrs));
      47    memset (reginfo2.sfrs, 0, sizeof (reginfo2.sfrs));
      48  }
      49  
      50  __attribute__((noinline,unused))
      51  static void compare_reginfo (unsigned long gpr_ignore)
      52  {
      53    signed char regno;
      54    const unsigned char *preg1 = ®info1.gprs[0];
      55    const unsigned char *preg2 = ®info2.gprs[0];
      56  
      57    if (memcmp (®info1, ®info2, 8))
      58      __builtin_abort();
      59  
      60    gpr_ignore >>= FIRST_REG;
      61  
      62      for (regno = FIRST_REG; regno < 32;
      63         regno++, preg1++, preg2++, gpr_ignore >>= 1)
      64      {
      65        if (gpr_ignore & 1)
      66          continue;
      67  
      68        if (*preg1 != *preg2)
      69          {
      70            static signed char volatile failed_regno;
      71            (void) failed_regno;
      72            failed_regno = regno;
      73            __builtin_abort();
      74          }
      75      }
      76  }
      77  
      78  /* STore GPR */
      79  #define ST(regno,M)                                     \
      80    CR "sts %[" #M "]+8-%[first]+" #regno ", r" #regno
      81  
      82  /* STore SFR */
      83  #define ST_SFR(sfr, n_sfr, M)                   \
      84    CR "in __tmp_reg__,%i[s_" #sfr "]"            \
      85    CR "sts %[" #M "]+" #n_sfr ", __tmp_reg__"
      86  
      87  /* Named asm OPerand for SFR */
      88  #define OP_SFR(sfr)                             \
      89    , [s_ ## sfr] "n" (&(sfr))
      90  
      91  /* Write funny value to SFR */
      92  #define XX_SFR(sfr)                             \
      93    CR "dec r31 $ out %i[s_" #sfr "], r31"
      94  
      95  /* Write 0 to SFR */
      96  #define OO_SFR(sfr)                             \
      97    CR "out %i[s_" #sfr "], __zero_reg__"
      98  
      99  /* Macros for SREG */
     100  #define ST_SREG(M) ST_SFR (SREG,0,M)
     101  #define OP_SREG    OP_SFR (SREG)
     102  #define XX_SREG    XX_SFR (SREG)
     103  
     104  /* Macros for EIND */
     105  #if defined __AVR_HAVE_EIJMP_EICALL__
     106  #define ST_EIND(M) ST_SFR (EIND,1,M)
     107  #define OP_EIND    OP_SFR (EIND)
     108  #else
     109  #define ST_EIND(M) /* empty */
     110  #define OP_EIND    /* empty */
     111  #endif
     112  
     113  /* Macros for RAMPX */
     114  #if defined (__AVR_HAVE_RAMPX__)
     115  #define ST_RAMPX(M) ST_SFR (RAMPX,2,M)
     116  #define OP_RAMPX    OP_SFR (RAMPX)
     117  #define XX_RAMPX    XX_SFR (RAMPX)
     118  #define OO_RAMPX    OO_SFR (RAMPX)
     119  #else
     120  #define ST_RAMPX(M) /* empty */
     121  #define OP_RAMPX    /* empty */
     122  #define XX_RAMPX    /* empty */
     123  #define OO_RAMPX    /* empty */
     124  #endif
     125  
     126  /* Macros for RAMPY */
     127  #if defined (__AVR_HAVE_RAMPY__)
     128  #define ST_RAMPY(M) ST_SFR (RAMPY,3,M)
     129  #define OP_RAMPY    OP_SFR (RAMPY)
     130  #define XX_RAMPY    XX_SFR (RAMPY)
     131  #define OO_RAMPY    OO_SFR (RAMPY)
     132  #else
     133  #define ST_RAMPY(M) /* empty */
     134  #define OP_RAMPY    /* empty */
     135  #define XX_RAMPY    /* empty */
     136  #define OO_RAMPY    /* empty */
     137  #endif
     138  
     139  /* Macros for RAMPZ */
     140  #if defined (__AVR_HAVE_RAMPZ__)
     141  #define ST_RAMPZ(M) ST_SFR (RAMPZ,4,M)
     142  #define OP_RAMPZ    OP_SFR (RAMPZ)
     143  #define XX_RAMPZ    XX_SFR (RAMPZ)
     144  #define OO_RAMPZ    OO_SFR (RAMPZ)
     145  #else
     146  #define ST_RAMPZ(M) /* empty */
     147  #define OP_RAMPZ    /* empty */
     148  #define XX_RAMPZ    /* empty */
     149  #define OO_RAMPZ    /* empty */
     150  #endif
     151  
     152  /* Macros for RAMPD */
     153  #if defined (__AVR_HAVE_RAMPD__)
     154  #define ST_RAMPD(M) ST_SFR (RAMPD,5,M)
     155  #define OP_RAMPD    OP_SFR (RAMPD)
     156  #else
     157  #define ST_RAMPD(M) /* empty */
     158  #define OP_RAMPD    /* empty */
     159  #endif
     160  
     161  /* Macros for all GPRs */
     162  #if defined __AVR_TINY__
     163  #define ST_REGS_LO(M) /* empty */
     164  #else
     165  #define ST_REGS_LO(M)                           \
     166    ST(0,M)   ST(1,M)   ST(2,M)   ST(3,M)         \
     167    ST(4,M)   ST(5,M)   ST(6,M)   ST(7,M)         \
     168    ST(8,M)   ST(9,M)   ST(10,M)  ST(11,M)        \
     169    ST(12,M)  ST(13,M)  ST(14,M)  ST(15,M)
     170  #endif /* AVR_TINY */
     171  
     172  #define ST_REGS_HI(M)                           \
     173    ST(16,M)    ST(17,M)    ST(18,M)    ST(19,M)  \
     174    ST(20,M)    ST(21,M)    ST(22,M)    ST(23,M)  \
     175    ST(24,M)    ST(25,M)    ST(26,M)    ST(27,M)  \
     176    ST(28,M)    ST(29,M)    ST(30,M)    ST(31,M)
     177  
     178  __attribute__((unused,naked,noinline,noclone))
     179  static void host_store1 (void)
     180  {
     181    __asm __volatile__
     182    ("nop"
     183     CR ".global do_stores_before"
     184     CR ".type   do_stores_before,@function"
     185     CR "do_stores_before:"
     186     /* Funny values to some SFRs */
     187     CR "ldi r31, 1 + 'Z'"
     188     XX_RAMPZ
     189     XX_RAMPY
     190     XX_RAMPX
     191     CR "dec __zero_reg__"
     192     CR "clr r31"
     193     XX_SREG
     194     /* Must set I-flag due to RETI of ISR */
     195     CR "sei"
     196     /* Store core regs before ISR */
     197     ST_RAMPX (mem1)
     198     ST_RAMPY (mem1)
     199     ST_RAMPZ (mem1)
     200     ST_RAMPD (mem1)
     201     ST_EIND  (mem1)
     202     ST_SREG  (mem1)
     203     CR "ldi r31, 0xaa"
     204     CR "mov __tmp_reg__, r31"
     205     CR "ldi r31, 31"
     206     ST_REGS_LO (mem1)
     207     ST_REGS_HI (mem1)
     208     CR "ret"
     209     : /* No outputs */
     210     : [mem1] "i" (®info1), [first] "n" (FIRST_REG)
     211     OP_RAMPX
     212     OP_RAMPY
     213     OP_RAMPZ
     214     OP_RAMPD
     215     OP_EIND
     216     OP_SREG
     217     : "memory", "r31");
     218  }
     219  
     220  __attribute__((unused,naked,noinline,noclone))
     221  static void host_store2 (void)
     222  {
     223    __asm __volatile__
     224    ("nop"
     225     CR ".global do_stores_after"
     226     CR ".type   do_stores_after,@function"
     227     CR "do_stores_after:"
     228     /* Store core regs after ISR */
     229     ST_REGS_LO (mem2)
     230     ST_REGS_HI (mem2)
     231     ST_RAMPX (mem2)
     232     ST_RAMPY (mem2)
     233     ST_RAMPZ (mem2)
     234     ST_RAMPD (mem2)
     235     ST_EIND  (mem2)
     236     ST_SREG  (mem2)
     237     /* Undo funny values */
     238     CR "clr __zero_reg__"
     239     OO_RAMPX
     240     OO_RAMPY
     241     OO_RAMPZ
     242     CR "ret"
     243     : /* No outputs */
     244     : [mem2] "i" (®info2), [first] "n" (FIRST_REG)
     245     OP_RAMPX
     246     OP_RAMPY
     247     OP_RAMPZ
     248     OP_RAMPD
     249     OP_EIND
     250     OP_SREG
     251     : "memory");
     252  }
     253  
     254  #define MK_CALL_ISR(vecno)                      \
     255    __asm __volatile__                            \
     256    (/* Funny values to some SFRs */              \
     257     /* Must set I-flag due to RETI of ISR */     \
     258     /* Store core regs before ISR */             \
     259     CR "%~call do_stores_before"                 \
     260     /* Execute ISR */                            \
     261     CR "%~call __vectors + %[vect]"              \
     262     /* Store core regs after ISR */              \
     263     /* Undo funny values */                      \
     264     CR "%~call do_stores_after"                  \
     265     : /* No outputs */                           \
     266     : [vect] "i" (VEC_SIZE * (vecno))            \
     267     , "i" (host_store1)                          \
     268     , "i" (host_store2)                          \
     269     : "memory", "r31")
     270  
     271  
     272  #define MK_RUN_ISR(N, IGMSK)                    \
     273                                                  \
     274  __attribute__((noinline,noclone))               \
     275  void run_isr_ ## N (void)                       \
     276  {                                               \
     277    clear_reginfo();                              \
     278    MK_CALL_ISR (N);                              \
     279    compare_reginfo (IGMSK);                      \
     280  }
     281  
     282  #endif /* ISR_TEST_H */
     283