📄 nblms.asm
字号:
;***********************************************************
; Version 2.20.01
;***********************************************************
;****************************************************************
; Function: nblms
; Description: nblms fir filter
;
; Copyright Texas instruments Inc, 1998
;---------------------------------------------------------------
; Revision History:
; 0.0 J. Nikolic-Popovic. Original code
; 1.00, A. Aboagye, 8/31/98 - changed calling conventions
; 2.00 - Li Yuan, 4/09/02. fixed overflow flag setup at the end of code.
;----------------------------------------------------------------
; Registers modified:
; a, b,
; ar1, ar2, ar3, ar4, ar5, ar6, ar7
; brc, sp, st1(sxm, frct, asm)
;********************************************************************************
.mmregs
.if __far_mode
offset .set 1
.else
offset .set 0
.endif
; local vars
.asg (0), error ;
.asg (1), inv_abs_power ; inverse absolute power
.asg (2), nh ; number of coefficients
.asg (3), mod_bsize_cnt ; block counter
; (points to block to be updated)
.asg (4), bsize_2 ; blocksize-2
.asg (5), y0_ptr ; pointer to the latest sample
.asg (6), abs_power ; absolute power (long aligned)
.asg (10), save_ar7
.asg (11), save_ar6 ; stack description
.asg (12), save_ar1
.asg (13), ret_addr
; arguments
; x in A
.asg (14 + offset), arg_h
.asg (15 + offset), arg_y
.asg (16 + offset), arg_d
.asg (17 + offset), arg_des
.asg (18 + offset), arg_nb
.asg (19 + offset), arg_n
.asg (20 + offset), arg_bsize
.asg (21 + offset), arg_norm_e
* .asg (22 + offset), arg_p_abs_power
.asg (22 + offset), arg_l_tau
.asg (23 + offset), arg_cutoff
.asg (24 + offset), arg_gain
; register usage
.asg ar1, ar_count
.asg ar2, ar_d
.asg ar3, ar_h
.asg ar7, ar_des
.asg ar4, ar_norm_e
.asg ar6, ar_y
.asg ar5, ar_x
;============================================================================
.global _nblms
_nblms:
; Preserve registers
;-------------------
pshm ar1
pshm ar6
pshm ar7
PSHM ST0 ; 1 cycle
PSHM ST1 ; 1 cycle
RSBX OVA ; 1 cycle
RSBX OVB ; 1 cycle
; Preserve space for local variables
; ----------------------------------
frame -8 ; local var
; error
; inverse_absy
; nh ( number of taps)
; modulo(blocksize) counter
; blocksize-2
; y0_ptr
; abs_power
; OJO: may need to clear OVA flag
; Set math and overflow modes
;---------------------------
ssbx sxm ; sign extension on
; Get arguments and Initialize registers
;---------------------------------------
stlm a, ar_x ; pointer to x
mvdk *sp(arg_y),*(ar_y) ; pointer to y
mvdk *sp(arg_d),*(ar_d) ; de-referencing
ld *ar_d,a ; pointer to d
stl a,*sp(y0_ptr) ; initialize the local variable
mvdk *ar_d,*(ar_d)
mvdk *sp(arg_des),*(ar_des) ;
mvdk *sp(arg_n), *(ar_count) ; sample counter
mar *ar_count- ; ar_count= nsamples-1
ld *sp(arg_nb),T ; calculate number of coefficients
mpy *sp(arg_bsize),a ; and store it as a local variable
sub #02,a,b ;
stl b, *sp(nh) ;
add *sp(arg_bsize),a
stlm a,bk ; bk = circular buffer size = nh+blocksize
ld *sp(arg_nb),b
sub #1,b
stl b,*sp(arg_nb) ; store (number of blocks -1)
ld *sp(arg_bsize),a
sub #2,a
stl a,*sp(bsize_2) ; store (blocksize - 2 )
ld *sp(arg_gain),a
add #15,a
stl a,*sp(arg_gain) ; store gain+15
ld #0h, a
dst a,*sp(abs_power) ; store abolute power as a local variable
ld #0,b
stl b,*sp(mod_bsize_cnt) ; initialize block couter to zero
ssbx frct
; Loop through remaining (n-1) samples
;-------------------------------------
next_sample:
stm #0ffffh,AR0 ; initialize to -1
mvdd *ar_x, *ar_d ; new sample --> dbuffer
; Adaptive Fir
;-------------
adaptive_fir:
mvdk *sp(arg_h),*(ar_h) ; pointer to h
ld #0,b
rpt *sp(nh) ; repeat nh-1 times
mac *ar_d+0%,*ar_h+,b
macr *ar_d+0%,*ar_h,b ; add rounding offset.
; Q0 * Q15 = Q15, shift by one = Q16
; Write output sample
; -------------------
sth b, *ar_y+ ; save in Q0
; Compute new error
; -----------------
sub *ar_des+,16,b,a ;
neg a ; ah = error(i)=des(i)-y(i)
sth a,*sp(error)
; Update power estimate
;----------------------
update_power_estimate:
ld *ar_x+, 0,b ; point to next entry in the input buffer
abs b
ld *sp(arg_l_tau),t
ld *sp(arg_l_tau),asm
dld *sp(abs_power),a ; double presicion load
sub *sp(abs_power),TS ,a ; a - ABSY *2^LTAU
add b,ASM,a ; a + ABSY0*2^LTAU
add *sp(arg_cutoff),TS,A ; a + CUTOFF*2^LTAU
dst a,*sp(abs_power) ; double precision store.
ld #1, 16, b
rpt #14
subc *sp(abs_power), b
stl b,*sp(inv_abs_power) ; inv_abs_power = 1 / abs_power
ld #0,asm ; clear asm for st||mpy
; Update normalized error buffer
;-------------------------------
mvdk *sp(arg_norm_e),ar_norm_e
ld *ar_norm_e,a
add *sp(bsize_2),a
stlm a,ar_norm_e ; point to end of the buffer
rpt *sp(bsize_2) ; rpt blocksize-2 times
delay *ar_norm_e-
ld *sp(error), T
mpy *sp(inv_abs_power), a ; Q0 * Q15 << 1 = Q16
sfta a, 15 ; Q31
sat a
sth a, *+ar_norm_e
; Update taps
;------------
update_taps:
ld *sp(arg_nb),a
stlm a, BRC
; set up the pointer to the reference buffer:
ld *sp(y0_ptr), A
sub *sp(mod_bsize_cnt),A
stlm A,ar_d ; pointer into delay buffer
ld *sp(arg_h),a
add *sp(mod_bsize_cnt), a
sub *sp(arg_bsize), a
stlm a, ar_h ; pointer to the block of coefficients
; to be updated
mvdk *sp(arg_norm_e),*(ar_norm_e) ; de-referencing
rptbd $block_end-1
mvdk *ar_norm_e,*(ar_norm_e) ; pointer to d
stm #0ffffh,AR0
ld #0,a
rpt *sp(bsize_2) ; actually, it should
; be blocksize-2!
mac *ar_d+0%, *ar_norm_e+, A ; Q0*Q15 = Q15, shifted by one = Q16
macr *ar_d+0%, *ar_norm_e, A ; Q0*Q15 = Q15, shifter by one = Q16
mpya *sp(inv_abs_power) ; Q0*Q15 = Q15, shifted by one = Q16
; (in B)
mvdk *sp(arg_bsize),*(AR0) ; index
mar *ar_h+0
ld *ar_h, 16, A
ld *sp(arg_gain),ASM
add b, ASM,a ; a = a + b << ASM
; ak(i+1) = ak(i) + b<<(15+GAIN)
; the 15 is to transform B
; from Q16 to Q31
sth a, *ar_h
; reset the pointer to delay buffer
mvdk *sp(arg_norm_e),*(ar_norm_e) ; de-referencing
mvdk *ar_norm_e,*(ar_norm_e) ; pointer to d
$block_end
; Update block counter (modulo blocksize)
;----------------------------------------
update_counter:
ld *sp(mod_bsize_cnt), a ; counter -> a
add #1, a ; a +1 -> a
sub *sp(arg_bsize),a,b
mvdk *sp(y0_ptr),*(ar_d) ; update y0_ptr
xc 1,beq ; reset counter if it
; it has reached max.
ld #0,a
STL a, *sp(mod_bsize_cnt) ; a -> counter
mar *ar_d+% ; increment pointer into ref. buffer
mvkd *(ar_d),*sp(y0_ptr) ; remember location of y(0)
banz next_sample, *ar_count-
; Return
;-------
.asg ar_h, ar_temp ; ar_h not used any more
mvdk *sp(arg_d), *(ar_temp)
mvkd *(ar_d), *ar_temp ; update new ar_d
; Return overflow flag
; --------------------
ld #0,a
xc 1,AOV
ld #1,a
; Adjust stack pointer and restore registers
; ------------------------------------------
frame +8 ; adjust for local vars
POPM ST1
POPM ST0
popm ar7
popm ar6
popm ar1
.if __far_mode
fretd ; 4 cycles
.else
retd ; 3 cycles
.endif
nop
nop
;end of file. please do not remove. it is left here to ensure that no lines of code are removed by any editor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -