📄 fft.asm
字号:
;// -------------------------------------------------------------------------------------------------
;// 函数名: 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 + -