diff --git a/include/interrupt-utils.h b/include/interrupt-utils.h new file mode 100644 index 000000000..29b307d88 --- /dev/null +++ b/include/interrupt-utils.h @@ -0,0 +1,272 @@ +/* + * Defines and Macros for Interrupt-Service-Routines + * collected and partly created by + * Martin Thomas + * + * Copyright 2005 M. Thomas + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + */ + +#ifndef interrupt_utils_ +#define interrupt_utils_ + +/* + The following defines are usefull for + interrupt service routine declarations. +*/ + +/* + RAMFUNC + Attribute which defines a function to be located + in memory section .fastrun and called via "long calls". + See linker-skript and startup-code to see how the + .fastrun-section is handled. + The definition is not only useful for ISRs but since + ISRs should be executed fast the macro is defined in + this header. +*/ +#define RAMFUNC __attribute__ ((long_call, section (".fastrun"))) + + +/* + INTFUNC + standard attribute for arm-elf-gcc which marks + a function as ISR (for the VIC). Since gcc seems + to produce wrong code if this attribute is used in + thumb/thumb-interwork the attribute should only be + used for "pure ARM-mode" binaries. +*/ +#define INTFUNC __attribute__ ((interrupt("IRQ"))) + + +/* + NACKEDFUNC + gcc will not add any code to a function declared + "nacked". The user has to take care to save registers + and add the needed code for ISR functions. Some + macros for this tasks are provided below. +*/ +#define NACKEDFUNC __attribute__((naked)) + + +/****************************************************************************** + * + * MACRO Name: ISR_STORE() + * + * Description: + * This MACRO is used upon entry to an ISR with interrupt nesting. + * Should be used together with ISR_ENABLE_NEST(). The MACRO + * performs the following steps: + * + * 1 - Save the non-banked registers r0-r12 and lr onto the IRQ stack. + * + *****************************************************************************/ +#define ISR_STORE() asm volatile( \ + "STMDB SP!,{R0-R12,LR}\n" ) + + /****************************************************************************** + * + * MACRO Name: ISR_RESTORE() + * + * Description: + * This MACRO is used upon exit from an ISR with interrupt nesting. + * Should be used together with ISR_DISABLE_NEST(). The MACRO + * performs the following steps: + * + * 1 - Load the non-banked registers r0-r12 and lr from the IRQ stack. + * 2 - Adjusts resume adress + * + *****************************************************************************/ +#define ISR_RESTORE() asm volatile( \ + "LDMIA SP!,{R0-R12,LR}\n" \ + "SUBS R15,R14,#0x0004\n" ) + +/****************************************************************************** + * + * MACRO Name: ISR_ENABLE_NEST() + * + * Description: + * This MACRO is used upon entry from an ISR with interrupt nesting. + * Should be used after ISR_STORE. + * + *****************************************************************************/ + +#define ISR_ENABLE_NEST() asm volatile( \ + "MRS LR, SPSR \n" \ + "STMFD SP!, {LR} \n" \ + "MSR CPSR_c, #0x1f \n" \ + "STMFD SP!, {LR} " ) + +/****************************************************************************** + * + * MACRO Name: ISR_DISABLE_NEST() + * + * Description: + * This MACRO is used upon entry from an ISR with interrupt nesting. + * Should be used before ISR_RESTORE. + * + *****************************************************************************/ + +#define ISR_DISABLE_NEST() asm volatile( \ + "LDMFD SP!, {LR} \n" \ + "MSR CPSR_c, #0x92 \n" \ + "LDMFD SP!, {LR} \n" \ + "MSR SPSR_cxsf, LR \n" ) + + + +/* + * The following marcos are from the file "armVIC.h" by: + * + * Copyright 2004, R O SoftWare + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + */ + +/****************************************************************************** + * + * MACRO Name: ISR_ENTRY() + * + * Description: + * This MACRO is used upon entry to an ISR. The current version of + * the gcc compiler for ARM does not produce correct code for + * interrupt routines to operate properly with THUMB code. The MACRO + * performs the following steps: + * + * 1 - Adjust address at which execution should resume after servicing + * ISR to compensate for IRQ entry + * 2 - Save the non-banked registers r0-r12 and lr onto the IRQ stack. + * 3 - Get the status of the interrupted program is in SPSR. + * 4 - Push it onto the IRQ stack as well. + * + *****************************************************************************/ +#define ISR_ENTRY() asm volatile(" sub lr, lr,#4\n" \ + " stmfd sp!,{r0-r12,lr}\n" \ + " mrs r1, spsr\n" \ + " stmfd sp!,{r1}") + +/****************************************************************************** + * + * MACRO Name: ISR_EXIT() + * + * Description: + * This MACRO is used to exit an ISR. The current version of the gcc + * compiler for ARM does not produce correct code for interrupt + * routines to operate properly with THUMB code. The MACRO performs + * the following steps: + * + * 1 - Recover SPSR value from stack + * 2 - and restore its value + * 3 - Pop the return address & the saved general registers from + * the IRQ stack & return + * + *****************************************************************************/ +#define ISR_EXIT() asm volatile(" ldmfd sp!,{r1}\n" \ + " msr spsr_c,r1\n" \ + " ldmfd sp!,{r0-r12,pc}^") + +/****************************************************************************** + * + * Function Name: disableIRQ() + * + * Description: + * This function sets the IRQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned disableIRQ(void); + +/****************************************************************************** + * + * Function Name: enableIRQ() + * + * Description: + * This function clears the IRQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned enableIRQ(void); + +/****************************************************************************** + * + * Function Name: restoreIRQ() + * + * Description: + * This function restores the IRQ disable bit in the status register + * to the value contained within passed oldCPSR + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned restoreIRQ(unsigned oldCPSR); + +/****************************************************************************** + * + * Function Name: disableFIQ() + * + * Description: + * This function sets the FIQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned disableFIQ(void); + +/****************************************************************************** + * + * Function Name: enableFIQ() + * + * Description: + * This function clears the FIQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned enableFIQ(void); + +/****************************************************************************** + * + * Function Name: restoreFIQ() + * + * Description: + * This function restores the FIQ disable bit in the status register + * to the value contained within passed oldCPSR + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned restoreFIQ(unsigned oldCPSR); + + +#endif + diff --git a/include/sys-interrupt.h b/include/sys-interrupt.h new file mode 100644 index 000000000..433db4a0f --- /dev/null +++ b/include/sys-interrupt.h @@ -0,0 +1,31 @@ +#ifndef __SYS_INTERRUPT_H__QIHZ66NP8K__ +#define __SYS_INTERRUPT_H__QIHZ66NP8K__ + + +/* Returns true if it handled an activbe interrupt */ +typedef int (*SystemInterruptFunc)(); + +typedef struct _SystemInterruptHandler SystemInterruptHandler; +struct _SystemInterruptHandler +{ + SystemInterruptHandler *next; + SystemInterruptFunc handler; +}; + + +void +sys_interrupt_enable(); + +void +sys_interrupt_disable(); + +void +sys_interrupt_append_handler(SystemInterruptHandler *handler); + +void +sys_interrupt_prepend_handler(SystemInterruptHandler *handler); + +void +sys_interrupt_remove_handler(SystemInterruptHandler *handler); + +#endif /* __SYS_INTERRUPT_H__QIHZ66NP8K__ */ diff --git a/src/interrupt-utils.c b/src/interrupt-utils.c index cd3e1bd81..2e2f7c1e2 100644 --- a/src/interrupt-utils.c +++ b/src/interrupt-utils.c @@ -17,18 +17,29 @@ #define FIQ_MASK 0x00000040 #define INT_MASK (IRQ_MASK | FIQ_MASK) -static inline unsigned __get_cpsr(void) +unsigned __get_cpsr(void) { unsigned long retval; - asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ ); + asm volatile ( + ".code 32;" + "mrs %0, cpsr;" + ".code 16;" + : "=r" (retval) : + ); return retval; } -static inline void __set_cpsr(unsigned val) +void __set_cpsr(unsigned val) { - asm volatile (" msr cpsr_c, %0" : /* no outputs */ : "r" (val) ); + asm volatile ( + ".code 32;" + "msr cpsr_c, %0;" + ".code 16;" + : : "r" (val) + ); } + unsigned disableIRQ(void) { unsigned _cpsr; diff --git a/src/sys-interrupt.c b/src/sys-interrupt.c index b540145cb..6a8b36e1d 100644 --- a/src/sys-interrupt.c +++ b/src/sys-interrupt.c @@ -1,6 +1,7 @@ -#include -#include -#include +#include "sys-interrupt.h" +#include "interrupt-utils.h" + +#include "embedded_types.h" #define ATTR @@ -30,24 +31,20 @@ system_int (void) /* System Interrupt Handler */ { ISR_ENTRY(); system_int_safe(); - *AT91C_AIC_EOICR = 0; /* End of Interrupt */ ISR_EXIT(); } static unsigned int enabled = 0; /* Number of times the system interrupt has been enabled */ -#define DIS_INT *AT91C_AIC_IDCR = (1 << AT91C_ID_SYS) -#define EN_INT if (enabled > 0) *AT91C_AIC_IECR = (1 << AT91C_ID_SYS) +#define INTCNTL 0x80020000 +#define DIS_INT *((volatile uint32_t *)INTCNTL) = 3 << 19; +#define EN_INT if (enabled > 0) *((volatile uint32_t *)INTCNTL) = 0; void sys_interrupt_enable() { if (enabled++ == 0) { - /* Level trigged at priority 5 */ - AT91C_AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 5; - /* Interrupt vector */ - AT91C_AIC_SVR[AT91C_ID_SYS] = (unsigned long) system_int; /* Enable */ EN_INT; }