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