xref: /nrf52832-nimble/rt-thread/libcpu/arm/cortex-m0/context_rvds.S (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero;/*
2*10465441SEvalZero; * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero; *
4*10465441SEvalZero; * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero; *
6*10465441SEvalZero; * Change Logs:
7*10465441SEvalZero; * Date           Author       Notes
8*10465441SEvalZero; * 2010-01-25     Bernard      first version
9*10465441SEvalZero; * 2012-06-01     aozima       set pendsv priority to 0xFF.
10*10465441SEvalZero; * 2012-08-17     aozima       fixed bug: store r8 - r11.
11*10465441SEvalZero; * 2013-06-18     aozima       add restore MSP feature.
12*10465441SEvalZero; */
13*10465441SEvalZero
14*10465441SEvalZero;/**
15*10465441SEvalZero; * @addtogroup CORTEX-M0
16*10465441SEvalZero; */
17*10465441SEvalZero;/*@{*/
18*10465441SEvalZero
19*10465441SEvalZeroSCB_VTOR        EQU     0xE000ED08               ; Vector Table Offset Register
20*10465441SEvalZeroNVIC_INT_CTRL   EQU     0xE000ED04               ; interrupt control state register
21*10465441SEvalZeroNVIC_SHPR3      EQU     0xE000ED20               ; system priority register (2)
22*10465441SEvalZeroNVIC_PENDSV_PRI EQU     0x00FF0000               ; PendSV priority value (lowest)
23*10465441SEvalZeroNVIC_PENDSVSET  EQU     0x10000000               ; value to trigger PendSV exception
24*10465441SEvalZero
25*10465441SEvalZero    AREA |.text|, CODE, READONLY, ALIGN=2
26*10465441SEvalZero    THUMB
27*10465441SEvalZero    REQUIRE8
28*10465441SEvalZero    PRESERVE8
29*10465441SEvalZero
30*10465441SEvalZero    IMPORT rt_thread_switch_interrupt_flag
31*10465441SEvalZero    IMPORT rt_interrupt_from_thread
32*10465441SEvalZero    IMPORT rt_interrupt_to_thread
33*10465441SEvalZero
34*10465441SEvalZero;/*
35*10465441SEvalZero; * rt_base_t rt_hw_interrupt_disable();
36*10465441SEvalZero; */
37*10465441SEvalZerort_hw_interrupt_disable    PROC
38*10465441SEvalZero    EXPORT  rt_hw_interrupt_disable
39*10465441SEvalZero    MRS     r0, PRIMASK
40*10465441SEvalZero    CPSID   I
41*10465441SEvalZero    BX      LR
42*10465441SEvalZero    ENDP
43*10465441SEvalZero
44*10465441SEvalZero;/*
45*10465441SEvalZero; * void rt_hw_interrupt_enable(rt_base_t level);
46*10465441SEvalZero; */
47*10465441SEvalZerort_hw_interrupt_enable    PROC
48*10465441SEvalZero    EXPORT  rt_hw_interrupt_enable
49*10465441SEvalZero    MSR		PRIMASK, r0
50*10465441SEvalZero    BX		LR
51*10465441SEvalZero    ENDP
52*10465441SEvalZero
53*10465441SEvalZero;/*
54*10465441SEvalZero; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
55*10465441SEvalZero; * r0 --> from
56*10465441SEvalZero; * r1 --> to
57*10465441SEvalZero; */
58*10465441SEvalZerort_hw_context_switch_interrupt
59*10465441SEvalZero    EXPORT rt_hw_context_switch_interrupt
60*10465441SEvalZerort_hw_context_switch    PROC
61*10465441SEvalZero    EXPORT rt_hw_context_switch
62*10465441SEvalZero
63*10465441SEvalZero    ; set rt_thread_switch_interrupt_flag to 1
64*10465441SEvalZero    LDR     r2, =rt_thread_switch_interrupt_flag
65*10465441SEvalZero    LDR     r3, [r2]
66*10465441SEvalZero    CMP     r3, #1
67*10465441SEvalZero    BEQ     _reswitch
68*10465441SEvalZero    MOVS    r3, #0x01
69*10465441SEvalZero    STR     r3, [r2]
70*10465441SEvalZero
71*10465441SEvalZero    LDR     r2, =rt_interrupt_from_thread   ; set rt_interrupt_from_thread
72*10465441SEvalZero    STR     r0, [r2]
73*10465441SEvalZero
74*10465441SEvalZero_reswitch
75*10465441SEvalZero    LDR     r2, =rt_interrupt_to_thread     ; set rt_interrupt_to_thread
76*10465441SEvalZero    STR     r1, [r2]
77*10465441SEvalZero
78*10465441SEvalZero    LDR     r0, =NVIC_INT_CTRL              ; trigger the PendSV exception (causes context switch)
79*10465441SEvalZero    LDR     r1, =NVIC_PENDSVSET
80*10465441SEvalZero    STR     r1, [r0]
81*10465441SEvalZero    BX      LR
82*10465441SEvalZero    ENDP
83*10465441SEvalZero
84*10465441SEvalZero; r0 --> switch from thread stack
85*10465441SEvalZero; r1 --> switch to thread stack
86*10465441SEvalZero; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
87*10465441SEvalZeroPendSV_Handler    PROC
88*10465441SEvalZero    EXPORT PendSV_Handler
89*10465441SEvalZero
90*10465441SEvalZero    ; disable interrupt to protect context switch
91*10465441SEvalZero    MRS     r2, PRIMASK
92*10465441SEvalZero    CPSID   I
93*10465441SEvalZero
94*10465441SEvalZero    ; get rt_thread_switch_interrupt_flag
95*10465441SEvalZero    LDR     r0, =rt_thread_switch_interrupt_flag
96*10465441SEvalZero    LDR     r1, [r0]
97*10465441SEvalZero    CMP     r1, #0x00
98*10465441SEvalZero    BEQ     pendsv_exit                ; pendsv already handled
99*10465441SEvalZero
100*10465441SEvalZero    ; clear rt_thread_switch_interrupt_flag to 0
101*10465441SEvalZero    MOVS    r1, #0x00
102*10465441SEvalZero    STR     r1, [r0]
103*10465441SEvalZero
104*10465441SEvalZero    LDR     r0, =rt_interrupt_from_thread
105*10465441SEvalZero    LDR     r1, [r0]
106*10465441SEvalZero    CMP     r1, #0x00
107*10465441SEvalZero    BEQ     switch_to_thread        ; skip register save at the first time
108*10465441SEvalZero
109*10465441SEvalZero    MRS     r1, psp                 ; get from thread stack pointer
110*10465441SEvalZero
111*10465441SEvalZero    SUBS    r1, r1, #0x20           ; space for {r4 - r7} and {r8 - r11}
112*10465441SEvalZero    LDR     r0, [r0]
113*10465441SEvalZero    STR     r1, [r0]                ; update from thread stack pointer
114*10465441SEvalZero
115*10465441SEvalZero    STMIA   r1!, {r4 - r7}          ; push thread {r4 - r7} register to thread stack
116*10465441SEvalZero
117*10465441SEvalZero    MOV     r4, r8                  ; mov thread {r8 - r11} to {r4 - r7}
118*10465441SEvalZero    MOV     r5, r9
119*10465441SEvalZero    MOV     r6, r10
120*10465441SEvalZero    MOV     r7, r11
121*10465441SEvalZero    STMIA   r1!, {r4 - r7}          ; push thread {r8 - r11} high register to thread stack
122*10465441SEvalZero
123*10465441SEvalZeroswitch_to_thread
124*10465441SEvalZero    LDR     r1, =rt_interrupt_to_thread
125*10465441SEvalZero    LDR     r1, [r1]
126*10465441SEvalZero    LDR     r1, [r1]                ; load thread stack pointer
127*10465441SEvalZero
128*10465441SEvalZero    LDMIA   r1!, {r4 - r7}          ; pop thread {r4 - r7} register from thread stack
129*10465441SEvalZero    PUSH    {r4 - r7}               ; push {r4 - r7} to MSP for copy {r8 - r11}
130*10465441SEvalZero
131*10465441SEvalZero    LDMIA   r1!, {r4 - r7}          ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
132*10465441SEvalZero    MOV     r8,  r4                 ; mov {r4 - r7} to {r8 - r11}
133*10465441SEvalZero    MOV     r9,  r5
134*10465441SEvalZero    MOV     r10, r6
135*10465441SEvalZero    MOV     r11, r7
136*10465441SEvalZero
137*10465441SEvalZero    POP     {r4 - r7}               ; pop {r4 - r7} from MSP
138*10465441SEvalZero
139*10465441SEvalZero    MSR     psp, r1                 ; update stack pointer
140*10465441SEvalZero
141*10465441SEvalZeropendsv_exit
142*10465441SEvalZero    ; restore interrupt
143*10465441SEvalZero    MSR     PRIMASK, r2
144*10465441SEvalZero
145*10465441SEvalZero    MOVS    r0, #0x04
146*10465441SEvalZero    RSBS    r0, r0, #0x00
147*10465441SEvalZero    BX      r0
148*10465441SEvalZero    ENDP
149*10465441SEvalZero
150*10465441SEvalZero;/*
151*10465441SEvalZero; * void rt_hw_context_switch_to(rt_uint32 to);
152*10465441SEvalZero; * r0 --> to
153*10465441SEvalZero; * this fucntion is used to perform the first thread switch
154*10465441SEvalZero; */
155*10465441SEvalZerort_hw_context_switch_to    PROC
156*10465441SEvalZero    EXPORT rt_hw_context_switch_to
157*10465441SEvalZero    ; set to thread
158*10465441SEvalZero    LDR     r1, =rt_interrupt_to_thread
159*10465441SEvalZero    STR     r0, [r1]
160*10465441SEvalZero
161*10465441SEvalZero    ; set from thread to 0
162*10465441SEvalZero    LDR     r1, =rt_interrupt_from_thread
163*10465441SEvalZero    MOVS    r0, #0x0
164*10465441SEvalZero    STR     r0, [r1]
165*10465441SEvalZero
166*10465441SEvalZero    ; set interrupt flag to 1
167*10465441SEvalZero    LDR     r1, =rt_thread_switch_interrupt_flag
168*10465441SEvalZero    MOVS    r0, #1
169*10465441SEvalZero    STR     r0, [r1]
170*10465441SEvalZero
171*10465441SEvalZero    ; set the PendSV exception priority
172*10465441SEvalZero    LDR     r0, =NVIC_SHPR3
173*10465441SEvalZero    LDR     r1, =NVIC_PENDSV_PRI
174*10465441SEvalZero    LDR     r2, [r0,#0x00]       ; read
175*10465441SEvalZero    ORRS    r1,r1,r2             ; modify
176*10465441SEvalZero    STR     r1, [r0]             ; write-back
177*10465441SEvalZero
178*10465441SEvalZero    ; trigger the PendSV exception (causes context switch)
179*10465441SEvalZero    LDR     r0, =NVIC_INT_CTRL
180*10465441SEvalZero    LDR     r1, =NVIC_PENDSVSET
181*10465441SEvalZero    STR     r1, [r0]
182*10465441SEvalZero
183*10465441SEvalZero    ; restore MSP
184*10465441SEvalZero    LDR     r0, =SCB_VTOR
185*10465441SEvalZero    LDR     r0, [r0]
186*10465441SEvalZero    LDR     r0, [r0]
187*10465441SEvalZero    MSR     msp, r0
188*10465441SEvalZero
189*10465441SEvalZero    ; enable interrupts at processor level
190*10465441SEvalZero    CPSIE   I
191*10465441SEvalZero
192*10465441SEvalZero    ; never reach here!
193*10465441SEvalZero    ENDP
194*10465441SEvalZero
195*10465441SEvalZero; compatible with old version
196*10465441SEvalZerort_hw_interrupt_thread_switch PROC
197*10465441SEvalZero    EXPORT rt_hw_interrupt_thread_switch
198*10465441SEvalZero    BX      lr
199*10465441SEvalZero    ENDP
200*10465441SEvalZero
201*10465441SEvalZero    IMPORT rt_hw_hard_fault_exception
202*10465441SEvalZero
203*10465441SEvalZeroHardFault_Handler    PROC
204*10465441SEvalZero    EXPORT HardFault_Handler
205*10465441SEvalZero
206*10465441SEvalZero    ; get current context
207*10465441SEvalZero    MRS     r0, psp                 ; get fault thread stack pointer
208*10465441SEvalZero    PUSH    {lr}
209*10465441SEvalZero    BL      rt_hw_hard_fault_exception
210*10465441SEvalZero    POP     {pc}
211*10465441SEvalZero    ENDP
212*10465441SEvalZero
213*10465441SEvalZero    ALIGN   4
214*10465441SEvalZero
215*10465441SEvalZero    END
216