mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-29 23:03:33 +08:00
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5145 7fd9a85b-ad96-42d3-883c-3090e2eb8679
374 lines
17 KiB
ArmAsm
Executable File
374 lines
17 KiB
ArmAsm
Executable File
/****************************************************************************
|
|
* arch/avr/src/avr32/up_exceptions.S
|
|
*
|
|
* Copyright (C) 2010 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <arch/avr32/avr32.h>
|
|
#include <arch/irq.h>
|
|
|
|
/****************************************************************************
|
|
* External Symbols
|
|
****************************************************************************/
|
|
|
|
.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
|
|
****************************************************************************/
|
|
|
|
/* 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:
|
|
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." */
|
|
|
|
/* REVISIT: This alignment requirement may be different on other AVR32s */
|
|
|
|
.text
|
|
.balign 0x200
|
|
|
|
.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 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 */
|
|
.endr
|
|
lda.w pc, avr32_itlbmiss /* EVBA+0x50 ITLB Miss */
|
|
.rept 3
|
|
lda.w pc, avr32_badvector /* EVBA+0x54-0x5c No such vector */
|
|
.endr
|
|
lda.w pc, avr32_rddtlb /* EVBA+0x60 DTLB Miss (Read) */
|
|
.rept 3
|
|
lda.w pc, avr32_badvector /* EVBA+0x64-0x6c No such vector */
|
|
.endr
|
|
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 */
|
|
.endr
|
|
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. */
|
|
|
|
.balign 4
|
|
.global avr32_int0
|
|
avr32_int0:
|
|
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 */
|
|
|
|
.balign 4
|
|
.global avr32_int2
|
|
avr32_int2:
|
|
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 */
|
|
|
|
/* 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 /* Negative returned if spurious interrupt */
|
|
brge avr32_common /* Jump to the common xcptn handling logic */
|
|
rete /* Ignore spurious interrupt */
|
|
|
|
.Lavr32_intirqno:
|
|
.word avr32_intirqno
|
|
|
|
/****************************************************************************
|
|
* Exception Vector 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 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 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 */
|
|
/* 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_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 r12, sp[4*4]
|
|
ld.w r11, 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
|
|
****************************************************************************/
|
|
|
|
/* After this point, logic to manage interrupts and exceptions is */
|
|
/* equivalent. Here we have: */
|
|
/* */
|
|
/* R8-R12, LR, SR, and the PC on the stack. */
|
|
/* R12 holds the IRQ number to be dispatched. */
|
|
/* */
|
|
/* 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 */
|
|
/* This function will finish construction of the register save structure */
|
|
/* and call the IRQ dispatching logic. */
|
|
|
|
avr32_common:
|
|
/* Disable interrupts in the current SR. This is necessary because the */
|
|
/* AVR32 permits nested interrupts (if they are of higher priority). */
|
|
/* We can support nested interrupts without some effort because: */
|
|
/* - The global variable current_regs permits only one interrupt, */
|
|
/* - If CONFIG_ARCH_INTERRUPTSTACK is defined, then there is a single */
|
|
/* interrupt stack, and */
|
|
/* - Probably other things. */
|
|
|
|
ssrf AVR32_SR_GM_SHIFT
|
|
|
|
/* Save the SP (as it was before the interrupt) in the conext save */
|
|
/* structure. */
|
|
/* xx xx xx xx xx xx xx xx SP SR PC LR 12 11 10 09 08 */
|
|
/* ^sp */
|
|
|
|
mov r8, sp
|
|
sub r8, -8*4
|
|
st.w --sp, r8
|
|
|
|
/* Saving R0-R7 is all that is left to complete the context save. */
|
|
/* 07 06 05 04 03 02 01 00 SP SR PC LR 12 11 10 09 08 */
|
|
/* ^sp */
|
|
|
|
stm --sp, r0-r7
|
|
|
|
/* Now call up_doirq passing the IRQ number in r12 and the base address */
|
|
/* of the register context save area in r11. */
|
|
|
|
mov r11, sp
|
|
|
|
/* Switch to the interrrupt stack if so configured. Move the current */
|
|
/* stack pointer into a preserved register (r7) and set the interrupt */
|
|
/* stack pointer. */
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
|
mov r7, sp
|
|
lddpc sp, .Linstackbaseptr
|
|
#endif
|
|
|
|
/* Call up_doirq with r12=IRQ number and r11=register save area */
|
|
|
|
mcall .Ldoirqptr
|
|
|
|
/* Restore the user stack pointer. */
|
|
/* 07 06 05 04 03 02 01 00 SP SR PC LR 12 11 10 09 08 */
|
|
/* ^sp */
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
|
mov sp, r7
|
|
#endif
|
|
|
|
/* On return, r12 will hold the new address of the register context */
|
|
/* save area. On an interrupt contex switch, this will (1) not be the */
|
|
/* same as the value of r12 passed to up_doirq(), and (2) may not */
|
|
/* reside on a stack. */
|
|
|
|
cp.w sp, r12
|
|
brne 1f
|
|
|
|
/* No context switch... do the simple return. First, restore r0-r7. */
|
|
/* xx xx xx xx xx xx xx xx SP SR PC LR 12 11 10 09 08 */
|
|
/* ^sp */
|
|
|
|
ldm sp++, r0-r7
|
|
|
|
/* Skip over the saved stack pointer and return from the interrupt. */
|
|
/* xx xx xx xx xx xx xx xx xx SR PC LR 12 11 10 09 08 */
|
|
/* ^sp */
|
|
|
|
sub sp, -4
|
|
rete
|
|
|
|
/* Context switch... jump to up_fullcontestrestor with r12=address of */
|
|
/* the task context to restore. */
|
|
|
|
1:
|
|
lddpc pc, .Lfullcontextrestoreptr
|
|
|
|
.Ldoirqptr:
|
|
.word up_doirq
|
|
.Lfullcontextrestoreptr:
|
|
.word up_fullcontextrestore
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
|
.Linstackbaseptr:
|
|
.word .Lintstackbase
|
|
#endif
|
|
.size vectortab, .-vectortab
|
|
|
|
/************************************************************************************
|
|
* Name: up_interruptstack
|
|
************************************************************************************/
|
|
|
|
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
|
.bss
|
|
.align 4
|
|
.globl up_interruptstack
|
|
.type up_interruptstack, object
|
|
up_interruptstack:
|
|
.skip (CONFIG_ARCH_INTERRUPTSTACK & ~3)
|
|
.Lintstackbase:
|
|
.size up_interruptstack, .-up_interruptstack
|
|
#endif
|
|
.end
|
|
|