📄 fft1.asm
字号:
;(3) FFT应用子程序
; -------------------------------------------------------------------------------------------------
; 函数名: void fft(void)
; 功能:实现32、64或128采样点的快速傅立叶变换
; 入口条件:
; _sintab 存放FFT运算中用到的sin和cosin函数值
; _input 存放FFT运算中用到的数据,包括实部和虚部,按二进制反序排列
; 注意:由于"*BR0+"间接寻址方式对_input的地址有特殊的要求,
; 所以最好将数组_input放置在一个独立的块中,如B1块。
; _nom 当_nom=0时,本函数将不对运算结果进行归一化。反之,将对每
; 一步运算结果进行归一化处理,避免溢出,但是,它会使运算精度降低。
; N 常数,参与FFT运输的点数,用户可根据需要选择,例如,需要进行128点
; FFT时,请在本函数中做出如下选择:
; N .set 128
; M .set 7
; 依此类推。
; 出口条件:
; _input 存放FFT的运算结果
; 本函数可供C调用,请用户在C主程序中作以下声明:
; extern void fft(void);
; const int sintab[N]={...}; N为128、64或32
; extern int _input[2*N];
; extern int nom;
;--------------------------------------------------------------------------------------------------
.def _fft
; 基2时间抽取的128点FFT算法需要定义的各量
; N .set 128 ; 点数
; M .set 7 ; N=2**M
; 基2时间抽取的64点FFT算法需要定义的各量
; N .set 64 ; 点数
; M .set 6 ; N=2**M
; 基2时间抽取的32点FFT算法需要定义的各量
N .set 32 ; 点数
M .set 5 ; N=2**M
_input .usect ".data0",2*N ; 输入数据
; .bss _sintab,N ; SIN和COSIN函数的存储表
.bss _nom,1 ; 当 _nom=1时,FFT需要归一化处理,为0时则不需要
.global _fft
.global _sintab
.global _input
.global _nom
.text
_fft:
; --------------------------------------
; 与C语言兼容的代码部分
; --------------------------------------
POPD *+ ; 存储返回地址ADDRESS
SAR AR6,*+ ; 存储 AR6
SAR AR7,*+ ; 存储 AR7
SAR AR0,*+ ; 存储 AR0
SAR AR1,* ; 堆栈分布情况:ADDRESS/AR6/AR7/AR0/AR1
; ARP=AR1,AR1:AR1
LAR AR0,#08h
LAR AR3,*0+,AR3 ; AR3:FP,SP=SP+size(size=frame的长度)
; ARP=AR3
LAR AR2,* ; AR2:AR1
LAR AR7,#_nom ; AR7 指向 _nom
; -----------------------------------------
; 初始化一些寄存器
; -----------------------------------------
SPLK #(N-1),*+
SPLK #(M-1),*+
; 堆栈分布情况:ADDRESS/AR6/AR7
; /AR0/N/M/Y(其中Y为没有确定的量)
; ARP=AR3,AR2:N,AR3:Y
SPLK #1,*+,AR2 ; ID=1,ARP=AR2
; 堆栈分布情况:ADDRESS/AR6/AR7/AR0/ ; N/M/ID/Y ARP=AR2,AR2:N,AR3:
; -----------------------------------------
; FFT运算处理部分
; -----------------------------------------
SETC OVM ; 使能溢出模式
SETC SXM ; 符号扩展使能
SPM 1 ; PREG寄存器的输出左移一位,
; 自动将两个Q15相乘后化为Q15的格式
LACC *+,AR3
ADD #1
SACL *+,1,AR2 ; IW=2*(N+1)
; 堆栈分布情况:ADDRESS/AR6/AR7
; /AR0/N/M/ID/IW/Y
; ARP:AR2,AR2:M,AR3:Y,
LAR AR5,*+ ; AR5=M,ARP:AR2,AR2:ID,
; AR3:Y,AR5=M
LOOP3
LAR AR6,#_input ; AR6:input-->Ri ,ARP:AR2,
; AR2:ID,AR3:Y,AR5=M,AR6:input
LACC *,1
SACL *+ ; ID=ID*2,ARP:AR2,AR2:IW,
; AR3:Y,AR5=M,AR6:input
LACC *,15
SACH * ; IW=IW/2
LACC *-,15,AR3
SACH *+,AR2 ; C2=IW/2
; 堆栈分布情况:ADDRESS/AR6/AR7/AR0/N/M/ID/IW/C2/Y
; ARP:AR2,AR2:ID,AR3:Y,AR5=M,AR6:input
LAR AR0,* ; AR0=ID
LOOP2
LAR AR4,#_sintab ; AR4:sintab
; ARP:AR2,AR0=ID,AR2:ID,AR3:Y,AR4:sintab,AR5=M,AR6:input
LACC *+,15,AR3
SACH *+,AR6 ; C1=ID/2=1
; 堆栈分布情况:ADDRESS/AR6/AR7/AR0/N/M/ID/IW/C2/C1/Y
; ARP:AR6,AR0=ID,AR2:IW,AR3:Y,AR4:sintab,AR5=M,AR6:input
MAR *0+,AR4
; ARP:AR4,AR0=ID,AR2:IW,AR3:Y,AR4:sintab,AR5=M,AR6=AR6+ID-->Rj
LOOP1
LACC #0
LT *+,AR6 ; TREG=COSαlk
MPY *+,AR4 ; Rj* COSαlk,ARP=AR4,AR4:SINαlk,AR6:Ij
LT *,AR6
MPYA *-,AR3 ; ACC=ACC+Rj*COSαlk,PREG=Ij*SINαlk
; ARP=AR3,AR4:SINαlk,AR6:Rj
SPAC ; ACC=ACC-Ij*SINαlk
SACH *+,AR4 ; XT=Rj*COSαlk-Ij*SINαlk
; 堆栈分布情况:ADDRESS/AR6/AR7/AR0/N/M/ID/IW/C2/C1/XT/Y
; ARP:AR4,AR0=ID,AR2:IW,AR3:Y,AR4:SINX,AR5=M,AR6:Q.X
LACC #0
LT *-,AR6
MPY *+,AR4 ; Rj*SINαlk,ARP=AR4,AR4:COSαlk,AR6:Ij
LT *,AR6
MPYA *-,AR3 ; ACC=ACC+Rj*SINαlk,PREG=Ij*COSαlk
; ARP=AR3,AR4:COSαlk,AR6:Rj
APAC
SACH *-,AR7 ; YT=Rj*SINαlk+Ij*COSαlk
; 堆栈分布情况:ADDRESS/AR6/AR7/AR0/N/M/ID/IW/C2/C1/XT/YT
; ARP:AR7,AR0=ID,AR2:IW,AR3:XT,AR4:COSX,AR5=M,AR6:Q.X
LACC *,AR6
BCND D2,NEQ ; 当_nom不为0时,需要在运算过程中进
; 行归一化操作
; ----------------------------------------
; 不进行归一化操作程序部分
; ----------------------------------------
MAR *0- ; AR6=AR6-ID-->Ri
LACC *,AR3
ADD *,AR6
SACL *0+,AR3 ; Ri=Ri+XT
; ARP:AR3,AR0=ID,AR2:IW,AR3:XT,AR4:COSαlk,AR5=M,AR6:Rj
SUB *+,1,AR6
SACL *+ ; Rj= Ri+XT -XT*2=Ri-XT,AR6:Ij,AR3:YT
; ARP:AR6,AR0=ID,AR2:IW,AR3:YT,AR4:COSαlk ,AR5=M,AR6:Ij
MAR *0- ; AR6:Ii
LACC *,AR3
ADD *-,AR6
SACL *0+,AR3 ; Ii= Ii +YT,AR6:Ij
; ARP:AR3,AR0=ID,AR2:IW,AR3:XT,AR4:COSαlk,AR5=M,AR6:Ij
SUB *,1,AR6
SACL *+,0,AR2 ; Ij= Ii +YT -YT*2=Ii-YT
; STACK:ADDRESS/AR6/AR7/AR0/N/M/ID/IW/C2/C1/XT/YT
; ARP:AR2,AR0=ID,AR2:IW,AR3:XT,AR4:COSαlk,AR5=M,AR6:NEXT Rj
B D ; AR6 指向下一个Rj
; ---------------------------------------
; 归一化处理程序部分
; ---------------------------------------
D2 MAR *0- ; AR6-->Ri
LAC *,15,AR3
ADD *,15,AR6
SACH *0+,AR3 ; Ri =( Ri +XT)/2
; ARP:AR3,AR0=ID,AR2:IW,AR3:XT,AR4:COSαlk,AR5=M,AR6:Rj
SUB *+,16,AR6
SACH *+ ; Rj=Ri-XT,AR6:Ij,AR3:YT
; ARP:AR6,AR0=ID,AR2:IW,AR3:YT,AR4:COSαlk,AR5=M,AR6:Ij
MAR *0- ; AR6:Ii
LACC *,15,AR3
ADD *,15,AR6
SACH *0+,AR3 ; Ii=(Ii+YT)/2,AR6:Ij
; ARP:AR3,AR0=ID,AR2:IW,AR3:YT,AR4:COSαlk,AR5=M,AR6:Ij
SUB *-,16,AR6
SACH *+,0,AR2 ; Ij=Ii-YT
; STACK:ADDRESS/AR6/AR7/AR0/N/M/ID/IW/C2/C1/XT/YT
; ARP:AR2,AR0=ID,AR2:IW,AR3:XT,AR4:COSαlk,AR5=M,AR6:下一个Rj
D
LAR AR0,*-,AR4 ; AR0=IW
; ARP=AR4,AR0=IW,AR2:ID,AR3:XT,AR4:COSαlk,AR5=M,AR6:下一个Rj
MAR *0+,AR2 ; AR4=AR4+IW-->下一个COSαlk
LAR AR0,* ; AR0=ID
ADRK #3 ; AR2:C1
; ARP=AR2,AR0=ID,AR2:C1,AR3:XT,AR4:下一个COSαlk,AR5=M,AR6:Rj
LACC *
SUB #1
SACL *- ; C1=C1-1
; ARP=AR2,AR0=ID,AR2:C2,AR3:XT,AR4:COSαlk,AR5=M,AR6:Rj
BCND LOOP4,LEQ ; 跳转至LOOP4,IF C1<0
MAR *-,AR4 ; AR2:IW
; ARP=AR4,AR0=ID,AR2:IW,AR3:XT,AR4:下一个COSαlk,AR5=M,AR6:Rj
B LOOP1
LOOP4 LACC *
SUB #1
SACL *-,AR3
MAR *-,AR2
; ARP=AR2,AR0=ID,AR2:IW,AR3:C1,AR4:下一个COSαlk,AR5=M,AR6:Ri
MAR *-
BCND LOOP2,GT
MAR *,AR3
MAR *-,AR5
; ARP=AR5,AR0=ID,AR2:IW,AR3:C2,AR4下一个COSαlk,AR5=M,AR6:Ri
BANZ LOOP3,*-,AR2
; ------------------------------------
; 与C语言兼容的代码部分
; ------------------------------------
CLRC OVM
SPM 0
MAR *,AR1
SBRK #09
LAR AR0,*-
LAR AR7,*-
LAR AR6,*-
PSHD *
RET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -