运用TMS320C54x汇编语言编写定点数运算浮点数运算程序.docx
《运用TMS320C54x汇编语言编写定点数运算浮点数运算程序.docx》由会员分享,可在线阅读,更多相关《运用TMS320C54x汇编语言编写定点数运算浮点数运算程序.docx(19页珍藏版)》请在冰点文库上搜索。
运用TMS320C54x汇编语言编写定点数运算浮点数运算程序
一、定点数的运算
在定点DSP芯片中,采用定点数进行数值运算,其操作数一般采用整数来表示。
一个整数的最大表示范围取决于DSP芯片所给定的字长,一般为16位或24位。
显然,字长越长,所能表示的数的范围越大,精度也越高。
在字长固定的前提下,所需要达到的精度越高,那么所能表示的浮点数的范围就会越小。
DSP芯片的数以2的补码形式表示。
每个16位数用一个符号位来表示数的正负,0表示数值为正,l则表示数值为负。
其余15位表示数值的大小。
如:
二进制数0010000000000011b=8195
二进制数1111111111111100b=-4
为了使得无论是无符号数还是符号数,都可以使用同样的加法减法规则,符号数中的负数用正数的补码表示。
对DSP芯片而言,参与数值运算的数就是16位的整数。
但在许多情况下,数学运算过程中的数不一定都是整数。
那么,DSP芯片是如何处理小数的呢?
这其中的关键就是数的定标,由程序员来确定一个数的小数点处于16位中的哪一位。
通过设定小数点在16位数中的不同位置,就可以表示不同大小和不同精度的小数了。
数的定标有Q表示法和S表示法两种。
定点数的加减法运算较为简单,只需遵循二进制数加减法运算规则相加减即可。
如:
两个8位数具有相同的Qn格式,保证隐含的小数点对齐。
下图中两个8位数相加,有溢出。
溢出是由于字长有限运算结果超出数值的表示范围引起的。
定点数的乘法运算
DSP处理器都有硬件乘法器和乘法指令,可实现单周期乘法运算,二进制乘法运算包含一系列的移位和加法运算。
定点数乘法运算不要求相乘数有相同的Qn格式。
两个相乘数分别为Qn和Qm格式,字长为N,结果为Q(n+m)格式,字长为2N。
如:
以下两个相乘数分别为Q7和Q6格式,8位字长。
两个定点小数作乘法运算,结果左移一位,保存高位得到运算结果,结果为Qm(
m)格式。
小数乘小数,整数乘小数都要求对乘积结果左移一位后,保存高位。
整数与整数相乘,须查询标志位确定保存的位数,结果不需要左移一位。
DSP处理器带有可选的自动左移一位的功能,消除移位操作的时间开销。
定点数的除法运算
除法是乘法的逆运算,包括一系列移位和条件减法运算,需要用除法子程序实现。
大多数DSP处理器不提供单周期除法指令。
如果除法运算中包含负数,应将负数变换为等值的正数,然后作除法运算,最后加上正确的符号。
下面详细分析32位整数乘法,32位小数乘法以及有符号/无符号整数除法的程序指令。
32位定点数乘法运算示意图
32位整数乘法参考程序:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Thisroutinemultipliestwo32-bitsignedintegersresulting;
;ina64-bitproduct.Theoperandsarefetchedfromdatamemoryand
;theresultiswrittenbacktodatamemory.
;DataStorage:
;X1,X032-bitoperand
;Y1,Y032-bitoperand
;W3,W2,W1,W064-bitproduct
;EntryConditions:
;SXM=1,OVM=0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.mmregs
STACK:
.usect“STACK”,100h;设置堆栈段
.bssX0,1
.bssX1,1
.bssY0,1
.bssY1,1
.bssW0,1
.bssW1,1
.bssW2,1
.bssW3,1
.defstart
.data
table1:
.word1
.word2
table2:
.word3
.word4
.text
start:
STM#X0,AR2;将X0的首地址存入AR2
STM#Y0,AR3;将Y0的首地址存入AR3
RPT#1;设置重复执行两次下条指令
MVPDtable1,*AR2+;将table1开始的两个值传给X0
RPT#1;设置重复执行两次下条指令
MVPDtable2,*AR3+;将table2开始的两个值传给Y0
STM#X0,AR2;将X0的首地址存入AR2
STM#Y0,AR3;将Y0的首地址存入AR3
LD*AR2,T;T=X0
MPYU*AR3+,A;A=无符号数X0
无符号数Y0
STLA,@W0;将A送入W0
LDA,-16,A;A值左移16位
MACSU*AR2+,*AR3-,A;A+=Y1
无符号数X0
MACSU*AR3+,*AR2,A;A+=X1
无符号数Y0
STLA,@W1;将A送入W1
LDA,-16,A;A值左移16位
MAC*AR2,*AR3,A;A+=
STLA,@W2;W2=A的低16位
STHA,@W3;W3=A的高16位
here:
Bhere
程序分析:
如原理图所示,32位整数乘法的计算过程是将两个32位的数X和Y各自分成X0、X1和Y0、Y1的16位数。
然后进行X0
Y0,A值左移16位,Y1
X0,X1
Y0,A值再左移16位,X1
Y1的操作。
需要注意的是在32位乘法运算中,实际上包括了三种乘法运算:
U
U、S
U和S
S。
U指无符号数,S指带符号数。
在编程时,要用到以下三条乘法指令:
MACSUXmem,Ymem,src;无符号数与带符号数相乘并累加;MPYUSmem,dst;无符号数相乘;MACXmem,Ymem,src;两个带符号数数相乘并累加。
32位小数乘法参考程序:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ThisroutinemultipliestwoQ31signedintegers
;resultinginaQ30product.Theoperandsarefetchedfromdatamemoryand
;theresultiswrittenbacktodatamemory
;datastorege:
;X1,X0Q31operand
;Y1,Y0Q31operand
;W1,W0Q30product
;EntryConditions:
;SXM=1,OVM=0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.mmregs
STACK:
.usect“STACK”,100h
.bssX0,1
.bssX1,1
.bssY0,1
.bssY1,1
.bssW0,1
.bssW1,1
.defstart
.data
table1:
.word1
.word2
table2:
.word3
.word4
.text
start:
STM#X0,AR2;将X0的首地址存入AR2
STM#Y0,AR3;将Y0的首地址存入AR2
RPT#1;设置重复执行两次下条指令
MVPDtable1,*AR2+;将table1开始的两个值传给X0
RPT#1;设置重复执行两次下条指令
MVPDtable2,*AR3+;将table1开始的两个值传给Y0
STM#X0,AR2;将X0的首地址存入AR2
STM#Y1,AR3;将Y1的首地址存入AR3
LD#0,A;将A置0
MACSU*AR2+,*AR3-,A;A=X0
Y1
MACSU*AR3+,*AR2,A;A+=X1
Y0
LDA,-16,A;将A左移16位
MAC*AR2,*AR3,A;A+=X1
Y1
STLA,@W0;将结果A的低16位送入W0
STHA,@W1;;将结果A的高16位送入W0
here:
Bhere
程序分析:
小数乘法与整数乘法的程序设计大致类似,不同在于小数乘法少了X与Y的低位相乘部分,即X0与Y0的相乘部分。
这是因为两个整数相乘时,乘积总是“向左增长”。
这意味着多次相乘后,乘积将会很快超出定点器件的控制范围。
但是,当两个小数相乘时,乘积总是“向右增长”。
这就意味着超出定点器件数据范围将是我们不感兴趣的部分,也就是指X0与Y0相乘得到的结果那部分,因此可不必计算这部分乘积。
有符号/无符号整数除法参考程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Description:
32bitby16bitUnsignedIntegerDivideAndModulus
;32位除16位的无符号整数除法
.mmregs
STACK:
.usect“STACK”,100h
.bssd_NumL,1;为分子低16位分配1个单元
.bssd_NumH,1;为分子高16位分配1个单元
.bssd_Den,1;为分母分配1个单元
.bssd_QuotL,1;为商的低16位分配1个单元
.bssd_QuotH,1;为商的高16位分配1个单元
.bssd_Rem,1;
.defDivModUI32
.defstart
.data
table1:
.word1
.word2
table2:
.word3
.text
DivModUI32:
RSBXSXM;signextentionmodeoff
LDd_NumH,A;将分子高位移到累加器A
RPT#(16–1);重复执行下一条指令15次
SUBCd_Den,A;A减去分母的值
STLA,d_QuotH;将A的值存到商的高位
XORd_QuotH,A;将A的低16位清零
ORd_NumL,A;AL=NumL
RPT#(16–1);重复执行下一条指令15次
SUBCd_Den,A;A减去分母的值
STLA,d_QuotL;将A的值存到商的低位
STHA,d_Rem;
RET
start:
STMd_NumL,AR2;将分子低16位所在单元的地址传给AR2
STMd_Den,AR3;将分母所在单元的地址传给AR2
RPT#1;重复执行两次下一条指令
MVPDtable1,*AR2+;将table1开始的两个值传给AR2
MVPDtable2,*AR3;将table2开始的值传给AR3
CALLDivModUI32;调用除法子程序
here:
Bhere
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Description:
16bitby16bitUnsignedIntegerDivideAndModulus
;16位除16位的无符号整数除法
.mmregs
STACK:
.usect“STACK”,100h
.bssd_Num,1;为分子分配单元
.bssd_Den,1;为分母分配单元
.bssd_Quot,1;为商分配单元
.bssd_Rem,1
.defDivModUI16;定义16位除法子程序
.defstart
.data
table1:
.word1000
table2:
.word5
.text
DivModUI16:
RSBXSXM;signextentionmodeoff
LD@d_Num,A;将分子移到累加器A
RPT#(16–1);重复执行下面指令16次
SUBC@d_Den,A;16次的减法循环,完成除法
STLA,@d_Quot;将A的结果保存为商
STHA,@d_Rem
RET
start:
STMd_NumL,AR2;将分子低16位所在单元的首地址传给AR2
STMd_Den,AR3;将分子低16位所在单元的首地址传给AR3
MVPDtable1,*AR2;将table1开始的值传给AR2
MVPDtable2,*AR3;将table2开始的值传给AR3
CALLDivModUI16;调用除法子程序
here:
Bhere
程序分析:
DSP做除法运算时,通过减法指令与重复循环指令实现无符号除法运算。
需要注意的是,当被除数的绝对值<除数的绝对值时,商为小数;当被除数的绝对值>除数的绝对值时,商为整数。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Description:
32bitby16bitsignedIntegerDivideAndModulus
;32位除16位有符号除法
.mmregs
STACK:
.usect“STACK”,100h
.bssd_NumL,1;为分子低16位分配单元
.bssd_NumH,1;为分子高16位分配单元
.bssd_Den,1;为分母分配单元
.bssd_QuotL,1;为商低16位分配单元
.bssd_QuotH,1;为商高16位分配单元
.bssd_Rem,1
.defDivModI32;定义32位除法子程序
.defstart
.data
table1:
.word1
.word2
table2:
.word3
.text
DivModI32:
SSBXSXM;signextentionmodeon
LDd_Den,16,A;将分母移到累加器
MPYAd_NumH;Bhassignofquotient
ABSA;分母取绝对值
STHA,d_Rem;d_Rem=abs(Den)temporarily
LDd_NumH,16,A;将分子高16位移到A
ADDSd_NumL,A;A加上分子低16位
ABSA;取A绝对值
STHA,d_QuotH;d_QuotH=abs(NumH)temporarily
STLA,d_QuotL;d_QuotL=abs(NumL)temporarily
LDd_QuotH,A;将商的高位移到A
RPT#(16–1);重复执行下条指令16次
SUBCd_Rem,A;16次减法循环运算,完成除法
STLA,d_QuotH;AH=abs(QuotH);
XORd_QuotH,A;clearAL
ORd_QuotL,A;AL=abs(NumL)
RPT#(16–1);重复执行下条指令16次
SUBCd_Rem,A;16次减法循环运算,完成除法
STLA,d_QuotL;AL=abs(QuotL)
STHA,d_Rem;AH=Rem
BCDDivModI32Skip,BGEQ;ifBneg,thenQuot=–abs(Quot)
LDd_QuotH,16,A;将商的高16位移到A
ADDSd_QuotL,A;A加上商的低16位
NEGA;如果B<0执行求反,否则跳过此指令
STHA,d_QuotH;商的高位存回原处
STLA,d_QuotL;商的低16位存回原处
DivModI32Skip:
RET;定义32位除法返回子程序
start:
STMd_NumL,AR2;将分子低16位首地址传给AR2
STMd_Den,AR3;将分母首地址传给AR2
RPT#1;重复执行下条指令两次
MVPDtable1,*AR2+;将table1开始的两个值传给AR2
MVPDtable2,*AR3;将table2开始的值传给AR2
CALLDivModI32;调用32位除法指令
here:
Bhere
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Description:
16bitby16bitsignedIntegerDivideAndModulus
;16位除16位有符号除法
.mmregs
STACK:
.usect“STACK”,100h
.bssd_Num,1;为分子分配单元
.bssd_Den,1;为分母分配单元
.bssd_Quot,1;为商分配单元
.bssd_Rem,1
.defDivModI16;定义16位除法子程序
.defstart
.data
table1:
.word16
table2:
.word-2
.text
DivModI16:
SSBXSXM;signextentionmodeon
STM#d_Quot,AR2;将商的值传给AR2
LDd_Den,16,A;将分母移到A累加器
MPYAd_Num;Bhassignofquotient
ABSA;分母取绝对值
STHA,d_Rem;d_Rem=abs(Den)temporarily;
LDd_Num,A;将分子移到A累加器
ABSA;分子取绝对值
RPT#(16–1);重复执行下条指令16次
SUBCd_Rem,A;分子循环相减16次,完成除法
STLA,d_Quot;将A的值保存到商
STHA,d_Rem;AH=Rem
LD#0,A;将A清零
SUBd_Quot,16,A;AH=–abs(Quot)
SACCDA,*AR2,BLT;IfBneg,Quot=–abs(Quot)
RET
start:
STMd_NumL,AR2;将分子低16位首地址传给AR2
STMd_Den,AR3;将分母16位首地址传给AR2
MVPDtable1,*AR2;将table1开始的值传给AR2
MVPDtable2,*AR3;将table1开始的值传给AR2
CALLDivModI16;调用除法子程序
here:
Bhere
程序分析:
有符号数除法与无符号数出发类似。
不同在于,有符号数除法得到的商的结果可能为正,也可能为负。
因此在用绝对值求出商后,不能直接存入quot段。
先要判断商值为正还是为负。
如果有符号数的商为负值时,需要变号,用到取反指令negA,然后才能将值存入quote段中。
二、浮点数的运算
在数字信号处理中,定点运算是将数据的整数和小数部分分开,小数点在一个固定位置,其优点是硬件实现比较容易,但动态范围受到限制。
为了扩大数据的范围和精度,需要采用浮点运算。
在C54X上实现浮点运算,操作数须先变成定点数,然后再返回浮点数。
通过规格化输入数据,可以将定点值变换为浮点值。
表示方法一个浮点数由尾数m、基数b和指数e三部分组成,即
浮点数的加减法运算,计算过程是左移指数较小的操作数的尾数,使得两个操作数的指数一致,相差几位移几位,再把尾数相加(减),归一化后输出。
主要是要比较两个操作数指数的大小,这样才能决定到底是尾数直接相加(减)还是移位以后再相加(减)。
如:
若
,则
。
浮点数的乘法运算,要经过分离指数和尾数,进行算术运算,估计结果的符号位,以及最后的归一化存储这几个过程。
做乘法运算时要遵循乘法运算的规则把指数相加,尾数相乘。
即:
。
需要注意的是,由于C54X的乘法器在一个指令周期内只能完成17bit*17bit的二进制补码运算,故相乘运算需要分步实现。
浮点数的除法运算与乘法运算浮点数的乘法运算类似,同样要经过分离指数和尾数,估计结果的符号位,对指数进行相减运算,对尾数进行相除运算,以及最后的归一化存储这几个过程。
即:
。
不同的是,在执行除法运算的时候,需要将除数和被除数都由24bit左移成32bit的形式,以减少误差。
不管是浮点数的加减运算还是乘除运算,完成对操作数之间的计算后就需要对结果数进行归一化操作。
所谓归一化操作就是把数据格式转换为第一位为符号位,紧接着的一位是非零的数的格式。
归一化完后要再把归一化后的定点数转变为浮点数。
下面来以浮点数的乘法运算为例具体分析浮点数的运算过程:
设是对两个数x1和x2进行乘法运算。
将被乘数数x1的尾数分为Q,R和S三部分,Q表示尾数的高位的8bit,R和S表示尾数低位的两字节。
同样,乘数x2也被分为X,Y和Z三部分,X表示尾数的高位,Y和Z表示尾数低位的两字节。
于是有
需要注意的是,进行的这种32bit*32bit的运算是有精度损失的。
如上图所示,32位数0QRS乘以32位数0XYZ所得的结果应该是一个64bit的值。
由于0Q*0X的高16bit始终为0,所以结果可以用一个48位的值准确表示。
但是用于存储结果的存储单元长度只有32bit,于是只有将最低的16bit省略掉,即把RS*YZ的低16bit略去,因此最后得到的是一个有精度损失的32bit结果。
浮点数乘法源程序如下:
.title“float.asm”
.defstart
STACK:
.usect“STACK”,100
.bssx1,1;x1是被乘数
.bssx2,1;x2是被乘数
.bsse1,1;e1是被乘数的指数
.bssm1,1;m1是被乘数的尾数
.bsse2,1;e2是乘数的指数
.bssm2,1;m2是乘数的尾数
.bssep,1;ep是乘积的指数
.bssmp,1;mp是成绩的尾数
.bssproduct,1;product是乘积
.bsstemp