source: rtems/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S @ 4b5e64a

Last change on this file since 4b5e64a was 4b5e64a, checked in by Joel Sherrill <joel@…>, on 02/16/22 at 22:51:56

score/cpu/nios2: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/*
4 * Copyright (c) 2011-2015 embedded brains GmbH.  All rights reserved.
5 *
6 *  embedded brains GmbH
7 *  Dornierstr. 4
8 *  82178 Puchheim
9 *  Germany
10 *  <rtems@embedded-brains.de>
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <rtems/score/percpu.h>
35#include <rtems/score/nios2-utility.h>
36
37#define FRAME_OFFSET_RA 0
38#define FRAME_OFFSET_AT 4
39#define FRAME_OFFSET_R2 8
40#define FRAME_OFFSET_R3 12
41#define FRAME_OFFSET_R4 16
42#define FRAME_OFFSET_R5 20
43#define FRAME_OFFSET_R6 24
44#define FRAME_OFFSET_R7 28
45#define FRAME_OFFSET_R8 32
46#define FRAME_OFFSET_R9 36
47#define FRAME_OFFSET_R10 40
48#define FRAME_OFFSET_R11 44
49#define FRAME_OFFSET_R12 48
50#define FRAME_OFFSET_R13 52
51#define FRAME_OFFSET_R14 56
52#define FRAME_OFFSET_R15 60
53#define FRAME_OFFSET_STATUS 64
54#define FRAME_OFFSET_EA  68
55
56#define FRAME_SIZE (FRAME_OFFSET_EA + 4)
57
58        .set    noat
59        .set    nobreak
60        .section        .text
61
62        .extern _Per_CPU_Information
63        .extern _Nios2_ISR_Status_interrupts_disabled
64
65        .globl  _Nios2_ISR_Dispatch_with_shadow_register_set
66
67_Nios2_ISR_Dispatch_with_shadow_register_set:
68
69        /* Load thread dispatch disable level */
70        ldw     r16, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp)
71
72        /* Read status */
73        rdctl   r18, status
74
75        /* Load high level handler address and argument */
76        ldw     r8, 4(et)
77        ldw     r4, 8(et)
78
79        /* Increment and store thread dispatch disable level */
80        addi    r17, r16, 1
81        stw     r17, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp)
82
83        /*
84         * Enable higher level interrupts.  This is safe since status.RSIE is
85         * always 0 and thread dispatching is disabled right above.  Higher
86         * priority interrupts shall not share shadow register sets with lower
87         * priority interrupts.
88         */
89        ori     r5, r18, 1
90        wrctl   status, r5
91
92        /* Call high level handler with argument */
93        callr   r8
94
95        /* Load the thread dispatch necessary indicator */
96        ldb     r12, %gprel(_Per_CPU_Information + PER_CPU_DISPATCH_NEEDED)(gp)
97
98        /* Load the thread dispatch after ISR disable indicator */
99        ldw     r13, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp)
100
101        /* Fix return address */
102        subi    ea, ea, 4
103
104        /*
105         * If the current thread dispatch disable level (r17) is one, then
106         * negate the thread dispatch necessary indicator, otherwise the value
107         * is irrelevant.  Or it with the previous thread dispatch disable
108         * level value (r16).  The r15 which will be used as a status to
109         * determine if a thread dispatch is necessary and allowed.
110         */
111        xor     r12, r17, r12
112        or      r15, r12, r16
113
114        /*
115         * Get the previous register set from r18.  If it is zero, then this is
116         * the outermost interrupt.  Or it to the thread dispatch status (r15).
117         */
118        andhi   r12, r18, 0x3f
119        or      r15, r12, r15
120
121        /*
122         * Or the thread dispatch after ISR disable indicator (r13) to the
123         * thread dispatch status (r15).
124         */
125        or      r15, r13, r15
126
127        /* Is a thread dispatch necessary and allowed? */
128        bne     r15, zero, no_thread_dispatch
129
130        /* Obtain stack frame in normal register set */
131        rdprs   r15, sp, -FRAME_SIZE
132
133        /* Disable thread dispatch after ISR */
134        stw     r17, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp)
135
136        /* Save context */
137        stw     sstatus, FRAME_OFFSET_STATUS(r15)
138        stw     ea, FRAME_OFFSET_EA(r15)
139
140        /* Set thread dispatch helper address */
141        movhi   ea, %hiadj(thread_dispatch_helper)
142        addi    ea, ea, %lo(thread_dispatch_helper)
143
144        /* Update stack pointer in normal register set */
145        wrprs   sp, r15
146
147        /* Jump to thread dispatch helper */
148        eret
149
150no_thread_dispatch:
151
152        /* Restore the thread dispatch disable level */
153        stw     r16, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp)
154
155        /* Return to interrupted context */
156        eret
157
158thread_dispatch_helper:
159
160        /* This code executes in the context of the interrupted thread */
161
162        /* Save volatile registers */
163        stw     ra, FRAME_OFFSET_RA(sp)
164        stw     at, FRAME_OFFSET_AT(sp)
165        stw     r2, FRAME_OFFSET_R2(sp)
166        stw     r3, FRAME_OFFSET_R3(sp)
167        stw     r4, FRAME_OFFSET_R4(sp)
168        stw     r5, FRAME_OFFSET_R5(sp)
169        stw     r6, FRAME_OFFSET_R6(sp)
170        stw     r7, FRAME_OFFSET_R7(sp)
171        stw     r8, FRAME_OFFSET_R8(sp)
172        stw     r9, FRAME_OFFSET_R9(sp)
173        stw     r10, FRAME_OFFSET_R10(sp)
174        stw     r11, FRAME_OFFSET_R11(sp)
175        stw     r12, FRAME_OFFSET_R12(sp)
176        stw     r13, FRAME_OFFSET_R13(sp)
177        stw     r14, FRAME_OFFSET_R14(sp)
178        stw     r15, FRAME_OFFSET_R15(sp)
179
180        /*
181         * Disable interrupts (1).
182         *
183         * We have the following invariants:
184         *   1. status.RSIE == 0: thread context initialization
185         *   2. status.CRS == 0: thread context initialization
186         *   3. status.PRS: arbitrary
187         *   4. status.IL < interrupt disable IL: else we would not be here
188         *   5. status.IH == 0: thread context initialization
189         *   6. status.U == 0: thread context initialization
190         *   7. status.PIE == 1: thread context initialization
191         * Thus we can use a constant to disable interrupts.
192         */
193        movi    r5, %lo(_Nios2_ISR_Status_interrupts_disabled)
194        wrctl   status, r5
195
196do_thread_dispatch:
197
198        addi    r4, gp, %gprel(_Per_CPU_Information)
199        call    _Thread_Do_dispatch
200
201        /* Restore some volatile registers */
202        ldw     ra, FRAME_OFFSET_RA(sp)
203        ldw     at, FRAME_OFFSET_AT(sp)
204        ldw     r2, FRAME_OFFSET_R2(sp)
205        ldw     r3, FRAME_OFFSET_R3(sp)
206        ldw     r4, FRAME_OFFSET_R4(sp)
207        ldw     r5, FRAME_OFFSET_R5(sp)
208        ldw     r6, FRAME_OFFSET_R6(sp)
209        ldw     r7, FRAME_OFFSET_R7(sp)
210        ldw     r8, FRAME_OFFSET_R8(sp)
211        ldw     r9, FRAME_OFFSET_R9(sp)
212        ldw     r10, FRAME_OFFSET_R10(sp)
213        ldw     r11, FRAME_OFFSET_R11(sp)
214        ldw     r12, FRAME_OFFSET_R12(sp)
215
216        /* Disable interrupts, see (1) */
217        rdctl   r14, status
218        movi    r15, %lo(_Nios2_ISR_Status_interrupts_disabled)
219        wrctl   status, r15
220
221        /* Load thread dispatch necessary */
222        ldb     r13, %gprel(_Per_CPU_Information + PER_CPU_DISPATCH_NEEDED)(gp)
223
224        /* Is thread dispatch necessary? */
225        bne     r13, zero, prepare_thread_dispatch
226
227        /* Enable thread dispatch after ISR */
228        stw     zero, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp)
229
230        /* Restore remaining volatile register */
231        ldw     r13, FRAME_OFFSET_R13(sp)
232        ldw     r14, FRAME_OFFSET_R14(sp)
233        ldw     r15, FRAME_OFFSET_R15(sp)
234
235        /* Restore context */
236        ldw     et, FRAME_OFFSET_STATUS(sp)
237        ldw     ea, FRAME_OFFSET_EA(sp)
238
239        /* Release stack frame */
240        addi    sp, sp, FRAME_SIZE
241
242        /* Restore context */
243        wrctl   estatus, et
244
245        /* Return to interrupted thread */
246        eret
247
248prepare_thread_dispatch:
249
250        /* Disable thread dispatching */
251        movi    r4, 1
252        stw     r4, %gprel(_Per_CPU_Information + PER_CPU_ISR_DISPATCH_DISABLE)(gp)
253        stw     r4, %gprel(_Per_CPU_Information + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)(gp)
254
255        /* Set interrupt level argument for _Thread_Do_dispatch() */
256        mov     r5, r15
257
258        br      do_thread_dispatch
Note: See TracBrowser for help on using the repository browser.