diff --git a/arch/avr/src/at91uc3/at91uc3_irq.c b/arch/avr/src/at91uc3/at91uc3_irq.c index 7e1204d253f..c05e7496a10 100644 --- a/arch/avr/src/at91uc3/at91uc3_irq.c +++ b/arch/avr/src/at91uc3/at91uc3_irq.c @@ -166,6 +166,22 @@ static int up_getgrp(unsigned int irq) return -EINVAL; } +/**************************************************************************** + * Name: avr32_xcptn + * + * Description: + * Handlers for unexpected execptions. All are fatal error conditions. + * + ****************************************************************************/ + +static int avr32_xcptn(int irq, FAR void *context) +{ + (void)irqsave(); + lldbg("PANIC!!! Exception IRQ: %d\n", irq); + PANIC(OSERR_UNEXPECTEDISR); + return 0; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -177,6 +193,7 @@ static int up_getgrp(unsigned int irq) void up_irqinitialize(void) { int group; + int irq; /* Initialize the table that provides the value of the IPR register to * use to assign a group to different interrupt priorities. @@ -194,9 +211,9 @@ void up_irqinitialize(void) */ for (group = 0; group < AVR32_IRQ_MAXGROUPS; group++) - { - putreg32(g_ipr[0], AVR32_INTC_IPR(group)); - } + { + putreg32(g_ipr[0], AVR32_INTC_IPR(group)); + } /* currents_regs is non-NULL only while processing an interrupt */ @@ -204,9 +221,10 @@ void up_irqinitialize(void) /* Attach the exception handlers */ -#ifdef CONFIG_DEBUG -#warning "Missing logic" -#endif + for (irq = 0; irq < AVR32_IRQ_NEVENTS; irq++) + { + irq_attach(irq, avr32_xcptn); + } /* And finally, enable interrupts */ @@ -246,10 +264,13 @@ int up_prioritize_irq(int irq, int priority) * Name: avr32_intirqno * * Description: - * Return the highest priority pending INT0 interrupt. + * Return the highest priority pending INTn interrupt (hwere n=level). + * This is called directly from interrupt handling logic. This should be + * save since the UC3B will save all C scratch/volatile registers (and + * this function should not alter the perserved/static registers). * ****************************************************************************/ -#warning "Is this safe to call from assembly?" + unsigned int avr32_intirqno(unsigned int level) { /* Get the group that caused the interrupt: "ICRn identifies the group with diff --git a/arch/avr/src/avr32/up_exceptions.S b/arch/avr/src/avr32/up_exceptions.S index 3dbb7d68cea..d7686e3d0a0 100755 --- a/arch/avr/src/avr32/up_exceptions.S +++ b/arch/avr/src/avr32/up_exceptions.S @@ -38,41 +38,51 @@ ****************************************************************************/ #include + #include +#include /**************************************************************************** * External Symbols ****************************************************************************/ - .global avr32_int0irqno /* Returns the IRQ number of an INT0 interrupt */ - .global avr32_int1irqno /* Returns the IRQ number of an INT1 interrupt */ - .global avr32_int2irqno /* Returns the IRQ number of an INT2 interrupt */ - .global avr32_int3irqno /* Returns the IRQ number of an INT3 interrupt */ - .global up_doirq /* Dispatch an IRQ */ - .global up_fullcontextrestore /* Restore new task contex */ + .global avr32_int0irqno /* Returns IRQ number of INT0 event */ + .global avr32_int1irqno /* Returns IRQ number of INT1 event */ + .global avr32_int2irqno /* Returns IRQ number of INT2 event */ + .global avr32_int3irqno /* Returns IRQ number of INT3 event */ + .global up_doirq /* Dispatch an IRQ */ + .global up_fullcontextrestore /* Restore new task contex */ /**************************************************************************** * Macros ****************************************************************************/ -#warning "Missing Logic" +/* Exception entry logic. On entry, thee context save area looks like: */ +/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx SR PC */ +/* ^ ^+2*4 */ +/* Upon joining common logic, the context save are will look like: */ +/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx 10 SR PC */ +/* ^ ^+3*4 */ +/* and r10 will hold the exception's IRQ number */ + .macro HANDLER, label, irqno \label: - rjmp avr32_excptcommon /* FIXME!!! Need IRQ in a register */ + st.w --sp, r10 + mov r10, \irqno + rjmp avr32_xcptcommon /* FIXME!!! Need IRQ in a register */ .endm /**************************************************************************** * Exception Vector Table ****************************************************************************/ -/* The Exception Vector Base Address (EVBA) register will contain "a pointer - * to the exception routines. All exception routines start at this address, - * or at a defined offset relative to the address. Special alignment - * requirements may apply for EVBA, depending on the implementation of the - * interrupt controller." - */ +/* The Exception Vector Base Address (EVBA) register will contain "a */ +/* pointer to the exception routines. All exception routines start at this */ +/* address, or at a defined offset relative to the address. Special */ +/* alignment requirements may apply for EVBA, depending on the */ +/* implementation of the interrupt controller." */ -/* REVISIT: This alignment requirement may be different on other AVR32s */ +/* REVISIT: This alignment requirement may be different on other AVR32s */ .text .balign 0x200 @@ -80,85 +90,83 @@ .global vectortab .type vectortab, @function vectortab: - lda.w pc, avr32_unrec /* EVBA+0x00 Unrecoverable exception */ - lda.w pc, avr32_tlbmult /* EVBA+0x04 TLB multiple hit */ - lda.w pc, avr32_busdata /* EVBA+0x08 Bus error data fetch */ - lda.w pc, avr32_businst /* EVBA+0x0c Bus error instruction fetch */ - lda.w pc, avr32_nmi /* EVBA+0x10 NMI */ - lda.w pc, avr32_instaddr /* EVBA+0x14 Instruction Address */ - lda.w pc, avr32_itlbrot /* EVBA+0x18 ITLB Protection */ - lda.w pc, avr32_bp /* EVBA+0x1c Breakpoint */ - lda.w pc, avr32_invinst /* EVBA+0x20 Illegal Opcode */ - lda.w pc, avr32_unimpinst /* EVBA+0x24 Unimplemented instruction */ - lda.w pc, avr32_priv /* EVBA+0x28 Privilege violation */ - lda.w pc, avr32_fp /* EVBA+0x2c Floating-point */ - lda.w pc, avr32_cop /* EVBA+0x30 Coprocessor absent */ - lda.w pc, avr32_rddata /* EVBA+0x34 Data Address (Read) */ - lda.w pc, avr32_wrdata /* EVBA+0x38 Data Address (Write) */ - lda.w pc, avr32_tddtlbprot /* EVBA+0x3c DTLB Protection (Read) */ - lda.w pc, avr32_wrdtlbprot /* EVBA+0x40 DTLB Protection (Write) */ - lda.w pc, avr32_dltbmod /* EVBA+0x44 DTLB Modified */ + lda.w pc, avr32_unrec /* EVBA+0x00 Unrecoverable exception */ + lda.w pc, avr32_tlbmult /* EVBA+0x04 TLB multiple hit */ + lda.w pc, avr32_busdata /* EVBA+0x08 Bus error data fetch */ + lda.w pc, avr32_businst /* EVBA+0x0c Bus error instr fetch */ + lda.w pc, avr32_nmi /* EVBA+0x10 NMI */ + lda.w pc, avr32_instaddr /* EVBA+0x14 Instruction Address */ + lda.w pc, avr32_itlbrot /* EVBA+0x18 ITLB Protection */ + lda.w pc, avr32_bp /* EVBA+0x1c Breakpoint */ + lda.w pc, avr32_invinst /* EVBA+0x20 Illegal Opcode */ + lda.w pc, avr32_unimpinst /* EVBA+0x24 Unimplemented instruction */ + lda.w pc, avr32_priv /* EVBA+0x28 Privilege violation */ + lda.w pc, avr32_fp /* EVBA+0x2c Floating-point */ + lda.w pc, avr32_cop /* EVBA+0x30 Coprocessor absent */ + lda.w pc, avr32_rddata /* EVBA+0x34 Data Address (Read) */ + lda.w pc, avr32_wrdata /* EVBA+0x38 Data Address (Write) */ + lda.w pc, avr32_tddtlbprot /* EVBA+0x3c DTLB Protection (Read) */ + lda.w pc, avr32_wrdtlbprot /* EVBA+0x40 DTLB Protection (Write) */ + lda.w pc, avr32_dltbmod /* EVBA+0x44 DTLB Modified */ .rept 2 - lda.w pc, avr32_badvector /* EVBA+0x48-0x4c No such vector */ + lda.w pc, avr32_badvector /* EVBA+0x48-0x4c No such vector */ .endr - lda.w pc, avr32_itlbmiss /* EVBA+0x50 ITLB Miss */ + lda.w pc, avr32_itlbmiss /* EVBA+0x50 ITLB Miss */ .rept 3 - lda.w pc, avr32_badvector /* EVBA+0x54-0x5c No such vector */ + lda.w pc, avr32_badvector /* EVBA+0x54-0x5c No such vector */ .endr - lda.w pc, avr32_rddtlb /* EVBA+0x60 DTLB Miss (Read) */ + lda.w pc, avr32_rddtlb /* EVBA+0x60 DTLB Miss (Read) */ .rept 3 - lda.w pc, avr32_badvector /* EVBA+0x64-0x6c No such vector */ + lda.w pc, avr32_badvector /* EVBA+0x64-0x6c No such vector */ .endr - lda.w pc, avr32_wrdtlb /* EVBA+0x70 DTLB Miss (Write) */ + lda.w pc, avr32_wrdtlb /* EVBA+0x70 DTLB Miss (Write) */ .rept (3+4*8) - lda.w pc, avr32_badvector /* EVBA+0x74-0xfc No such vector */ + lda.w pc, avr32_badvector /* EVBA+0x74-0xfc No such vector */ .endr - lda.w pc, avr32_super /* EVBA+0x100 Supervisor call */ + lda.w pc, avr32_super /* EVBA+0x100 Supervisor call */ /**************************************************************************** * Interrupts ****************************************************************************/ -/* The interrupt controller must provide an address that is relative to the - * the EVBA so it is natural to define these interrupt vectors just after - * the exception table. - * On entry to each interrupt handler, R8-R12, LR, PC and SR have already been - * pushed onto the system stack by the MCU. - * - * An interrupt may disappear while it is being fetched by the CPU and, hence, - * spurious interrupt may result. - */ +/* The interrupt controller must provide an address that is relative to the */ +/* the EVBA so it is natural to define these interrupt vectors just after */ +/* the exception table. On entry to each interrupt handler, R8-R12, LR, PC */ +/* and SR have already been pushed onto the system stack by the MCU. */ +/* */ +/* An interrupt may disappear while it is being fetched by the CPU and, */ +/* hence spurious interrupt may result. */ .balign 4 .global avr32_int0 avr32_int0: - mov r12, 0 /* r12=interrupt level 0 */ - rjmp avr32_intcommon /* Jump to common interrupt handling logic */ + mov r12, 0 /* r12=interrupt level 0 */ + rjmp avr32_intcommon /* Jump to common interrupt handling logic */ .balign 4 .global avr32_int1 avr32_int1: - mov r12, 1 /* r12=interrupt level 1 */ - rjmp avr32_intcommon /* Jump to common interrupt handling logic */ + mov r12, 1 /* r12=interrupt level 1 */ + rjmp avr32_intcommon /* Jump to common interrupt handling logic */ .balign 4 .global avr32_int2 avr32_int2: - mov r12, 2 /* r12=interrupt level 2 */ - rjmp avr32_intcommon /* Jump to common interrupt handling logic */ + mov r12, 2 /* r12=interrupt level 2 */ + rjmp avr32_intcommon /* Jump to common interrupt handling logic */ .balign 4 .global avr32_int3 avr32_int3: - mov r12, 3 /* r12=interrupt level 3 */ + mov r12, 3 /* r12=interrupt level 3 */ -/* Common interrupt handling logic. R12 holds the interrupt level index */ +/* Common interrupt handling logic. R12 holds the interrupt level index */ avr32_intcommon: - mcall .Lavr32_intirqno /* Get the IRQ number of the int0 event */ - cp.w r12, 0 /* Negated errno returned if spurious interrupt */ - brge avr32_common /* Jump to the common exception handling logic */ - rete /* Ignore spurious interrupt */ + mcall .Lavr32_intirqno /* Get the IRQ number of the int0 event */ + cp.w r12, 0 /* Negative returned if spurious interrupt */ + brge avr32_common /* Jump to the common xcptn handling logic */ + rete /* Ignore spurious interrupt */ .Lavr32_intirqno: .word avr32_intirqno @@ -167,41 +175,79 @@ avr32_intcommon: * Exception Vector Handlers ****************************************************************************/ - /* Exception Handlers */ +/* Exception Handlers: */ +/* On entry to each, the context save area looks like this: */ +/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx SR PC */ +/* ^ ^+2*4 */ - HANDLER avr32_unrec, AVR32_IRQ_UNREC /* Unrecoverable exception */ - HANDLER avr32_tlbmult, AVR32_IRQ_TLBMULT /* TLB multiple hit */ + HANDLER avr32_unrec, AVR32_IRQ_UNREC /* Unrecoverable xcptn */ + HANDLER avr32_tlbmult, AVR32_IRQ_TLBMULT /* TLB multiple hit */ HANDLER avr32_busdata, AVR32_IRQ_BUSDATA /* Bus error data fetch */ - HANDLER avr32_businst, AVR32_IRQ_BUSINST /* Bus error instruction fetch */ - HANDLER avr32_nmi, AVR32_IRQ_NMI /* NMI */ - HANDLER avr32_instaddr, AVR32_IRQ_INSTADDR /* Instruction Address */ - HANDLER avr32_itlbrot, AVR32_IRQ_ITLBPROT /* ITLB Protection */ - HANDLER avr32_bp, AVR32_IRQ_BP /* Breakpoint */ - HANDLER avr32_invinst, AVR32_IRQ_INVINST /* Illegal Opcode */ - HANDLER avr32_unimpinst, AVR32_IRQ_UNIMPINST /* Unimplemented instruction */ - HANDLER avr32_priv, AVR32_IRQ_PRIV /* Privilege violation */ - HANDLER avr32_fp, AVR32_IRQ_FP /* Floating-point */ - HANDLER avr32_cop, AVR32_IRQ_COP /* Coprocessor absent */ - HANDLER avr32_rddata, AVR32_IRQ_RDDATA /* Data Address (Read) */ - HANDLER avr32_wrdata, AVR32_IRQ_WRDATA /* Data Address (Write) */ - HANDLER avr32_tddtlbprot, AVR32_IRQ_RDDTLBPROT /* DTLB Protection (Read) */ - HANDLER avr32_wrdtlbprot, AVR32_IRQ_WRDTLBPROT /* DTLB Protection (Write) */ - HANDLER avr32_dltbmod, AVR32_IRQ_DLTBMOD /* DTLB Modified */ - HANDLER avr32_itlbmiss, AVR32_IRQ_ITLBMISS /* ITLB Miss */ - HANDLER avr32_rddtlb, AVR32_IRQ_RDDTLB /* DTLB Miss (Read) */ - HANDLER avr32_wrdtlb, AVR32_IRQ_WRDTLB /* DTLB Miss (Write) */ - HANDLER avr32_super, AVR32_IRQ_SUPER /* Supervisor call */ - HANDLER avr32_badvector, AVR32_IRQ_BADVECTOR /* No such vector */ + HANDLER avr32_businst, AVR32_IRQ_BUSINST /* Bus err instr fetch */ + HANDLER avr32_nmi, AVR32_IRQ_NMI /* NMI */ + HANDLER avr32_instaddr, AVR32_IRQ_INSTADDR /* Instruction Address */ + HANDLER avr32_itlbrot, AVR32_IRQ_ITLBPROT /* ITLB Protection */ + HANDLER avr32_bp, AVR32_IRQ_BP /* Breakpoint */ + HANDLER avr32_invinst, AVR32_IRQ_INVINST /* Illegal Opcode */ + HANDLER avr32_unimpinst, AVR32_IRQ_UNIMPINST /* Unimplemented intsr */ + HANDLER avr32_priv, AVR32_IRQ_PRIV /* Privilege violation */ + HANDLER avr32_fp, AVR32_IRQ_FP /* Floating-point */ + HANDLER avr32_cop, AVR32_IRQ_COP /* Coprocessor absent */ + HANDLER avr32_rddata, AVR32_IRQ_RDDATA /* Data Address (RD) */ + HANDLER avr32_wrdata, AVR32_IRQ_WRDATA /* Data Address (WR) */ + HANDLER avr32_tddtlbprot, AVR32_IRQ_RDDTLBPROT /* DTLB Protection (RD) */ + HANDLER avr32_wrdtlbprot, AVR32_IRQ_WRDTLBPROT /* DTLB Protection (WR) */ + HANDLER avr32_dltbmod, AVR32_IRQ_DLTBMOD /* DTLB Modified */ + HANDLER avr32_itlbmiss, AVR32_IRQ_ITLBMISS /* ITLB Miss */ + HANDLER avr32_rddtlb, AVR32_IRQ_RDDTLB /* DTLB Miss (RD) */ + HANDLER avr32_wrdtlb, AVR32_IRQ_WRDTLB /* DTLB Miss (WR) */ + HANDLER avr32_super, AVR32_IRQ_SUPER /* Supervisor call */ + HANDLER avr32_badvector, AVR32_IRQ_BADVECTOR /* No such vector */ -/* Common exception handling logic. Unlike the interrupt handlers, the - * exception handlers do not save R8-R12, and LR on the stack. Only the PC - * and SR have been pushed onto the system stack by the MCU. The following - * loic creates a common stack frame for exception handlers prior to joining - * to the common interrupt/exception logic below. - */ +/* Common exception handling logic. Unlike the interrupt handlers, the */ +/* exception handlers do not save R8-R12, and LR on the stack. Only the PC */ +/* and SR have been pushed onto the system stack by the MCU. The following */ +/* logic creates a common stack frame for exception handlers prior to */ +/* joining to the common interrupt/exception logic below. */ +/* */ +/* The context save area looks like this on entry to the HANDLER above. */ +/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx SR PC */ +/* ^ ^+2*4 */ +/* Upon joining common logic here, the context save are will loke: */ +/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx 10 SR PC */ +/* ^ ^+3*4 */ +/* and r10 will hold the exception's IRQ number */ +/* */ +/* either (1) non-time-critical, or (2) fatal. Obvious, that would not be */ +/* the case if TLB missing handling is required. Such time-critical vector */ +/* handling should be handled differently. */ -avr32_excptcommon: -#warning "Missing Logic" +avr32_xcptcommon: +/* Save r10-r12, lr on the stack: */ +/* xx xx xx xx xx xx xx xx xx xx xx LR 12 11 10 SR PC */ +/* ^ ^+4*4 ^+6*4 */ + + stm --sp, r11-r12, lr + +/* Move SR and PC into the expected position: */ +/* xx xx xx xx xx xx xx xx xx SR PC LI 12 11 10 SR PC */ +/* ^ ^+8*4 */ + + ld.w r11, sp[4*4] + ld.w r12, sp[5*4] + stm --sp, r11-r12 + +/* Save r8 and r8: */ +/* xx xx xx xx xx xx xx xx xx SR PC LI 12 11 10 SR PC */ +/* ^ ^+6*4 ^+8*4 */ + + st.w sp[6*4], r9 + st.w sp[7*4], r8 + +/* Move the IRQ number in r12 and fall through to the common event handling */ +/* logic. */ + + mov r12, r10 /**************************************************************************** * Common Event Handling Logic @@ -215,7 +261,7 @@ avr32_excptcommon: /* */ /* The context save area looks like this: */ /* xx xx xx xx xx xx xx xx xx SR PC LR 12 11 10 09 08 */ -/* ^ +8*4 */ +/* ^ ^+8*4 */ /* This function will finish construction of the register save structure */ /* and call the IRQ dispatching logic. */ @@ -256,12 +302,12 @@ avr32_common: #if CONFIG_ARCH_INTERRUPTSTACK > 3 mov r7, sp - lddpc sp, .Lup_instackbase + lddpc sp, .Linstackbaseptr #endif /* Call up_doirq with r12=IRQ number and r11=register save area */ - mcall .Lup_doirq + mcall .Ldoirqptr /* Restore the user stack pointer. */ /* 07 06 05 04 03 02 01 00 SP SR PC LR 12 11 10 09 08 */ @@ -296,13 +342,19 @@ avr32_common: /* the task context to restore. */ 1: - lddpc pc, .Lup_fullcontextrestore + lddpc pc, .Lfullcontextrestoreptr -.Lup_doirq: +.Ldoirqptr: .word up_doirq -.Lup_fullcontextrestore: +.Lfullcontextrestoreptr: .word up_fullcontextrestore +#if CONFIG_ARCH_INTERRUPTSTACK > 3 +.Linstackbaseptr: + .word .Lintstackbase +#endif + .size vectortab, .-vectortab + /************************************************************************************ * Name: up_interruptstack ************************************************************************************/ @@ -314,11 +366,8 @@ avr32_common: .type up_interruptstack, object up_interruptstack: .skip (CONFIG_ARCH_INTERRUPTSTACK & ~3) -up_intstackbase: +.Lintstackbase: .size up_interruptstack, .-up_interruptstack -.Lup_instackbase - .word up_intstackbase - .size .Lup_instackbase, .-.Lup_instackbase #endif .end