/***************************************************************************** * arch/sh/src/sh1/sh1_vector.S * * Copyright (C) 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * 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 configuration settings */ #include /* Board-specific settings */ #include /* IRQ definitons */ #include "chip.h" /* Chip-specific settings */ #include "up_internal.h" /***************************************************************************** * Definitions *****************************************************************************/ /***************************************************************************** * External references *****************************************************************************/ /* Called functions */ .globl _up_doirq /* C interrupt processing logic */ /***************************************************************************** * Macros *****************************************************************************/ /************************************************************************************ * Macro: trampoline * * Description: * Enter on exception with: * * SP -> PC * SR * * Branch to up_vector with: * * R4 : IRQ vector number * SP -> Saved R4 * PC * SR * ************************************************************************************/ .macro trampoline, irq, label mov.l r4, @-r15 /* Save the value of R4 on the stack */ mov.w .L\label, r4 /* R4=IRQ number */ bra _up_vector /* Jump to the common vector handling logic */ nop .L\label: .word \irq .endm /***************************************************************************** * Text *****************************************************************************/ .section .reset /***************************************************************************** * Name: _up_*_handler * * Description: * Trampoline entry points for each, individual IRQ * * R4 : Points to a the register save structure * *****************************************************************************/ .globl _up_invalid_handler _up_invalid_handler: trampoline NR_IRQS, 1 #ifdef CONFIG_SH1_DMAC0 .globl _up_dmac0_handler _up_dmac0_handler: trampoline SH1_DEI0_IRQ, 2 /* DEI0 */ #endif #ifdef CONFIG_SH1_DMAC1 .globl _up_dmac1_handler _up_dmac1_handler: trampoline SH1_DEI1_IRQ, 3 /* DEI1 */ #endif #ifdef CONFIG_SH1_DMAC2 .globl _up_dmac2_handler _up_dmac2_handler: trampoline SH1_DEI2_IRQ, 4 /* DEI2 */ #endif #ifdef CONFIG_SH1_DMAC3 .globl _up_dmac3_handler _up_dmac4_handler: trampoline SH1_DEI3_IRQ, 5 /* DEI3 */ #endif .globl _up_imia0_handler .globl _up_imib0_handler .globl _up_ovi0_handler _up_imia0_handler: trampoline SH1_IMIA0_IRQ, 6 /* IMIA0 */ _up_imib0_handler: trampoline SH1_IMIB0_IRQ, 7 /* IMIB0 */ _up_ovi0_handler: trampoline SH1_OVI0_IRQ, 8 /* OVI0 */ #ifdef CONFIG_SH1_ITU1 .globl _up_imia1_handler .globl _up_imib1_handler .globl _up_ovi1_handler _up_imia1_handler: trampoline SH1_IMIA1_IRQ, 9 /* IMIA1 */ _up_imib1_handler: trampoline SH1_IMIB1_IRQ, 10 /* IMIB1 */ _up_ovi1_handler: trampoline SH1_OVI1_IRQ, 11 /* OVI1 */ #endif #ifdef CONFIG_SH1_ITU2 .globl _up_imia2_handler .globl _up_imib2_handler .globl _up_ovi2_handler _up_imia2_handler: trampoline SH1_IMIA2_IRQ, 12 /* IMIA2 */ _up_imib2_handler: trampoline SH1_IMIB2_IRQ, 13 /* IMIB2 */ _up_ovi2_handler: trampoline SH1_OVI2_IRQ, 14 /* OVI2 */ #endif #ifdef CONFIG_SH1_ITU3 .globl _up_imia3_handler .globl _up_imib3_handler .globl _up_ovi3_handler _up_imia3_handler: trampoline SH1_IMIA3_IRQ, 15 /* IMIA3 */ _up_imib3_handler: trampoline SH1_IMIB3_IRQ, 16 /* IMIB3 */ _up_ovi3_handler: trampoline SH1_OVI3_IRQ, 17 /* OVI3 */ #endif #ifdef CONFIG_SH1_ITU4 .globl _up_imia4_handler .globl _up_imib4_handler .globl _up_ovi4_handler _up_imia4_handler: trampoline SH1_IMIA4_IRQ, 18 /* IMIA4 */ _up_imib4_handler: trampoline SH1_IMIB4_IRQ, 19 /* IMIB4 */ _up_ovi4_handler: trampoline SH1_OVI4_IRQ, 20 /* OVI4 */ #endif #ifdef CONFIG_SH1_SCI0 .globl _up_eri0_handler .globl _up_rxi0_handler .globl _up_txi0_handler .globl _up_tei0_handler _up_eri0_handler: trampoline SH1_ERI0_IRQ, 21 /* ERI0 */ _up_rxi0_handler: trampoline SH1_RXI0_IRQ, 22 /* RxI0 */ _up_txi0_handler: trampoline SH1_TXI0_IRQ, 23 /* TxI0 */ _up_tei0_handler: trampoline SH1_TEI0_IRQ, 24 /* TEI0 */ #endif #ifdef CONFIG_SH1_SCI1 .globl _up_eri1_handler .globl _up_rxi1_handler .globl _up_txi1_handler .globl _up_tei1_handler _up_eri1_handler: trampoline SH1_ERI1_IRQ, 25 /* ERI1 */ _up_rxi1_handler: trampoline SH1_RXI1_IRQ, 26 /* RxI1 */ _up_txi1_handler: trampoline SH1_TXI1_IRQ, 27 /* TxI1 */ _up_tei1_handler: trampoline SH1_TEI1_IRQ, 28 /* TEI1 */ #endif #ifdef CONFIG_SH1_PCU .globl _up_pei_handler _up_pei_handler: trampoline SH1_PEI_IRQ, 29 /* Parity control unit PEI */ #endif #ifdef CONFIG_SH1_AD .globl _up_aditi_handler _up_aditi_handler: trampoline SH1_ADITI_IRQ, 30 /* A/D ITI */ #endif #ifdef CONFIG_SH1_WDT .globl _up_wdt_handler _up_wdt_handler: trampoline SH1_WDTITI_IRQ, 31 /* WDT ITI */ #endif #ifdef CONFIG_SH1_CMI .globl _up_cmi_handler _up_cmi_handler: trampoline SH1_CMI_IRQ,32 /* REF CMI */ #endif /***************************************************************************** * Name: _up_vector * * Description: * Execption entry point. Upon entry: * * R4 : Holds IRQ number * SP -> Saved R4 (REG_R4=19) See irq.h * PC (REG_PC=20) * SR (REG_SR=21) * *****************************************************************************/ .global _up_vector .type _up_vector, #function _up_vector: /* Save r0-r3, r5-r7 on the stack so that we have a registers to work with. * After this, the stack will look like: * * SP -> macl (REG_MACL=10) See irq.h * mach (REG_MACH=11) * r0 (REG_R0=12) * r1 (REG_R1=13) * r2 (REG_R2=14) * r3 (REG_R3=15) * r5 (REG_R5=16) * r6 (REG_R6=17) * r7 (REG_R7=18) * R4 (REG_R4=19) * ... */ mov.l r7, @-r15 mov.l r6, @-r15 stc sr, r6 /* Mask all interrupts */ mov.l .Lintmask, r7 or r7, r6 ldc r6, sr mov.l r5, @-r15 mov.l r3, @-r15 mov.l r2, @-r15 mov.l r1, @-r15 mov.l r0, @-r15 sts.l mach, @-r15 sts.l macl, @-r15 /* Then save the value of the SP *before* the interrupt ocurred * * SP -> SP (REG_SP=9) See irq.h * macl (REG_MACL=10) * mach (REG_MACH=11) * ... */ mov r15, r5 /* R5 = current SP */ add #(12*4), r5 /* Account for sr, pc, r0-r7, mach, and macl */ mov.l r5, @-r15 /* Save the SP before the interrupt */ /* Save the remaining registers on the stack: * * SP -> r8 (REG_R8=0) See irq.h * r9 (REG_R9=1) * r10 (REG_R10=2) * r11 (REG_R11=3) * r12 (REG_R12=4) * r13 (REG_R13=5) * r14 (REG_R14=6) * pr (REG_PR=7) * gbr (REG_GBR=8) * SP (REG_SP=9) * ... */ stc.l gbr, @-r15 sts.l pr, @-r15 mov.l r14, @-r15 mov.l r13, @-r15 mov.l r12, @-r15 mov.l r11, @-r15 mov.l r10, @-r15 mov.l r9, @-r15 mov.l r8, @-r15 /* Setup parameters: R4=IRQ number, R5=base of saved state */ mov r15, r5 /* Switch to the interrupt stack */ #if CONFIG_ARCH_INTERRUPTSTACK > 3 mov.l .Lintstack, r15 /* SP = interrupt stack base */ mov.l r5, @r15 /* Save the user stack pointer (pre-decremented) */ /* Dispatch the interrupt */ mov.l .Ldoirq, r0 jsr @r0 nop /* Recover the user stack point */ mov.l @15, r15 #else /* Dispatch the interrupt */ mov.l .Ldoirq, r0 jsr @r0 nop #endif /* On return, R0 holds the address of the base of the XCPTCONTEXT * structure to use for the return -- may not be the same as the * one that we passed in via r5. If the value is different, then * we cannot assume that the values lie on the stack and we will * need to execute some more complete logic. */ cmp/eq r0, r15 bf .Lcontextswitch mov r0, r15 /* Restore registers from the stack. NOTE: We coudl improve interrupt * performance by skipping the restore of r8-r14. These will not * be modified by the called C code */ #if 1 /* Skip over static registers -- these will not be modified by the * called C code (r8-r14) */ add #(7*4), r15 /* 0-6: Skip over r8-r14 */ #else mov.l @r15+, r8 /* 0-6: r8-r14 */ mov.l @r15+, r9 mov.l @r15+, r10 mov.l @r15+, r11 mov.l @r15+, r12 mov.l @r15+, r13 mov.l @r15+, r14 #endif lds.l @r15+, pr /* 7-8: pr and gbr */ ldc.l @r15+, gbr add #4, r15 /* 9: Skip SP restore */ lds.l @r15+, macl /* 10-11: mach and macl */ lds.l @r15+, mach mov.l @r15+, r0 /* 12-18: r0-r3, r5-r7 */ mov.l @r15+, r1 mov.l @r15+, r2 mov.l @r15+, r3 mov.l @r15+, r5 mov.l @r15+, r6 mov.l @r15+, r7 mov.l @r15+, r4 /* 19: r4 */ rte /* 20-21: pc and sr */ nop .align 2 #if CONFIG_ARCH_INTERRUPTSTACK > 3 .Lintstack: .long _up_stackbase #endif .Ldoirq: .long _up_doirq .size _up_vector, .-_up_vector /***************************************************************************** * Name: _up_fullcontextrestore * * Description: * restore context from a set of save registers * * R4 : Points to a the register save structure * *****************************************************************************/ .global _up_fullcontextrestore .type _up_fullcontextrestore, #function _up_fullcontextrestore: /* Mask all interrupts */ stc sr, r8 mov.l .Lintmask, r9 or r9, r8 ldc r8, sr /* Replace stack pointer with the context save */ mov r4, r15 /* Restore registers from a context structure */ .Lcontextswitch: mov.l @r15+, r8 /* 0-8: r8-r14, pr, and gbr */ mov.l @r15+, r9 mov.l @r15+, r10 mov.l @r15+, r11 mov.l @r15+, r12 mov.l @r15+, r13 mov.l @r15+, r14 lds.l @r15+, pr ldc.l @r15+, gbr mov.l @r15+, r4 /* r4: Saved SP */ lds.l @r15+, macl /* 10-11: mach and macl */ lds.l @r15+, mach mov.l @r15+, r0 /* 12-17: r0-r3, r5-r6 */ mov.l @r15+, r1 mov.l @r15+, r2 mov.l @r15+, r3 mov.l @r15+, r5 mov.l @r15+, r6 /* Copy the remainder of the stack context to the target stack. * At this point r15 points to offset REG_R6. */ add #-16, r4 /* R4 points to offset REG_R7 in the new stack */ mov.l @r15+, r7 /* R7=Saved R7 value */ mov.l r7, @r4 /* Save at offset REG_R7 in the new stack */ mov.l @r15+, r7 /* R7=Save R4 value */ mov.l r7, @(4,r4) /* Save at offset REG_R4 in the new stack */ mov.l @r15+, r7 /* R7=Save PC value */ mov.l r7, @(8,r4) /* Save at offset REG_PC in the new stack */ mov.l @r15+, r7 /* R7=Save SR value */ mov.l r7, @(12,r4) /* Save at offset REG_SR in the new stack */ /* Set the new stack pointer */ mov r4, r15 /* Then recover the final register values from the new stack */ mov.l @r15+, r7 mov.l @r15+, r4 /* And return from interrupt */ rte nop .align 2 .Lintmask: .long 0x000000f0 .size _up_fullcontextrestore, .-_up_fullcontextrestore /************************************************************************************ * Name: up_interruptstack/g_userstack * * Description: * Shouldn't happen * ************************************************************************************/ #if CONFIG_ARCH_INTERRUPTSTACK > 3 .bss .align 2 .globl _g_userstack .type _g_userstack, object _up_interruptstack: .skip ((CONFIG_ARCH_INTERRUPTSTACK & ~3) - 4) _g_userstack: _up_stackbase: .skip 2 .size _g_userstack, 4 .size _up_interruptstack, (CONFIG_ARCH_INTERRUPTSTACK & ~3) #endif .end