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