diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-05-19 22:00:49 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-05-19 22:00:49 +0000 |
commit | 12bb64b7481f31b499b2ffeccedc70353b56a138 (patch) | |
tree | c3d6b069b7c4fa09e050a425b459ad57d28d100c | |
parent | fc82157191bad57057ad7ae97ed74a26a05d307b (diff) | |
download | px4-nuttx-12bb64b7481f31b499b2ffeccedc70353b56a138.tar.gz px4-nuttx-12bb64b7481f31b499b2ffeccedc70353b56a138.tar.bz2 px4-nuttx-12bb64b7481f31b499b2ffeccedc70353b56a138.zip |
Add PIC32 exception handling macros
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3629 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-x | nuttx/arch/mips/src/mips32/mips32-excptmacros.h | 410 | ||||
-rw-r--r-- | nuttx/arch/mips/src/mips32/up_initialstate.c | 30 | ||||
-rwxr-xr-x | nuttx/arch/mips/src/pic32mx/pic32mx-irq.c | 5 |
3 files changed, 435 insertions, 10 deletions
diff --git a/nuttx/arch/mips/src/mips32/mips32-excptmacros.h b/nuttx/arch/mips/src/mips32/mips32-excptmacros.h new file mode 100755 index 000000000..ed88f33e6 --- /dev/null +++ b/nuttx/arch/mips/src/mips32/mips32-excptmacros.h @@ -0,0 +1,410 @@ +/********************************************************************************************
+ * arch/mips/src/mips32/mips32-excptmacros.h
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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.
+ *
+ ********************************************************************************************/
+
+#ifndef __ARCH_MIPS_SRC_MIPS32_MIPS32_EXCPTMACROS_H
+#define __ARCH_MIPS_SRC_MIPS32_MIPS32_EXCPTMACROS_H
+
+/********************************************************************************************
+ * Included Files
+ ********************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <arch/irq.h>
+#include <arch/mips32/cp0.h>
+
+#ifdef __ASSEMBLY__
+
+/********************************************************************************************
+ * Pre-Processor Definitions
+ ********************************************************************************************/
+
+/********************************************************************************************
+ * Global Symbols
+ ********************************************************************************************/
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 3
+ .global g_stackbase
+ .global g_nestlevel
+#endif
+
+/********************************************************************************************
+ * Assembly Language Macros
+ ********************************************************************************************/
+
+/********************************************************************************************
+ * General Usage Example:
+ *
+ * my_exception:
+ * EXCPT_PROLOGUE t0 - Save registers on stack, enable nested interrupts
+ * move a0, sp - Pass register save structure as the parameter 1
+ * USE_INTSTACK, t0, t1, t2 - Switch to the interrupt stack
+ * jal handler - Handle the exception IN=old regs OUT=new regs
+ * di - Disable interrupts
+ * RESTORE_STACK t0, t1 - Undo the operations of USE_STACK
+ * EXCPT_EPILOGUE v0 - Return to the context returned by handler()
+ *
+ ********************************************************************************************/
+/********************************************************************************************
+ * Name: EXCPT_PROLOGUE
+ *
+ * Description:
+ * Provides the "prologue" logic that should appear at the beginning of every exception
+ * handler.
+ *
+ * On Entry:
+ * sp - Points to the top of the stack
+ * tmp - Is a register the can be modified for scratch usage (after it has been saved)
+ * k0 and k1 - Since we are in an exception handler, these are available for use
+ *
+ * At completion:
+ * Register state is saved on the stack; All registers are available for usage except sp
+ * and k1:
+ *
+ * - sp points the beginning of the register save area
+ * - k1 holds the value of the STATUS register
+ *
+ * The following registers are modified: k0, k1, sp, a0
+ *
+ ********************************************************************************************/
+
+ .macro EXCPT_PROLOGUE, tmp
+
+ /* Get the SP from the previous shadow set */
+
+#if 0
+ rdpgpr sp, sp
+#endif
+
+ /* "When entering the interrupt handler routine, the interrupt controller must first
+ * save the current priority and exception PC counter from Interrupt Priority (IPL)
+ * bits (Status<15:10>) and the ErrorEPC register, respectively, on the stack. ..."
+ */
+
+ mfc0 k0, MIPS32_CP0_CAUSE
+ mfc0 k1, MIPS32_CP0_EPC
+
+ /* Isolate the pending interrupt level in bits 0-5 of k0 */
+
+ srl k0, k0, CP0_CAUSE_IP_SHIFT
+
+ /* Create the register context stack frame large enough to hold the entire register save
+ * array.
+ */
+
+ addiu sp, sp, -XCPTCONTEXT_SIZE
+
+ /* Save the EPC and STATUS in the register context array */
+
+ sw k1, REG_EPC(sp)
+ mfc0 k1, MIPS32_CP0_STATUS
+ sw k1, REG_STATUS(sp)
+
+ /* Then insert pending interrupt level as the current mask level in the CP0 status
+ * register. Also clear bits 1-4 in new value of the status register:
+ *
+ * Bit 1: Exception Level
+ * Bit 2: Error Level
+ * Bit 3: (not used in PIC32MX)
+ * Bit 4: Operating mode == USER
+ */
+
+ ins k1, \tmp, CP0_STATUS_IPL_SHIFT, 6
+ ins k1, zero, 1, 4
+
+ /* And Enable interrupts */
+
+ mtc0 k1, MIPS32_CP0_STATUS
+
+ /* Save floating point registers */
+
+ mfhi k0
+ sw k0, REG_MFHI(sp)
+ mflo k0
+ sw k0, REG_MFLO(sp)
+
+ /* Save general purpose registers */
+ /* $1: at_reg, assembler temporary */
+
+ sw $1, REG_AT(sp)
+
+ /* $2-$3 = v0-v1: Return value registers */
+
+ sw v0, REG_V0(sp)
+ sw v1, REG_V1(sp)
+
+ /* $4-$7 = a0-a3: Argument registers */
+
+ sw a0, REG_A0(sp)
+ sw a1, REG_A1(sp)
+ sw a2, REG_A2(sp)
+ sw a3, REG_A3(sp)
+
+ /* $8-$15 = t0-t7: Volatile registers */
+
+ sw t0, REG_T0(sp)
+ sw t1, REG_T1(sp)
+ sw t2, REG_T2(sp)
+ sw t3, REG_T3(sp)
+ sw t4, REG_T4(sp)
+ sw t5, REG_T5(sp)
+ sw t6, REG_T6(sp)
+ sw t7, REG_T7(sp)
+
+ /* $16-$23 = s0-s7: Static registers */
+
+ sw s0, REG_S0(sp)
+ sw s1, REG_S1(sp)
+ sw s2, REG_S2(sp)
+ sw s3, REG_S3(sp)
+ sw s4, REG_S4(sp)
+ sw s5, REG_S5(sp)
+ sw s6, REG_S6(sp)
+ sw s7, REG_S7(sp)
+
+ /* $24-25 = t8-t9: More Volatile registers */
+
+ sw t8, REG_T8(sp)
+ sw t9, REG_T9(sp)
+
+ /* $26-$27 = ko-k1: Reserved for use in exeption handers. These do not need to be
+ * saved.
+ *
+ * $28 = gp: Only needs to be saved under conditions where there are multiple, per-
+ * thread values for the GP.
+ */
+
+#ifdef MIPS32_SAVE_GP
+ sw gp, REG_GP(sp)
+#endif
+
+ /* $30 = either s8 or fp: Depends if a frame pointer is used or not */
+
+ sw s8, REG_S8(sp)
+
+ /* $31 = ra: Return address */
+
+ sw ra, REG_RA(sp)
+
+ /* $29 = sp: The value of the stack pointer on return from the exception. a0 is
+ * used as a temporary
+ */
+
+ addiu \tmp, sp, XCPTCONTEXT_SIZE
+ sw \tmp, REG_SP(sp)
+ .endm
+
+/********************************************************************************************
+ * Name: EXCPT_EPILOGUE
+ *
+ * Description:
+ * Provides the "epilogue" logic that should appear at the end of every exception handler.
+ *
+ * On input:
+ * regs - points to the register save structure. NOTE: This *may not* be an address
+ * lying in a stack! It might be an address in a TCB!
+ * Interrupts are disabled (via 'di')
+ *
+ * On completion:
+ * All registers restored
+ * eret is executed to return from the exception
+ *
+ ********************************************************************************************/
+
+ .macro EXCPT_EXIT, regs
+
+ /* Since interrupts are disabled via di can now use k0 and k1 again. Use k1 as the
+ * pointer to the register save array.
+ */
+
+ move k1, \regs
+
+ /* Restore the floating point register state */
+
+ lw k0, REG_MTLO(k1)
+ mtlo k0
+ lw k0, REG_MTHI(k1)
+ mthi k0
+
+ /* Restore general purpose registers */
+ /* $1: at_reg, assembler temporary */
+
+ lw $1, REG_AT(k1)
+
+ /* $2-$3 = v0-v1: Return value registers */
+
+ lw v0, REG_V0(k1)
+ lw v1, REG_V1(k1)
+
+ /* $4-$7 = a0-a3: Argument registers */
+
+ lw a0, REG_A0(k1)
+ lw a1, REG_A1(k1)
+ lw a2, REG_A2(k1)
+ lw a3, REG_A3(k1)
+
+ /* $8-$15 = t0-t7: Volatile registers */
+
+ lw t0, REG_T0(k1)
+ lw t1, REG_T1(k1)
+ lw t2, REG_T2(k1)
+ lw t3, REG_T3(k1)
+ lw t4, REG_T4(k1)
+ lw t5, REG_T5(k1)
+ lw t6, REG_T6(k1)
+ lw t7, REG_T7(k1)
+
+ /* $16-$23 = s0-s7: Static registers */
+
+ lw s0, REG_S0(k1)
+ lw s1, REG_S1(k1)
+ lw s2, REG_S2(k1)
+ lw s3, REG_S3(k1)
+ lw s4, REG_S4(k1)
+ lw s5, REG_S5(k1)
+ lw s6, REG_S6(k1)
+ lw s7, REG_S7(k1)
+
+ /* $24-25 = t8-t9: More Volatile registers */
+
+ lw t8, REG_T8(k1)
+ lw t9, REG_T9(k1)
+
+ /* $26-$27 = ko-k1: Reserved for use in exeption handers. These do not need to be
+ * saved.
+ *
+ * $28 = gp: Only needs to be saved under conditions where there are multiple, per-
+ * thread values for the GP.
+ */
+
+#ifdef MIPS32_SAVE_GP
+ lw gp, REG_GP(k1)
+#endif
+
+ /* $30 = either s8 or fp: Depends if a frame pointer is used or not */
+
+ lw s8, REG_S8(k1)
+
+ /* $31 = ra: Return address */
+
+ lw ra, REG_RA(k1)
+
+ /* Finally, restore CP status and the EPC */
+
+ lw k0, REG_STATUS(k1)
+ lw k1, REG_EPC(k1)
+ mtc0 k0, MIPS32_CP0_STATUS
+ ehb
+ mtc0 k1, MIPS32_CP0_EPC
+ eret
+ nop
+ .endm
+
+/********************************************************************************************
+ * Name: USE_INTSTACK
+ *
+ * Description:
+ * Switch to the interrupt stack (if enabled in the configuration).
+ *
+ * On Entry:
+ * sp - Current value of the user stack pointer
+ * tmp1, tmp2, and tmp3 are registers that can be used temporarily.
+ * All interrupts should still be disabled.
+ *
+ * At completion:
+ * If the nesting level is 0, then (1) the user stack pointer is saved at the base of the
+ * interrupt stack and sp points to the interrupt stack.
+ * The values of tmp1, tmp2, tmp3, and sp have been altered
+ *
+ ********************************************************************************************/
+
+ .macro USE_INTSTACK, tmp1, tmp2, tmp3
+#if CONFIG_ARCH_INTERRUPTSTACK > 3
+
+ /* Check the nesting level. If there are no nested interrupts, then we can
+ * claim the interrupt stack.
+ */
+
+ la \tmp1, g_nestlevel
+ lw \tmp2, (\tmp1)
+ bne 1f
+ nop
+
+ /* Use the interrupt stack, pushing the user stack pointer onto the interrupt
+ * stack first.
+ */
+
+ la \tmp3, g_intstack
+ sw sp, (\tmp3)
+ move sp, \tmp3
+1:
+ /* Increment the interrupt nesting level */
+
+ addiu \tmp2, \tmp2, 1
+ sw \tmp2, 0(\tmp1)
+#endif
+ .endm
+
+/********************************************************************************************
+ * Name: RESTORE_STACK
+ *
+ * Description:
+ * Restore the user stack. Not really.. actually only decrements the nesting level. We
+ * always get the new stack pointer for the register save array.
+ *
+ * On Entry:
+ * tmp1 and tmp2 are registers that can be used temporarily.
+ * All interrupts must be disabled.
+ *
+ * At completion:
+ * Current nesting level is decremented
+ * The values of tmp1 and tmp2 have been altered
+ *
+ ********************************************************************************************/
+
+ .macro RESTORE_STACK, tmp1, tmp2
+#if CONFIG_ARCH_INTERRUPTSTACK > 3
+
+ /* Decrement the nesting level */
+
+ la \tmp1, g_nestlevel
+ lw \tmp2, (\tmp1)
+ addiu \tmp2, \tmp2, -1
+ sw \tmp2, 0(\tmp1)
+#endif
+ .endm
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_MIPS_SRC_MIPS32_MIPS32_EXCPTMACROS_H */
diff --git a/nuttx/arch/mips/src/mips32/up_initialstate.c b/nuttx/arch/mips/src/mips32/up_initialstate.c index 89db4d7b9..2b200947e 100644 --- a/nuttx/arch/mips/src/mips32/up_initialstate.c +++ b/nuttx/arch/mips/src/mips32/up_initialstate.c @@ -54,6 +54,20 @@ * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_SUPPRESS_INTERRUPTS + + /* Enable only software interrupts */ + +# define INITIAL_STATUS (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_IM_SWINTS) + +#else + + /* Enable all interrupts */ + +# define INITIAL_STATUS (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_IM_ALL) + +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -83,13 +97,16 @@ void up_initial_state(_TCB *tcb) { struct xcptcontext *xcp = &tcb->xcp; - irqstate_t status; /* Initialize the initial exception register context structure */ memset(xcp, 0, sizeof(struct xcptcontext)); - /* Save the initial stack pointer */ + /* Save the initial stack pointer. Hmmm.. the stack is set to the very + * beginning of the stack region. Some functions may want to store data on + * the caller's stack and it might be good to reserve some space. However, + * only the start function would do that and we have control over that one + */ xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr; @@ -118,13 +135,6 @@ void up_initial_state(_TCB *tcb) /* Enable or disable interrupts, based on user configuration */ - status = cp0_getstatus(); -# ifdef CONFIG_SUPPRESS_INTERRUPTS - status &= ~CP0_STATUS_IM_MASK; /* Disable all interrupts */ - status |= CP0_STATUS_IM_SWINTS; /* Make sure that S/W interrupts enabled */ -#else - status |= CP0_STATUS_IM_ALL; /* Enable all interrupts */ -# endif - xcp->regs[REG_STATUS] = status; + xcp->regs[REG_STATUS] = INITIAL_STATUS; } diff --git a/nuttx/arch/mips/src/pic32mx/pic32mx-irq.c b/nuttx/arch/mips/src/pic32mx/pic32mx-irq.c index 3d7d363bc..fdaa232dc 100755 --- a/nuttx/arch/mips/src/pic32mx/pic32mx-irq.c +++ b/nuttx/arch/mips/src/pic32mx/pic32mx-irq.c @@ -60,6 +60,11 @@ /**************************************************************************** * Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifdef CONFIG_PIC32MX_MVEC +# error "Multi-vectors not supported" +#endif /**************************************************************************** * Public Data |