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