updates
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal-eddystone by
Diff: source/asm/CortexContextSwitch.s.gcc
- Revision:
- 1:8aa5cdb4ab67
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/asm/CortexContextSwitch.s.gcc Thu Apr 07 01:33:22 2016 +0100 @@ -0,0 +1,292 @@ +@ The MIT License (MIT) + +@ Copyright (c) 2016 British Broadcasting Corporation. +@ This software is provided by Lancaster University by arrangement with the BBC. + +@ Permission is hereby granted, free of charge, to any person obtaining a +@ copy of this software and associated documentation files (the "Software"), +@ to deal in the Software without restriction, including without limitation +@ the rights to use, copy, modify, merge, publish, distribute, sublicense, +@ and/or sell copies of the Software, and to permit persons to whom the +@ Software is furnished to do so, subject to the following conditions: + +@ The above copyright notice and this permission notice shall be included in +@ all copies or substantial portions of the Software. + +@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +@ DEALINGS IN THE SOFTWARE. + + .syntax unified + .cpu cortex-m0 + .thumb + .text + .align 2 + +@ Export our context switching subroutine as a C function for use in mbed + .global swap_context + .global save_context + .global save_register_context + .global restore_register_context + +@ R0 Contains a pointer to the TCB of the fibre being scheduled out. +@ R1 Contains a pointer to the TCB of the fibre being scheduled in. +@ R2 Contains a pointer to the base of the stack of the fibre being scheduled out. +@ R3 Contains a pointer to the base of the stack of the fibre being scheduled in. + +swap_context: + + @ Write our core registers into the TCB + @ First, store the general registers + + @ Skip this is we're given a NULL parameter for the TCB + CMP R0, #0 + BEQ store_context_complete + + STR R0, [R0,#0] + STR R1, [R0,#4] + STR R2, [R0,#8] + STR R3, [R0,#12] + STR R4, [R0,#16] + STR R5, [R0,#20] + STR R6, [R0,#24] + STR R7, [R0,#28] + + @ Now the high general purpose registers + MOV R4, R8 + STR R4, [R0,#32] + MOV R4, R9 + STR R4, [R0,#36] + MOV R4, R10 + STR R4, [R0,#40] + MOV R4, R11 + STR R4, [R0,#44] + MOV R4, R12 + STR R4, [R0,#48] + + @ Now the Stack and Link Register. + @ As this context is only intended for use with a fiber scheduler, + @ we don't need the PC. + MOV R6, SP + STR R6, [R0,#52] + MOV R4, LR + STR R4, [R0,#56] + +store_context_complete: + @ Finally, Copy the stack. We do this to reduce RAM footprint, as stack is usually very small at the point + @ of scheduling, but we need a lot of capacity for interrupt handling and other functions. + + @ Skip this is we're given a NULL parameter for the stack. + CMP R2, #0 + BEQ store_stack_complete + + LDR R4, [R0,#60] @ Load R4 with the fiber's defined stack_base. +store_stack: + SUBS R4, #4 + SUBS R2, #4 + + LDR R5, [R4] + STR R5, [R2] + + CMP R4, R6 + BNE store_stack + +store_stack_complete: + + @ + @ Now page in the new context. + @ Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler. + @ + LDR R4, [R1, #56] + MOV LR, R4 + LDR R6, [R1, #52] + MOV SP, R6 + + @ Copy the stack in. + @ n.b. we do this after setting the SP to make comparisons easier. + + @ Skip this is we're given a NULL parameter for the stack. + CMP R3, #0 + BEQ restore_stack_complete + + LDR R4, [R1,#60] @ Load R4 with the fiber's defined stack_base. + +restore_stack: + SUBS R4, #4 + SUBS R3, #4 + + LDR R5, [R3] + STR R5, [R4] + + CMP R4, R6 + BNE restore_stack + +restore_stack_complete: + LDR R4, [R1, #48] + MOV R12, R4 + LDR R4, [R1, #44] + MOV R11, R4 + LDR R4, [R1, #40] + MOV R10, R4 + LDR R4, [R1, #36] + MOV R9, R4 + LDR R4, [R1, #32] + MOV R8, R4 + + LDR R7, [R1, #28] + LDR R6, [R1, #24] + LDR R5, [R1, #20] + LDR R4, [R1, #16] + LDR R3, [R1, #12] + LDR R2, [R1, #8] + LDR R0, [R1, #0] + LDR R1, [R1, #4] + + @ Return to caller (scheduler). + BX LR + + +@ R0 Contains a pointer to the TCB of the fibre to snapshot +@ R1 Contains a pointer to the base of the stack of the fibre being snapshotted + +save_context: + + @ Write our core registers into the TCB + @ First, store the general registers + + STR R0, [R0,#0] + STR R1, [R0,#4] + STR R2, [R0,#8] + STR R3, [R0,#12] + STR R4, [R0,#16] + STR R5, [R0,#20] + STR R6, [R0,#24] + STR R7, [R0,#28] + + @ Now the high general purpose registers + MOV R4, R8 + STR R4, [R0,#32] + MOV R4, R9 + STR R4, [R0,#36] + MOV R4, R10 + STR R4, [R0,#40] + MOV R4, R11 + STR R4, [R0,#44] + MOV R4, R12 + STR R4, [R0,#48] + + @ Now the Stack and Link Register. + @ As this context is only intended for use with a fiber scheduler, + @ we don't need the PC. + MOV R6, SP + STR R6, [R0,#52] + MOV R4, LR + STR R4, [R0,#56] + + @ Finally, Copy the stack. We do this to reduce RAM footprint, as stackis usually very small at the point + @ of sceduling, but we need a lot of capacity for interrupt handling and other functions. + + LDR R4, [R0,#60] @ Load R4 with the fiber's defined stack_base. + +store_stack1: + SUBS R4, #4 + SUBS R1, #4 + + LDR R5, [R4] + STR R5, [R1] + + CMP R4, R6 + BNE store_stack1 + + @ Restore scratch registers. + + LDR R7, [R0, #28] + LDR R6, [R0, #24] + LDR R5, [R0, #20] + LDR R4, [R0, #16] + + @ Return to caller (scheduler). + BX LR + + +@ R0 Contains a pointer to the TCB of the fiber to snapshot +save_register_context: + + @ Write our core registers into the TCB + @ First, store the general registers + + STR R0, [R0,#0] + STR R1, [R0,#4] + STR R2, [R0,#8] + STR R3, [R0,#12] + STR R4, [R0,#16] + STR R5, [R0,#20] + STR R6, [R0,#24] + STR R7, [R0,#28] + + @ Now the high general purpose registers + MOV R4, R8 + STR R4, [R0,#32] + MOV R4, R9 + STR R4, [R0,#36] + MOV R4, R10 + STR R4, [R0,#40] + MOV R4, R11 + STR R4, [R0,#44] + MOV R4, R12 + STR R4, [R0,#48] + + @ Now the Stack Pointer and Link Register. + @ As this context is only intended for use with a fiber scheduler, + @ we don't need the PC. + MOV R4, SP + STR R4, [R0,#52] + MOV R4, LR + STR R4, [R0,#56] + + @ Restore scratch registers. + LDR R4, [R0, #16] + + @ Return to caller (scheduler). + BX LR + + +restore_register_context: + + @ + @ Now page in the new context. + @ Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler. + @ + LDR R4, [R0, #56] + MOV LR, R4 + LDR R4, [R0, #52] + MOV SP, R4 + + @ High registers... + LDR R4, [R0, #48] + MOV R12, R4 + LDR R4, [R0, #44] + MOV R11, R4 + LDR R4, [R0, #40] + MOV R10, R4 + LDR R4, [R0, #36] + MOV R9, R4 + LDR R4, [R0, #32] + MOV R8, R4 + + @ Low registers... + LDR R7, [R0, #28] + LDR R6, [R0, #24] + LDR R5, [R0, #20] + LDR R4, [R0, #16] + LDR R3, [R0, #12] + LDR R2, [R0, #8] + LDR R0, [R0, #0] + LDR R1, [R0, #4] + + @ Return to caller (normally the scheduler). + BX LR