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    .syntax unified
26#if defined(THUMB_MODE)
27    .thumb
28#else
29    .arm
30#endif
31
32/* Define Assembly language external references...  */
33
34    .global     _tx_timer_time_slice
35    .global     _tx_timer_system_clock
36    .global     _tx_timer_current_ptr
37    .global     _tx_timer_list_start
38    .global     _tx_timer_list_end
39    .global     _tx_timer_expired_time_slice
40    .global     _tx_timer_expired
41    .global     _tx_thread_time_slice
42
43    .text
44    .align 2
45/**************************************************************************/
46/*                                                                        */
47/*  FUNCTION                                               RELEASE        */
48/*                                                                        */
49/*    _tx_timer_interrupt                                  ARMv7-A        */
50/*                                                           6.4.0        */
51/*  AUTHOR                                                                */
52/*                                                                        */
53/*    William E. Lamie, Microsoft Corporation                             */
54/*                                                                        */
55/*  DESCRIPTION                                                           */
56/*                                                                        */
57/*    This function processes the hardware timer interrupt.  This         */
58/*    processing includes incrementing the system clock and checking for  */
59/*    time slice and/or timer expiration.  If either is found, the        */
60/*    interrupt context save/restore functions are called along with the  */
61/*    expiration functions.                                               */
62/*                                                                        */
63/*  INPUT                                                                 */
64/*                                                                        */
65/*    None                                                                */
66/*                                                                        */
67/*  OUTPUT                                                                */
68/*                                                                        */
69/*    None                                                                */
70/*                                                                        */
71/*  CALLS                                                                 */
72/*                                                                        */
73/*    _tx_thread_time_slice                 Time slice interrupted thread */
74/*    _tx_timer_expiration_process          Timer expiration processing   */
75/*                                                                        */
76/*  CALLED BY                                                             */
77/*                                                                        */
78/*    interrupt vector                                                    */
79/*                                                                        */
80/*  RELEASE HISTORY                                                       */
81/*                                                                        */
82/*    DATE              NAME                      DESCRIPTION             */
83/*                                                                        */
84/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
85/*  04-25-2022     Zhen Kong                Updated comments,             */
86/*                                            resulting in version 6.1.11 */
87/*  10-31-2023     Tiejun Zhou              Modified comment(s), added    */
88/*                                            #include tx_user.h,         */
89/*                                            resulting in version 6.3.0  */
90/*  12-31-2023     Yajun Xia                Modified comment(s),          */
91/*                                            Added thumb mode support,   */
92/*                                            resulting in version 6.4.0  */
93/*                                                                        */
94/**************************************************************************/
95#if defined(THUMB_MODE)
96    .thumb_func
97#endif
98    .global _tx_timer_interrupt
99    .type   _tx_timer_interrupt,function
100_tx_timer_interrupt:
101
102    /* Upon entry to this routine, it is assumed that context save has already
103       been called, and therefore the compiler scratch registers are available
104       for use.  */
105
106    /* Increment the system clock.  */
107
108    LDR     r1, =_tx_timer_system_clock         // Pickup address of system clock
109    LDR     r0, [r1]                            // Pickup system clock
110    ADD     r0, r0, #1                          // Increment system clock
111    STR     r0, [r1]                            // Store new system clock
112
113    /* Test for time-slice expiration.  */
114
115    LDR     r3, =_tx_timer_time_slice           // Pickup address of time-slice
116    LDR     r2, [r3]                            // Pickup time-slice
117    CMP     r2, #0                              // Is it non-active?
118    BEQ     __tx_timer_no_time_slice            // Yes, skip time-slice processing
119
120    /* Decrement the time_slice.  */
121
122    SUB     r2, r2, #1                          // Decrement the time-slice
123    STR     r2, [r3]                            // Store new time-slice value
124
125    /* Check for expiration.  */
126
127    CMP     r2, #0                              // Has it expired?
128    BNE     __tx_timer_no_time_slice            // No, skip expiration processing
129
130    /* Set the time-slice expired flag.  */
131
132    LDR     r3, =_tx_timer_expired_time_slice   // Pickup address of expired flag
133    MOV     r0, #1                              // Build expired value
134    STR     r0, [r3]                            // Set time-slice expiration flag
135
136__tx_timer_no_time_slice:
137
138    /* Test for timer expiration.  */
139
140    LDR     r1, =_tx_timer_current_ptr          // Pickup current timer pointer address
141    LDR     r0, [r1]                            // Pickup current timer
142    LDR     r2, [r0]                            // Pickup timer list entry
143    CMP     r2, #0                              // Is there anything in the list?
144    BEQ     __tx_timer_no_timer                 // No, just increment the timer
145
146    /* Set expiration flag.  */
147
148    LDR     r3, =_tx_timer_expired              // Pickup expiration flag address
149    MOV     r2, #1                              // Build expired value
150    STR     r2, [r3]                            // Set expired flag
151    B       __tx_timer_done                     // Finished timer processing
152
153__tx_timer_no_timer:
154
155    /* No timer expired, increment the timer pointer.  */
156    ADD     r0, r0, #4                          // Move to next timer
157
158    /* Check for wraparound.  */
159
160    LDR     r3, =_tx_timer_list_end             // Pickup address of timer list end
161    LDR     r2, [r3]                            // Pickup list end
162    CMP     r0, r2                              // Are we at list end?
163    BNE     __tx_timer_skip_wrap                // No, skip wraparound logic
164
165    /* Wrap to beginning of list.  */
166
167    LDR     r3, =_tx_timer_list_start           // Pickup address of timer list start
168    LDR     r0, [r3]                            // Set current pointer to list start
169
170__tx_timer_skip_wrap:
171
172    STR     r0, [r1]                            // Store new current timer pointer
173
174__tx_timer_done:
175
176    /* See if anything has expired.  */
177
178    LDR     r3, =_tx_timer_expired_time_slice   // Pickup address of expired flag
179    LDR     r2, [r3]                            // Pickup time-slice expired flag
180    CMP     r2, #0                              // Did a time-slice expire?
181    BNE     __tx_something_expired              // If non-zero, time-slice expired
182    LDR     r1, =_tx_timer_expired              // Pickup address of other expired flag
183    LDR     r0, [r1]                            // Pickup timer expired flag
184    CMP     r0, #0                              // Did a timer expire?
185    BEQ     __tx_timer_nothing_expired          // No, nothing expired
186
187__tx_something_expired:
188
189    PUSH    {r0, lr}                            // Save the lr register on the stack
190                                                //   and save r0 just to keep 8-byte alignment
191
192    /* Did a timer expire?  */
193
194    LDR     r1, =_tx_timer_expired              // Pickup address of expired flag
195    LDR     r0, [r1]                            // Pickup timer expired flag
196    CMP     r0, #0                              // Check for timer expiration
197    BEQ     __tx_timer_dont_activate            // If not set, skip timer activation
198
199    /* Process timer expiration.  */
200    BL      _tx_timer_expiration_process        // Call the timer expiration handling routine
201
202__tx_timer_dont_activate:
203
204    /* Did time slice expire?  */
205
206    LDR     r3, =_tx_timer_expired_time_slice   // Pickup address of time-slice expired
207    LDR     r2, [r3]                            // Pickup the actual flag
208    CMP     r2, #0                              // See if the flag is set
209    BEQ     __tx_timer_not_ts_expiration        // No, skip time-slice processing
210
211    /* Time slice interrupted thread.  */
212
213    BL      _tx_thread_time_slice               // Call time-slice processing
214
215__tx_timer_not_ts_expiration:
216
217    POP     {r0, lr}                            // Recover lr register (r0 is just there for
218                                                //   the 8-byte stack alignment
219
220__tx_timer_nothing_expired:
221
222    BX      lr                                  // Return to caller
223