1@/*************************************************************************** 2@ * Copyright (c) 2024 Microsoft Corporation 3@ * 4@ * This program and the accompanying materials are made available under the 5@ * terms of the MIT License which is available at 6@ * https://opensource.org/licenses/MIT. 7@ * 8@ * SPDX-License-Identifier: MIT 9@ **************************************************************************/ 10@ 11@ 12@/**************************************************************************/ 13@/**************************************************************************/ 14@/** */ 15@/** ThreadX Component */ 16@/** */ 17@/** Timer */ 18@/** */ 19@/**************************************************************************/ 20@/**************************************************************************/ 21#ifdef TX_INCLUDE_USER_DEFINE_FILE 22#include "tx_user.h" 23#endif 24 25 .arm 26 27@ 28@/* Define Assembly language external references... */ 29@ 30 .global _tx_timer_time_slice 31 .global _tx_timer_system_clock 32 .global _tx_timer_current_ptr 33 .global _tx_timer_list_start 34 .global _tx_timer_list_end 35 .global _tx_timer_expired_time_slice 36 .global _tx_timer_expired 37 .global _tx_thread_time_slice 38@ 39@ 40@ 41@/* Define the 16-bit Thumb mode veneer for _tx_timer_interrupt for 42@ applications calling this function from to 16-bit Thumb mode. */ 43@ 44 .text 45 .align 2 46 .thumb 47 .global $_tx_timer_interrupt 48 .type $_tx_timer_interrupt,function 49$_tx_timer_interrupt: 50 BX pc @ Switch to 32-bit mode 51 NOP @ 52 .arm 53 STMFD sp!, {lr} @ Save return address 54 BL _tx_timer_interrupt @ Call _tx_timer_interrupt function 55 LDMFD sp!, {lr} @ Recover saved return address 56 BX lr @ Return to 16-bit caller 57@ 58@ 59 .text 60 .align 2 61@/**************************************************************************/ 62@/* */ 63@/* FUNCTION RELEASE */ 64@/* */ 65@/* _tx_timer_interrupt ARM9/GNU */ 66@/* 6.2.1 */ 67@/* AUTHOR */ 68@/* */ 69@/* William E. Lamie, Microsoft Corporation */ 70@/* */ 71@/* DESCRIPTION */ 72@/* */ 73@/* This function processes the hardware timer interrupt. This */ 74@/* processing includes incrementing the system clock and checking for */ 75@/* time slice and/or timer expiration. If either is found, the */ 76@/* interrupt context save/restore functions are called along with the */ 77@/* expiration functions. */ 78@/* */ 79@/* INPUT */ 80@/* */ 81@/* None */ 82@/* */ 83@/* OUTPUT */ 84@/* */ 85@/* None */ 86@/* */ 87@/* CALLS */ 88@/* */ 89@/* _tx_thread_time_slice Time slice interrupted thread */ 90@/* _tx_timer_expiration_process Timer expiration processing */ 91@/* */ 92@/* CALLED BY */ 93@/* */ 94@/* interrupt vector */ 95@/* */ 96@/* RELEASE HISTORY */ 97@/* */ 98@/* DATE NAME DESCRIPTION */ 99@/* */ 100@/* 09-30-2020 William E. Lamie Initial Version 6.1 */ 101@/* 03-08-2023 Cindy Deng Modified comment(s), added */ 102@/* #include tx_user.h, */ 103@/* resulting in version 6.2.1 */ 104@/* */ 105@/**************************************************************************/ 106@VOID _tx_timer_interrupt(VOID) 107@{ 108 .global _tx_timer_interrupt 109 .type _tx_timer_interrupt,function 110_tx_timer_interrupt: 111@ 112@ /* Upon entry to this routine, it is assumed that context save has already 113@ been called, and therefore the compiler scratch registers are available 114@ for use. */ 115@ 116@ /* Increment the system clock. */ 117@ _tx_timer_system_clock++; 118@ 119 LDR r1, =_tx_timer_system_clock @ Pickup address of system clock 120 LDR r0, [r1] @ Pickup system clock 121 ADD r0, r0, #1 @ Increment system clock 122 STR r0, [r1] @ Store new system clock 123@ 124@ /* Test for time-slice expiration. */ 125@ if (_tx_timer_time_slice) 126@ { 127@ 128 LDR r3, =_tx_timer_time_slice @ Pickup address of time-slice 129 LDR r2, [r3] @ Pickup time-slice 130 CMP r2, #0 @ Is it non-active? 131 BEQ __tx_timer_no_time_slice @ Yes, skip time-slice processing 132@ 133@ /* Decrement the time_slice. */ 134@ _tx_timer_time_slice--; 135@ 136 SUB r2, r2, #1 @ Decrement the time-slice 137 STR r2, [r3] @ Store new time-slice value 138@ 139@ /* Check for expiration. */ 140@ if (__tx_timer_time_slice == 0) 141@ 142 CMP r2, #0 @ Has it expired? 143 BNE __tx_timer_no_time_slice @ No, skip expiration processing 144@ 145@ /* Set the time-slice expired flag. */ 146@ _tx_timer_expired_time_slice = TX_TRUE; 147@ 148 LDR r3, =_tx_timer_expired_time_slice @ Pickup address of expired flag 149 MOV r0, #1 @ Build expired value 150 STR r0, [r3] @ Set time-slice expiration flag 151@ 152@ } 153@ 154__tx_timer_no_time_slice: 155@ 156@ /* Test for timer expiration. */ 157@ if (*_tx_timer_current_ptr) 158@ { 159@ 160 LDR r1, =_tx_timer_current_ptr @ Pickup current timer pointer address 161 LDR r0, [r1] @ Pickup current timer 162 LDR r2, [r0] @ Pickup timer list entry 163 CMP r2, #0 @ Is there anything in the list? 164 BEQ __tx_timer_no_timer @ No, just increment the timer 165@ 166@ /* Set expiration flag. */ 167@ _tx_timer_expired = TX_TRUE; 168@ 169 LDR r3, =_tx_timer_expired @ Pickup expiration flag address 170 MOV r2, #1 @ Build expired value 171 STR r2, [r3] @ Set expired flag 172 B __tx_timer_done @ Finished timer processing 173@ 174@ } 175@ else 176@ { 177__tx_timer_no_timer: 178@ 179@ /* No timer expired, increment the timer pointer. */ 180@ _tx_timer_current_ptr++; 181@ 182 ADD r0, r0, #4 @ Move to next timer 183@ 184@ /* Check for wraparound. */ 185@ if (_tx_timer_current_ptr == _tx_timer_list_end) 186@ 187 LDR r3, =_tx_timer_list_end @ Pickup address of timer list end 188 LDR r2, [r3] @ Pickup list end 189 CMP r0, r2 @ Are we at list end? 190 BNE __tx_timer_skip_wrap @ No, skip wraparound logic 191@ 192@ /* Wrap to beginning of list. */ 193@ _tx_timer_current_ptr = _tx_timer_list_start; 194@ 195 LDR r3, =_tx_timer_list_start @ Pickup address of timer list start 196 LDR r0, [r3] @ Set current pointer to list start 197@ 198__tx_timer_skip_wrap: 199@ 200 STR r0, [r1] @ Store new current timer pointer 201@ } 202@ 203__tx_timer_done: 204@ 205@ 206@ /* See if anything has expired. */ 207@ if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) 208@ { 209@ 210 LDR r3, =_tx_timer_expired_time_slice @ Pickup address of expired flag 211 LDR r2, [r3] @ Pickup time-slice expired flag 212 CMP r2, #0 @ Did a time-slice expire? 213 BNE __tx_something_expired @ If non-zero, time-slice expired 214 LDR r1, =_tx_timer_expired @ Pickup address of other expired flag 215 LDR r0, [r1] @ Pickup timer expired flag 216 CMP r0, #0 @ Did a timer expire? 217 BEQ __tx_timer_nothing_expired @ No, nothing expired 218@ 219__tx_something_expired: 220@ 221@ 222 STMDB sp!, {r0, lr} @ Save the lr register on the stack 223 @ and save r0 just to keep 8-byte alignment 224@ 225@ /* Did a timer expire? */ 226@ if (_tx_timer_expired) 227@ { 228@ 229 LDR r1, =_tx_timer_expired @ Pickup address of expired flag 230 LDR r0, [r1] @ Pickup timer expired flag 231 CMP r0, #0 @ Check for timer expiration 232 BEQ __tx_timer_dont_activate @ If not set, skip timer activation 233@ 234@ /* Process timer expiration. */ 235@ _tx_timer_expiration_process(); 236@ 237 BL _tx_timer_expiration_process @ Call the timer expiration handling routine 238@ 239@ } 240__tx_timer_dont_activate: 241@ 242@ /* Did time slice expire? */ 243@ if (_tx_timer_expired_time_slice) 244@ { 245@ 246 LDR r3, =_tx_timer_expired_time_slice @ Pickup address of time-slice expired 247 LDR r2, [r3] @ Pickup the actual flag 248 CMP r2, #0 @ See if the flag is set 249 BEQ __tx_timer_not_ts_expiration @ No, skip time-slice processing 250@ 251@ /* Time slice interrupted thread. */ 252@ _tx_thread_time_slice(); 253@ 254 BL _tx_thread_time_slice @ Call time-slice processing 255@ 256@ } 257@ 258__tx_timer_not_ts_expiration: 259@ 260 LDMIA sp!, {r0, lr} @ Recover lr register (r0 is just there for 261 @ the 8-byte stack alignment 262@ 263@ } 264@ 265__tx_timer_nothing_expired: 266@ 267#ifdef __THUMB_INTERWORK 268 BX lr @ Return to caller 269#else 270 MOV pc, lr @ Return to caller 271#endif 272@ 273@} 274 275