context_ccs.asm
7.1 KB
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
;/*
; * Copyright (c) 2006-2022, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2009-01-20 Bernard first version
; * 2011-07-22 Bernard added thumb mode porting
; * 2013-05-24 Grissiom port to CCS
; * 2013-05-26 Grissiom optimize for ARMv7
; */
.text
.arm
.ref rt_thread_switch_interrupt_flag
.ref rt_interrupt_from_thread
.ref rt_interrupt_to_thread
.ref rt_interrupt_enter
.ref rt_interrupt_leave
.ref rt_hw_trap_irq
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
.def rt_hw_interrupt_disable
.asmfunc
rt_hw_interrupt_disable
MRS r0, cpsr
CPSID IF
BX lr
.endasmfunc
;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
.def rt_hw_interrupt_enable
.asmfunc
rt_hw_interrupt_enable
MSR cpsr_c, r0
BX lr
.endasmfunc
;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
.def rt_hw_context_switch
.asmfunc
rt_hw_context_switch
STMDB sp!, {lr} ; push pc (lr should be pushed in place of PC)
STMDB sp!, {r0-r12, lr} ; push lr & register file
MRS r4, cpsr
TST lr, #0x01
ORRNE r4, r4, #0x20 ; it's thumb code
STMDB sp!, {r4} ; push cpsr
.if (__TI_VFP_SUPPORT__)
VMRS r4, fpexc
TST r4, #0x40000000
BEQ __no_vfp_frame1
VSTMDB sp!, {d0-d15}
VMRS r5, fpscr
; TODO: add support for Common VFPv3.
; Save registers like FPINST, FPINST2
STMDB sp!, {r5}
__no_vfp_frame1
STMDB sp!, {r4}
.endif
STR sp, [r0] ; store sp in preempted tasks TCB
LDR sp, [r1] ; get new task stack pointer
.if (__TI_VFP_SUPPORT__)
LDMIA sp!, {r0} ; get fpexc
VMSR fpexc, r0 ; restore fpexc
TST r0, #0x40000000
BEQ __no_vfp_frame2
LDMIA sp!, {r1} ; get fpscr
VMSR fpscr, r1
VLDMIA sp!, {d0-d15}
__no_vfp_frame2
.endif
LDMIA sp!, {r4} ; pop new task cpsr to spsr
MSR spsr_cxsf, r4
LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr
.endasmfunc
;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; */
.def rt_hw_context_switch_to
.asmfunc
rt_hw_context_switch_to
LDR sp, [r0] ; get new task stack pointer
.if (__TI_VFP_SUPPORT__)
LDMIA sp!, {r0} ; get fpexc
VMSR fpexc, r0
TST r0, #0x40000000
BEQ __no_vfp_frame_to
LDMIA sp!, {r1} ; get fpscr
VMSR fpscr, r1
VLDMIA sp!, {d0-d15}
__no_vfp_frame_to
.endif
LDMIA sp!, {r4} ; pop new task cpsr to spsr
MSR spsr_cxsf, r4
LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr
.endasmfunc
;/*
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
; */
.def rt_hw_context_switch_interrupt
.asmfunc
rt_hw_context_switch_interrupt
LDR r2, pintflag
LDR r3, [r2]
CMP r3, #1
BEQ _reswitch
MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1
STR r3, [r2]
LDR r2, pfromthread ; set rt_interrupt_from_thread
STR r0, [r2]
_reswitch
LDR r2, ptothread ; set rt_interrupt_to_thread
STR r1, [r2]
BX lr
.endasmfunc
.def IRQ_Handler
IRQ_Handler
STMDB sp!, {r0-r12,lr}
.if (__TI_VFP_SUPPORT__)
VMRS r0, fpexc
TST r0, #0x40000000
BEQ __no_vfp_frame_str_irq
VSTMDB sp!, {d0-d15}
VMRS r1, fpscr
; TODO: add support for Common VFPv3.
; Save registers like FPINST, FPINST2
STMDB sp!, {r1}
__no_vfp_frame_str_irq
STMDB sp!, {r0}
.endif
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
; if rt_thread_switch_interrupt_flag set, jump to
; rt_hw_context_switch_interrupt_do and don't return
LDR r0, pintflag
LDR r1, [r0]
CMP r1, #1
BEQ rt_hw_context_switch_interrupt_do
.if (__TI_VFP_SUPPORT__)
LDMIA sp!, {r0} ; get fpexc
VMSR fpexc, r0
TST r0, #0x40000000
BEQ __no_vfp_frame_ldr_irq
LDMIA sp!, {r1} ; get fpscr
VMSR fpscr, r1
VLDMIA sp!, {d0-d15}
__no_vfp_frame_ldr_irq
.endif
LDMIA sp!, {r0-r12,lr}
SUBS pc, lr, #4
; /*
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
; */
.def rt_hw_context_switch_interrupt_do
rt_hw_context_switch_interrupt_do
MOV r1, #0 ; clear flag
STR r1, [r0]
.if (__TI_VFP_SUPPORT__)
LDMIA sp!, {r0} ; get fpexc
VMSR fpexc, r0
TST r0, #0x40000000
BEQ __no_vfp_frame_do1
LDMIA sp!, {r1} ; get fpscr
VMSR fpscr, r1
VLDMIA sp!, {d0-d15}
__no_vfp_frame_do1
.endif
LDMIA sp!, {r0-r12,lr} ; reload saved registers
STMDB sp, {r0-r3} ; save r0-r3. We will restore r0-r3 in the SVC
; mode so there is no need to update SP.
SUB r1, sp, #16 ; save the right SP value in r1, so we could restore r0-r3.
SUB r2, lr, #4 ; save old task's pc to r2
MRS r3, spsr ; get cpsr of interrupt thread
; switch to SVC mode and no interrupt
CPSID IF, #0x13
STMDB sp!, {r2} ; push old task's pc
STMDB sp!, {r4-r12,lr} ; push old task's lr,r12-r4
LDMIA r1!, {r4-r7} ; restore r0-r3 of the interrupted thread
STMDB sp!, {r4-r7} ; push old task's r3-r0. We don't need to push/pop them to
; r0-r3 because we just want to transfer the data and don't
; use them here.
STMDB sp!, {r3} ; push old task's cpsr
.if (__TI_VFP_SUPPORT__)
VMRS r0, fpexc
TST r0, #0x40000000
BEQ __no_vfp_frame_do2
VSTMDB sp!, {d0-d15}
VMRS r1, fpscr
; TODO: add support for Common VFPv3.
; Save registers like FPINST, FPINST2
STMDB sp!, {r1}
__no_vfp_frame_do2
STMDB sp!, {r0}
.endif
LDR r4, pfromthread
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
LDR r6, ptothread
LDR r6, [r6]
LDR sp, [r6] ; get new task's stack pointer
.if (__TI_VFP_SUPPORT__)
LDMIA sp!, {r0} ; get fpexc
VMSR fpexc, r0
TST r0, #0x40000000
BEQ __no_vfp_frame_do3
LDMIA sp!, {r1} ; get fpscr
VMSR fpscr, r1
VLDMIA sp!, {d0-d15}
__no_vfp_frame_do3
.endif
LDMIA sp!, {r4} ; pop new task's cpsr to spsr
MSR spsr_cxsf, r4
LDMIA sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr
pintflag .word rt_thread_switch_interrupt_flag
pfromthread .word rt_interrupt_from_thread
ptothread .word rt_interrupt_to_thread