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    .equ        SWI0, 872E0H
35    .global     __tx_timer_time_slice
36    .global     __tx_timer_system_clock
37    .global     __tx_timer_current_ptr
38    .global     __tx_timer_list_start
39    .global     __tx_timer_list_end
40    .global     __tx_timer_expired_time_slice
41    .global     __tx_timer_expired
42    .global     __tx_timer_expiration_process
43    .global     __tx_thread_context_save
44    .global     __tx_thread_time_slice
45    .global     __tx_thread_context_restore
46    .global     __tx_thread_preempt_disable
47    .global     __tx_thread_execute_ptr
48    .global     __tx_thread_current_ptr
49;
50    .SECTION    P,CODE
51;/**************************************************************************/
52;/*                                                                        */
53;/*  FUNCTION                                               RELEASE        */
54;/*                                                                        */
55;/*    _tx_timer_interrupt                                  RXv3/GNURX     */
56;/*                                                           6.1.11       */
57;/*  AUTHOR                                                                */
58;/*                                                                        */
59;/*    William E. Lamie, Microsoft Corporation                             */
60;/*                                                                        */
61;/*  DESCRIPTION                                                           */
62;/*                                                                        */
63;/*    This function processes the hardware timer interrupt.  This         */
64;/*    processing includes incrementing the system clock and checking for  */
65;/*    time slice and/or timer expiration.  If either is found, the        */
66;/*    interrupt context save/restore functions are called along with the  */
67;/*    expiration functions.                                               */
68;/*                                                                        */
69;/*  INPUT                                                                 */
70;/*                                                                        */
71;/*    None                                                                */
72;/*                                                                        */
73;/*  OUTPUT                                                                */
74;/*                                                                        */
75;/*    None                                                                */
76;/*                                                                        */
77;/*  CALLS                                                                 */
78;/*                                                                        */
79;/*    _tx_thread_context_save               Save interrupted context      */
80;/*    _tx_timer_expiration_process          Timer expiration processing   */
81;/*    _tx_thread_time_slice                 Time slice interrupted thread */
82;/*    _tx_thread_context_restore            Restore interrupted context   */
83;/*                                                                        */
84;/*  CALLED BY                                                             */
85;/*                                                                        */
86;/*    interrupt vector                                                    */
87;/*                                                                        */
88;/*  RELEASE HISTORY                                                       */
89;/*                                                                        */
90;/*    DATE              NAME                      DESCRIPTION             */
91;/*                                                                        */
92;/*  06-02-2021     William E. Lamie         Initial Version 6.1.7         */
93;/*  10-15-2021     William E. Lamie         Modified comment(s),          */
94;/*                                            resulting in version 6.1.9  */
95;/*  01-31-2022     William E. Lamie         Modified comment(s), and      */
96;/*                                            added missing thread        */
97;/*                                            preemption logic,           */
98;/*                                            resulting in version 6.1.10 */
99;/*  04-25-2022     William E. Lamie         Modified comment(s),          */
100;/*                                            resulting in version 6.1.11 */
101;/*                                                                        */
102;/**************************************************************************/
103;VOID   _tx_timer_interrupt(VOID)
104;{
105    .global __tx_timer_interrupt
106__tx_timer_interrupt:
107;
108;    /* Upon entry to this routine, it is assumed that all interrupts are locked
109;       out and the stack looks like the following:
110;                            SP+4 ->    Interrupted PC
111;                            SP+8->    Interrupted SR
112;   */
113;
114;    /* Increment the system clock.  */
115;    _tx_timer_system_clock++;
116;
117    PUSHM    R14-R15
118    PUSHM    R1-R5
119
120    MOV.L    #__tx_timer_system_clock, R1       ; Pickup address of system clock
121    MOV.L    [R1], R2                           ; Pickup system clock
122    ADD      #1, R2                             ; Increment system clock
123    MOV.L    R2,[R1]                            ; Store new system clock
124;
125;    /* Test for time-slice expiration.  */
126;    if (_tx_timer_time_slice)
127;    {
128;
129    MOV.L   #__tx_timer_time_slice, R1          ; Pickup address of time slice
130    MOV.L   [R1], R2                            ; Pickup the current time slice
131    CMP     #0, R2                              ; Is a time slice active?
132    BEQ     __tx_timer_no_time_slice            ; No, skip timer slice processing
133;
134;       /* Decrement the time_slice.  */
135;       _tx_timer_time_slice--;
136;
137    SUB     #1, R2                              ; Decrement the time-slice
138    MOV.L   R2, [R1]                            ; Store time-slice
139;
140;       /* Check for expiration.  */
141;       if (__tx_timer_time_slice == 0)
142;
143    CMP     #0, R2                              ; Has it expired?
144    BNE     __tx_timer_no_time_slice            ; No, time-slice has not expired
145;
146;       /* Set the time-slice expired flag.  */
147;       _tx_timer_expired_time_slice =  TX_TRUE;
148;
149    MOV.L   #__tx_timer_expired_time_slice, R1  ; Pickup address of expired time-slice
150    MOV.L   #1, R2                              ; Build expired value
151    MOV.L   R2, [R1]                            ; Set expired time slice variable
152;    }
153;
154__tx_timer_no_time_slice:
155;
156;    /* Test for timer expiration.  */
157;    if (*_tx_timer_current_ptr)
158;    {
159;
160    MOV.L   #__tx_timer_current_ptr, R1         ; Pickup address of current timer ptr
161    MOV.L   [R1], R2                            ; Pickup current pointer
162    MOV.L   [R2+], R1                           ; Pickup timer list entry, _tx_timer_current_ptr++
163    CMP     #0, R1                              ; Is timer pointer NULL?
164    BEQ     __tx_timer_no_timer                 ; Yes, no timer has expired
165
166;
167;        /* Set expiration flag.  */
168;        _tx_timer_expired =  TX_TRUE;
169;
170    MOV.L   #__tx_timer_expired,R2              ; Build address of expired flag
171    MOV.L   #1, R1                              ; Build expired value
172    MOV.L   R1, [R2]
173    BRA     __tx_timer_done                     ; Finished with timer processing
174;
175;    }
176;    else
177;    {
178__tx_timer_no_timer:
179;
180;        /* No timer expired, increment the timer pointer.  */
181;        _tx_timer_current_ptr++;
182;
183;       /* R2 already contains __tx_timer_current_ptr++ */
184;
185;        /* Check for wrap-around.  */
186;        if (_tx_timer_current_ptr == _tx_timer_list_end)
187;
188    MOV.L   #__tx_timer_list_end, R1            ; Pickup the timer list end ptr
189    MOV.L   [R1], R1                            ; Pickup actual timer list end
190    CMP     R1, R2                              ; Are we at list end?
191    BNE     __tx_timer_skip_wrap                ; No, don't move pointer to the
192                                                ;   top of the list
193;
194;            /* Wrap to beginning of list.  */
195;            _tx_timer_current_ptr =  _tx_timer_list_start;
196;
197    MOV.L   #__tx_timer_list_start, R2          ; Pickup the timer list start ptr
198    MOV.L   [R2], R2                            ; Pickup the start of the list
199;    }
200;
201__tx_timer_skip_wrap:
202    MOV.L   #__tx_timer_current_ptr,R1
203    MOV.L   R2, [R1]                            ; Store in updated pointer in  _tx_timer_current_ptr
204
205__tx_timer_done:
206;
207;    /* See if anything has expired.  */
208;    if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
209;    {
210;
211    MOV.L  #__tx_timer_expired_time_slice, R1   ; Pickup expired time slice addr
212    MOV.L  [R1], R1                             ; Pickup expired time slice
213    MOV.L   #__tx_timer_expired, R2             ; Pickup expired timer flag address
214    MOV.L   [R2], R2                            ; Pickup actual flag
215    OR      R1, R2                              ; Or flags together
216    BEQ     __tx_timer_nothing_expired          ; If Z set, nothing has expired
217
218__tx_something_expired:
219;    /* Did a timer expire?  */
220;    if (_tx_timer_expired)
221;    {
222    MOV.L   #__tx_timer_expired,R1              ; Pickup expired flag address
223    MOV.L   [R1], R1                            ; Pickup expired flag
224    CMP     #0,R1                               ; Is the expired timer flag set?
225    BEQ     __tx_timer_dont_activate            ; No, skip timer activation
226;
227;        /* Process timer expiration.  */
228;        _tx_timer_expiration_process();
229;
230    BSR    __tx_timer_expiration_process        ; Call the timer expiration handling routine
231;
232;    }
233__tx_timer_dont_activate:
234;
235;    /* Did time slice expire?  */
236;    if (_tx_timer_expired_time_slice)
237;    {
238;
239    MOV.L   #__tx_timer_expired_time_slice, R1  ; Pickup time-slice expired flag addr
240    MOV.L   [R1], R1                            ; Pickup actual flag
241    CMP     #0,R1                               ; Has time-slice expired?
242    BEQ      __tx_timer_not_ts_expiration       ; No, skip time-slice expiration
243;
244;        /* Time slice interrupted thread.  */
245;        _tx_thread_time_slice();
246
247    BSR     __tx_thread_time_slice              ; Call time-slice processing
248
249;   /* Check if we must trigger a context switch. */
250    MOV.L   #__tx_thread_preempt_disable, R1     ; Load prempt disable flag.
251    MOV.L  [R1], R1
252    CMP    #0, R1
253	BNE    __tx_timer_not_ts_expiration          ; Skip if prempt disabled.
254
255    MOV.L   #__tx_thread_execute_ptr, R1
256    MOV.L  [R1], R1
257    MOV.L   #__tx_thread_current_ptr, R2
258    MOV.L  [R2], R2
259    CMP    R1, R2
260    BEQ    __tx_timer_not_ts_expiration
261
262    MOV.L   #SWI0, R1
263    MOV.L   #1, [R1]
264
265;    }
266;
267__tx_timer_not_ts_expiration:
268
269__tx_timer_nothing_expired:
270
271    POPM R1-R5
272    POPM R14-R15
273;
274    RTS                                         ; Return to point of interrupt
275;
276;}
277
278    .end
279
280
281
282