;/*************************************************************************** ; * 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 */ ;/** */ ;/**************************************************************************/ ;/**************************************************************************/ ; ; .text .align 4 ;/**************************************************************************/ ;/* */ ;/* FUNCTION RELEASE */ ;/* */ ;/* _tx_timer_interrupt Cortex-M4/GHS */ ;/* 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 */ ;/* expiration functions are called. */ ;/* */ ;/* INPUT */ ;/* */ ;/* None */ ;/* */ ;/* OUTPUT */ ;/* */ ;/* None */ ;/* */ ;/* CALLS */ ;/* */ ;/* _tx_timer_expiration_process Timer expiration processing */ ;/* _tx_thread_time_slice Time slice interrupted thread */ ;/* */ ;/* CALLED BY */ ;/* */ ;/* interrupt vector */ ;/* */ ;/* RELEASE HISTORY */ ;/* */ ;/* DATE NAME DESCRIPTION */ ;/* */ ;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ ;/* */ ;/**************************************************************************/ ;VOID _tx_timer_interrupt(VOID) ;{ .globl _tx_timer_interrupt _tx_timer_interrupt: ; ; /* Upon entry to this routine, it is assumed that the compiler scratch registers are available ; for use. */ ; ; /* Increment the system clock. */ ; _tx_timer_system_clock++; ; LDR r1, =_tx_timer_system_clock ; Pickup address of system clock LDR r0, [r1, #0] ; Pickup system clock ADD r0, r0, #1 ; Increment system clock STR r0, [r1, #0] ; Store new system clock ; ; /* Test for time-slice expiration. */ ; if (_tx_timer_time_slice) ; { ; LDR r3, =_tx_timer_time_slice ; Pickup address of time-slice LDR r2, [r3, #0] ; Pickup time-slice CBZ r2, __tx_timer_no_time_slice ; Is it non-active? ; Yes, skip time-slice processing ; ; /* Decrement the time_slice. */ ; _tx_timer_time_slice--; ; SUB r2, r2, #1 ; Decrement the time-slice STR r2, [r3, #0] ; Store new time-slice value ; ; /* Check for expiration. */ ; if (__tx_timer_time_slice == 0) ; CBNZ r2, __tx_timer_no_time_slice ; Has it expired? ; ; /* Set the time-slice expired flag. */ ; _tx_timer_expired_time_slice = TX_TRUE; ; LDR r3, =_tx_timer_expired_time_slice ; Pickup address of expired flag MOV r0, #1 ; Build expired value STR r0, [r3, #0] ; Set time-slice expiration flag ; ; } ; __tx_timer_no_time_slice: ; ; /* Test for timer expiration. */ ; if (*_tx_timer_current_ptr) ; { ; LDR r1, =_tx_timer_current_ptr ; Pickup current timer pointer addr LDR r0, [r1, #0] ; Pickup current timer LDR r2, [r0, #0] ; Pickup timer list entry CBZ r2, __tx_timer_no_timer ; Is there anything in the list? ; No, just increment the timer ; ; /* Set expiration flag. */ ; _tx_timer_expired = TX_TRUE; ; LDR r3, =_tx_timer_expired ; Pickup expiration flag address MOV r2, #1 ; Build expired value STR r2, [r3, #0] ; Set expired flag B __tx_timer_done ; Finished timer processing ; ; } ; else ; { __tx_timer_no_timer: ; ; /* No timer expired, increment the timer pointer. */ ; _tx_timer_current_ptr++; ; ADD r0, r0, #4 ; Move to next timer ; ; /* Check for wrap-around. */ ; if (_tx_timer_current_ptr == _tx_timer_list_end) ; LDR r3, =_tx_timer_list_end ; Pickup addr of timer list end LDR r2, [r3, #0] ; Pickup list end CMP r0, r2 ; Are we at list end? BNE __tx_timer_skip_wrap ; No, skip wrap-around logic ; ; /* Wrap to beginning of list. */ ; _tx_timer_current_ptr = _tx_timer_list_start; ; LDR r3, =_tx_timer_list_start ; Pickup addr of timer list start LDR r0, [r3, #0] ; Set current pointer to list start ; __tx_timer_skip_wrap: ; STR r0, [r1, #0] ; Store new current timer pointer ; } ; __tx_timer_done: ; ; ; /* See if anything has expired. */ ; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) ; { ; LDR r3, =_tx_timer_expired_time_slice ; Pickup addr of expired flag LDR r2, [r3, #0] ; Pickup time-slice expired flag CBNZ r2, __tx_something_expired ; Did a time-slice expire? ; If non-zero, time-slice expired LDR r1, =_tx_timer_expired ; Pickup addr of other expired flag LDR r0, [r1, #0] ; Pickup timer expired flag CBZ r0, __tx_timer_nothing_expired ; Did a timer expire? ; No, nothing expired ; __tx_something_expired: ; ; STMDB sp!, {r0, lr} ; Save the lr register on the stack ; and save r0 just to keep 8-byte alignment ; ; /* Did a timer expire? */ ; if (_tx_timer_expired) ; { ; LDR r1, =_tx_timer_expired ; Pickup addr of expired flag LDR r0, [r1, #0] ; Pickup timer expired flag CBZ r0, __tx_timer_dont_activate ; Check for timer expiration ; If not set, skip timer activation ; ; /* Process timer expiration. */ ; _tx_timer_expiration_process(); ; BL _tx_timer_expiration_process ; Call the timer expiration handling routine ; ; } __tx_timer_dont_activate: ; ; /* Did time slice expire? */ ; if (_tx_timer_expired_time_slice) ; { ; LDR r3, =_tx_timer_expired_time_slice ; Pickup addr of time-slice expired LDR r2, [r3, #0] ; Pickup the actual flag CBZ r2, __tx_timer_not_ts_expiration ; See if the flag is set ; No, skip time-slice processing ; ; /* Time slice interrupted thread. */ ; _tx_thread_time_slice(); BL _tx_thread_time_slice ; Call time-slice processing LDR r0, =_tx_thread_preempt_disable ; Build address of preempt disable flag LDR r1, [r0] ; Is the preempt disable flag set? CBNZ r1, __tx_timer_skip_time_slice ; Yes, skip the PendSV logic LDR r0, =_tx_thread_current_ptr ; Build current thread pointer address LDR r1, [r0] ; Pickup the current thread pointer LDR r2, =_tx_thread_execute_ptr ; Build execute thread pointer address LDR r3, [r2] ; Pickup the execute thread pointer LDR r0, =0xE000ED04 ; Build address of control register LDR r2, =0x10000000 ; Build value for PendSV bit CMP r1, r3 ; Are they the same? BEQ __tx_timer_skip_time_slice ; If the same, there was no time-slice performed STR r2, [r0] ; Not the same, issue the PendSV for preemption __tx_timer_skip_time_slice: ; ; } ; __tx_timer_not_ts_expiration: ; LDMIA sp!, {r0, lr} ; Recover lr register (r0 is just there for ; the 8-byte stack alignment ; ; } ; __tx_timer_nothing_expired: DSB ; Complete all memory access BX lr ; Return to caller ; ;} .type _tx_timer_interrupt,$function .size _tx_timer_interrupt,.-_tx_timer_interrupt