;/**************************************************************************/
;/*                                                                        */
;/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
;/*                                                                        */
;/*       This software is licensed under the Microsoft Software License   */
;/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
;/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
;/*       and in the root directory of this software.                      */
;/*                                                                        */
;/**************************************************************************/
;
;
;/**************************************************************************/
;/**************************************************************************/
;/**                                                                       */ 
;/** ThreadX Component                                                     */ 
;/**                                                                       */
;/**   Thread                                                              */
;/**                                                                       */
;/**************************************************************************/
;/**************************************************************************/
;
;
;#define TX_SOURCE_CODE
;
;
;/* Include necessary system files.  */
;
;#include "tx_api.h"
;#include "tx_thread.h"
;#include "tx_timer.h"
;
    .GLB     __tx_thread_system_state
    .GLB     __tx_thread_current_ptr
    .GLB     __tx_thread_system_stack_ptr

    .SECTION    P,CODE
;/**************************************************************************/ 
;/*                                                                        */ 
;/*  FUNCTION                                               RELEASE        */ 
;/*                                                                        */ 
;/*    _tx_thread_context_save                              RXv2/CCRX      */
;/*                                                           6.1.11       */
;/*  AUTHOR                                                                */ 
;/*                                                                        */ 
;/*    William E. Lamie, Microsoft Corporation                             */
;/*                                                                        */ 
;/*  DESCRIPTION                                                           */ 
;/*                                                                        */ 
;/*    This function saves the context of an executing thread in the       */ 
;/*    beginning of interrupt processing.  The function also ensures that  */ 
;/*    the system stack is used upon return to the calling ISR.            */ 
;/*                                                                        */ 
;/*  INPUT                                                                 */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  OUTPUT                                                                */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  CALLS                                                                 */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  CALLED BY                                                             */ 
;/*                                                                        */ 
;/*    ISRs                                                                */ 
;/*                                                                        */ 
;/*  RELEASE HISTORY                                                       */ 
;/*                                                                        */ 
;/*    DATE              NAME                      DESCRIPTION             */ 
;/*                                                                        */ 
;/*  12-30-2020     William E. Lamie         Initial Version 6.1.3         */
;/*  10-15-2021     William E. Lamie         Modified comment(s),          */
;/*                                            resulting in version 6.1.9  */
;/*  01-31-2022     William E. Lamie         Modified comment(s),          */
;/*                                            resulting in version 6.1.10 */
;/*  04-25-2022     William E. Lamie         Modified comment(s),          */
;/*                                            resulting in version 6.1.11 */
;/*                                                                        */ 
;/**************************************************************************/ 
;VOID   _tx_thread_context_save(VOID)
;{
    .GLB __tx_thread_context_save
__tx_thread_context_save:
;
;    /* Upon entry to this routine, it is assumed that interrupts are locked
;       out and the (interrupt) stack frame looks like the following:
;
;           (lower address) SP   ->     [return address of this call]
;                           SP+4 ->     Saved R1
;                           SP+8 ->     Saved R2
;                           SP+12->     Interrupted PC
;                           SP+16->     Interrupted PSW
;
;    /* Check for a nested interrupt condition.  */
;    if (_tx_thread_system_state++)
;    {
;

    MOV.L   #__tx_thread_system_state, R1        ; Pick up address of system state
    MOV.L   [R1], R2                             ; Pick up system state
    CMP     #0, R2                               ; 0 -> no nesting
    BEQ     __tx_thread_not_nested_save
;
;    /* Nested interrupt condition.  */
;   
    ADD   #1, r2                                 ; _tx_thread_system_state++
    MOV.L   r2, [r1]

;
;   /* Save the rest of the scratch registers on the interrupt stack and return to the
;       calling ISR.  */
    POP R1                                       ; Recuperate return address from stack
    PUSHM   R3-R5
    PUSHM   R14-R15
    PUSHC   FPSW                                 ; (top) FPSW, R14, R15, R3, R4, R5, R1, R2, PC, PSW (bottom)
    JMP     R1                                   ; Return address was preserved in R1

;
__tx_thread_not_nested_save:
;    }
;
;    /* Otherwise, not nested, check to see if a thread was running.  */
;    else if (_tx_thread_current_ptr)
;    {
;
    ADD     #1, R2                               ; _tx_thread_system_state++
    MOV.L   R2, [R1]

    MOV.L   #__tx_thread_current_ptr, R2         ; Pickup current thread pointer
    MOV.L   [R2], R2
    CMP     #0,R2                                ; Is it NULL?
    BEQ      __tx_thread_idle_system_save        ; Yes, idle system is running - idle restore
;
;    /* Move stack frame over to the current threads stack.  */
;    /* complete stack frame with registers not saved yet (R3-R5, R14-R15, FPSW)   */
;
    MVFC    USP, R1                              ; Pick up user stack pointer
    MOV.L   16[R0], R2
    MOV.L   R2, [-R1]                            ; Save PSW on thread stack
    MOV.L   12[R0], R2
    MOV.L   R2, [-R1]                            ; Save PC on thread stack
    MOV.L   8[R0], R2
    MOV.L   R2, [-R1]                            ; Save R2 on thread stack
    MOV.L   4[R0], R2
    MOV.L   R2, [-R1]                            ; Save R1 on thread stack
    MOV.L   R5, [-R1]                            ; Save R5 on thread stack
    MOV.L   R4, [-R1]                            ; Save R4 on thread stack
    MOV.L   R3, [-R1]                            ; Save R3 on thread stack
    MOV.L   R15, [-R1]                           ; Save R15 on thread stack
    MOV.L   R14, [-R1]                           ; Save R14 on thread stack
    MVFC    FPSW, R3
    MOV.L   R3, [-R1]                            ; Save FPSW on thread stack
	
    POP     R2                                   ; Pick up return address from interrupt stack
    ADD     #16, R0, R0                          ; Correct interrupt stack pointer back to the bottom
    MVTC    R1, USP                              ; Set user/thread stack pointer
    JMP     R2                                   ; Return to ISR

;    }
;    else
;    {
;
__tx_thread_idle_system_save:
;
;        /* Interrupt occurred in the scheduling loop.  */
;
    POP     R1                                   ; Pick up return address
    ADD     #16, R0, R0                          ; Correct interrupt stack pointer back to the bottom (PC), don't care about saved registers
    JMP     R1                                   ; Return to caller
;
;    }
;}
    .END
