source: rtems/cpukit/score/cpu/arm/arm_exc_interrupt.S @ 13c5cea

4.104.115
Last change on this file since 13c5cea was 9364cf66, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 07/17/09 at 15:16:50

adding lpc24xx BSP parts

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/**
2 * @file
3 *
4 * @brief ARM interrupt exception prologue and epilogue.
5 */
6
7/*
8 * Copyright (c) 2009
9 * embedded brains GmbH
10 * Obere Lagerstr. 30
11 * D-82178 Puchheim
12 * Germany
13 * <rtems@embedded-brains.de>
14 *
15 * The license and distribution terms for this file may be
16 * found in the file LICENSE in this distribution or at
17 * http://www.rtems.com/license/LICENSE.
18 */
19
20/*
21 * These two non-volatile registers contain the program status for INT and SVC
22 * mode.  It is important that they are directly accessible in THUMB
23 * instruction mode.
24 */
25#define MODE_INT r4
26#define MODE_SVC r5
27
28/*
29 * These three non-volatile registers are used to exchange information between
30 * INT and SVC mode.
31 */
32#define SCRATCH_0 r6
33#define SCRATCH_1 r7
34#define SCRATCH_2 r8
35
36/* List of scratch registers.  They will be saved and restored in INT mode. */
37#define SCRATCH_LIST {SCRATCH_0, SCRATCH_1, SCRATCH_2}
38
39/*
40 * List of all volatile registers (r0, r1, r2, r3, r12 and lr), registers
41 * containing the interrupt context (return address in SCRATCH_0 and saved
42 * program status in SCRATCH_1) and non-volatile registers used for modes
43 * (MODE_INT and MODE_SVC).  They will be saved and restored in SVC mode.
44 */
45#define TASK_CONTEXT_LIST \
46        {r0, r1, r2, r3, MODE_INT, MODE_SVC, SCRATCH_0, SCRATCH_1, r12, lr}
47
48/*
49 * List of all volatile registers (r0, r1, r2, r3, r12 and lr) and the saved
50 * program status (SCRATCH_0 register).  They will be saved and restored in INT
51 * mode.
52 */
53#define INTERRUPT_CONTEXT_LIST \
54        {r0, r1, r2, r3, SCRATCH_0, r12, lr}
55
56.extern _ISR_Thread_dispatch
57.extern _ISR_Nest_level
58.extern _Thread_Dispatch_disable_level
59.extern bsp_interrupt_dispatch
60
61.arm
62.globl arm_exc_interrupt
63arm_exc_interrupt:
64
65        /* Save scratch registers on INT stack */
66        stmdb   sp!, SCRATCH_LIST
67
68        /* Increment interrupt nest level */
69        ldr     SCRATCH_0, =_ISR_Nest_level
70        ldr     SCRATCH_1, [SCRATCH_0]
71        add     SCRATCH_2, SCRATCH_1, #1
72        str     SCRATCH_2, [SCRATCH_0]
73
74        /* Branch for nested interrupts */
75        cmp     SCRATCH_1, #0
76        bne     nested_interrupt_context_save
77
78        /* Move interrupt context and CPSR to scratch registers */
79        mov     SCRATCH_0, lr
80        mrs     SCRATCH_1, spsr
81        mrs     SCRATCH_2, cpsr
82
83        /* Switch to SVC mode */
84        orr     SCRATCH_2, SCRATCH_2, #0x1
85        msr     cpsr_c, SCRATCH_2
86
87        /* Save context on SVC stack */
88        stmdb   sp!, TASK_CONTEXT_LIST
89
90        /* Save SVC mode program status to non-volatile register */
91        mov     MODE_SVC, SCRATCH_2
92
93        /* Save INT mode program status to non-volatile register */
94        bic     MODE_INT, MODE_SVC, #0x1
95       
96        /* Switch to INT mode */
97        msr     cpsr_c, MODE_INT
98
99        /* Restore scratch registers from INT stack */
100        ldmia   sp!, SCRATCH_LIST
101
102        /*
103         * At this point the INT stack is in the exception entry state and
104         * contains no data for us.  The context is saved on the SVC stack.  We
105         * can easily switch modes via the registers MODE_INT and MODE_SVC
106         * which are valid through subroutine calls.  We can use all volatile
107         * registers in both modes.  Note that this comment describes the non
108         * nested interrupt entry.  For a nested interrupt things are
109         * different, since we can save everything on the INT stack and there
110         * is no need to switch modes.
111         */
112
113task_context_save_done:
114
115        /* Switch to THUMB instructions if necessary */
116#ifdef __thumb__
117        add     r0, pc, #1
118        bx      r0
119.thumb
120#endif /* __thumb__ */
121
122        /* Increment thread dispatch disable level */
123        ldr     r1, =_Thread_Dispatch_disable_level
124        ldr     r3, [r1]
125        add     r3, r3, #1
126        str     r3, [r1]
127
128        /* Call BSP dependent interrrupt dispatcher */
129        bl      bsp_interrupt_dispatch
130
131        /* Decrement interrupt nest and thread dispatch disable level */
132        ldr     r0, =_ISR_Nest_level
133        ldr     r1, =_Thread_Dispatch_disable_level
134        ldr     r2, [r0]
135        ldr     r3, [r1]
136        sub     r2, r2, #1
137        sub     r3, r3, #1
138        str     r2, [r0]
139        str     r3, [r1]
140
141        /* Switch to ARM instructions if necessary */
142#ifdef __thumb__
143.align 2
144        bx      pc
145.arm
146#endif /* __thumb__ */
147
148        /* Branch if we have a nested interrupt */
149        cmp     r2, #0
150        bne     nested_interrupt_return
151
152        /* Branch if thread dispatching is disabled */
153        cmp     r3, #0
154        bne     thread_dispatch_done
155       
156        /*
157         * Switch to SVC mode.  It is important to call the thread dispatcher
158         * in SVC mode since overwise the INT stack may need to store an
159         * arbitrary number of contexts and it may lead to an invalid order of
160         * stack operations.
161         */
162        msr     cpsr_c, MODE_SVC
163
164        /* Call thread dispatcher */
165#ifdef __thumb__
166        ldr     r0, =_ISR_Thread_dispatch
167        mov     lr, pc
168        bx      r0
169.thumb
170        bx      pc
171        nop
172.arm
173#else
174        bl      _ISR_Thread_dispatch
175#endif
176
177        /* Switch to INT mode */
178        msr     cpsr_c, MODE_INT
179
180thread_dispatch_done:
181
182        /* Save scratch registers on INT stack */
183        stmdb   sp!, SCRATCH_LIST
184
185        /* Switch to SVC mode */
186        msr     cpsr_c, MODE_SVC
187
188        /* Move INT mode program status to scratch register */
189        mov     SCRATCH_2, MODE_INT
190
191        /* Restore context from SVC stack */
192        ldmia   sp!, TASK_CONTEXT_LIST
193
194        /* Switch to INT mode */
195        msr     cpsr_c, SCRATCH_2
196
197        /* Restore interrupt context */
198        mov     lr, SCRATCH_0
199        msr     spsr, SCRATCH_1
200
201        /* Restore scratch registers from INT stack */
202        ldmia   sp!, SCRATCH_LIST
203
204        /* Return from interrupt */
205        subs    pc, lr, #4
206
207nested_interrupt_context_save:
208
209        /* Move saved program status register to scratch register */
210        mrs     SCRATCH_0, spsr
211
212        /* Save context on INT stack */
213        stmdb   sp!, INTERRUPT_CONTEXT_LIST
214
215        b       task_context_save_done
216
217nested_interrupt_return:
218
219        /* Restore context from INT stack */
220        ldmia   sp!, INTERRUPT_CONTEXT_LIST
221
222        /* Restore saved program status register */
223        msr     spsr, SCRATCH_0
224
225        /* Restore scratch registers from INT stack */
226        ldmia   sp!, SCRATCH_LIST
227
228        /* Return from interrupt */
229        subs    pc, lr, #4
Note: See TracBrowser for help on using the repository browser.