summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/arm/cpu_asm.S
blob: 60c638d80a66e3f6248b162978f20bb2389581bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
 *  $Id$
 *
 *  This file contains all assembly code for the ARM implementation
 *  of RTEMS.
 *
 *  Copyright (c) 2002 by Advent Networks, Inc.
 *          Jay Monkman <jmonkman@adventnetworks.com>
 *
 *  COPYRIGHT (c) 2000 Canon Research Centre France SA.
 *  Emmanuel Raguet, mailto:raguet@crf.canon.fr
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.OARcorp.com/rtems/license.html.
 *
 */

#include <asm.h>
#include <rtems/score/cpu_asm.h>


/*
 *  void _CPU_Context_switch( run_context, heir_context )
 *  void _CPU_Context_restore( run_context, heir_context )
 *
 *  This routine performs a normal non-FP context.
 *
 *  R0 = run_context    R1 = heir_context
 *
 *  This function copies the current registers to where r0 points, then
 *  restores the ones from where r1 points.
 *
 *
 *  NOTE:  The function should be able to only save/restore the registers
 *         that would be saved by a C function since the others have already
 *         been saved.
 *        
 *         It should also be able to use the stm/ldm instructions.
 *        
 */

        .globl _CPU_Context_switch
_CPU_Context_switch:
/* FIXME: This should use load and store multiple instructions */
/* Start saving context */
	str     r2,  [r0, #REG_R2]
	str     r3,  [r0, #REG_R3]
	str     r4,  [r0, #REG_R4]
	str     r5,  [r0, #REG_R5]
	str     r6,  [r0, #REG_R6]
	str     r7,  [r0, #REG_R7]
	str     r8,  [r0, #REG_R8]
	str     r9,  [r0, #REG_R9]
	str     r10, [r0, #REG_R10]
	
	str     r11, [r0, #REG_R11]
	str     r12, [r0, #REG_R12]	
	
	str     sp,  [r0, #REG_SP]
	str     lr,  [r0, #REG_PC]     /* save LR at PC's location */
	
	mrs	r2, cpsr
	str	r2,  [r0, #REG_CPSR]

/* Start restoring context */
        
       	ldr	r2,  [r1, #REG_CPSR]
	msr	cpsr, r2

	ldr     r2,  [r1, #REG_R2]
	ldr     r3,  [r1, #REG_R3]
	ldr     r4,  [r1, #REG_R4]
	ldr     r5,  [r1, #REG_R5]
	ldr     r6,  [r1, #REG_R6]
	ldr     r7,  [r1, #REG_R7]
	ldr     r8,  [r1, #REG_R8]
	ldr     r9,  [r1, #REG_R9]
	ldr     r10, [r1, #REG_R10]	
	ldr     r11, [r1, #REG_R11]
	ldr     r12, [r1, #REG_R12]	
	
	ldr     sp,  [r1, #REG_SP]
	ldr     lr,  [r1, #REG_PC]	
	mov	pc, lr

/*
 *  void _CPU_Context_restore( new_context )
 *
 *  This function copies the restores the registers from where r0 points.
 *  It must match _CPU_Context_switch()
 *
 *  NOTE:  The function should be able to only save/restore the registers
 *         that would be saved by a C function since the others have already
 *         been saved.
 *        
 *         It should also be able to use the stm/ldm instructions.
 *        
 */
        .globl _CPU_Context_restore
_CPU_Context_restore:
/* FIXME: This should use load and store multiple instructions */
	ldr	r2,  [r0, #REG_CPSR]
	msr	cpsr, r2

	ldr     r2,  [r0, #REG_R2]	
	ldr     r3,  [r0, #REG_R3]
	ldr     r4,  [r0, #REG_R4]
	ldr     r5,  [r0, #REG_R5]
	ldr     r6,  [r0, #REG_R6]
	ldr     r7,  [r0, #REG_R7]
	ldr     r8,  [r0, #REG_R8]
	ldr     r9,  [r0, #REG_R9]
	ldr     r10, [r0, #REG_R10]	
	ldr     r11, [r1, #REG_R11]
	ldr     r12, [r1, #REG_R12]	
			
	ldr     sp,  [r0, #REG_SP]
	ldr     lr,  [r0, #REG_PC]
	mov     pc,  lr	


/* FIXME:       _Exception_Handler_Undef_Swi is untested */
        .globl _Exception_Handler_Undef_Swi
_Exception_Handler_Undef_Swi:
/* FIXME: This should use load and store multiple instructions */
	sub     r13,r13,#SIZE_REGS
	str     r0,  [r13, #REG_R0]
	str     r1,  [r13, #REG_R1]
	str     r2,  [r13, #REG_R2]
	str     r3,  [r13, #REG_R3]
	str     r4,  [r13, #REG_R4]
	str     r5,  [r13, #REG_R5]
	str     r6,  [r13, #REG_R6]
	str     r7,  [r13, #REG_R7]
	str     r8,  [r13, #REG_R8]
	str     r9,  [r13, #REG_R9]
	str     r10, [r13, #REG_R10]
	str     r11, [r13, #REG_R11]
	str     r12, [r13, #REG_R12]
	str     sp,  [r13, #REG_SP]
	str     lr,  [r13, #REG_LR]
	mrs	r0,  cpsr		/* read the status */
	and	r0,  r0,#0x1f		/* we keep the mode as exception number */
	str	r0,  [r13, #REG_PC]     /* we store it in a free place */
	mov	r0,  r13		/* put frame address in r0 (C arg 1) */

	ldr	r1, =SWI_Handler
	ldr     lr, =_go_back_1
	ldr	pc,[r1]				/* call handler  */
_go_back_1:
	ldr     r0,  [r13, #REG_R0]
	ldr     r1,  [r13, #REG_R1]
	ldr     r2,  [r13, #REG_R2]
	ldr     r3,  [r13, #REG_R3]
	ldr     r4,  [r13, #REG_R4]
	ldr     r5,  [r13, #REG_R5]
	ldr     r6,  [r13, #REG_R6]
	ldr     r7,  [r13, #REG_R7]
	ldr     r8,  [r13, #REG_R8]
	ldr     r9,  [r13, #REG_R9]
	ldr     r10, [r13, #REG_R10]
	ldr     r11, [r13, #REG_R11]
	ldr     r12, [r13, #REG_R12]
	ldr     sp,  [r13, #REG_SP]
	ldr     lr,  [r13, #REG_LR]
	add     r13,r13,#SIZE_REGS
	movs	pc,r14			/* return  */ 
	
/* FIXME:       _Exception_Handler_Abort is untested */
        .globl _Exception_Handler_Abort
_Exception_Handler_Abort:
/* FIXME: This should use load and store multiple instructions */
	sub     r13,r13,#SIZE_REGS
	str     r0,  [r13, #REG_R0]
	str     r1,  [r13, #REG_R1]
	str     r2,  [r13, #REG_R2]
	str     r3,  [r13, #REG_R3]
	str     r4,  [r13, #REG_R4]
	str     r5,  [r13, #REG_R5]
	str     r6,  [r13, #REG_R6]
	str     r7,  [r13, #REG_R7]
	str     r8,  [r13, #REG_R8]
	str     r9,  [r13, #REG_R9]
	str     r10, [r13, #REG_R10]
	str     sp,  [r13, #REG_R11]
	str     lr,  [r13, #REG_R12]
	str     lr,  [r13, #REG_SP]
	str     lr,  [r13, #REG_LR]
	mrs	r0,  cpsr		/* read the status */
	and	r0,  r0,#0x1f		/* we keep the mode as exception number */
	str	r0,  [r13, #REG_PC]     /* we store it in a free place */
	mov	r0,  r13		/* put frame address in ro (C arg 1) */
	
	ldr	r1, =_currentExcHandler
	ldr     lr, =_go_back_2
	ldr	pc,[r1]				/* call handler  */
_go_back_2:
	ldr     r0,  [r13, #REG_R0]
	ldr     r1,  [r13, #REG_R1]
	ldr     r2,  [r13, #REG_R2]
	ldr     r3,  [r13, #REG_R3]
	ldr     r4,  [r13, #REG_R4]
	ldr     r5,  [r13, #REG_R5]
	ldr     r6,  [r13, #REG_R6]
	ldr     r7,  [r13, #REG_R7]
	ldr     r8,  [r13, #REG_R8]
	ldr     r9,  [r13, #REG_R9]
	ldr     r10, [r13, #REG_R10]
	ldr     sp,  [r13, #REG_R11]
	ldr     lr,  [r13, #REG_R12]
	ldr     lr,  [r13, #REG_SP]
	ldr     lr,  [r13, #REG_LR]
	add     r13,r13,#SIZE_REGS
	subs	pc,r14,#4			/* return */