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;#define TX_SOURCE_CODE
23;
24;
25;/* Include necessary system files.  */
26;
27;#include "tx_api.h"
28;#include "tx_timer.h"
29;#include "tx_thread.h"
30;
31;
32;Define Assembly language external references...
33;
34    IMPORT      _tx_timer_time_slice
35    IMPORT      _tx_timer_system_clock
36    IMPORT      _tx_timer_current_ptr
37    IMPORT      _tx_timer_list_start
38    IMPORT      _tx_timer_list_end
39    IMPORT      _tx_timer_expired_time_slice
40    IMPORT      _tx_timer_expired
41    IMPORT      _tx_thread_time_slice
42    IMPORT      _tx_timer_expiration_process
43;
44;
45        AREA ||.text||, CODE, READONLY
46        PRESERVE8
47;/**************************************************************************/
48;/*                                                                        */
49;/*  FUNCTION                                               RELEASE        */
50;/*                                                                        */
51;/*    _tx_timer_interrupt                                 ARM11/AC5       */
52;/*                                                            6.1         */
53;/*  AUTHOR                                                                */
54;/*                                                                        */
55;/*    William E. Lamie, Microsoft Corporation                             */
56;/*                                                                        */
57;/*  DESCRIPTION                                                           */
58;/*                                                                        */
59;/*    This function processes the hardware timer interrupt.  This         */
60;/*    processing includes incrementing the system clock and checking for  */
61;/*    time slice and/or timer expiration.  If either is found, the        */
62;/*    interrupt context save/restore functions are called along with the  */
63;/*    expiration functions.                                               */
64;/*                                                                        */
65;/*  INPUT                                                                 */
66;/*                                                                        */
67;/*    None                                                                */
68;/*                                                                        */
69;/*  OUTPUT                                                                */
70;/*                                                                        */
71;/*    None                                                                */
72;/*                                                                        */
73;/*  CALLS                                                                 */
74;/*                                                                        */
75;/*    _tx_timer_expiration_process          Timer expiration processing   */
76;/*    _tx_thread_time_slice                 Time slice interrupted thread */
77;/*                                                                        */
78;/*  CALLED BY                                                             */
79;/*                                                                        */
80;/*    interrupt vector                                                    */
81;/*                                                                        */
82;/*  RELEASE HISTORY                                                       */
83;/*                                                                        */
84;/*    DATE              NAME                      DESCRIPTION             */
85;/*                                                                        */
86;/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
87;/*                                                                        */
88;/**************************************************************************/
89;VOID   _tx_timer_interrupt(VOID)
90;{
91    EXPORT  _tx_timer_interrupt
92_tx_timer_interrupt
93;
94;    /* Upon entry to this routine, it is assumed that context save has already
95;       been called, and therefore the compiler scratch registers are available
96;       for use.  */
97;
98;    /* Increment the system clock.  */
99;    _tx_timer_system_clock++;
100;
101    LDR     r1, =_tx_timer_system_clock         ; Pickup address of system clock
102    LDR     r0, [r1, #0]                        ; Pickup system clock
103    ADD     r0, r0, #1                          ; Increment system clock
104    STR     r0, [r1, #0]                        ; Store new system clock
105;
106;    /* Test for time-slice expiration.  */
107;    if (_tx_timer_time_slice)
108;    {
109;
110    LDR     r3, =_tx_timer_time_slice           ; Pickup address of time-slice
111    LDR     r2, [r3, #0]                        ; Pickup time-slice
112    CMP     r2, #0                              ; Is it non-active?
113    BEQ     __tx_timer_no_time_slice            ; Yes, skip time-slice processing
114;
115;       /* Decrement the time_slice.  */
116;       _tx_timer_time_slice--;
117;
118    SUB     r2, r2, #1                          ; Decrement the time-slice
119    STR     r2, [r3, #0]                        ; Store new time-slice value
120;
121;       /* Check for expiration.  */
122;       if (__tx_timer_time_slice == 0)
123;
124    CMP     r2, #0                              ; Has it expired?
125    BNE     __tx_timer_no_time_slice            ; No, skip expiration processing
126;
127;       /* Set the time-slice expired flag.  */
128;       _tx_timer_expired_time_slice =  TX_TRUE;
129;
130    LDR     r3, =_tx_timer_expired_time_slice   ; Pickup address of expired flag
131    MOV     r0, #1                              ; Build expired value
132    STR     r0, [r3, #0]                        ; Set time-slice expiration flag
133;
134;    }
135;
136__tx_timer_no_time_slice
137;
138;    /* Test for timer expiration.  */
139;    if (*_tx_timer_current_ptr)
140;    {
141;
142    LDR     r1, =_tx_timer_current_ptr          ; Pickup current timer pointer addr
143    LDR     r0, [r1, #0]                        ; Pickup current timer
144    LDR     r2, [r0, #0]                        ; Pickup timer list entry
145    CMP     r2, #0                              ; Is there anything in the list?
146    BEQ     __tx_timer_no_timer                 ; No, just increment the timer
147;
148;        /* Set expiration flag.  */
149;        _tx_timer_expired =  TX_TRUE;
150;
151    LDR     r3, =_tx_timer_expired              ; Pickup expiration flag address
152    MOV     r2, #1                              ; Build expired value
153    STR     r2, [r3, #0]                        ; Set expired flag
154    B       __tx_timer_done                     ; Finished timer processing
155;
156;    }
157;    else
158;    {
159__tx_timer_no_timer
160;
161;        /* No timer expired, increment the timer pointer.  */
162;        _tx_timer_current_ptr++;
163;
164    ADD     r0, r0, #4                          ; Move to next timer
165;
166;        /* Check for wrap-around.  */
167;        if (_tx_timer_current_ptr == _tx_timer_list_end)
168;
169    LDR     r3, =_tx_timer_list_end             ; Pickup addr of timer list end
170    LDR     r2, [r3, #0]                        ; Pickup list end
171    CMP     r0, r2                              ; Are we at list end?
172    BNE     __tx_timer_skip_wrap                ; No, skip wrap-around logic
173;
174;            /* Wrap to beginning of list.  */
175;            _tx_timer_current_ptr =  _tx_timer_list_start;
176;
177    LDR     r3, =_tx_timer_list_start           ; Pickup addr of timer list start
178    LDR     r0, [r3, #0]                        ; Set current pointer to list start
179;
180__tx_timer_skip_wrap
181;
182    STR     r0, [r1, #0]                        ; Store new current timer pointer
183;    }
184;
185__tx_timer_done
186;
187;
188;    /* See if anything has expired.  */
189;    if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
190;    {
191;
192    LDR     r3, =_tx_timer_expired_time_slice   ; Pickup addr of expired flag
193    LDR     r2, [r3, #0]                        ; Pickup time-slice expired flag
194    CMP     r2, #0                              ; Did a time-slice expire?
195    BNE     __tx_something_expired              ; If non-zero, time-slice expired
196    LDR     r1, =_tx_timer_expired              ; Pickup addr of other expired flag
197    LDR     r0, [r1, #0]                        ; Pickup timer expired flag
198    CMP     r0, #0                              ; Did a timer expire?
199    BEQ     __tx_timer_nothing_expired          ; No, nothing expired
200;
201__tx_something_expired
202;
203;
204    STMDB   sp!, {r0, lr}                       ; Save the lr register on the stack
205                                                ;   and save r0 just to keep 8-byte alignment
206;
207;    /* Did a timer expire?  */
208;    if (_tx_timer_expired)
209;    {
210;
211    LDR     r1, =_tx_timer_expired              ; Pickup addr of expired flag
212    LDR     r0, [r1, #0]                        ; Pickup timer expired flag
213    CMP     r0, #0                              ; Check for timer expiration
214    BEQ     __tx_timer_dont_activate            ; If not set, skip timer activation
215;
216;        /* Process timer expiration.  */
217;        _tx_timer_expiration_process();
218;
219    BL      _tx_timer_expiration_process        ; Call the timer expiration handling routine
220;
221;    }
222__tx_timer_dont_activate
223;
224;    /* Did time slice expire?  */
225;    if (_tx_timer_expired_time_slice)
226;    {
227;
228    LDR     r3, =_tx_timer_expired_time_slice   ; Pickup addr of time-slice expired
229    LDR     r2, [r3, #0]                        ; Pickup the actual flag
230    CMP     r2, #0                              ; See if the flag is set
231    BEQ     __tx_timer_not_ts_expiration        ; No, skip time-slice processing
232;
233;        /* Time slice interrupted thread.  */
234;        _tx_thread_time_slice();
235
236    BL      _tx_thread_time_slice               ; Call time-slice processing
237;
238;    }
239;
240__tx_timer_not_ts_expiration
241;
242    LDMIA   sp!, {r0, lr}                       ; Recover lr register (r0 is just there for
243                                                ;   the 8-byte stack alignment
244;
245;    }
246;
247__tx_timer_nothing_expired
248;
249    IF  {INTER} = {TRUE}
250    BX      lr                                  ; Return to caller
251    ELSE
252    MOV     pc, lr                              ; Return to caller
253    ENDIF
254;
255;}
256    END
257
258