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
22#ifdef TX_INCLUDE_USER_DEFINE_FILE
23#include "tx_user.h"
24#endif
25
26    EXTERN      _tx_timer_time_slice
27    EXTERN      _tx_timer_system_clock
28    EXTERN      _tx_timer_current_ptr
29    EXTERN      _tx_timer_list_start
30    EXTERN      _tx_timer_list_end
31    EXTERN      _tx_timer_expired_time_slice
32    EXTERN      _tx_timer_expired
33    EXTERN      _tx_thread_time_slice
34    EXTERN      _tx_timer_expiration_process
35    EXTERN      _tx_thread_current_ptr
36    EXTERN      _tx_thread_execute_ptr
37    EXTERN      _tx_thread_preempt_disable
38
39    SECTION `.text`:CODE:NOROOT(2)
40    THUMB
41/**************************************************************************/
42/*                                                                        */
43/*  FUNCTION                                               RELEASE        */
44/*                                                                        */
45/*    _tx_timer_interrupt                              Cortex-Mx/IAR      */
46/*                                                           6.3.0        */
47/*  AUTHOR                                                                */
48/*                                                                        */
49/*    Scott Larson, Microsoft Corporation                                 */
50/*                                                                        */
51/*  DESCRIPTION                                                           */
52/*                                                                        */
53/*    This function processes the hardware timer interrupt.  This         */
54/*    processing includes incrementing the system clock and checking for  */
55/*    time slice and/or timer expiration.  If either is found, the        */
56/*    expiration functions are called.                                    */
57/*                                                                        */
58/*  INPUT                                                                 */
59/*                                                                        */
60/*    None                                                                */
61/*                                                                        */
62/*  OUTPUT                                                                */
63/*                                                                        */
64/*    None                                                                */
65/*                                                                        */
66/*  CALLS                                                                 */
67/*                                                                        */
68/*    _tx_timer_expiration_process          Timer expiration processing   */
69/*    _tx_thread_time_slice                 Time slice interrupted thread */
70/*                                                                        */
71/*  CALLED BY                                                             */
72/*                                                                        */
73/*    interrupt vector                                                    */
74/*                                                                        */
75/*  RELEASE HISTORY                                                       */
76/*                                                                        */
77/*    DATE              NAME                      DESCRIPTION             */
78/*                                                                        */
79/*  06-02-2021      Scott Larson            Initial Version 6.1.7         */
80/*  01-31-2022      Scott Larson            Modified comment(s), added    */
81/*                                            TX_NO_TIMER support,        */
82/*                                            resulting in version 6.1.10 */
83/*  10-31-2023      Tiejun Zhou             Included tx_user.h,           */
84/*                                            resulting in version 6.3.0  */
85/*                                                                        */
86/**************************************************************************/
87// VOID   _tx_timer_interrupt(VOID)
88// {
89#ifndef TX_NO_TIMER
90    PUBLIC  _tx_timer_interrupt
91_tx_timer_interrupt:
92
93    /* Upon entry to this routine, it is assumed that the compiler scratch registers are available
94       for use.  */
95
96    /* Increment the system clock.  */
97    // _tx_timer_system_clock++;
98
99    LDR     r1, =_tx_timer_system_clock             // Pickup address of system clock
100    LDR     r0, [r1, #0]                            // Pickup system clock
101    ADD     r0, r0, #1                              // Increment system clock
102    STR     r0, [r1, #0]                            // Store new system clock
103
104    /* Test for time-slice expiration.  */
105    // if (_tx_timer_time_slice)
106    // {
107
108    LDR     r3, =_tx_timer_time_slice               // Pickup address of time-slice
109    LDR     r2, [r3, #0]                            // Pickup time-slice
110    CBZ     r2, __tx_timer_no_time_slice            // Is it non-active?
111                                                    // Yes, skip time-slice processing
112
113       /* Decrement the time_slice.  */
114       // _tx_timer_time_slice--;
115
116    SUB     r2, r2, #1                              // Decrement the time-slice
117    STR     r2, [r3, #0]                            // Store new time-slice value
118
119       /* Check for expiration.  */
120       // if (__tx_timer_time_slice == 0)
121
122    CBNZ    r2, __tx_timer_no_time_slice            // Has it expired?
123                                                    // No, skip expiration processing
124
125       /* Set the time-slice expired flag.  */
126       // _tx_timer_expired_time_slice =  TX_TRUE;
127
128    LDR     r3, =_tx_timer_expired_time_slice       // Pickup address of expired flag
129    MOV     r0, #1                                  // Build expired value
130    STR     r0, [r3, #0]                            // Set time-slice expiration flag
131
132    // }
133
134__tx_timer_no_time_slice:
135
136    /* Test for timer expiration.  */
137    // if (*_tx_timer_current_ptr)
138    // {
139
140    LDR     r1, =_tx_timer_current_ptr              // Pickup current timer pointer address
141    LDR     r0, [r1, #0]                            // Pickup current timer
142    LDR     r2, [r0, #0]                            // Pickup timer list entry
143    CBZ     r2, __tx_timer_no_timer                 // Is there anything in the list?
144                                                    // No, just increment the timer
145
146        /* Set expiration flag.  */
147        // _tx_timer_expired =  TX_TRUE;
148
149    LDR     r3, =_tx_timer_expired                  // Pickup expiration flag address
150    MOV     r2, #1                                  // Build expired value
151    STR     r2, [r3, #0]                            // Set expired flag
152    B       __tx_timer_done                         // Finished timer processing
153
154    // }
155    // else
156    // {
157__tx_timer_no_timer:
158
159        /* No timer expired, increment the timer pointer.  */
160        // _tx_timer_current_ptr++;
161
162    ADD     r0, r0, #4                              // Move to next timer
163
164        /* Check for wrap-around.  */
165        // if (_tx_timer_current_ptr == _tx_timer_list_end)
166
167    LDR     r3, =_tx_timer_list_end                 // Pickup addr of timer list end
168    LDR     r2, [r3, #0]                            // Pickup list end
169    CMP     r0, r2                                  // Are we at list end?
170    BNE     __tx_timer_skip_wrap                    // No, skip wrap-around logic
171
172            /* Wrap to beginning of list.  */
173            // _tx_timer_current_ptr =  _tx_timer_list_start;
174
175    LDR     r3, =_tx_timer_list_start               // Pickup addr of timer list start
176    LDR     r0, [r3, #0]                            // Set current pointer to list start
177
178__tx_timer_skip_wrap:
179
180    STR     r0, [r1, #0]                            // Store new current timer pointer
181    // }
182
183__tx_timer_done:
184
185    /* See if anything has expired.  */
186    // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
187    // {
188
189    LDR     r3, =_tx_timer_expired_time_slice       // Pickup addr of expired flag
190    LDR     r2, [r3, #0]                            // Pickup time-slice expired flag
191    CBNZ    r2, __tx_something_expired              // Did a time-slice expire?
192                                                    // If non-zero, time-slice expired
193    LDR     r1, =_tx_timer_expired                  // Pickup addr of other expired flag
194    LDR     r0, [r1, #0]                            // Pickup timer expired flag
195    CBZ     r0, __tx_timer_nothing_expired          // Did a timer expire?
196                                                    // No, nothing expired
197
198__tx_something_expired:
199
200    STMDB   sp!, {r0, lr}                           // Save the lr register on the stack
201                                                    //   and save r0 just to keep 8-byte alignment
202
203    /* Did a timer expire?  */
204    // if (_tx_timer_expired)
205    // {
206
207    LDR     r1, =_tx_timer_expired                  // Pickup addr of expired flag
208    LDR     r0, [r1, #0]                            // Pickup timer expired flag
209    CBZ     r0, __tx_timer_dont_activate            // Check for timer expiration
210                                                    // If not set, skip timer activation
211
212        /* Process timer expiration.  */
213        // _tx_timer_expiration_process();
214
215    BL      _tx_timer_expiration_process            // Call the timer expiration handling routine
216
217    // }
218__tx_timer_dont_activate:
219
220    /* Did time slice expire?  */
221    // if (_tx_timer_expired_time_slice)
222    // {
223
224    LDR     r3, =_tx_timer_expired_time_slice       // Pickup addr of time-slice expired
225    LDR     r2, [r3, #0]                            // Pickup the actual flag
226    CBZ     r2, __tx_timer_not_ts_expiration        // See if the flag is set
227                                                    // No, skip time-slice processing
228
229        /* Time slice interrupted thread.  */
230        // _tx_thread_time_slice();
231
232    BL      _tx_thread_time_slice                   // Call time-slice processing
233    LDR     r0, =_tx_thread_preempt_disable         // Build address of preempt disable flag
234    LDR     r1, [r0]                                // Is the preempt disable flag set?
235    CBNZ    r1, __tx_timer_skip_time_slice          // Yes, skip the PendSV logic
236    LDR     r0, =_tx_thread_current_ptr             // Build current thread pointer address
237    LDR     r1, [r0]                                // Pickup the current thread pointer
238    LDR     r2, =_tx_thread_execute_ptr             // Build execute thread pointer address
239    LDR     r3, [r2]                                // Pickup the execute thread pointer
240    LDR     r0, =0xE000ED04                         // Build address of control register
241    LDR     r2, =0x10000000                         // Build value for PendSV bit
242    CMP     r1, r3                                  // Are they the same?
243    BEQ     __tx_timer_skip_time_slice              // If the same, there was no time-slice performed
244    STR     r2, [r0]                                // Not the same, issue the PendSV for preemption
245__tx_timer_skip_time_slice:
246
247    // }
248
249__tx_timer_not_ts_expiration:
250
251    LDMIA   sp!, {r0, lr}                           // Recover lr register (r0 is just there for
252                                                    //   the 8-byte stack alignment
253
254    // }
255
256__tx_timer_nothing_expired:
257
258    DSB                                             // Complete all memory access
259    BX      lr                                      // Return to caller
260// }
261#endif
262    END
263