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