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/* Copyright (c) Cadence Design Systems, Inc. */ 13/* */ 14/* Permission is hereby granted, free of charge, to any person obtaining */ 15/* a copy of this software and associated documentation files (the */ 16/* "Software"), to deal in the Software without restriction, including */ 17/* without limitation the rights to use, copy, modify, merge, publish, */ 18/* distribute, sublicense, and/or sell copies of the Software, and to */ 19/* permit persons to whom the Software is furnished to do so, subject to */ 20/* the following conditions: */ 21/* */ 22/* The above copyright notice and this permission notice shall be */ 23/* included in all copies or substantial portions of the Software. */ 24/* */ 25/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 26/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 27/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ 28/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ 29/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ 30/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ 31/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 32/**************************************************************************/ 33 34/**************************************************************************/ 35/**************************************************************************/ 36/** */ 37/** ThreadX Component */ 38/** */ 39/** Timer */ 40/** */ 41/**************************************************************************/ 42/**************************************************************************/ 43 44 45#include "xtensa_rtos.h" 46#include "tx_api_asm.h" 47 48#ifndef TX_NO_TIMER 49 50 .text 51 52/**************************************************************************/ 53/* */ 54/* DESCRIPTION */ 55/* */ 56/* This function processes the hardware timer interrupt. This */ 57/* processing includes incrementing the system clock and checking for */ 58/* time slice and/or timer expiration. If either is found, the */ 59/* interrupt context save/restore functions are called along with the */ 60/* expiration functions. */ 61/* */ 62/* RELEASE HISTORY */ 63/* */ 64/* DATE NAME DESCRIPTION */ 65/* */ 66/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ 67/* 04-25-2022 Scott Larson Modified comments and updated */ 68/* function name, */ 69/* resulting in version 6.1.11 */ 70/* */ 71/**************************************************************************/ 72 73// VOID _tx_timer_interrupt(VOID) 74// { 75 .globl _tx_timer_interrupt 76 .type _tx_timer_interrupt,@function 77 .align 4 78_tx_timer_interrupt: 79 80 #ifdef __XTENSA_CALL0_ABI__ 81 /* Define local variable spill offsets in stack frame for Call0 ABI. */ 82 #define __tx_timer_interrupt_a0 0 /* ENTRY()/RET() saves/restores */ 83 #define __tx_timer_interrupt_a2 4 /* preserve a2 */ 84 #define __tx_timer_interrupt_a3 8 /* preserve a3 */ 85 #endif 86 87 ENTRY(16) 88 89 .globl tx_timer_user_isr 90 .weak tx_timer_user_isr 91 movi a2, tx_timer_user_isr 92 beqz a2, 1f 93 #ifdef __XTENSA_CALL0_ABI__ 94 callx0 a2 95 #else 96 callx8 a2 97 #endif 981: 99 100 /* 101 Xtensa timers work by comparing a cycle counter with a preset value. 102 Once the match occurs an interrupt is generated, and the handler has 103 to set a new cycle count into the comparator. To avoid clock drift 104 due to interrupt latency, the new cycle count is computed from the old, 105 not the time the interrupt was serviced. However if a timer interrupt 106 is ever serviced more than one tick late, it is necessary to process 107 multiple ticks until the new cycle count is in the future, otherwise 108 the next timer interrupt would not occur until after the cycle counter 109 had wrapped (2^32 cycles later). 110 111 do { 112 ticks++; 113 old_ccompare = read_ccompare_i(); 114 write_ccompare_i( old_ccompare + divisor ); 115 service one tick; 116 diff = read_ccount() - old_ccompare; 117 } while ( diff > divisor ); 118 */ 119 120.L_tx_timer_catchup: 121 122 /* Increment the system clock. */ 123 // _tx_timer_system_clock++; 124 movi a2, _tx_timer_system_clock /* a2 = &_tx_timer_system_clock */ 125 l32i a3, a2, 0 /* a3 = _tx_timer_system_clock++ */ 126 addi a3, a3, 1 127 s32i a3, a2, 0 128 129 /* Update the timer comparator for the next tick. */ 130 #ifdef XT_CLOCK_FREQ 131 movi a2, XT_TICK_DIVISOR /* a2 = comparator increment */ 132 #else 133 movi a3, xt_tick_divisor 134 l32i a2, a3, 0 /* a2 = comparator increment */ 135 #endif 136 rsr a3, XT_CCOMPARE /* a3 = old comparator value */ 137 add a4, a3, a2 /* a4 = new comparator value */ 138 wsr a4, XT_CCOMPARE /* update comp. and clear interrupt */ 139 esync 140 141 /* Test for time-slice expiration. */ 142 // if (_tx_timer_time_slice) 143 // { 144 movi a4, _tx_timer_time_slice /* a4 = &_tx_timer_time_slice */ 145 l32i a5, a4, 0 /* a5 = _tx_timer_time_slice */ 146 beqz a5, .L_tx_timer_no_time_slice 147 148 /* Decrement the time_slice. */ 149 // _tx_timer_time_slice--; 150 addi a5, a5, -1 151 s32i a5, a4, 0 152 153 /* Check for expiration. */ 154 // if (_tx_timer_time_slice == 0) 155 bnez a5, .L_tx_timer_no_time_slice 156 157 /* Set the time-slice expired flag. */ 158 // _tx_timer_expired_time_slice = TX_TRUE; 159 movi a4, _tx_timer_expired_time_slice 160 movi a5, TX_TRUE 161 s32i a5, a4, 0 162 163 // } 164 165.L_tx_timer_no_time_slice: 166 167 /* Test for timer expiration. */ 168 // if (*_tx_timer_current_ptr) 169 // { 170 movi a4, _tx_timer_current_ptr /* a4 = &_tx_timer_current_ptr */ 171 l32i a5, a4, 0 /* a5 = _tx_timer_current_ptr */ 172 l32i a6, a5, 0 /* a6 = *_tx_timer_current_ptr */ 173 beqz a6, .L_tx_timer_no_timer 174 175 /* Set expiration flag. */ 176 // _tx_timer_expired = TX_TRUE; 177 movi a6, _tx_timer_expired 178 movi a7, TX_TRUE 179 s32i a7, a6, 0 180 j .L_tx_timer_done 181 182 // } 183 // else 184 // { 185 186.L_tx_timer_no_timer: 187 188 /* No timer expired, increment the timer pointer. */ 189 // _tx_timer_current_ptr++; 190 191 /* Check for wrap-around. */ 192 // if (_tx_timer_current_ptr == _tx_timer_list_end) 193 movi a6, _tx_timer_list_end 194 l32i a6, a6, 0 /* a6 = _tx_timer_list_end */ 195 addi a5, a5, 4 /* a5 = ++_tx_timer_current_ptr */ 196 bne a5, a6, .L_tx_timer_skip_wrap 197 198 /* Wrap to beginning of list. */ 199 // _tx_timer_current_ptr = _tx_timer_list_start; 200 movi a6, _tx_timer_list_start 201 l32i a5, a6, 0 /* a5 = _tx_timer_list_start */ 202 203.L_tx_timer_skip_wrap: 204 205 s32i a5, a4, 0 /* _tx_timer_current_ptr = a5 */ 206 // } 207 208.L_tx_timer_done: 209 210 /* See if anything has expired. */ 211 // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) 212 // { 213 214 #ifdef __XTENSA_CALL0_ABI__ 215 /* Preserve a2 and a3 across calls. */ 216 s32i a2, sp, __tx_timer_interrupt_a2 217 s32i a3, sp, __tx_timer_interrupt_a3 218 #endif 219 220 /* Did a timer expire? */ 221 // if (_tx_timer_expired) 222 // { 223 movi a4, _tx_timer_expired 224 l32i a5, a4, 0 225 beqz a5, .L_tx_timer_dont_activate 226 227 /* Call the timer expiration processing. */ 228 // _tx_timer_expiration_process(); 229 #ifdef __XTENSA_CALL0_ABI__ 230 call0 _tx_timer_expiration_process 231 #else 232 call8 _tx_timer_expiration_process 233 #endif 234 235 // } 236 237.L_tx_timer_dont_activate: 238 239 /* Did time slice expire? */ 240 // if (_tx_timer_expired_time_slice) 241 // { 242 movi a4, _tx_timer_expired_time_slice 243 l32i a5, a4, 0 244 beqz a5, .L_tx_timer_not_ts_expiration 245 246 /* Time slice interrupted thread. */ 247 // _tx_thread_time_slice(); 248 #ifdef __XTENSA_CALL0_ABI__ 249 call0 _tx_thread_time_slice 250 #else 251 call8 _tx_thread_time_slice 252 #endif 253 254 // } 255 256.L_tx_timer_not_ts_expiration: 257 258 #ifdef __XTENSA_CALL0_ABI__ 259 /* Restore a2 and a3. */ 260 l32i a2, sp, __tx_timer_interrupt_a2 261 l32i a3, sp, __tx_timer_interrupt_a3 262 #endif 263 264 // } 265 266.Ln_tx_timer_nothing_expired: 267 268 /* Check if we need to process more ticks to catch up. */ 269 esync /* ensure comparator update complete */ 270 rsr a4, CCOUNT /* a4 = cycle count */ 271 sub a4, a4, a3 /* diff = ccount - old comparator */ 272 blt a2, a4, .L_tx_timer_catchup /* repeat while diff > divisor */ 273 274 RET(16) 275 276// } 277 278#endif /* TX_NO_TIMER */ 279 280