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))
clear_reginfo(void)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))
compare_reginfo(unsigned long gpr_ignore)51 static void compare_reginfo (unsigned long gpr_ignore)
52 {
53   signed char regno;
54   const unsigned char *preg1 = &reginfo1.gprs[0];
55   const unsigned char *preg2 = &reginfo2.gprs[0];
56 
57   if (memcmp (&reginfo1, &reginfo2, 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))
host_store1(void)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" (&reginfo1), [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))
host_store2(void)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" (&reginfo2), [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 
284