C28x FIR - Filter 示例汇编代码解读

SECTIONS
{    D_LINE: align(256) { }  > RAM  PAGE 1
    . . . 
}

上面是cmd文件的配置,D_LINE用于保存FIR要处理的数据。由于使用了循环间接寻址(Circular Indirect Addressing Modes (XAR6, XAR1)),用XAR6来做数据指针,它指向的初始地址必须是256对齐的,即XAR6开始赋给它的指针低8位必须为0,(XAR6 points to the current address in the buffer. The top of the buffer must be at an address where the 8 LSBs are all 0s.),用XAR1的AR1[7:0]来指示一个循环要处理多少数据,处理AR1个数据即循环一次。由于只用了AR1的8位来表示循环范围,所以一个循环最大只能是(0~255)个字(TI 16位dsp中一个字16bit)。

参考:spru430d,TMS320C28x DSP CPU and Instruction Set Reference Guide,p145~146

TAPS    .set    4       ; FIR – Order +1
xn    .usect “D_LINE”,TAPS       ; sample array in I1Q15 
    .data           ; FIR – Coeffs in I1Q15
tbl    .word    32768*707/1000       ; 0.707    
    .word    32768*123/1000       ; 0.123
     .word   32768*(-175)/1000       ; -0.175
    .word    32768*345/1000       ; 0.345
    .text
FIR:    SETC  SXM       ; 2’s complement math
    CLRC  OVM       ; no clipping mode
    SPM    1       ; fractional math
    MOVL    XAR7,#tbl       ; coefficient pointer
    MOVL  XAR6,#xn       ; circular buffer pointer
    MOV   AR1,#TAPS-1       ; buffer offset
    MOV    *XAR6%++,*(0:adc)       ; get new sample ( x(n) )
    ZAPA           ; clear ACC,P,OVC    
    RPT     #(TAPS/2)-1       ; RPT next instr.(#+1)times
||    DMAC    ACC:P,*XAR6%++,*XAR7++ ; multiply & accumulate 2pairs
    ADDL    ACC:P       ; add even & odd pair-sums
    MOV    *(0:dac),AH       ; update output ( y(n) )
    RET
.word    32768*707/1000       ; 0.707 
上面这个表示FIR的系数,乘以32768表示使用IQ15, .word表示这个用16bit存储, 707/1000是为了精度考虑
SPM    1 表示DMAC乘了之后结果左移1位。具体说明见后面。
MOV    *XAR6%++,*(0:adc)       ; get new sample ( x(n) )
上面这个原型为 MOV loc16,*(0:16bit) ; [loc16] = [0:16bit],由于是loc16(指向16bit的地址),所以XAR6++表示跳到下一个字(16bit),XAR6后面的%表示循环间接寻址
 loc16
Selects Direct/Stack/Indirect/Register addressing mode for 16-bit data access.
 loc32
Selects Direct/Stack/Indirect/Register addressing mode for 32-bit data access.

from:spru430d,p126

*XARn++
if(loc16), XARn = XARn + 1
if(loc32), XARn = XARn + 2

from:spru430d,p134

 

RPT     #(TAPS/2)-1       ; RPT next instr.(#+1)times
这个重复指令作用于它的下一条指令,指示循环多少次

DMAC    ACC:P,*XAR6%++,*XAR7++ ; multiply & accumulate 2pairs
原型:DMAC ACC:P,loc32,*XAR7++ 由于是loc32,所以一次++表示加了两个字(共32bit)。DMAC表示Dual 16-bit x 16-bit signed multiply and accumulate.具体如下图:

一个32bit的数据拆成2个字,分别相乘,各自结果都移位PM,上半个字乘、移位后累加到ACC,下半个字乘、移位后的结果累加到P,等效的过程如下:
XT = [loc32];
Temp = Prog[*XAR7 or *XAR7++];
ACC = ACC + (XT.MSW * Temp.MSW) << PM;
P = P + (XT.LSW * Temp.LSW) << PM;

参考:spru430d,p243
ADDL    ACC:P
循环之后,把ACC和P的结果累加。为什么要累加,见FIR的算法:


MOV    *(0:dac),AH       ; update output ( y(n) )

只取了累加器的高字给16bit的DAC结果缓冲器,由于是取高半字(高16bit),所以相当于右移16bit,前面化为IQ15是左移15位,差了1位,所以让PM等于1,就刚刚好了。

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>分隔>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

但是上面的代码好像有些问题,因为MOV *XAR6%++,*(0:adc)仅仅移动了一个字,而DMAC ACC:P,*XAR6%++,*XAR7++ 这里一++”就是两个字,所以到边界的时候有可能就对不齐了。
目前还不清楚,DMAC指令当在用循环间接寻址,取32位数的时候,XAR6刚好是一个奇数,刚好距离循环寻址的边界仅剩一个字的时候,这个32位的数值的高字节究竟是循环寻址区的第一个字节还是越循环寻址区,取与寻址区相邻的一个字节呢?根据TI的文档,应该是后一种比较有可能,因为文档中提到If one of the instructions accessing the circular buffer performs a 32-bit operation,make sure XAR6 and AR1 are both even (都是偶数)before the buffer is accessed.所以上面代码是有问题的,但是作为参考,还是有益的。
开始TI的Filter库是放在sprc082,后来出了controlsuite,sprc082就没更新了,对比sprc082的0.9c(不是上面这个,比较完善了)与controlsuite的代码,还是有点区别的,这部分代码还没仔细看,以后应当用controlSUITE的代码。刚刚下的一个controlSUITE是v3.1.1 - October 8, 2012

controlSUITE:http://www.ti.com/tool/controlsuite

controlSUITE里面的代码分析,暂缓吧

原创:  TrueElement转载请注来源>>

posted @ 2012-11-22 11:31  果壳中的宇宙  阅读(1773)  评论(0编辑  收藏  举报