summaryrefslogtreecommitdiff
path: root/libcpu/ti-dsp/c28x/context.s
blob: 82207bce1b7f5bb02dd1f60d831dc286b6e64518 (plain)
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