📄 hwi.h62
字号:
;
; Copyright 2003 by Texas Instruments Incorporated.
; All rights reserved. Property of Texas Instruments Incorporated.
; Restricted rights to use, duplicate or disclose this code are
; granted through contract.
;
;
; "@(#) DSP/BIOS 4.90.270 12-18-03 (barracuda-o04)"
;
; ======== hwi.h62 ========
; Assembly language HWI macros for C62
;
;
.if ($isdefed("HWI_") = 0) ; prevent multiple includes of this file
HWI_ .set 1
HWI_REGS .set 019c0000h ; interrupt selector register base
HWI_SAT .set 0200h ; bit position of SAT in CSR
.include c62.h62
.include chk.h62
.include swi.h62
.include trc.h62
;
;# ======== HWI_Obj ========
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
.asg ":HWI_mkStub$regs:", HWI_Obj$regs
HWI_Obj .macro cflag, name, id, fxn, monitor, addr, type, operation, client, dispatch, arg, intrmask, ccmask
CHK_nargs "HWI_Obj", client
.if ($symcmp(":CHK_status:", "error") = 0)
.mexit
.endif
.global :name:, fxn
.if (cflag != 0)
:name: .set :id:
.endif
.var vector, clientcfg
.asg hwi:id:, vector ; default vector = self branch
; set clientcfg to 1 (or 0) according to whether the client module
; is configured (or not).
.asg 0, clientcfg
.if ($symcmp(client, "USER") != 0)
.if ($symcmp(client, "CSL") == 0)
.asg 1, clientcfg
.else
.if (:client:$ = 1)
.asg 1, clientcfg
.endif
.endif
.endif
; The following call to .mexit is to avoid generation of HWI objects
; for interrupts greater that INT15. This allows an HWI_UNUSED object
; to be listed in the configuration. This exit code was first put at
; the start of the macro but this caused an error saying that USER$
; was undefined. The exit was put at this point in the macro to avoid
; the build error.
.if (id > 15)
.mexit
.endif
.asg :dispatch:, local_dispatch
.asg :fxn:, local_fxn
; if this object is configured *and* is not "HWI_unused"
.if ((cflag != 0) & ($symcmp(":local_fxn:", "HWI_unused") != 0))
; if client is USER or another configured system module
.if (($symcmp(client, "USER") = 0) | (:clientcfg: = 1))
; if no monitor, simply branch to user function directly
.if ($symcmp(monitor, "Nothing") = 0)
.asg :local_fxn:, vector ; vector = user specified fxn
; else when need to monitor, create a function stub and call it
.else
.if ( local_dispatch )
.if ( $symcmp(":local_fxn:", "CLK_F_isr") = 0 )
HWI_mkStub :name:_stub, monitor, addr, operation, :name:_STS, CLK_F_isr
.else
HWI_mkStub :name:_stub, monitor, addr, operation, :name:_STS, HWI_F_dispatch
.endif
.else
HWI_mkStub :name:_stub, monitor, addr, operation, :name:_STS, :local_fxn:
.endif
.asg :name:_stub, vector ; vector = HWI stub
.endif
.endif
.endif
.if ($isdefed("HWI_GENERATE_RESET_VEC") = 0)
.asg 0, HWI_GENERATE_RESET_VEC
.endif
.if HWI_GENERATE_RESET_VEC = 1 ; HWI_GENERATE_RESET_VEC is generated
; by the config tool
.sect ".hwi_reset"
.if ((id == 0))
; For reset vector do not save/restore register used for
; branch, because b15 has not been initialized yet, and this
; causes an access to an indeterminate place in memory.
mvkl :vector:,b0 ; load destination function address to b0
mvkh :vector:,b0
b b0 ; start branch to destination function
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
.endif
.endif
; Now define ISFP. Use a register for branching so can reach whole
; address space.
.sect ".hwi_vec"
.global hwi:id:
hwi:id::
.if ((id == 0))
; For reset vector do not save/restore register used for branch,
; because b15 has not been initialized yet, and this causes an
; access to an indeterminate place in memory.
mvkl :vector:,b0 ; load destination function address to b0
mvkh :vector:,b0
b b0 ; start branch to destination function
zero b0 ; disable interrupts by clearing 'IER'
mvc b0,ier
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
.elseif (id == 2)
.if (RTDX_USERTEXECUTION)
.ref RTEMU_exe
stw b0,*b15--[2] ; temp save b0 on stack
mvkl RTEMU_exe,b0 ; load destination function address
mvkh RTEMU_exe,b0
b b0 ; start branch to destination function
ldw *++b15[2],b0 ; restore b0 register
nop 2 ; fill 2 b0 restore/branch delay slots
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
.else
spin?
b spin? ; nested branches to block interrupts
nop 4
b spin?
nop
nop
nop
nop
nop
.endif
.elseif (($symcmp(local_fxn, "HWI_unused") == 0) & (!local_dispatch))
; plug inifinite loop -- with nested branches to
; disable interrupts -- for all undefined vectors that
; aren't checked to "Use HWI Dispatcher"
spin?
b spin? ; nested branches to block interrupts
nop 4
b spin?
nop
nop
nop
nop
nop
.else
.if ( local_dispatch )
.global _HWI_dispatchTab
.var dispatch_fxn
.var vec_fxn
.if ( $symcmp(":local_fxn:", "CLK_F_isr") = 0 )
.global CLK_F_isr
.global FXN_F_run
.if ($symcmp(monitor, "Nothing") = 0)
.asg CLK_F_isr, vec_fxn
.else
.asg :name:_stub, vec_fxn
.endif
.asg FXN_F_run, dispatch_fxn
.else
.global HWI_F_dispatch
;
; We allow dispatcher to be selected even for HWIs that
; are HWI_unused. Call FXN_F_nop in this case.
; The assumption is that the user will subsequently call
; IRQ_config to set the function to something real.
;
.if ($symcmp(local_fxn, "HWI_unused") == 0)
.asg FXN_F_nop, local_fxn
.endif
.if ($symcmp(monitor, "Nothing") = 0)
.asg HWI_F_dispatch, vec_fxn
.else
; HWI_F_dispatch will be called by monitor
.asg :name:_stub, vec_fxn
.endif
.asg :local_fxn:, dispatch_fxn
.endif
stw b0, *b15--[2]
mvk :id:, b0
stw b0, *+b15[1]
mvkl :vec_fxn:, b0
mvkh :vec_fxn:, b0
b b0
ldw *+b15[2], b0
nop 4
.sect ".cinit"
.align 8
.field 4 * STD_TARGWORDMAUS
.field _HWI_dispatchTab + (4 * :id: * STD_TARGWORDMAUS)
.field :dispatch_fxn:
.field :intrmask:
.field :ccmask:
.field :arg:
.else
; For all vectors besides reset use a common packet format. This
; packet can be used for self branches as well as branches to
; HWI stubs.
stw b0,*b15--[2] ; temp save b0 on stack
mvkl :vector:,b0 ; load destination function address to b0
mvkh :vector:,b0
b b0 ; start branch to destination function
ldw *++b15[2],b0 ; restore b0 register
nop 2 ; fill 2 of b0 restore and branch delay slots
nop ; fill delay slot, pad packet
nop ; fill delay slot, pad packet
.endif
.endif
.endm
;
;# ======== HWI_config ========
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
.asg "", HWI_config$regs
HWI_config .macro _zerotab, _generate_reset_vec, _polaritymask, _intrmultlow, intrmulthigh
.endm
;
;# ======== HWI_disable ========
; Clears the GIE bit, returns the previous
; CSR register value.
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# GIE = 0
;# a4 = CSR when HWI_disable was invoked.
;
; Note: The modified register list indicates a4. If another register is
; specified as a parameter to the macro then it will not be listed in the
; modified register list, but a4 will because it is the default.
;
.asg "a4,b0,csr",HWI_disable$regs
HWI_disable .macro regname
.if ($symlen(regname) = 0) ; if no register as parameter use a4
.asg "a4",regname
.endif
b hwid?
mvc csr,b0
mv b0,:regname:
and ~GIE,b0,b0
mvc b0,csr
nop
hwid?:
.endm
;
;# ======== HWI_enable ========
; Sets the GIE bit.
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# GIE = 1
;#
;
.asg "b0,csr",HWI_enable$regs
HWI_enable .macro dummy
b hwie?
mvc csr,b0
or GIE,b0,b0
mvc b0,csr
nop 2
hwie?:
.endm
;
;# ======== HWI_mkStub ========
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
.asg "", HWI_mkStub$regs
HWI_mkStub .macro name, monitor, addr, operation, stsName, fxn
.sect ".hwi"
; first look at passed parameters and figure out what is to be done
.var firstChar, unaryop, stsop, len, monreg
.eval 0, monreg
; compute stsop; the STS operation to perform
.eval $firstch(operation, '(') - 1, len
.asg ":operation(1, len):", stsop
; compute unary operation to perform (if any).
.asg "; no unary operation specified", unaryop
.if ($symcmp(":operation(len + 2):", "-") = 0)
.asg "neg", unaryop
.endif
.if ($symcmp(":operation(len + 2):", "|") = 0)
.asg "abs", unaryop
.endif
; determine if a register is to be monitored
.if ($isreg(monitor) = 1)
.eval 1, monreg ; set flag saying are monitoring a register
.elseif ($symcmp("Stack Pointer",monitor) = 0)
.eval 1, monreg ; set flag saying are monitoring a register
.asg "b15", monitor
.endif
; convert addr to a suitable constant
.asg ":addr(1):", firstChar
.if ($iscons(firstChar) = 5)
; if first char is 0-9, addr's a number
.elseif ($isname(addr) & ($isdefed(addr) = 0))
.global addr ; must be external user defined symbol
.endif
; now generate the stub function
.global :stsName:
:name::
; check if TRC_STSHWI is enabled
stw a2,*b15--[2] ; push registers used by TRC_query
stw a4,*b15--[2]
stw DP,*b15--[2]
|| mvkl $bss, DP ; TRC_query needs b14 (DP) set to .bss
mvkh $bss, DP
TRC_query TRC_STSHWI ; TRC_query modifies a2 and a4
mv a4,a2
|| ldw *++b15[2], DP ; done with b14 (DP)
; if TRC_STSHWI not enabled simply branch to interrupt function
[a2] mvkl :fxn:,a4 ; form address of function to branch to
[a2] mvkh :fxn:,a4
[a2] b a4 ; branch to interrupt function
|| ldw *++b15[2],a4 ; pop registers used by TRC_query
ldw *++b15[2],a2
nop 4 ; pad delay slots of ldw instruction
; Put value to be monitored into a temp register. If a unary
; operation is specified then do it.
stw b1,*b15--[2] ; push registers used as temps
stw b0,*b15--[2]
.if(monreg = 1) ; if monitoring register
; When monitoring register values and get to this point all
; registers are intact except b15.
; b15 has been modified for the two registers that were
; pushed on the stack.
; When b15 is to be monitored we adjust the value to correspond
; to the b15 value when the ISR was taken.
.asg 0,monitor_b15 ; test if monitoring b15
.if $symcmp(monitor,"b15") == 0
.eval 1,monitor_b15
.elseif $symcmp(monitor,"B15") == 0
.eval 1,monitor_b15
.endif
.if(monitor_b15 = 1) ; indeed, monitor b15 ...
mvk 16,b1 ; 2 regs * 8 bytes/reg = 16 bytes
addu b15,b1,b1:b0 ; set b0 = b15 + 16
.else ; all other registers
mv monitor,b0 ; put register value into temp register
.endif
unaryop b0,b0 ; do NEG or ABS on value
.else ; else if monitoring memory
mvkl addr,b1 ; get address of memory value
mvkh addr,b1
ldw *b1,b0 ; get memory value to temp register
nop 4 ; wait for value to arrive
unaryop b0,b0 ; do NEG or ABS on value
.endif
; save registers used for STS operation:
; STS_add uses: a1, a3, b1, b2, b3
; STS_delta uses: b1, b3, b4, b5
; the address of the STS object will be put in a4
; b1 has already been saved as a temp register
;
.if .TMS320C6400
.eval C64_A1|C64_A3|C64_A4, STSAREGS
.eval C64_B2|C64_B3|C64_B4|C64_B5, STSBREGS
C64_save STSAREGS, STSBREGS, 0
.else
.eval C62_A1|C62_A3|C62_A4|C62_B2|C62_B3|C62_B4|C62_B5, STSREGS
C62_save STSREGS, 0
.endif
; ensure linear addressing for STS operation
mvc amr,b4 ; note: direct AMR save/restore is more
|| zero b1 ; efficient than C62_save/C62_restore
stw b4,*b15--[2] ; save current AMR onto stack
|| mvc b1,amr ; set AMR=0
; invoke specified STS macro
mvkl stsName,a4 ; put address of STS object in a4
mvkh stsName,a4 ; put address of STS object in a4
mv b0,b4 ; put monitor value (b0) in b4
stsop ; invoke STS macro
ldw *++b15[2],b0 ; get saved AMR into temp reg b0;
; C62_restore takes care of delay slots
; restore registers used for STS operation:
.if .TMS320C6400
C64_restore STSAREGS, STSBREGS, 0
.else
C62_restore STSREGS, 0
.endif
mvc b0,amr ; restore saved AMR
; branch to interrupt function
mvkl :fxn:,b0 ; form address of function to branch to
mvkh :fxn:,b0
b b0 ; branch to interrupt function
|| ldw *++b15[2],b0 ; pop b0 register
ldw *++b15[2],b1 ; pop b1 register
nop 4 ; pad delay slots
.endm
;
;# ======== HWI_restore ========
; Conditionally sets the GIE bit.
;#
;# Preconditions:
;# a4 = mask (GIE will be set to the value of bit 0)
;# GIE = 0
;#
;# Postconditions:
;# none
;#
;# Constraints and Calling Environment:
;# This macro must be invoked from an atomic context. i.e., the
;# instructions of this macro should not be interrupted.
;
.asg "a1,b0,csr",HWI_restore$regs
HWI_restore .macro regname
.if ($symlen(regname) = 0) ; if no register as parameter use a4
.asg "a4",regname
.endif
; NOTE: the following four instructions may not be interrupted.
; This macro must be invoked from an atomic context.
and :regname:,GIE,a1
[a1] mvc csr,b0
[a1] or GIE,b0,b0
[a1] mvc b0,csr
.endm
;
;# ======== HWI_end ========
; Invoked by confend.s62 at the end of all other configuration
; declarations.
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
.asg "", HWI_end$regs
HWI_end .macro
.endm
;
;# ======== HWI_init ========
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -