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