context.asm 9.76 KB
;
; Copyright (c) 2021, Shenzhen Academy of Aerospace Technology
;
; SPDX-License-Identifier: Apache-2.0
;
; Change Logs:
; Date           Author       Notes
; 2021-11-16     Dystopia     the first version
;

;-----------------------------------------------------------
;               context switch for C6000 DSP
;-----------------------------------------------------------

    .include "contextinc.asm"
;-----------------------------------------------------------
;                      macro definition
;-----------------------------------------------------------
DP  .set    B14
SP  .set    B15
;
;-----------------------------------------------------------
;

;-----------------------------------------------------------
;                      global variable
;-----------------------------------------------------------
    .global rt_interrupt_from_thread
    .global rt_interrupt_to_thread
    .global rt_thread_switch_interrupt_flag
;
;-----------------------------------------------------------
;
    .sect   ".text"
;-----------------------------------------------------------
; void rt_hw_enable_exception(void)
;-----------------------------------------------------------
    .global rt_hw_enable_exception
rt_hw_enable_exception:
    DINT
    MVC .S2 TSR,B0
    MVC .S2 B3,NRP
    MVK .L2 0xC,B1
    OR  .D2 B0,B1,B0
    MVC .S2 B0,TSR    ; Set GEE and XEN in TSR
    B   .S2 NRP
    NOP 5

;-----------------------------------------------------------
; rt_base_t rt_hw_interrupt_enable(void)
;-----------------------------------------------------------
    .global rt_hw_interrupt_disable
rt_hw_interrupt_disable:
;{
    MVC CSR,B4
    MV  B4,A4
    AND 1,B4,B0
 [!B0]  CLR B4,1,1,B4
 [B0]   SET B4,1,1,B4
    CLR B4,0,0,B4
    MVC B4,CSR
    B   B3
    NOP 5
;}

;-----------------------------------------------------------
; void rt_hw_interrupt_enable(rt_base_t scr)
;-----------------------------------------------------------
    .global rt_hw_interrupt_enable
rt_hw_interrupt_enable:
;{
    MVC A4,CSR
    B   B3
    NOP 5
;}

;-----------------------------------------------------------
; rt_uint32_t rt_hw_get_current_dp(void)
;-----------------------------------------------------------
    .global rt_hw_get_current_dp
rt_hw_get_current_dp:
;{
    B   B3
    MV  B14,    A4
    NOP 4
;}

;-----------------------------------------------------------
; rt_int32_t __fls(rt_int32_t val)
;-----------------------------------------------------------
    .global __fls
__fls:
;{
    B   B3
    LMBD  .L1  1,A4,A4
    NOP 4
;}

;-----------------------------------------------------------
; rt_int32_t __ffs(rt_int32_t val)
;-----------------------------------------------------------
    .global __ffs
__ffs:
;{
    BITR  .M1  A4,A4
    B   B3
    LMBD  .L1  1,A4,A4
    NOP 4
;}

;
;-----------------------------------------------------------
;

;
; void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; A4 --> from
; B4 --> to
;
    .global rt_hw_context_switch
rt_hw_context_switch:
; {
    SUBAW   .D2 SP,2,SP
    ADD .D1X    SP,-8,A15
 || STDW    .D2T1   A15:A14,*SP--[3]    ; Store A15:A14

    STDW    .D2T2   B13:B12,*SP--[1]    ; Store B13:B12
 || STDW    .D1T1   A13:A12,*A15--[1]   ; Store A13:A12
 || MV      B3,B13
    STDW    .D2T2   B11:B10,*SP--[1]    ; Store B11:B10
 || STDW    .D1T1   A11:A10,*A15--[1]   ; Store A11:A10
 || MVC .S2 CSR,B12
    STDW    .D2T2   B13:B12,*SP--[1]    ; Store PC:CSR
 || MVC .S2 TSR,B5

    MVC .S2 ILC,B11
    MVC .S2 RILC,B10
    STDW    .D2T2   B11:B10,*SP--[1]    ; Store RILC:ILC
 || MV  .S1X    B5,A3

    ZERO    A2                          ;
    STDW    .D2T1   A3:A2,*SP--[1]      ; Store TSR:stack type
    STW SP,*A4                          ; Save thread's stack pointer
    B   rt_hw_context_switch_to
    MV  B4,A4
    NOP 4
;}

;
; void rt_hw_context_switch_to(rt_uint32 to);
; A4 --> to
;
    .global rt_hw_context_switch_to
rt_hw_context_switch_to:
;{
    LDW *A4,SP
    NOP 4
    LDDW    .D2T2   *++SP[1],B9:B8      ; get TSR (B9) and stack frame type (B8)
    LDDW    .D2T2   *++SP[1],B11:B10    ; get RILC (B11) and ILC (B10)
    LDDW    .D2T2   *++SP[1],B13:B12    ; get PC (B13) and CSR (B12)
    NOP 2
    MV  B8,B0
 [B0]  BNOP _rt_thread_interrupt_stack, 5
;
; this maybe do better
;
    LDDW    .D2T2   *++SP[1],B11:B10
 || MVC .S2 B11,RILC                    ; Restore RILC
    LDDW    .D2T2   *++SP[1],B13:B12
 || MVC .S2 B10,ILC                     ; Restore ILC
    LDDW    .D2T1   *++SP[1],A11:A10
 || MV  B13,B3                          ; Restore PC
    LDDW    .D2T1   *++SP[1],A13:A12
 || MVC .S2 B12,CSR                     ; Restore CSR
    LDDW    .D2T1   *++SP[1],A15:A14
    B   B3                              ; Return to caller
    ADDAW   .D2 SP,2,SP
    NOP 4                               ; Delay slots
_rt_thread_interrupt_stack:
    ADDAW   .D1X    SP,30,A15
    LDDW    .D1T1   *++A15[1],A17:A16
 || LDDW    .D2T2   *++SP[1],B17:B16
    LDDW    .D1T1   *++A15[1],A19:A18
 || LDDW    .D2T2   *++SP[1],B19:B18
    LDDW    .D1T1   *++A15[1],A21:A20
 || LDDW    .D2T2   *++SP[1],B21:B20
    LDDW    .D1T1   *++A15[1],A23:A22
 || LDDW    .D2T2   *++SP[1],B23:B22
    LDDW    .D1T1   *++A15[1],A25:A24
 || LDDW    .D2T2   *++SP[1],B25:B24
    LDDW    .D1T1   *++A15[1],A27:A26
 || LDDW    .D2T2   *++SP[1],B27:B26
    LDDW    .D1T1   *++A15[1],A29:A28
 || LDDW    .D2T2   *++SP[1],B29:B28
    LDDW    .D1T1   *++A15[1],A31:A30
 || LDDW    .D2T2   *++SP[1],B31:B30

    LDDW    .D1T1   *++A15[1],A1:A0
 || LDDW    .D2T2   *++SP[1],B1:B0

    LDDW    .D1T1   *++A15[1],A3:A2
 || LDDW    .D2T2   *++SP[1],B3:B2
 || MVC .S2 B9,ITSR                     ; Restore ITSR
    LDDW    .D1T1   *++A15[1],A5:A4
 || LDDW    .D2T2   *++SP[1],B5:B4
 || MVC .S2 B11,RILC                    ; Restore RILC
    LDDW    .D1T1   *++A15[1],A7:A6
 || LDDW    .D2T2   *++SP[1],B7:B6
 || MVC .S2 B10,ILC                     ; Restore ILC

    LDDW    .D1T1   *++A15[1],A9:A8
 || LDDW    .D2T2   *++SP[1],B9:B8
 || MVC .S2 B13,IRP                     ; Restore IPR

    LDDW    .D1T1   *++A15[1],A11:A10
 || LDDW    .D2T2   *++SP[1],B11:B10
 || MVC .S2 B12,CSR                     ; Restore CSR

    LDDW    .D1T1   *++A15[1],A13:A12
 || LDDW    .D2T2   *++SP[1],B13:B12

    MV  .D2X    A15,SP
    LDDW    .D2T1   *++SP[1],A15:A14
    B   IRP                             ; Return to point of interrupt
    LDDW    .D2T2   *+SP[1],SP:DP
    NOP 4                               ; Delay slots
;}

;
;-----------------------------------------------------------
;

;
; void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to)
; A4 --> from
; B4 --> to
;{
    .global rt_hw_context_switch_interrupt
rt_hw_context_switch_interrupt:
    SUB     B15,0x8,B15
    STW     B4,*B15[2]
    STW     A4,*B15[1]
    LDW     *+B14(rt_thread_switch_interrupt_flag),B4
    NOP     4
    CMPEQ   1,B4,B0
    [ B0]  BNOP _reswitch,5
    MVK     1,B4
    STW     B4,*+B14(rt_thread_switch_interrupt_flag)
    MV          A4,B4
    STW     B4,*+B14(rt_interrupt_from_thread)
_reswitch:
    LDW     *B15[2],B4
    NOP     4
    STW     B4,*+B14(rt_interrupt_to_thread)
    ADD     8,B15,B15
    BNOP    B3,5
;}

;-----------------------------------------------------------
;
;void rt_interrupt_context_restore(void)
;
    .global rt_interrupt_context_restore
rt_interrupt_context_restore:
;{
    MVKL    rt_thread_switch_interrupt_flag,A3
    MVKH    rt_thread_switch_interrupt_flag,A3
    LDW     *A3,A1
    NOP     4
    CMPEQ   1,A1,A2
 [A2]  BNOP  rt_preempt_context_restore,5
    LDDW    .D2T2   *++SP[1],B9:B8      ; get TSR (B9)
    LDDW    .D2T2   *++SP[1],B11:B10    ; get RILC (B11) and ILC (B10)
    LDDW    .D2T2   *++SP[1],B13:B12    ; get PC (B13) and CSR (B12)

    ADDAW   .D1X    SP,30,A15

    LDDW    .D1T1   *++A15[1],A17:A16
 || LDDW    .D2T2   *++SP[1],B17:B16
    LDDW    .D1T1   *++A15[1],A19:A18
 || LDDW    .D2T2   *++SP[1],B19:B18
    LDDW    .D1T1   *++A15[1],A21:A20
 || LDDW    .D2T2   *++SP[1],B21:B20
    LDDW    .D1T1   *++A15[1],A23:A22
 || LDDW    .D2T2   *++SP[1],B23:B22
    LDDW    .D1T1   *++A15[1],A25:A24
 || LDDW    .D2T2   *++SP[1],B25:B24
    LDDW    .D1T1   *++A15[1],A27:A26
 || LDDW    .D2T2   *++SP[1],B27:B26
    LDDW    .D1T1   *++A15[1],A29:A28
 || LDDW    .D2T2   *++SP[1],B29:B28
    LDDW    .D1T1   *++A15[1],A31:A30
 || LDDW    .D2T2   *++SP[1],B31:B30

    LDDW    .D1T1   *++A15[1],A1:A0
 || LDDW    .D2T2   *++SP[1],B1:B0
    LDDW    .D1T1   *++A15[1],A3:A2
 || LDDW    .D2T2   *++SP[1],B3:B2
 || MVC .S2 B9,ITSR
    LDDW    .D1T1   *++A15[1],A5:A4
 || LDDW    .D2T2   *++SP[1],B5:B4
 || MVC .S2 B11,RILC
    LDDW    .D1T1   *++A15[1],A7:A6
 || LDDW    .D2T2   *++SP[1],B7:B6
 || MVC .S2 B10,ILC
    LDDW    .D1T1   *++A15[1],A9:A8
 || LDDW    .D2T2   *++SP[1],B9:B8
 || MVC .S2 B13,IRP

    LDDW    .D1T1   *++A15[1],A11:A10
 || LDDW    .D2T2   *++SP[1],B11:B10
 || MVC .S2 B12,CSR
    LDDW    .D1T1   *++A15[1],A13:A12
 || LDDW    .D2T2   *++SP[1],B13:B12

    MV  .D2X    A15,SP
 || MVKL    .S1 rt_system_stack_top,A15
    MVKH    .S1 rt_system_stack_top,A15
 || ADDAW   .D1X    SP,6,A14
    STW .D1T1   A14,*A15                ; save system stack pointer

    LDDW    .D2T1   *++SP[1],A15:A14
    B   .S2 IRP                         ; return from interruption
    LDDW    .D2T2   *+SP[1],SP:DP
    NOP     4
rt_preempt_context_restore:
    ZERO    A12
    STW A12,*A3                         ; clear rt_thread_switch_interrupt_flag
;
; restore saved registers by system stack
;
    RESTORE_ALL IRP,ITSR
;
; store registers to thread stack
;
    THREAD_SAVE_ALL IRP,ITSR

    MVKL    rt_interrupt_from_thread,A11
    MVKH    rt_interrupt_from_thread,A11
    LDW     *A11,A10
    NOP
    MVKL    rt_interrupt_to_thread,B10
    MVKH    rt_interrupt_to_thread,B10
    LDW     *B10,B11
    NOP     3
    STW     SP,*A10                     ; store sp in preempted tasks's TCB
    B       rt_hw_context_switch_to
    MV      B11,A4
    NOP     4
;}
    .end