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