.syntax unified @ See https://sourceware.org/binutils/docs/as/ARM_002dInstruction_002dSet.html
.cpu cortex-m4
.fpu softvfp
.thumb
 
@ The .global directive gives the symbols external linkage.
@ For clarity, the fn OSAsm_ThreadSwitch is exported as TIM2_IRQHandler, so that the vector table
@   in startup.s doesn't need to be modified.
.global OSAsm_Start
.set TIM2_IRQHandler, OSAsm_ThreadSwitch
.global TIM2_IRQHandler

.extern RunPt
.extern SchedlTimer_ClearITFlag
.extern OS_Scheduler

.section    .text.OSAsm_Start
.type	OSAsm_Start, %function
OSAsm_Start:
    CPSID   I                       @ disable interrupts
    LDR     R0, =RunPt              @ R0 = &RunPt;  // TCB_t**  R0 = &RunPt
    LDR     R1, [R0]                @ R1 = *R0;     // TCB_t*   R1 = RunPt
    LDR     SP, [R1]                @ SP = *R1;     // uint32_t SP = *(RunPt.sp)
                                    @ now we switched to the thread's stack, which we populated before
    POP     {R4-R11}                @ pop regs R4-R11
    POP     {R0-R3}                 @ pop regs R0-R3
    POP     {R12}                   @ pop reg  R12
    POP     {LR}                    @ discard LR
    POP     {LR}                    @ pop PC to the link register (start location)
    POP     {R1}                    @ discard PSR
    CPSIE   I                       @ enable interrupts
    BX      LR                      @ start first thread
 
.section    .text.OSAsm_ThreadSwitch
.type	OSAsm_ThreadSwitch, %function
OSAsm_ThreadSwitch:
                                    @ save R0-R3,R12,LR,PC,PSR
    CPSID   I                       @ prevent interrupt during context-switch
    PUSH    {R4-R11}                @ save remaining regs R4-R11
    LDR     R0, =RunPt              @ R0 = &RunPt;  // TCB_t** R0  = &RunPt
    LDR     R1, [R0]                @ R1 = *R0;     // TCB_t*  R1  = RunPt
    STR     SP, [R1]                @ *R1 = SP;     // *(RunPt.sp) = SP

    PUSH    {R0, LR}                @ push R0 and LR, so that fn calls don't loose them
    BL      SchedlTimer_ClearITFlag @ clear SchedlTimer interrupt flag
    BL      OS_Scheduler            @ call OS_Scheduler, RunPt is updated
    POP     {R0, LR}                @ restore R0 and LR

    LDR     R1, [R0]                @ R1 = *R0;     // TCB_t*   R1 = RunPt
    LDR     SP, [R1]                @ SP = *R1;     // uint32_t SP = *(RunPt.sp)
                                    @ now we switched to the new thread's stack
    POP     {R4-R11}                @ restore regs R4-R11
    CPSIE   I                       @ tasks run with interrupts enabled
    BX      LR                      @ restore R0-R3,R12,LR,PC,PSR
