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