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-02-20   aozima       port to gcc.
12 * 2013-06-18   aozima       add restore MSP feature.
13 * 2013-11-04   bright       fixed hardfault bug for gcc.
14 * 2019-03-31   xuzhuoyi     port to Cortex-M23.
15 */
16
17    .cpu    cortex-m23
18    .fpu    softvfp
19    .syntax unified
20    .thumb
21    .text
22
23    .equ    SCB_VTOR, 0xE000ED08            /* Vector Table Offset Register */
24    .equ    NVIC_INT_CTRL, 0xE000ED04       /* interrupt control state register */
25    .equ    NVIC_SHPR3, 0xE000ED20          /* system priority register (3) */
26    .equ    NVIC_PENDSV_PRI, 0xFFFF0000     /* PendSV and SysTick priority value (lowest) */
27    .equ    NVIC_PENDSVSET, 0x10000000      /* value to trigger PendSV exception */
28
29/*
30 * rt_base_t rt_hw_interrupt_disable();
31 */
32    .global rt_hw_interrupt_disable
33    .type rt_hw_interrupt_disable, %function
34rt_hw_interrupt_disable:
35    MRS     R0, PRIMASK
36    CPSID   I
37    BX      LR
38
39/*
40 * void rt_hw_interrupt_enable(rt_base_t level);
41 */
42    .global rt_hw_interrupt_enable
43    .type rt_hw_interrupt_enable, %function
44rt_hw_interrupt_enable:
45    MSR     PRIMASK, R0
46    BX      LR
47
48/*
49 * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
50 * R0 --> from
51 * R1 --> to
52 */
53    .global rt_hw_context_switch_interrupt
54    .type rt_hw_context_switch_interrupt, %function
55    .global rt_hw_context_switch
56    .type rt_hw_context_switch, %function
57rt_hw_context_switch_interrupt:
58rt_hw_context_switch:
59    /* set rt_thread_switch_interrupt_flag to 1 */
60    LDR     R2, =rt_thread_switch_interrupt_flag
61    LDR     R3, [R2]
62    CMP     R3, #1
63    BEQ     _reswitch
64    MOVS    R3, #1
65    STR     R3, [R2]
66
67    LDR     R2, =rt_interrupt_from_thread   /* set rt_interrupt_from_thread */
68    STR     R0, [R2]
69
70_reswitch:
71    LDR     R2, =rt_interrupt_to_thread     /* set rt_interrupt_to_thread */
72    STR     R1, [R2]
73
74    LDR     R0, =NVIC_INT_CTRL           /* trigger the PendSV exception (causes context switch) */
75    LDR     R1, =NVIC_PENDSVSET
76    STR     R1, [R0]
77    BX      LR
78
79/* R0 --> switch from thread stack
80 * R1 --> switch to thread stack
81 * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
82 */
83    .global PendSV_Handler
84    .type PendSV_Handler, %function
85PendSV_Handler:
86    /* disable interrupt to protect context switch */
87    MRS     R2, PRIMASK
88    CPSID   I
89
90    /* get rt_thread_switch_interrupt_flag */
91    LDR     R0, =rt_thread_switch_interrupt_flag
92    LDR     R1, [R0]
93    CMP     R1, #0x00
94    BEQ     pendsv_exit     /* pendsv already handled */
95
96    /* clear rt_thread_switch_interrupt_flag to 0 */
97    MOVS    R1, #0
98    STR     R1, [R0]
99
100    LDR     R0, =rt_interrupt_from_thread
101    LDR     R1, [R0]
102    CMP     R1, #0x00
103    BEQ     switch_to_thread    /* skip register save at the first time */
104
105    MRS     R1, PSP                 /* get from thread stack pointer */
106
107    SUBS    R1, R1, #0x20           /* space for {R4 - R7} and {R8 - R11} */
108    LDR     R0, [R0]
109    STR     R1, [R0]                /* update from thread stack pointer */
110
111    STMIA   R1!, {R4 - R7}          /* push thread {R4 - R7} register to thread stack */
112
113    MOV     R4, R8                  /* mov thread {R8 - R11} to {R4 - R7} */
114    MOV     R5, R9
115    MOV     R6, R10
116    MOV     R7, R11
117    STMIA   R1!, {R4 - R7}          /* push thread {R8 - R11} high register to thread stack */
118switch_to_thread:
119    LDR     R1, =rt_interrupt_to_thread
120    LDR     R1, [R1]
121    LDR     R1, [R1]                /* load thread stack pointer */
122
123    LDMIA   R1!, {R4 - R7}          /* pop thread {R4 - R7} register from thread stack */
124    PUSH    {R4 - R7}               /* push {R4 - R7} to MSP for copy {R8 - R11} */
125
126    LDMIA   R1!, {R4 - R7}          /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */
127    MOV     R8,  R4                 /* mov {R4 - R7} to {R8 - R11} */
128    MOV     R9,  R5
129    MOV     R10, R6
130    MOV     R11, R7
131
132    POP     {R4 - R7}               /* pop {R4 - R7} from MSP */
133
134    MSR     PSP, R1                 /* update stack pointer */
135
136pendsv_exit:
137    /* restore interrupt */
138    MSR     PRIMASK, R2
139
140    MOVS    R0, #0x03
141    RSBS    R0, R0, #0x00
142    BX      R0
143/*
144 * void rt_hw_context_switch_to(rt_uint32 to);
145 * R0 --> to
146 */
147    .global rt_hw_context_switch_to
148    .type rt_hw_context_switch_to, %function
149rt_hw_context_switch_to:
150    LDR     R1, =rt_interrupt_to_thread
151    STR     R0, [R1]
152
153    /* set from thread to 0 */
154    LDR     R1, =rt_interrupt_from_thread
155    MOVS    R0, #0
156    STR     R0, [R1]
157
158    /* set interrupt flag to 1 */
159    LDR     R1, =rt_thread_switch_interrupt_flag
160    MOVS    R0, #1
161    STR     R0, [R1]
162
163    /* set the PendSV and SysTick exception priority */
164    LDR     R0, =NVIC_SHPR3
165    LDR     R1, =NVIC_PENDSV_PRI
166    LDR     R2, [R0,#0x00]       /* read */
167    ORRS    R1, R1, R2             /* modify */
168    STR     R1, [R0]             /* write-back */
169
170    LDR     R0, =NVIC_INT_CTRL               /* trigger the PendSV exception (causes context switch) */
171    LDR     R1, =NVIC_PENDSVSET
172    STR     R1, [R0]
173    NOP
174    /* restore MSP */
175    LDR     R0, =SCB_VTOR
176    LDR     R0, [R0]
177    LDR     R0, [R0]
178    NOP
179    MSR     MSP, R0
180
181    /* enable interrupts at processor level */
182    CPSIE   I
183
184    /* ensure PendSV exception taken place before subsequent operation */
185    DSB
186    ISB
187
188    /* never reach here! */
189
190/* compatible with old version */
191    .global rt_hw_interrupt_thread_switch
192    .type rt_hw_interrupt_thread_switch, %function
193rt_hw_interrupt_thread_switch:
194    BX      LR
195    NOP
196
197    .global HardFault_Handler
198    .type HardFault_Handler, %function
199HardFault_Handler:
200    /* get current context */
201    MRS     R0, PSP                 /* get fault thread stack pointer */
202    PUSH    {LR}
203    BL      rt_hw_hard_fault_exception
204    POP     {PC}
205
206
207/*
208 * rt_uint32_t rt_hw_interrupt_check(void);
209 * R0 --> state
210 */
211    .global rt_hw_interrupt_check
212    .type rt_hw_interrupt_check, %function
213rt_hw_interrupt_check:
214    MRS     R0, IPSR
215    BX      LR
216