Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:25

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  This file contains all assembly code for the
0005  *  NIOS2 implementation of RTEMS.
0006  *
0007  *  Copyright (c) 2006 Kolja Waschk (rtemsdev/ixo.de)
0008  *
0009  *  Derived from no_cpu/cpu_asm.S, copyright (c) 1989-1999,
0010  *    On-Line Applications Research Corporation (OAR).
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  *
0033  */
0034 
0035 #ifdef HAVE_CONFIG_H
0036 #include "config.h"
0037 #endif
0038 
0039 #include <rtems/asm.h>
0040 #include <rtems/score/cpu_asm.h>
0041 
0042     .set noat
0043 
0044     .globl _exception_vector
0045 
0046 _exception_vector:
0047 
0048     /*
0049      * First, re-wind so we're pointed to the instruction where the exception
0050      * occurred.
0051      */
0052 
0053     addi ea, ea, -4
0054 
0055     /*
0056      * Now test to determine the cause of the exception.
0057      */
0058 
0059     /* TODO: Look at [ea] if there was an unknown/trap instruction */
0060 
0061     /* If interrupts are globally disabled, it certainly was no interrupt */
0062     rdctl et, estatus
0063     andi et, et, 1
0064     beq et, zero, _Exception_Handler
0065 
0066     /* If no interrupts are pending, it was a software exception */
0067     rdctl et, ipending
0068     beq et, zero, _Exception_Handler
0069 
0070     /*
0071      * Falling through to here means that this was a hardware interrupt.
0072      */
0073 
0074     br _ISR_Handler
0075 
0076 /* =====================================================================
0077  * Exception handler:
0078  *   Responsible for unimplemented instructions and other software
0079  *   exceptions. Not responsible for hardware interrupts. Currently,
0080  *   software exceptions are regarded as error conditions, and the
0081  *   handling isn't perfect. */
0082 
0083 _Exception_Handler:
0084 
0085     /* stw et, 108(sp') => stw et, -20(sp) */
0086     stw et, -20(sp)
0087     mov et, sp
0088     addi sp, sp, -128
0089 
0090     stw r1,   0(sp)
0091     stw r2,   4(sp)
0092     stw r3,   8(sp)
0093 
0094     rdctl r1, estatus
0095     rdctl r2, ienable
0096     rdctl r3, ipending
0097 
0098     stw r4,   12(sp)
0099     stw r5,   16(sp)
0100     stw r6,   20(sp)
0101     stw r7,   24(sp)
0102     stw r8,   28(sp)
0103     stw r9,   32(sp)
0104     stw r10,  36(sp)
0105     stw r11,  40(sp)
0106     stw r12,  44(sp)
0107     stw r13,  48(sp)
0108     stw r14,  52(sp)
0109     stw r15,  56(sp)
0110     stw r16,  60(sp)
0111     stw r17,  64(sp)
0112     stw r18,  68(sp)
0113     stw r19,  72(sp)
0114     stw r20,  76(sp)
0115     stw r21,  80(sp)
0116     stw r22,  84(sp)
0117     stw r23,  88(sp)
0118     stw gp,   92(sp)
0119     stw fp,   96(sp)
0120     /* sp */
0121     stw et,  100(sp)
0122     stw ra,  104(sp)
0123     /* stw et,  108(sp) */
0124     stw ea,  112(sp)
0125 
0126     /* status */
0127     stw r1, 116(sp)
0128     /* ienable */
0129     stw r2, 120(sp)
0130     /* ipending */
0131     stw r3, 124(sp)
0132 
0133     /*
0134      * Restore the global pointer.
0135      */
0136 
0137     movhi gp, %hiadj(_gp)
0138     addi gp, gp, %lo(_gp)
0139 
0140     /*
0141      * Pass a pointer to the stack frame as the input argument of the
0142      * exception handler (CPU_Exception_frame *).
0143      */
0144 
0145     mov r4, sp
0146 
0147     /*
0148      * Call the exception handler.
0149      */
0150 
0151     .extern __Exception_Handler
0152     call __Exception_Handler
0153 
0154 stuck_in_exception:
0155     br stuck_in_exception
0156 
0157     /*
0158      * Restore the saved registers, so that all general purpose registers
0159      * have been restored to their state at the time the interrupt occurred.
0160      */
0161 
0162     ldw r1,   0(sp)
0163     ldw r2,   4(sp)
0164     ldw r3,   8(sp)
0165     ldw r4,   12(sp)
0166     ldw r5,   16(sp)
0167     ldw r6,   20(sp)
0168     ldw r7,   24(sp)
0169     ldw r8,   28(sp)
0170     ldw r9,   32(sp)
0171     ldw r10,  36(sp)
0172     ldw r11,  40(sp)
0173     ldw r12,  44(sp)
0174     ldw r13,  48(sp)
0175     ldw r14,  52(sp)
0176     ldw r15,  56(sp)
0177     ldw r16,  60(sp)
0178     ldw r17,  64(sp)
0179     ldw r18,  68(sp)
0180     ldw r19,  72(sp)
0181     ldw r20,  76(sp)
0182     ldw r21,  80(sp)
0183     ldw r22,  84(sp)
0184     ldw r23,  88(sp)
0185     ldw gp,   92(sp)
0186     ldw fp,   96(sp)
0187     ldw ra,  104(sp)
0188 
0189     /* Disable interrupts */
0190     wrctl status, r0
0191 
0192     ldw ea,  112(sp)
0193     ldw et,  116(sp)
0194 
0195     /* FIXME: Enable interrupts after exception processing */
0196     ori et, et, 1
0197     wrctl estatus, et
0198     ldw et,  108(sp)
0199 
0200     /* Restore stack pointer */
0201     ldw sp,  100(sp)
0202 
0203     eret
0204 
0205 /* ===================================================================== */
0206 
0207     .section .text
0208 
0209 _ISR_Handler:
0210 
0211     /*
0212      * Process an external hardware interrupt.
0213      *
0214      * First, preserve all callee saved registers on
0215      * the stack. (See the Nios2 ABI documentation for details).
0216      *
0217      * Do we really need to save all?
0218      *
0219      * If this is interrupting a task (and not another interrupt),
0220      * everything is saved into the task's stack, thus putting us
0221      * in a situation similar to when the task calls a subroutine
0222      * (and only the CPU_Context_Control subset needs to be changed)
0223      */
0224 
0225     rdctl et, estatus
0226 
0227     /* Keep this in the same order as CPU_Interrupt_frame: */
0228 
0229     addi sp, sp, -76
0230     stw r1,  0(sp)
0231     stw r2,  4(sp)
0232     stw r3,  8(sp)
0233     stw r4,  12(sp)
0234     stw r5,  16(sp)
0235     stw r6,  20(sp)
0236     stw r7,  24(sp)
0237     stw r8,  28(sp)
0238     stw r9,  32(sp)
0239     stw r10, 36(sp)
0240     stw r11, 40(sp)
0241     stw r12, 44(sp)
0242     stw r13, 48(sp)
0243     stw r14, 52(sp)
0244     stw r15, 56(sp)
0245     stw ra,  60(sp)
0246     stw gp,  64(sp)
0247     /* et contains status */
0248     stw et,  68(sp)
0249     stw ea,  72(sp)
0250 
0251 #if REMOVED_BY_CCJ
0252     /*
0253      * Obtain a bitlist of the pending interrupts.
0254      */
0255 
0256     rdctl et, ipending
0257 
0258     /*
0259      * Restore the global pointer to the expected value.
0260      */
0261 
0262     movhi gp, %hiadj(_gp)
0263     addi gp, gp, %lo(_gp)
0264 
0265     /*
0266      * Search through the bit list stored in r24(et) to find the first enabled
0267      * bit. The offset of this bit is the index of the interrupt that is
0268      * to be handled.
0269      */
0270 
0271     mov r4, zero
0272 6:
0273     andi r3, r24, 1
0274     bne r3, zero, 7f
0275     addi r4, r4, 1
0276     srli r24, r24, 1
0277     br 6b
0278 7:
0279 
0280     /*
0281      * Having located the interrupt source, r4 contains the index of the
0282      * interrupt to be handled. r5, the 2nd argument to the function,
0283      * will point to the CPU_Interrupt_frame.
0284      */
0285 
0286     mov     r5, sp
0287 #endif
0288     
0289     .extern __ISR_Handler
0290     call    __ISR_Handler
0291 
0292     /*
0293      * Now that the interrupt processing is complete, prepare to return to
0294      * the interrupted code.
0295      */
0296 
0297     /*
0298      * Restore the saved registers, so that all general purpose registers
0299      * have been restored to their state at the time the interrupt occurred.
0300      */
0301 
0302     ldw r1,   0(sp)
0303     ldw r2,   4(sp)
0304     ldw r3,   8(sp)
0305     ldw r4,  12(sp)
0306     ldw r5,  16(sp)
0307     ldw r6,  20(sp)
0308     ldw r7,  24(sp)
0309     ldw r8,  28(sp)
0310     ldw r9,  32(sp)
0311     ldw r10, 36(sp)
0312     ldw r11, 40(sp)
0313     ldw r12, 44(sp)
0314     ldw r13, 48(sp)
0315     ldw r14, 52(sp)
0316     ldw r15, 56(sp)
0317     ldw ra,  60(sp)
0318     ldw gp,  64(sp)
0319 
0320     /* Disable interrupts */
0321     wrctl status, r0
0322 
0323     /* Restore the exception registers */
0324 
0325     /* load saved ea into ea */
0326     ldw ea,  72(sp)
0327     /* load saved estatus into et */
0328     ldw et,  68(sp)
0329     /* Always have interrupts enabled when we return from interrupt */
0330     ori et, et, 1
0331     wrctl estatus, et
0332     /* Restore the stack pointer */
0333     addi sp, sp, 76
0334 
0335     /*
0336      * Return to the interrupted instruction.
0337      */
0338     eret
0339 
0340