1;
2; Copyright (c) 2006-2022, RT-Thread Development Team
3;
4; SPDX-License-Identifier: Apache-2.0
5;
6; Change Logs:
7; Date           Author       Notes
8; 2018-09-01     xuzhuoyi     the first version.
9; 2019-06-17     zhaoxiaowei  fix bugs of old c28x interrupt api.
10; 2019-07-03     zhaoxiaowei  add _rt_hw_calc_csb function to support __rt_ffs.
11; 2019-12-05     xiaolifan    add support for hardware fpu32
12; 2022-06-21     guyunjie     trim pendsv (RTOSINT_Handler)
13; 2022-08-24     guyunjie     fix bugs in context switching
14; 2022-10-15     guyunjie     add zero-latency interrupt
15
16    .ref   rt_interrupt_to_thread
17    .ref   rt_interrupt_from_thread
18    .ref   rt_thread_switch_interrupt_flag
19
20    .def   rtosint_handler
21    .def   rt_hw_get_st0
22    .def   rt_hw_get_st1
23    .def   rt_hw_calc_csb
24    .def   rt_hw_context_switch_interrupt
25    .def   rt_hw_context_switch
26    .def   rt_hw_context_switch_to
27    .def   rt_hw_interrupt_thread_switch
28    .def   rt_hw_interrupt_disable
29    .def   rt_hw_interrupt_enable
30
31    ;importing settings from compiler and config
32    .cdecls C,NOLIST
33    %{
34        #include <rtconfig.h>
35
36        #ifdef __TMS320C28XX_FPU32__
37            #define __FPU32__ 1
38        #else
39            #define __FPU32__ 0
40        #endif
41
42        #ifdef __TMS320C28XX_FPU64__
43            #define __FPU64__ 1
44        #else
45            #define __FPU64__ 0
46        #endif
47
48        #ifdef __TMS320C28XX_VCRC__
49            #define __VCRC__ 1
50        #else
51            #define __VCRC__ 0
52        #endif
53
54        #ifdef RT_USING_ZERO_LATENCY
55            #define ZERO_LATENCY 1
56            #ifndef ZERO_LATENCY_INT_MASK
57                #error ZERO_LATENCY_INT_MASK must be defined for zero latency interrupt
58            #elif ZERO_LATENCY_INT_MASK & 0x8000
59                #error RTOS bit (0x8000) must not be set in ZERO_LATENCY_INT_MASK
60            #endif
61        #else
62            #define ZERO_LATENCY 0
63        #endif
64    %}
65
66
67.text
68    .newblock
69
70;
71; rt_base_t rt_hw_interrupt_disable();
72;
73    .asmfunc
74rt_hw_interrupt_disable:
75    .if ZERO_LATENCY
76    MOV   AL, IER
77    AND   IER, #ZERO_LATENCY_INT_MASK
78    .else
79    PUSH  ST1
80    SETC  INTM
81    POP   AL
82    .endif
83    MOV   AH, #0
84    LRETR
85    .endasmfunc
86
87;
88; void rt_hw_interrupt_enable(rt_base_t level);
89;
90    .asmfunc
91rt_hw_interrupt_enable:
92    .if ZERO_LATENCY
93    MOV   IER, AL
94    .else
95    PUSH  AL
96    POP   ST1
97    .endif
98    LRETR
99    .endasmfunc
100
101;
102; void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
103; ACC   --> from
104; SP[4] --> to
105;
106    .asmfunc
107rt_hw_context_switch_interrupt:
108
109; ACC, XAR4-7 are "save on call" following TI C28x C/C++ compiler convention
110; and therefore can be used in a function without being saved on stack first
111; (the compiler has already saved it before the call).
112; Reference: TMS320C28x Optimizing CC++ Compiler
113; note this convention is only applicable to normal functions not to isrs
114
115    MOVL    XAR6, ACC
116    MOVL    XAR4, *-SP[4]
117    ; set rt_thread_switch_interrupt_flag to 1
118    MOVL    XAR5, #rt_thread_switch_interrupt_flag
119    MOVL    ACC, *XAR5
120    BF      reswitch2, NEQ                    ; ACC!=0
121    MOVB    ACC, #1
122    MOVL    *XAR5, ACC
123
124    MOVL    XAR5, #rt_interrupt_from_thread   ; set rt_interrupt_from_thread
125    MOVL    *XAR5, XAR6
126
127reswitch2:
128    MOVL    XAR5, #rt_interrupt_to_thread     ; set rt_interrupt_to_thread
129    MOVL    *XAR5, XAR4
130    LRETR
131    .endasmfunc
132
133;
134; void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
135; ACC   --> from
136; SP[4] --> to
137;
138    .asmfunc
139rt_hw_context_switch:
140
141    MOVL    XAR6, ACC
142    MOVL    XAR4, *-SP[4]
143    ; set rt_thread_switch_interrupt_flag to 1
144    MOVL    XAR5, #rt_thread_switch_interrupt_flag
145    MOVL    ACC, *XAR5
146    BF      reswitch1, NEQ                    ; ACC!=0
147    MOVB    ACC, #1
148    MOVL    *XAR5, ACC
149
150    MOVL    XAR5, #rt_interrupt_from_thread   ; set rt_interrupt_from_thread
151    MOVL    *XAR5, XAR6
152
153reswitch1:
154    MOVL    XAR5, #rt_interrupt_to_thread     ; set rt_interrupt_to_thread
155    MOVL    *XAR5, XAR4
156    OR      IFR, #0x8000
157    LRETR
158    .endasmfunc
159;
160; * void rt_hw_context_switch_to(rt_uint32 to);
161; * ACC --> to
162;
163    .asmfunc
164rt_hw_context_switch_to:
165    ; get to thread
166    MOVL    XAR5, #rt_interrupt_to_thread
167    MOVL    *XAR5, ACC
168
169    ; set from thread to 0
170    MOVL    XAR5, #rt_interrupt_from_thread
171    MOVL    XAR4, #0
172    MOVL    *XAR5, XAR4
173
174    ; set interrupt flag to 1
175    MOVL    XAR5, #rt_thread_switch_interrupt_flag
176    MOVL    XAR4, #1
177    MOVL    *XAR5, XAR4
178
179    ; trigger rtos interrupt
180    OR      IFR, #0x8000
181    OR      IER, #0x8000
182    CLRC    INTM
183
184    ; never reach here!
185    .endasmfunc
186
187    .asmfunc
188rtosint_handler:
189
190    .if ZERO_LATENCY
191    ; mask out non-critical interrupts and enable global interrupt
192    ; so rtosint_handler won't block critical interrupts
193    AND  IER, #ZERO_LATENCY_INT_MASK
194    CLRC INTM
195    .endif
196
197    MOVL ACC, *-SP[4]
198    MOV  AR0, AL   ; save original IER
199
200    PUSH    AR1H:AR0H
201    PUSH    XAR2
202
203    ; get rt_thread_switch_interrupt_flag
204    MOVL    XAR1, #rt_thread_switch_interrupt_flag
205    MOVL    ACC, *XAR1
206    BF      rtosint_exit, EQ         ; rtos_int already handled
207
208    ; clear rt_thread_switch_interrupt_flag to 0
209    MOVL    XAR2, #0
210    MOVL    *XAR1, XAR2
211
212    MOVL    XAR1, #rt_interrupt_from_thread
213    MOVL    ACC, *XAR1
214    BF      switch_to_thread, EQ     ; skip register save at the first time
215
216    PUSH    XAR3
217    PUSH    XAR4
218    PUSH    XAR5
219    PUSH    XAR6
220    PUSH    XAR7
221    PUSH    XT
222    PUSH    RPC
223
224    .if __FPU32__
225    PUSH    RB
226    MOV32   *SP++, STF
227    MOV32   *SP++, R0H
228    MOV32   *SP++, R1H
229    MOV32   *SP++, R2H
230    MOV32   *SP++, R3H
231    MOV32   *SP++, R4H
232    MOV32   *SP++, R5H
233    MOV32   *SP++, R6H
234    MOV32   *SP++, R7H
235    .endif
236
237    .if __FPU64__
238    MOV32   *SP++, R0L
239    MOV32   *SP++, R1L
240    MOV32   *SP++, R2L
241    MOV32   *SP++, R3L
242    MOV32   *SP++, R4L
243    MOV32   *SP++, R5L
244    MOV32   *SP++, R6L
245    MOV32   *SP++, R7L
246    .endif
247
248    .if __VCRC__
249    VMOV32  *SP++, VCRC
250    VMOV32  *SP++, VSTATUS
251    VMOV32  *SP++, VCRCPOLY
252    VMOV32  *SP++, VCRCSIZE
253    .endif
254
255    MOVL    ACC, *XAR1
256    MOVL    XAR1, ACC
257    MOVZ    AR2, @SP                 ; get from thread stack pointer
258    MOVL    *XAR1, XAR2              ; update from thread stack pointer
259
260switch_to_thread:
261    MOVL    XAR1, #rt_interrupt_to_thread
262    MOVL    ACC, *XAR1
263    MOVL    XAR1, ACC
264    MOVL    ACC, *XAR1
265    MOV     @SP, AL                  ; load thread stack pointer
266
267    .if __VCRC__
268    VMOV32  VCRCSIZE, *--SP
269    VMOV32  VCRCPOLY, *--SP
270    VMOV32  VSTATUS, *--SP
271    VMOV32  VCRC, *--SP
272    .endif
273
274    .if __FPU64__
275    MOV32   R7L, *--SP
276    MOV32   R6L, *--SP
277    MOV32   R5L, *--SP
278    MOV32   R4L, *--SP
279    MOV32   R3L, *--SP
280    MOV32   R2L, *--SP
281    MOV32   R1L, *--SP
282    MOV32   R0L, *--SP
283    .endif
284
285    .if __FPU32__
286    MOV32   R7H, *--SP
287    MOV32   R6H, *--SP
288    MOV32   R5H, *--SP
289    MOV32   R4H, *--SP
290    MOV32   R3H, *--SP
291    MOV32   R2H, *--SP
292    MOV32   R1H, *--SP
293    MOV32   R0H, *--SP
294    MOV32   STF, *--SP
295    POP     RB
296    .endif
297
298    POP     RPC
299    POP     XT
300    POP     XAR7
301    POP     XAR6
302    POP     XAR5
303    POP     XAR4
304    POP     XAR3
305
306rtosint_exit:
307    ; do not restore interrupt here: to be restored according to the
308    ; switched-to context during IRET (automaticlly by hardware)
309
310    POP     XAR2
311    POP     AR1H:AR0H
312
313    MOVL    ACC , *-SP[4]
314    MOV     AL, AR0
315    MOVL    *-SP[4], ACC
316
317    IRET
318    .endasmfunc
319
320    .asmfunc
321rt_hw_get_st0:
322    PUSH    ST0
323    POP     AL
324    LRETR
325    .endasmfunc
326
327    .asmfunc
328rt_hw_get_st1:
329    PUSH    ST1
330    POP     AL
331    LRETR
332    .endasmfunc
333
334; C28x do not have a build-in "__ffs" func in its C compiler.
335; We can use the "Count Sign Bits" (CSB) instruction to make one.
336; CSB will return the number of 0's minus 1 above the highest set bit.
337; The count is placed in T. For example:
338;    ACC        T     maxbit
339; 0x00000001    30      0
340; 0x00000010    26      4
341; 0x000001FF    22      8
342; 0x000001F0    22      8
343    .asmfunc
344rt_hw_calc_csb:
345    MOV     AH, #0
346    CSB     ACC                   ; T = no. of sign bits - 1
347    MOVU    ACC, T                ; ACC = no. of sign bits - 1
348    SUBB    ACC, #30              ; ACC = ACC - 30
349    ABS     ACC                   ; ACC = |ACC|
350    LRETR
351    .endasmfunc
352
353; compatible with old version
354    .asmfunc
355rt_hw_interrupt_thread_switch:
356    LRETR
357    NOP
358    .endasmfunc
359
360.end
361