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