;/***************************************************************************
; * Copyright (c) 2024 Microsoft Corporation 
; * 
; * This program and the accompanying materials are made available under the
; * terms of the MIT License which is available at
; * https://opensource.org/licenses/MIT.
; * 
; * SPDX-License-Identifier: MIT
; **************************************************************************/
;
;
;/**************************************************************************/
;/**************************************************************************/
;/**                                                                       */ 
;/** ThreadX Component                                                     */ 
;/**                                                                       */
;/**   Timer                                                               */
;/**                                                                       */
;/**************************************************************************/
;/**************************************************************************/
;
;#define TX_SOURCE_CODE
;
;
;/* Include necessary system files.  */
;
;#include "tx_api.h"
;#include "tx_timer.h"
;#include "tx_thread.h"
;
FP          .set    A15
DP          .set    B14
SP          .set    B15
;
;Define Assembly language external references...
;
    .global     _tx_timer_time_slice
    .global     _tx_timer_system_clock
    .global     _tx_timer_current_ptr
    .global     _tx_timer_list_start
    .global     _tx_timer_list_end
    .global     _tx_timer_expired_time_slice
    .global     _tx_timer_expired
    .global     _tx_timer_expiration_process
    .global     _tx_thread_time_slice
    .global     _tx_thread_context_save
    .global     _tx_thread_context_restore
;
;
    .sect   ".text"
;/**************************************************************************/ 
;/*                                                                        */ 
;/*  FUNCTION                                               RELEASE        */ 
;/*                                                                        */ 
;/*    _tx_timer_interrupt                                 C667x/TI        */ 
;/*                                                           6.1          */
;/*  AUTHOR                                                                */
;/*                                                                        */
;/*    William E. Lamie, Microsoft Corporation                             */
;/*                                                                        */
;/*  DESCRIPTION                                                           */
;/*                                                                        */ 
;/*    This function processes the hardware timer interrupt.  This         */ 
;/*    processing includes incrementing the system clock and checking for  */ 
;/*    time slice and/or timer expiration.  If either is found, the        */ 
;/*    interrupt context save/restore functions are called along with the  */ 
;/*    expiration functions.                                               */ 
;/*                                                                        */ 
;/*  INPUT                                                                 */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  OUTPUT                                                                */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  CALLS                                                                 */ 
;/*                                                                        */ 
;/*    _tx_thread_context_save               Context save                  */ 
;/*    _tx_thread_context_restore            Context restore               */ 
;/*    _tx_thread_time_slice                 Time slice interrupted thread */ 
;/*    _tx_timer_expiration_process          Timer expiration processing   */ 
;/*                                                                        */ 
;/*  CALLED BY                                                             */ 
;/*                                                                        */ 
;/*    interrupt vector                                                    */ 
;/*                                                                        */ 
;/*  RELEASE HISTORY                                                       */ 
;/*                                                                        */ 
;/*    DATE              NAME                      DESCRIPTION             */
;/*                                                                        */
;/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
;/*                                                                        */
;/**************************************************************************/
;VOID   _tx_timer_interrupt(VOID)
;{
    .global _tx_timer_interrupt
_tx_timer_interrupt:
;
;    /* Upon entry to this routine, it is assumed that registers B3, A0-A4 have
;       already been saved and the space for saving additional registers has
;       already been reserved.  In addition, interrupts are locked out and must
;       remain so until context save returns.  */
;
;    /* Increment the system clock.  */
;    _tx_timer_system_clock++;
;
        MVKL        _tx_timer_system_clock,A0           ; Build address of system clock
        MVKH        _tx_timer_system_clock,A0           ; 
        LDW         *A0,A2                              ; Pickup system clock
        MVKL        _tx_timer_time_slice,A3             ; Build address of time slice
        MVKH        _tx_timer_time_slice,A3             ; 
        LDW         *A3,A1                              ; Pickup time slice
        NOP         2                                   ; Delay
        ADD         1,A2,A2                             ; Increment the system clock
        STW         A2,*A0                              ; Store it back in memory
;
;    /* Test for time-slice expiration.  */
;    if (_tx_timer_time_slice)
;    {
;
 [!A1]  B           _tx_timer_no_time_slice             ; If 0, skip time slice processing
        SUB         A1,1,A1                             ; Decrement time-slice value 
        NOP         4                                   ; Delay slots
;
;       /* Decrement the time_slice.  */
;       _tx_timer_time_slice--;
;
;       /* Check for expiration.  */
;       if (_tx_timer_time_slice == 0)
;
 [A1]   B           _tx_timer_no_time_slice             ; If non-zero, not expired yet
        STW         A1,*A3                              ; Store new time-slice    
        MVKL        _tx_timer_expired_time_slice,A0     ; Build address of expired flag
        MVKH        _tx_timer_expired_time_slice,A0     ; 
        MVKL        1,A4                                ; Expired flag
        NOP                                             ; Delay
;
;       /* Set the time-slice expired flag.  */
;       _tx_timer_expired_time_slice =  TX_TRUE;
;
        STW         A4,*A0                              ; Set expired flag
;    }
;
_tx_timer_no_time_slice:
;
;    /* Test for timer expiration.  */
;    if (*_tx_timer_current_ptr)
;    {
;
        MVKL        _tx_timer_current_ptr,A2            ; Build address of current timer pointer
        MVKH        _tx_timer_current_ptr,A2            ; 
        LDW         *A2,A0                              ; Pickup timer list address
        MVKL        _tx_timer_expired,A3                ; Build address of expired flag
        MVKH        _tx_timer_expired,A3                ; 
        NOP         2                                   ; Delay slots
        LDW         *A0,A1                              ; Pickup current timer entry
        ADD         4,A0,A0                             ; Increment the current pointer
        NOP         3                                   ; Delay slots
 [A1]   B           _tx_timer_done                      ; If non-NULL, something has expired
;
;
;        /* Set expiration flag.  */
;        _tx_timer_expired =  TX_TRUE;
;
        MVKL        1,A4                                ; Build expired flag
 [A1]   STW         A4,*A3                              ; Set expired flag
        NOP         3                                   ; Delay slots
;
;    }
;    else
;    {
_tx_timer_no_timer:
;
;        /* No timer expired, increment the timer pointer.  */
;        _tx_timer_current_ptr++;
;
;        /* Check for wrap-around.  */
;        if (_tx_timer_current_ptr == _tx_timer_list_end)
;
        MVKL        _tx_timer_list_end,A3               ; Build timer list end address
        MVKH        _tx_timer_list_end,A3               ; 
        LDW         *A3,A4                              ; Pickup list end address
        MVKL        _tx_timer_list_start,A3             ; Build timer list start address
        MVKH        _tx_timer_list_start,A3             ; 
        NOP         2                                   ; Delay slots
        CMPEQ       A4,A0,A1                            ; Compare current pointer with end
 [A1]   LDW         *A3,A0                              ; If at the end, pickup timer list start
        NOP         4                                   ; Delay slots
;
;            /* Wrap to beginning of list.  */
;            _tx_timer_current_ptr =  _tx_timer_list_start;
;
_tx_timer_skip_wrap:
;
;
        STW         A0,*A2                              ; Store current timer pointer
;    }
;
_tx_timer_done:
;
;
;    /* See if anything has expired.  */
;    if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
;    {
;
        MVKL        _tx_timer_expired_time_slice,A3     ; Build time-slice expired flag
        MVKH        _tx_timer_expired_time_slice,A3     ; 
        LDW         *A3,A4                              ; Pickup time-slice expired flag
        MVKL        _tx_timer_expired,A0                ; Build timer expired flag
        MVKH        _tx_timer_expired,A0                ; 
        LDW         *A0,A2                              ; Pickup timer expired flag
        NOP         4                                   ; Delay slots
        OR          A2,A4,A1                            ; Combine expired flags
 [!A1]  B           _tx_timer_nothing_expired
        NOP         5                                   ; Delay slots
;
_tx_something_expired:
;
;
;    /* Something expired, call context save.  */
;    _tx_thread_context_save();
;
        B           _tx_thread_context_save             ; Call context save routine
        MVKL        _tx_timer_ISR_return,B3             ; Build return address
        MVKH        _tx_timer_ISR_return,B3             ; 
        NOP         3                                   ; Delay slots  
_tx_timer_ISR_return:
;
;    /* Did a timer expire?  */
;    if (_tx_timer_expired)
;    {
;
        MVKL        _tx_timer_expired,A0                ; Build timer expired address
        MVKH        _tx_timer_expired,A0                ; 
        LDW         *A0,A1                              ; Pickup expired flag
        NOP         4                                   ; Delay slots
 [!A1]  B           _tx_timer_dont_activate             ; If not set, skip timer activation
        NOP         5                                   ; Delay slots
;
;        /* Process timer expiration.  */
;        _tx_timer_expiration_process();
;
        B           _tx_timer_expiration_process        ; Process timer expiration
        MVKL        _tx_timer_ISR_return_1,B3           ; Build return address
        MVKH        _tx_timer_ISR_return_1,B3           ; 
        NOP         3                                   ; Delay slots
_tx_timer_ISR_return_1:
;
;    }
_tx_timer_dont_activate:
;
;    /* Did time slice expire?  */
;    if (_tx_timer_expired_time_slice)
;    {
;
        MVKL        _tx_timer_expired_time_slice,A0     ; Build address of expired flag
        MVKH        _tx_timer_expired_time_slice,A0     ; 
        LDW         *A0,A1                              ; Pickup expired flag
        NOP         4                                   ; Delay slots
 [!A1]  B           _tx_timer_not_ts_expiration         ; If not set, skip time-slice processing
        NOP         5                                   ; Delay slots
;
;        /* Time slice interrupted thread.  */
;        _tx_thread_time_slice();
;
        B           _tx_thread_time_slice               ; Call time-slice processing
        MVKL        _tx_timer_ISR_return_2,B3           ; Build return address
        MVKH        _tx_timer_ISR_return_2,B3           ; 
        NOP         3                                   ; Delay slots
_tx_timer_ISR_return_2:
;
;    }
;
_tx_timer_not_ts_expiration:
;
;
;    /* Call context restore.  */
;    _tx_thread_context_restore();
;
        B           _tx_thread_context_restore          ; Jump to context restore - no return!
        NOP         5                                   ; Delay slots
;
;    }
;
_tx_timer_nothing_expired:
;
        LDW         *+SP(20),A0                         ; Recover A0
        LDW         *+SP(24),A1                         ; Recover A1
        LDW         *+SP(28),A2                         ; Recover A2
        LDW         *+SP(32),A3                         ; Recover A3
        B           IRP                                 ; Return to point of interrupt
||      LDW         *+SP(36),A4                         ; Recover A4
        LDW         *+SP(96),B3                         ; Recover B3
        ADDK.S2     288,SP                              ; Recover stack space
        NOP         3                                   ; Delay slots
;
;}

