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