| #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,unused)) |
| static void clear_reginfo (void) |
| { |
| memset (reginfo1.sfrs, 0, sizeof (reginfo1.sfrs)); |
| memset (reginfo2.sfrs, 0, sizeof (reginfo2.sfrs)); |
| } |
| |
| __attribute__((noinline,unused)) |
| static void compare_reginfo (unsigned long gpr_ignore) |
| { |
| signed char regno; |
| const unsigned char *preg1 = ®info1.gprs[0]; |
| const unsigned char *preg2 = ®info2.gprs[0]; |
| |
| if (memcmp (®info1, ®info2, 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; |
| (void) 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__((unused,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" (®info1), [first] "n" (FIRST_REG) |
| OP_RAMPX |
| OP_RAMPY |
| OP_RAMPZ |
| OP_RAMPD |
| OP_EIND |
| OP_SREG |
| : "memory", "r31"); |
| } |
| |
| __attribute__((unused,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" (®info2), [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 */ |
| |