xref: /nrf52832-nimble/rt-thread/libcpu/arm/cortex-r4/context_ccs.asm (revision 104654410c56c573564690304ae786df310c91fc)
1;/*
2; * Copyright (c) 2006-2018, RT-Thread Development Team
3; *
4; * SPDX-License-Identifier: Apache-2.0
5; *
6; * Change Logs:
7; * Date           Author       Notes
8; * 2009-01-20     Bernard      first version
9; * 2011-07-22     Bernard      added thumb mode porting
10; * 2013-05-24     Grissiom     port to CCS
11; * 2013-05-26     Grissiom     optimize for ARMv7
12; */
13
14   .text
15   .arm
16   .ref rt_thread_switch_interrupt_flag
17   .ref rt_interrupt_from_thread
18   .ref rt_interrupt_to_thread
19   .ref rt_interrupt_enter
20   .ref rt_interrupt_leave
21   .ref rt_hw_trap_irq
22
23;/*
24; * rt_base_t rt_hw_interrupt_disable();
25; */
26    .def rt_hw_interrupt_disable
27    .asmfunc
28rt_hw_interrupt_disable
29    MRS r0, cpsr
30    CPSID IF
31    BX  lr
32    .endasmfunc
33
34;/*
35; * void rt_hw_interrupt_enable(rt_base_t level);
36; */
37    .def rt_hw_interrupt_enable
38    .asmfunc
39rt_hw_interrupt_enable
40    MSR cpsr_c, r0
41    BX  lr
42    .endasmfunc
43
44;/*
45; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
46; * r0 --> from
47; * r1 --> to
48; */
49    .def rt_hw_context_switch
50    .asmfunc
51rt_hw_context_switch
52    STMDB   sp!, {lr}           ; push pc (lr should be pushed in place of PC)
53    STMDB   sp!, {r0-r12, lr}   ; push lr & register file
54
55    MRS     r4, cpsr
56    TST     lr, #0x01
57    ORRNE   r4, r4, #0x20       ; it's thumb code
58
59    STMDB   sp!, {r4}           ; push cpsr
60
61    .if (__TI_VFP_SUPPORT__)
62		VMRS    r4,  fpexc
63        TST     r4,  #0x40000000
64        BEQ     __no_vfp_frame1
65		VSTMDB  sp!, {d0-d15}
66        VMRS    r5, fpscr
67        ; TODO: add support for Common VFPv3.
68        ;       Save registers like FPINST, FPINST2
69        STMDB   sp!, {r5}
70__no_vfp_frame1
71        STMDB   sp!, {r4}
72	.endif
73
74    STR     sp, [r0]            ; store sp in preempted tasks TCB
75    LDR     sp, [r1]            ; get new task stack pointer
76
77    .if (__TI_VFP_SUPPORT__)
78        LDMIA   sp!, {r0}       ; get fpexc
79        VMSR    fpexc,  r0      ; restore fpexc
80        TST     r0,  #0x40000000
81        BEQ     __no_vfp_frame2
82        LDMIA   sp!, {r1}       ; get fpscr
83        VMSR    fpscr, r1
84		VLDMIA  sp!, {d0-d15}
85__no_vfp_frame2
86    .endif
87
88    LDMIA   sp!, {r4}           ; pop new task cpsr to spsr
89    MSR     spsr_cxsf, r4
90
91    LDMIA   sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr
92    .endasmfunc
93
94;/*
95; * void rt_hw_context_switch_to(rt_uint32 to);
96; * r0 --> to
97; */
98    .def rt_hw_context_switch_to
99    .asmfunc
100rt_hw_context_switch_to
101    LDR     sp, [r0]            ; get new task stack pointer
102
103    .if (__TI_VFP_SUPPORT__)
104        LDMIA   sp!, {r0}       ; get fpexc
105        VMSR    fpexc, r0
106        TST     r0,  #0x40000000
107        BEQ     __no_vfp_frame_to
108        LDMIA   sp!, {r1}       ; get fpscr
109        VMSR    fpscr, r1
110		VLDMIA  sp!, {d0-d15}
111__no_vfp_frame_to
112    .endif
113
114    LDMIA   sp!, {r4}           ; pop new task cpsr to spsr
115    MSR     spsr_cxsf, r4
116
117    LDMIA   sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr
118    .endasmfunc
119
120;/*
121; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
122; */
123
124    .def rt_hw_context_switch_interrupt
125    .asmfunc
126rt_hw_context_switch_interrupt
127    LDR r2, pintflag
128    LDR r3, [r2]
129    CMP r3, #1
130    BEQ _reswitch
131    MOV r3, #1              ; set rt_thread_switch_interrupt_flag to 1
132    STR r3, [r2]
133    LDR r2, pfromthread     ; set rt_interrupt_from_thread
134    STR r0, [r2]
135_reswitch
136    LDR r2, ptothread       ; set rt_interrupt_to_thread
137    STR r1, [r2]
138    BX  lr
139    .endasmfunc
140
141    .def IRQ_Handler
142IRQ_Handler
143    STMDB   sp!, {r0-r12,lr}
144
145    .if (__TI_VFP_SUPPORT__)
146		VMRS    r0,  fpexc
147        TST     r0,  #0x40000000
148        BEQ     __no_vfp_frame_str_irq
149		VSTMDB  sp!, {d0-d15}
150        VMRS    r1, fpscr
151        ; TODO: add support for Common VFPv3.
152        ;       Save registers like FPINST, FPINST2
153        STMDB   sp!, {r1}
154__no_vfp_frame_str_irq
155        STMDB   sp!, {r0}
156	.endif
157
158    BL  rt_interrupt_enter
159    BL  rt_hw_trap_irq
160    BL  rt_interrupt_leave
161
162    ; if rt_thread_switch_interrupt_flag set, jump to
163    ; rt_hw_context_switch_interrupt_do and don't return
164    LDR r0, pintflag
165    LDR r1, [r0]
166    CMP r1, #1
167    BEQ rt_hw_context_switch_interrupt_do
168
169    .if (__TI_VFP_SUPPORT__)
170        LDMIA   sp!, {r0}       ; get fpexc
171        VMSR    fpexc, r0
172        TST     r0,  #0x40000000
173        BEQ     __no_vfp_frame_ldr_irq
174        LDMIA   sp!, {r1}       ; get fpscr
175        VMSR    fpscr, r1
176		VLDMIA  sp!, {d0-d15}
177__no_vfp_frame_ldr_irq
178    .endif
179
180    LDMIA   sp!, {r0-r12,lr}
181    SUBS    pc, lr, #4
182
183; /*
184; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
185; */
186    .def rt_hw_context_switch_interrupt_do
187rt_hw_context_switch_interrupt_do
188    MOV     r1,  #0           ; clear flag
189    STR     r1,  [r0]
190
191    .if (__TI_VFP_SUPPORT__)
192        LDMIA   sp!, {r0}       ; get fpexc
193        VMSR    fpexc, r0
194        TST     r0,  #0x40000000
195        BEQ     __no_vfp_frame_do1
196        LDMIA   sp!, {r1}       ; get fpscr
197        VMSR    fpscr, r1
198		VLDMIA  sp!, {d0-d15}
199__no_vfp_frame_do1
200    .endif
201
202    LDMIA   sp!, {r0-r12,lr}  ; reload saved registers
203    STMDB   sp, {r0-r3}       ; save r0-r3. We will restore r0-r3 in the SVC
204                              ; mode so there is no need to update SP.
205    SUB     r1,  sp, #16      ; save the right SP value in r1, so we could restore r0-r3.
206    SUB     r2,  lr, #4       ; save old task's pc to r2
207
208    MRS     r3,  spsr         ; get cpsr of interrupt thread
209
210    ; switch to SVC mode and no interrupt
211    CPSID   IF, #0x13
212
213    STMDB   sp!, {r2}         ; push old task's pc
214    STMDB   sp!, {r4-r12,lr}  ; push old task's lr,r12-r4
215    LDMIA   r1!, {r4-r7}      ; restore r0-r3 of the interrupted thread
216    STMDB   sp!, {r4-r7}      ; push old task's r3-r0. We don't need to push/pop them to
217                              ; r0-r3 because we just want to transfer the data and don't
218                              ; use them here.
219    STMDB   sp!, {r3}         ; push old task's cpsr
220
221    .if (__TI_VFP_SUPPORT__)
222		VMRS    r0,  fpexc
223        TST     r0,  #0x40000000
224        BEQ     __no_vfp_frame_do2
225        VSTMDB  sp!, {d0-d15}
226        VMRS    r1, fpscr
227        ; TODO: add support for Common VFPv3.
228        ;       Save registers like FPINST, FPINST2
229        STMDB   sp!, {r1}
230__no_vfp_frame_do2
231        STMDB   sp!, {r0}
232	.endif
233
234    LDR     r4,  pfromthread
235    LDR     r5,  [r4]
236    STR     sp,  [r5]         ; store sp in preempted tasks's TCB
237
238    LDR     r6,  ptothread
239    LDR     r6,  [r6]
240    LDR     sp,  [r6]         ; get new task's stack pointer
241
242    .if (__TI_VFP_SUPPORT__)
243        LDMIA   sp!, {r0}       ; get fpexc
244        VMSR    fpexc, r0
245        TST     r0,  #0x40000000
246        BEQ     __no_vfp_frame_do3
247        LDMIA   sp!, {r1}       ; get fpscr
248        VMSR    fpscr, r1
249		VLDMIA  sp!, {d0-d15}
250__no_vfp_frame_do3
251    .endif
252
253    LDMIA   sp!, {r4}         ; pop new task's cpsr to spsr
254    MSR     spsr_cxsf, r4
255
256    LDMIA   sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr
257
258pintflag     .word   rt_thread_switch_interrupt_flag
259pfromthread  .word   rt_interrupt_from_thread
260ptothread    .word   rt_interrupt_to_thread
261