📄 dtmfsub.asm
字号:
**************************************************************
* (C) COPYRIGHT TEXAS INSTRUMENTS, INC. 1996 *
**************************************************************
* Program Name: DTMF tone decoder *
* File Name: dtmfsub.asm *
* File Description: This file contains the ASM-subroutines *
* used for a DTMF tone detector *
* (TMS320C54x EVM version) *
* Author: Gunter Schmer *
* Date: 03/24/97 *
* Revision: 3.0 *
* Latest working date: 03/24/97 *
**************************************************************
.mmregs
.include "globals.inc" ;global labels
.include "tables.inc" ;various tables
.text
***********************************************************************
* SUBROUTINE: initoscis (approx. 1600 cycles)
*
* Input: ptr to DTMFENCOBJ
* Output: none
* Uses:
*
* Description:
* This subroutine initializes the digital sinusoidal oscillator
* states. It uses a generic set of states and copies them into
* the channel specific osci state buffer.
*
***********************************************************************
_initoscis
nop
pshm ST0
pshm ST1
pshm AR1
pshm AR6
pshm AR7
nop
;---- local variables -----
; none
;---- arguments -----------
; (A) = ptr to DTMFENCOBJ
; *SP(6) = digit
stlm A,AR6 ;AR6 is used as pointer to struct elements
; *AR6(0) = ptr to data
; *AR6(1) = ptr to oscis
ld #0,ASM ;ASM=0
stm #OSCIS,AR2 ;AR2 points to generic osci states
ld *AR6(1),A
stlm A,AR3 ;AR3 points to channel osci states
ld *AR2+,16,A ;load first value
rpt #(16-1) ;for(k=0;k<16;k++) {
st A,*AR3+ ; store (AH)
|| ld *AR2+,A ; load (AH)
;}
popm AR7
popm AR6
popm AR1
popm ST1
popm ST0
ret
***********************************************************************
* SUBROUTINE: dtmftone (approx. 1600 cycles)
*
* Input: ptr to DTMFENCOBJ
* Output: none
* Uses:
*
* Description:
* This subroutine computes 102 samples of DTMF tones. The routine
* expects a ptr to a encoder object in the accu A and the digit to
* be encoded on the stack.
*
***********************************************************************
_dtmftone
nop
pshm ST0
pshm ST1
pshm AR1
pshm AR6
pshm AR7
nop
frame #-2 ;---- local variables -----
; *SP(0) = attenuation
;---- arguments -----------
; (A) = ptr to DTMFENCOBJ
; *SP(8) = digit
stlm A,AR6 ;AR6 is used as pointer to struct elements
; *AR6(0) = ptr to data
; *AR6(1) = ptr to oscis
; *AR6(2) = attenuation of tone
ssbx FRCT ;set fractional mode
;---- unpack digit and find pointers to oscillator taps ----
ld *SP(8),A
stlm A,AR0 ;AR0 is offset within mapping table
stm #KEYS,AR2 ;AR2 points to mapping table
nop
mar *AR2+0 ;AR2 points to mapping table value
ld *AR2,A ;load mapping table value
ld A,B ; in (A) and (B)
and #0f00h,A ;mask out the row portion
sftl A,-8 ;right shift (A) by 8
stlm A,AR2 ;AR2 contains coef-table offset for row-tone
sftl A,1 ;left shift (A) by 1
stlm A,AR4 ;AR4 contains oscis-table offset for row-tone
and #000fh,B ;mask out the column portion
add #4,B ;add 4 to offset to point into column portion
stlm B,AR3 ;AR3 contains coef-table offset for col-tone
sftl B,1 ;left shift (B) by 1
stm #COEFFS,AR0 ;AR0 points to coef-table
stlm B,AR5 ;AR5 contains oscis-table offset for col-tone
mar *AR2+0 ;AR2 points to row-tone coefficient
mar *AR3+0 ;AR3 points to col-tone coefficient
ld *AR6(1),A ;load ptr to data
stlm A,AR0 ;AR0 points to oscis-table
ld *AR6(2),B ;load attenuation
stl B,*SP(0) ;store in local variable
mar *AR4+0 ;AR4 points to row-tone osci
mar *AR5+0 ;AR5 points to col-tone osci
mar *AR4+ ;AR4 points to row-tone y(n-2)
mar *AR5+ ;AR5 points to col-tone y(n-2)
;---- generate DTMF tones ----------------------------------
ld *AR6(0),A
stlm A,AR1 ;AR1 points to data
stm #(N-1),BRC
rptb osci1-1 ;for(n=0;n<N;n++) {
ld #0,A ; ---- generate row-tone sample -----
sub *AR4-,16,A ; (A) = -y(n-2)
mac *AR4,*AR2,A ; (A) = coef*y(n-1) - y(n-2)
mac *AR4,*AR2,A ; (A) = 2*coef*y(n-1) - y(n-2)
delay *AR4 ; y(n-1) ---> y(n-2)
sth A,*AR4 ; (A) ---> y(n-1)
ld #0,A ; ---- generate col-tone sample -----
sub *AR5-,16,A ; (A) = -y(n-2)
mac *AR5,*AR3,A ; (A) = coef*y(n-1) - y(n-2)
mac *AR5,*AR3,A ; (A) = 2*coef*y(n-1) - y(n-2)
delay *AR5 ; y(n-1) ---> y(n-2)
sth A,*AR5+ ; (A) ---> y(n-1)
add *AR4+,16,A ; (A) = row-tone + col-tone
mpya *SP(0) ; (A) = attn*(AH)
sth B,*AR1+ ; (A) ---> x(n)
osci1
frame #2
nop
popm AR7
popm AR6
popm AR1
popm ST1
popm ST0
ret
*******************************************************************
* SUBROUTINE: gaincntrl (approx. 575 cycles)
*
* Input: ptr to DTMFDECOBJ
* Output: none
* Uses:
*
* Description: Scales a block of input data in order to ensure
* no overflow when running the goertzel routine
* approx. 6 cycles per sample (negligable)
*
* gain_power = (1/64) * SUM{0,N-1}[x(n)*x(n)]
* = (1/64) * N * signalpower
*
* gain_lim = (1/64) * (1/N)
* = minimum signalpower (-..dB)
*
* gain_const = 0.5*sqrt(2)*sqrt(64/N)
* gain_amp = gain_const * sqrt(gain_power)
* gain_lev = 1/N
* gain_scale = gain_lev/gain_amp
*
* x(n) = x(n) * gain_scale
*
* FRCT=1, SXM=1
*******************************************************************
_gaincntrl:
nop
pshm ST0
pshm ST1
pshm AR1
pshm AR6
pshm AR7
nop
frame #-10 ;---- local variables -----
; *SP(0) = gain_pow (HI)
; *SP(1) = gain_pow (LO)
; *SP(2) = gain_lim (HI)
; *SP(3) = gain_lim (LO)
; *SP(4) = gain_amp
; *SP(5) = gain_lev
; *SP(6) = gain_scale
; *SP(7) = gain_const
; *SP(8) = gain_delta
; *SP(9) = ptr to data
;---- arguments -----------
; (A) = ptr to DTMFDECOBJ
stlm A,AR5
nop
nop
nop
ld *AR5,A
stl A,*SP(9)
;---- value initializations --------------------------
ld #0005h,16,A ;(A) = 00050000h
or #0505h,A ;(A) = 00050505h = 1/(64*N) (Q31)
sth A,*SP(2) ;(A) --> gain_lim (32bit)
stl A,*SP(3)
ld #00E3h,A ;(AL) = 00E3h = (0.5*sqrt(2))/N
stl A,*SP(5) ;(AL) --> gain_lev (16bit)
ld #6564h,A ;(AL) = 6564h = sqrt(64/102)
stl A,*SP(7) ;(AL) --> gain_const
ld #4000h,A ;(AL) = 4000h = 0.5
stl A,*SP(8) ;(AL) --> gain_delta
ssbx FRCT
;---- compute signal power ---------------------------
ld *SP(9),A
stlm A,AR2 ;AR2 points to data buffer
rptz B,#(N-1) ;for(n=0;n<N-1;n++)
squra *AR2+,B ; (B)=(B)+x(n)*x(n)
sfta B,-6 ;(B)=(1/64)*(B)
sth B,*SP(0) ;(B) --> gain_pow (32bit)
stl B,*SP(1) ; gain_pow = (N/64)*sigpower
ld *SP(2),16,A ;(A) = gain_lim = 1/(64*N) (32bit)
or *SP(3),A
sub A,B ;(B) = gain_pow - gain_lim
bc gain2,BLEQ ;if(gain_pow > gain_lim)
;{
;---- compute gain_amp = sqrt(gain_pow) -------------
st #4000h,*SP(4) ; initialize gain_amp estimate
st #4000h,*SP(8) ; initialize gain_delta to 0.5
mvmm SP,AR2
mar *+AR2(8) ; AR2 points to gain_delta
stm #(sqrt_iterations-1),BRC
rptbd sqrtloopend-1
squr *SP(4),A ; (A) = yold*yold
dsub *SP(0),A ; (A) = yold*yold - x
sqrtloop
bcd sqrt1,AGT
ld *SP(4),16,B ; (B) = yold
sub *AR2,15,B ; (B) = yold - (1/2)*delta
; if(y needs to be larger)
add *AR2,16,B ; (B) = yold + (1/2)*delta
sqrt1 sth B,*SP(4) ; (BH) --> ynew
ld *AR2,15,A ; (AH) = (1/2)delta
sth A,*AR2 ; (AH) --> delta new
squr *SP(4),A
dsub *SP(0),A ; (A) = yold*yold - x
sqrtloopend
;---- compute gain_amp = sqrt(64/N)*gain_amp --------
ld *SP(7),T ; (T) = gain_const
mpy *SP(4),A ; (A)=sqrt(64/102)*gain_amp
sth A,*SP(4) ; (AH) --> gain_amp
;---- compute gain_lev/gain_amp ---------------------
ld *SP(5),16,A ; (AH) = gain_lev
rpt #(16-1)
subc *SP(4),A ; compute (gain_lev/gain_amp)
and #0ffffh,A ; retain quotient (AL), mask remainder
sfta A,15 ; shift quotient into high accu
sth A,*SP(6) ; (AH) --> gain_scale
;---- scale data with (gain_lev/gain_amp) ---------
ld *SP(9),A ;
stlm A,AR2 ; AR2 points to data
mvmm SP,AR3 ;
mar *+AR3(6) ; AR3 points to gain_scale
stm #(N-1),BRC ;
rptb gain1-1 ; for(n=0;n<N;n++)
mpy *AR2,*AR3,A ; (A) = x(n)*(gain_lev/gain_amp)
sth A,*AR2+ ; (AH) --> x(n)
gain1 ;}
gain2 frame #10
nop
popm AR7
popm AR6
popm AR1
popm ST1
popm ST0
ret
***********************************************************************
* SUBROUTINE: goertzel (w/o OV check approx. 4637 cycles)
*
* Input: ptr to DTMFDECOBJ
* Output: none
* Uses:
*
* Description:
* This new version of the subroutine operates on a block of data
* 102 samples long and computes the following difference equation
* It does thereby not check for overflow and assumes a prescaling
* gain control function to protect from possible overflow.
* Since 2nd harmonic frequencies are computed conditionally in
* subroutine dtmfchecks(), this routine now only computes the
* fundamental frequency information (8 freqs)
* This routine also computes the energy template for the 8 fundamental
* frequencies. It thereafter sets the filter taps to zero for the next
* round.
*
*
***********************************************************************
_goertzel:
nop
pshm ST0
pshm ST1
pshm AR1
pshm AR6
pshm AR7
;---- local variables -----
; none
;---- arguments -----------
; (A) = ptr to DTMFDECOBJ
rsbx OVA ;clear overflow bit for A
ssbx FRCT ;set fractional mode
stlm A,AR5 ;AR5 is used as pointer to struct elements
; *AR5(0) = ptr to data
; *AR5(1) = ptr to taps
; *AR5(2) = ptr to energy template
; *AR5(3) = digitptr
; *AR5(4) = digitlast
; *AR5(5) = detectstat
; *AR5(6) = err_flags
;---------------------------------------------------------------------
; Goertzel filter computation
;
; vk(n) = 2*coef*vk(n-1) - vk(n-2) + x(n)
;
; Coefficients are in order starting with location COEF1st
; COEF1st .word xxxx ;coef1
; .word yyyy ;coef2
; ....
;
; Data vk(n-1), vk(n-2) is ordered as follows
; v9(n-1)
; v9(n-2) column's second harm
; v8(n-1)
; v8(n-2) row's 2nd harm
;
; v7(n-1)
; v7(n-2)
; ....
; v0(n-1)
; v0(n-2) <--AR2
;
; FRCT=1, SXM=1
;
;---------------------------------------------------------------------
ld *AR5,A ;
stlm A,AR1 ;AR1 points to data buffer
ld *AR5(1),A ;
add #19,A ;
stlm A,AR6 ;AR6 points to end of taps block
stm #(N-1),BRC
goer1 rptb goer2-1 ;for(n=0;n<N;n++) {
mvmm AR6,AR2 ; AR2 points to end of taps block
stm #COEF1st,AR3 ; AR3 points to Coefficients
ld *AR1+,16,A ; (A) = x(n)
; ------ filter k=0 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=1 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=2 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=3 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=4 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=5 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=6 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
; ------ filter k=7 -----------------
sub *AR2-,16,A,B ; (B) = -vk(n-2) + x(n)
mac *AR2,*AR3,B ; (B) = coef*vk(n-1) - vk(n-2) +x(n)
mac *AR2,*AR3+,B ; (B) = 2*coef*vk(n-1) - vk(n-2) +x(n)
delay *AR2 ; vk(n-1) ---> vk(n-2)
sth B,*AR2- ; (B) ---> vk(n-1)
goer2 ;}
;-------------------------------------------------------------------------
; Energy computation for fundamental frequencies (8 freqs)
;
; y(N)y*(N) = vk(N)*vk(N) - 2*coef*vk(N)*vk(N-1) + vk(N-1)*vk(N-1)
;
; Coefficients are in pmem in order starting with location COEF1st
; COEF1st .word xxxx ;coef0 <--AR3
; .word yyyy ;coef1
; ....
;
; Data vk(n-1), vk(n-2) is ordered
; v9(n-1)
; v9(n-2) 2nd harm column
; v8(n-1)
; v8(n-2) 2nd harm row
; v7(n-1)
; v7(n-2)
; ....
; v0(n-1)
; v0(n-2) <--AR2
;
; FRCT=1, SXM=1
;
;-------------------------------------------------------------------------
goer3 ld *AR5(1),A
add #19,A
stlm A,AR2 ;AR2 points to end of filter taps block
stm #COEF1st,AR3 ;AR3 points to beg of coefficient table
ld *AR5(2),A
stlm A,AR4 ;AR4 points to energy template
stm #(8-1),BRC
rptb goer4-1 ;for(k=0;k<8;k++) {
ld *AR2,16,A ; (A) = vk(N-1), A(32:16) loaded
mpya *AR2- ; (B) = vk(N-1)*vk(N-1), (T) = vk(N-1)
mpy *AR2,A ; (A) = vk(N)*vk(N-1)
ld *AR3+,T ; (T) = coef
mpya A ; (A) = coef*vk(N)*vk(N-1)
sub A,1,B ; (B) = -2*coef*vk(N)*vk(N-1) + vk(N-1)*vk(N-1)
ld *AR2,T ; (T) = vk(N)
mac *AR2-,B ; (B) = vk(N)*vk(N) - 2*coef*vk(N)*vk(N-1) + vk(N-1)*vk(N-1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -