实验三C54X的浮点数的算术运算
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三、C54X 的浮点数的算术运算
1. 实验目的
(1) 练习TMS320C54X 汇编程序的编写与调试方法,重点练习C54X 程序流程控制的方
法。
(2) 学习并掌握应用TMS320C54X 来进行浮点数的各种算术运算的算法实现。
(3) 练习并掌握TMS320C54X 的汇编语言的汇编指令系统的使用方法,重点练习具有
C54X 特点的一些在功能上有所扩展的特殊指令,并了解这些指令在进行算术运算或各种控制时所带来的方便。
(4) 练习并掌握用CCS 调试程序的一些基本操作。
2. 实验原理
(1)浮点数的表示方法
在定点运算中,小数点是在一个特定的固定位置。
例如,如果一个32-bit 的数把小数点放在最高有效位(也就是符号位)之后,那么就只有分数(绝对值小于1)才能被显示。
在定点运算系统中,虽然在硬件上实现简单,但是表示的操作数的动态范围要受到限制。
使用浮点数,可以避免这个困难。
一个浮点数由尾数m 、基数b 和指数e 三部分组成。
即:
下图举例说明了IEEE 标准里的浮点数表示方法。
这个格式用带符号的表示方法来表示尾数,指数含有127的偏移。
在一个32-bit 表示的浮点数中,第一位是符号位,记为S 。
接下来的8-bit 表示指数,采用127的偏移格式(实际是e-127)。
然后的23-bit 表示尾数的绝对值,考虑到最高一位是符号位,它也应归于尾数的范围,所以尾数一共有24-bit
通常用该格式所表示的浮点数值如下:
在特殊情况下:
比如说:十进制数-29.625可以用二进制表示为-11101.101B ,用科学计数法表示为 -1.1101101*24,其指数为127+4=131,化为二进制表示为B ,故此数的浮点格式表示为00,转换成16进制表示为0xC1ED0000。
又如在下面程序中将要使用的浮点数12.0,用二进制表示为1100B ,用科学记数法表示为1.1*23,其指数部分为127+3=130,化为二进制表示为B ,因此该数的浮点数格式为00000000000000000,转换成16进制表示为0x 。
浮点数144.0,用二进制表示为B ,科学记数法记为1.001*27,指数部分为127+7=134=B ,该数的浮点数格式为00000000000000000,转换成16进制表示为H 。
e
b *m )
.1(*2*)1(2550127f e e s --<<为时
当)0.0(*)1(00s f e -==为时且当)
.0(*2*)1(00126f f e s --<>=为时
且当无穷大
为时
且当*)1(0255s f e -==)
(0255不表示一个数时
且当NAN f e <>=
(2)浮点数运算的步骤
①加法的运算步骤
要在C54X上实现浮点运算,操作数必须变换成定点数,实际上就是一个数据格式的转换问题,可以用以下代码段来实现:
dld op1_hsw,a ;将OP1装入累加器A中。
sfta a,8
sfta a,-8 ;通过先左移后右移使AG = 0。
bc op1_zero,AEQ ;如果OP1是零,转入特殊处理。
sth a,-7,op1se ;将符号和指数存储到OP1SE中。
stl a,op1lm ;存储尾数的低位。
and #07Fh,16,a ;将浮点数格式中的符号和指数去掉得到尾数的高位。
add #080h,16,a ;给尾数加上小数点前的“1”。
sth a,op1hm ;存储尾数的高位。
执行完这段代码之后,操作数1就从原来在op1_hsw和op1_lsw(共32bit)中的浮点数格式转换为三部分:指数和符号位(存储于op1se中)、尾数低位(存储于op1lm中)以及尾数高位(存储于op1hm中),这时所有的数值就都转换为定点数的格式了。
在上述程序段中执行了
sfta a,8
sfta a,-8
它是先把累加器A中的值作算术左移8位再算术右移8位,其结果是使累加器A中的8位保护位(bit39-bit32)全清为0以免对以后的运算产生错误影响。
注意上述代码中使用了一种双精度的寻址方式,指令为:
dld op1_hsw,a ;
它受st1中的C16位的影响,在C16=0的情况下采用双精度的寻址方式,把op1_hsw 以及紧跟其后的一个字节的数据(op1_lsw)一起作为一个32bit的数装入累加器A中。
在C16=1的情况下该指令把op1_hsw和op1_lsw作为两个16bit的数装入累加器A中,op1_hsw装在AH中,op1_lsw装在AL中。
使用该指令比较有效,只需用一个时钟周期就可以装入32bit的数,这就比分步来装入要节约空间和时间。
在这段程序中作了一个判断以提高程序运行的效率:当op1是零时就执行相对应的特殊处理程序段op1-zero:
op1_zero:
return_op2:
bd return_value ;延迟跳转
dld op2_hsw,a ;将OP2 作为结果装入acc A中
执行该段程序即可快速的返回op2的值。
这段程序在后面判断完op2远大于op1之后也将被调用来返回op2的值。
由于实行的是带符号位的运算,所以要把尾数变成带符号的形式,即如果是正数就不改变其存储格式,而如果是负数,就要用补码来表示尾数,这部分的代码如下:bitf op1se,#100h ;取出op1符号位的值于TC位中
bc testop2,NTC ;如果TC = 0则跳转到testop2处
ld #0,a ;
dsub op1hm,a ;0 – op1的尾数,得到尾数的补码表示
dst a,op1hm ;将尾数存入op1hm和op1lm中
testop2:
bitf op2se,#100h ;取出op1符号位的值于TC位中
bc compexp,NTC ;如果TC = 0则跳转到compexp处
ld #0,a ;
dsub op2hm,a ;0 – op1的尾数,得到尾数的补码表示
dst a,op2hm ;将尾数存入op1hm和op1lm中
通过上述过程,把浮点数分解为尾数和指数两个部分,对于浮点数的加法而言,计算过程是左移指数较小的操作数的尾数,使得两个操作数的指数一致,相差几位移几位,再把尾数相加,归一化后输出。
主要是要比较两个操作数指数的大小,这样才能决定到底是尾数直接相加还是移位以后再相加,该段过程可以用以下的代码来实现:compexp:
ld op1se,a ;将操作数1的符号和指数位装入acc A中
and #00ffh,a ;去掉符号位的影响
ld op2se,b ;将操作数2的符号和指数位装入acc B中
and #00ffh,a ;去掉符号位的影响
sub a,b ;op2的指数- op1的指数结果赋给acc B
bc op1_gt_op2,BLT ;跳到进行op1 > op2的操作处
bc op2_gt_op1,BGT ;跳到进行op2 > op1的操作处
a_eq_b: ;执行A = B的操作
dld op1hm,a ;将操作数1的尾数(32bit)放到acc A中
dadd op2hm,a ;将操作数2的尾数与操作数1的尾数进行32bit的双精
;度加法
bc res_zero,AEQ ;如果结果零就转入专门处理过程
ld op1se,b ;将指数装入acc B中以准备规一化处理
这里又有一个特殊的处理程序:结果是零的情况。
当这种情况发生时,处理很简单,只需如下几步就可以完成处理:
res_zero:
bd return_value ;延迟跳转
sub a,a ;acc A中清零处理。
nop
在以上的程序中比较了OP1和OP2的指数,需要注意的是,在比较完指数大小之后如果OP1的指数比较大就执行op1_gt_op2段代码,在这段代码中以OP1为基准,左移次数较低的OP2的尾数,使OP2的指数与OP1的指数一致,具体程序如下:op1_gt_op2:
abs b ;去掉符号位的影响
sub #24,b ;判断op1_se是否比op2_se大24
bc return_op1,BGEQ ;如果op1_se远远大于op2_se则转入相应的返回op1的
;操作
add #23,b ;恢复指数的差值
stl b,rltsign ;存储指数差值以准备作为RPC使用
dld op2hm,a ;将OP2的尾数(32bit)装入acc A中
rpt rltsign ;规范OP2以适应OP1
sfta a,-1
bd normalize ;延迟方式执行跳转到normalize 处
ld op1se,b ;将指数值装入acc B以准备规一化处理
dadd op1hm,a ;将OP1和OP2的尾数相加
……
该段代码使用指令
rpt rltsign
sfta a,-1
来实现了对OP2的尾数的移位操作。
rpt指令执行的循环次数由rltsign中的值决定,当rltsign中的值为N时,sfta指令就执行N+1次,所以B累加器中的值在先减去24以后只需要加23就可以装入rltsign中了。
该段程序中还有一个需要值得注意的是使用了延迟指令:
bd normalize ;延迟方式执行跳转到normalize 处
ld op1se,b ;将指数值装入acc B以准备规一化处理
dadd o p1hm,a ;将OP1和OP2的尾数相加
bd 指令表示紧接着该指令的后面两条单字指令:ld、dadd都要从程序存储器中取出先执行。
这段程序执行完后,程序跳到normalize段,并且acc B中值为op1se中的值,acc A 中的值为OP1和OP2的尾数的和(用双精度加法实现)。
完成对操作数之间的计算后就需要对结果数进行归一化操作。
所谓归一化操作就是把数据格式转换为第一位为符号位,紧接着的一位是非零的数的格式,即是:S1xxxxxxxxxxxxxx的形式。
可以用如下的代码来实现:
normalize:
sth a,rltsign ;将带符号的尾数高位存入rltsign单元中
abs a ;去掉符号位的影响
sftl a,6 ;进行归一化的预处理,将acc中的值左移6位
exp a ;对acc A中的值进行规一化操作
norm a
st t,rltexp ;存储规一化时左移的数值到rltexp中
add #1,b ;考虑到进位位所以要给指数加上“1”
sub rltexp,b ;完成指数的归一化工作
normalized:
stl b,rltexp ;将结果指数存在rltexp中
bc underflow,BLEQ ;如果B〈0 进行下溢处理
sub #0ffh,b ;进行上溢处理判断
bc overflow,BGEQ ;如果B 〉0 进行上溢处理
sftl a,-7 ;将尾数右移7位以方便以后合成为32bit的浮点数格式
stl a,rltlm ;存储低位的尾数
and #07f00h,8,a ;将最开始中小数点前的“1”省略
sth a,rlthm ;存储高位的尾数
在这段代码中acc A中的值是由两个24bit的操作数定点相加而得到的,其MSB可能在bit24-bit0中的任何一位,所以首先左移6位让bit24移至bit30,接下来通过:exp a
norm a
来归一化acc A中的数据,exp和norm指令联合使用之后acc A中的数据变成归一化形式。
比如:这两条指令执行之前acc A中的值为0x01800000,执行以后A中的值为0x。
操作数左移的位数被存于寄存器T中,如上述操作后寄存器T中的值为0x0006,所以最后的指数的计算还要减去寄存器T中的值才是最后结果的指数值。
归一化完后要再把归一化后的定点数转变为浮点数,这是前面的转变浮点数为定点数的逆过程,参照前述步骤可以用如下程序实现:
;----------- Conversion of Floating Point Format to Pack ---------
ld rltsign,9,a ;将rltsign左移9位后acc A中
and #100h,16,a ;取出rltsign中的符号位,使acc A中的格式为
;0000 000S 0000 0000 0000 0000 0000 0000
add rltexp,16,a ;将结果的指数存入acc A中满足浮点数格式的相应位置
;A中格式为:0000 000S EEEE EEEE 0000 0000 0000 0000 sftl a,7 ;A中格式为:SEEE EEEE E000 0000 0000 0000 0000 0000
dadd rlthm,a ;最终在acc A中得到32位的浮点数格式如下:
;SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM 这样综合上述的各个步骤,加法运算就可以实现了。
②减法的运算步骤
减法运算的实现与加法运算几乎完全一样,只是在具体进行运算时使用的是减法指令而不是加法指令。
比如要进行的是被减数(OP3)与减数(OP4)的减法运算。
首先是转换数据格式,这一步与加法运算中的过转换程完全一样,在此就不再赘述了。
然后要进行的是指数比较判断、尾数移位对齐小数点后相减的操作,该部分程序代码如下:
ld op3se,a ;将操作数3的符号和指数位装入acc A中
and #00ffh,a ;去掉符号位的影响
ld op4se,b ;将操作数4的符号和指数位装入acc B中
and #00ffh,b ;去掉符号位的影响
sub a,b ;op4的指数– op3的指数结果赋给acc B
bc op3_gt_op4,BLT ;进行op3 > op4的操作
bc op4_gt_op3,BGT ;进行op4 > op3的操作
a_eq_b: ;执行A = B的操作
dld op3hm,a ;将操作数3的尾数(32bit)放到acc A中
dsub op4hm,a ;将操作数4的尾数与操作数1的尾数进行32bit的双精
;度减法
ld op3se,b ;将指数装入acc B中以准备规一化处理
在这段程序中比较了OP3和OP4的指数,需要注意的是,在比较完指数大小之后,如果OP4的指数比较大就执行op4_gt_op3段代码,在这段代码中以OP4为基准,左移次数较低的OP3的尾数,使OP4的指数与OP3的指数一致,具体程序如下:op4_gt_op3:
sub #24,b ;判断op4_se是否比op3_se大24
bc return_op4,BGEQ ;如果op4_se远远大于op3_se则转入相应的返回op4的
;操作
add #23,b ;恢复指数的差值
stl b,rltsign ;存储指数差值以准备作为RPC使用
dld op3hm,a ;将OP3的尾数(32bit)装入acc A中
rpt rltsign ;规范OP3以适应OP4
sfta a,-1
bd normalize ;延迟方式执行跳转到normalize 处
ld op4se,b ;将指数值装入acc B以准备规一化处理
dsub op4hm,a
;将 OP4和OP3的尾数相减
完成对操作数之间的计算后就需要对结果数进行归一化,之后转变为浮点数存储。
该过程与浮点数加法运算的归一化存储过程完全一样,读者可以参照前面的程序段编写出这部分的代码。
③ 乘法的运算步骤
当两个数相乘时,编程的大体框架还是与加减法一样的。
同样要经过分离指数和尾数,进行算术运算,以及最后的归一化存储这几个过程,只是运算时要遵循乘法运算的规则把指数相加,尾数相乘。
需要注意的是,由于C54X 的乘法器在一个指令周期内只能完成17bit*17bit 的二进制补码运算,故相乘运算需要分步实现,具体原理如下: 设是对两个数OP5和OP6进行乘法运算。
将被乘数数OP5的尾数分为Q ,R 和S 三部分,Q 表示尾数的高位的8bit ,R 和S 表示尾数低位的两字节。
同样,乘数OP6也被分为X ,Y 和Z 三部分,X 表示尾数的高位,Y 和Z 表示尾数低位的两字节。
于是有
需要注意的是,进行的这种32bit*32bit 的运算是有精度损失的。
如上图所示,32位数0QRS 乘以32位数0XYZ 所得的结果应该是一个64bit 的值。
由于0Q*0X 的高16bit 始终为0,所以结果可以用一个48位的值准确表示。
但是用于存储结果的存储单元长度只有32bit ,于是只有将最低的16bit 省略掉,即把RS*YZ 的低16bit 略去,因此最后得到的是一个有精度损失的32bit 结果。
由于进行的是带符号的运算,所以在进行相乘运算时首先要确定最后结果的符号位。
根据“同号为正,异号为负”的原则,可以写出以下代码:
;------ sign evaluation ----------------- ld
op5se,a
;装入op5的指数和符号位 xor op6se,a ;与op6的指数和符号位相异或 and #00100h,a ;屏蔽指数得到符号位
stl
a,rltsign
;得到结果的符号位
具体相乘的步骤可以用如下代码来实现,首先进行指数位的相加: ;------ exponent summation -------------- ld op5se,a and #00FFh,a ;去掉符号位的影响
ld
op6se,b
and #00FFh,b
;去掉符号位的影响 0 Q R S 0 X Y Z *
RS * YZ RS * 0X 0Q * YZ
0Q * 0X result
op5的尾数
op6的尾数
只存储了结果 的高16位
高16位始终 为0结果只表示了64bit 中的32bit
+
sub #07fh,b ;op6的指数减去127(避免结果加上两个127偏移)
add b,a ;加上op5的指数
stl a,rltexp ;将指数结果存于rltexp中
bc underflow,ALT ;如果exp < 0则跳转到下溢处理underflow处
sub #0FFh,a ;测试是否产生上溢
bc overflow,AGT ;如果exp > 255则跳转到下溢处理overflow处
然后对尾数运用上面的公式进行运算:
ld op5lm,t ;将OP5的低位尾数装入T寄存器
mpyu op6lm,a ;RS*YZ
mpyu op6hm,b ;RS*0X
add a,-16,b ;B=(RS*YZ)+(RS*0X)
ld op5hm,t ;将OP5的高位尾数装入T寄存器
mpyu op6lm,a ;A=0Q*YZ
add b,a ;A=(RS*YZ)+(RS*0X)+(0Q*YZ)
mpyu op6hm,b ;B=0Q*0X
stl b,rlthm ;得到0Q*0X的低16bit
add rlthm,16,a ;A=最后的结果
值得注意的是,该段代码中使用了mpyu指令,该指令将T寄存器中的值看作一个无符号数与无符号的单数据存储器操作数相乘,将结果放于指定的累加器中。
这条指令在执行这种多精度乘法运算时相当有效。
同加法减法一样,乘法运算同样会产生上溢出和下溢出的情况,当上溢出发生,即指数部分的值大于254时,就需要进行相应的上溢出的处理工作,具体的程序如下:overflow:
st #2,errno ;将出错位置以相应的表示位
ld rltsign,16,b ;将符号位装入acc B中
ld #0FFFFh,a ;下溢出的结果低位为0FFFFh
or b,7,a ;;Add sign bit
bd return_value ;延迟跳转
add #07F7Fh,16,a ;将结果的指数置为0FEh且把尾数的高7位bit全置为零
当下溢出情况发生,即指数部分的值小于等于0时,执行下溢出处理的程序如下:underflow:
st #1,errno ;将出错位置以相应的表示位
bd return_value ;延迟跳转
sub a,a ;对于下出溢结果= 0
nop
④除法的运算步骤
除法运算的实现与乘法运算差不多,同样要经过分离指数和尾数,估计结果的符号位,对指数进行相减运算,对尾数进行相除运算,以及最后的归一化存储这几个过程。
不同的是,在执行除法运算的时候,需要将除数和被除数都由24bit左移成32bit的形式,以减少误差。
设是对两个数OP7和OP8进行除法运算,被除数OP7左移后被分为OP7’HI (高16bit),OP7’LO(低16bit)两部分,除数OP8左移后被分为OP8’HI(高16bit),OP8’LO(低16bit)两部分,设结果被分为QHI(高16bit)和QLO(低16bit)两部分,于是就有
设X = OP8’LO/OP8’HI ,由泰勒展开式可知:
在进行数学计算时,x 的平方以后的项可以忽略,即可以用1 – x 代入式中进行计算,
故有:
这就是用DSP 进行除法运算的公式。
根据这个公式,可以写出有关除法运算的代码:
dld op7hm,a; ;将被除数装入acc A 中
sftl a,6 ;将被除数左移为除法作准备,因为SUBC 要求被除数最高
;位为0,且被除数要小于除数故只移6位 dld op8hm,b ;将除数装入acc B 中
sftl b,7
;将除数左移为除法作准备,因为SXM =1,故要求最高 ;位为零,只移7位
dst b,op8hm ;将除数存于op8hm 和op8lm 中 rpt #14 ;Q ’HI=OP 7’HI/OP 8’HI subc op8hm,a
stl
a,rlthm
;存储Q ’HI
subs rlthm,a ;从acc A 中清除Q ’HI rpt #15 ;Q ’LO=OP 7’LO/OP 8’HI subc op8hm,a
stl a,rltlm ;存储Q ’LO ld
rlthm,T
;T =Q ’HI
mpyu o p8lm,a ;存储Q ’HI *OP8’LO 于acc A
sftl a,-1 ;考虑到符号位对商的影响,所以应该右移一位得到正确
;的有符号数
rpt #15
;计算Q ’HI *OP8’LO/OP8’HI
subc op8hm,a ;所得到的结果是修正值,放于acc A 中 and #0FFFFh,a ;将修正值(在低16bit )取出 neg a
;将修正值的负号加上 adds rltlm,a
;加上 Q ’LO add rlthm,16,a
;加上 Q ’HI
在经过上述这段除法运算程序之后,结果就存储在累加器A 中,再对之进行归一化,
QHI+QLO=
OP7'HI+OP7'LO
OP8'HI+OP8'LO
=
OP7'HI+OP7'LO
OP8'HI
*
1
OP8'LO OP8'HI
+
111 + x
= 1 - x + x 2 - x 3 ... ...
QH I+QLO=
OP 1'H I+OP 1'LO
OP 2'H I+OP 2'LO
=
OP 1'H I + OP 1'LO
OP 2'H I *
OP
2'LO OP 2'H
I
1 -
*
OP 2'LO OP 2'H I
1 -
=
Q'HI + Q'LO
=Q'HI + Q'LO -
Q'HI *
OP 2'LO OP 2'H I
并把数据格式从定点数转换为浮点数存储就完成了的除法计算。
3.实验内容
本实验需要使用C54X汇编语言实现两个浮点数的加、减、乘、除运算,并通过CCS 的存储器窗口观察最后的结果是否正确。
实验可以分为以下两步完成:
(1)编写实验程序代码
由于本实验是要用C54X的汇编语言实现两个浮点数的四种运算,其中加、减法比较类似故可以用一个程序流程图来表示。
加法的主要步骤是转换浮点数为定点数,执行加法时就像前面所讲的那样把尾数移位对齐,再相加,同时还要注意一些特殊情况,比如其中一个数为零,或者是其中一个数比另一个数小许多(即指数相差太大)等等。
其程序的主要流程图如下:对于乘法运算,同样需要首先把被乘数和乘数的从浮点数格式分解为符号,指数,尾数三部分,然后再把指数相加,注意是否产生上溢出(>=0FFh)或下溢出(<0),如果没有溢出,则进行24bit*24bit的尾数相乘运算。
具体的程序流程如下:
除法程序的流程图与乘法运算的流程图大同小异,如下所示:
程序编制过程中需要注意的是:
①在把浮点数转换成定点数的过程中,注意要将尾数前面省略的小数点前面的“1”加上,这样在进行加法运算时才能得到正确的结果。
②在运算过程中,需要对数值结果进行归一化操作,对于C54X汇编而言,有一个很简单的方法,就是使用语句
EXP A
NORM A
这两条语句执行之后的结果是把累加器A中的带符号数进行归一化操作,操作中所移位的位数在寄存器T中。
③注意对最后结果的溢出、为零等一些细节情况的处理。
(2)在CCS的C54xx simulator上调试观察实验结果
程序代码分成四个ASM文件输入,通过编译生成.obj文件,并用命令:
lnk500 fa1.obj fs1.obj fm1.obj fd1.obj -o fc.out user.cmd
连接成功,生成.out文件后就可以在DES板上调试运行。
步骤如下:
a.首先启动setup CCS C5000,在其中设置目前需要的CCS的工作状态为C54xx
simulator,保存这一设置并退出。
然后再启动CCS实验系统软件CCS C5000.EXE。
b.在下拉菜单中选择“File”——“Load Program”以装入所要调试的程序f
c.out,
这时,在反汇编窗口中能看到程序的源代码。
c.在下拉菜单中选择“View”――“CPU Registers”――“CPU Register”,可以看见在
CCS界面下部份会出现CPU中的相关寄存器;选择“View”――“Memory…”,在弹出的“Memory Window Options”窗口中选择要观察的区域为数据区,地址开始为0x80h,然后就可以看见出现一个Data Memory窗口,其中显示了从0x80h开始的.bss区。
d.在反汇编窗口中需要观察的地方设置断点:在这条指令处双击将其点为红色即可。
比如在加法程序中有指令nop的位置都可以加一个断点。
e.在下拉菜单中选择“调试”——“连续运行”(或直接点击“运行程序”按钮)运
行浮点数程序。
如果编写程序时在计算完毕后遇到一个断点,那么程序到此会自动停止。
f.当示范程序在第一个断点处停下来时,此时就可以看见程序初始化后的情况:被
加数12.0以浮点数的格式放在内存区0x08a-0x08b中,其值为4140h和0000h。
加数12.0放在内存区0x08c-0x08d中,其值也为4140h和0000h。
g.再点击“运行程序”按钮,之后程序会在下一个断点处停下来,这时可以看见被
加数被格式转换后的变量op1hm、op1lm和op1se的值在内存区0x084-0x086中,分别为00c0h、0000h和0082h。
同样加数被格式转换后的变量op2se、op2hm和op2lm的值在内存区0x087-0x089中,分别为0082h、00c0h和0000h。
h.再点击“运行程序”按钮,程序停下来时就可以观察到在存储器窗口中表示结果
的变量rlthm、rltlm、rltsign和rltexp的值在内存区0x080-0x083中,其值分别为0040h、0000h、0180h和0083h。
i.这时可以看到A寄存器中的值为AH=41c0h,AL=0000h这就是最后的以浮点数的
格式表示的结果值24(=12+12)。
加法运算到此结束。
j.继续点击“运行程序”按钮,当程序再次停下来时就可以看见在A寄存器中显示的13.0与12.0进行减法运算的结果:AH=3f80h,AL=0000h。
这是用浮点数格式表示的数1(=13-12)。
减法运算的程序到此结束。
k.继续点击“运行程序”按钮,当程序再次停下来时就可以看见在A寄存器中显示的12.0与12.0进行乘法运算的结果:AH=4310h,AL=0000h。
这是用浮点数格式
表示的数144(=12*12)。
乘法运算的程序到此结束。
l.继续点击“运行程序”按钮,当程序再次停下来时就可以看见在A寄存器中显示的12.0与4.0进行除法运算的结果:AH=4040h,AL=0000h。
这是用浮点数格式
表示的数3(=12/4)。
至此加、减、乘、除四种运算都运行完毕。
m.如果程序运行不正确,请检查源程序是否有误,必要时可以在源程序中多插入断点语句。
程序在执行到断点语句时自动暂停,此时可以通过检查各个寄存器中的
值以及内存单元中的值来判断程序执行是否正确。
4.思考题:
(1)假设累加器A中的值在开始时为AH = 0x147a,AL = 0x0000考虑在执行指令EXP A
NORM A
之后,累加器A中的值的变化情况如何?如果要实现同样的效果而不用这两条指
令,又该怎么办?
(2)试分析下列指令的执行方式与特点:
BD、BANZD、BCD、CALLD、RETD。
(3)利用本实验程序计算以下算式,看看结果是否正确。
41E80000 + (浮点数29 + 浮点数13)=?
42C90000 - (浮点数100.5 - 浮点数50)=?
C2FA4000 * (浮点数-125.125 * 浮点数8)=?
41A00000 / (浮点数20 / 浮点数10)=?
(4)请参照本实验中所介绍的原理自己编写一下转换浮点数格式成定点数格式的代码,尽量使用与示范程序不同的寻址方式和指令代码。
5.附实验源程序
浮点数加法源程序fa1.asm:
.title "for test user program ... "
.mmregs
.global mainstart
.ref fs_start,errno
op1valh .set 4140h ;floating point number 12.0
op1vall .set 0000h
op2valh .set 4140h ;floating point number 12.0
op2vall .set 0000h
initst0 .set 1800h ;set st0 initial number
initst1 .set 2900h ;set st1 initial number
.bss rlthm,1 ;result high mantissa
.bss rltlm,1 ;result low mantissa
.bss rltsign,1 ;ressult sigh
.bss rltexp,1 ;result exponent
.bss op1hm,1 ;op1 high mantissa
.bss op1lm,1 ;op1 low mantissa
.bss op1se,1 ;op1 sigh and exp
.bss op2se,1 ;op2 sigh and exponent
.bss op2hm,1 ;op2 high mantissa
.bss op2lm,1 ;op2 low mantissa
.bss op1_hsw,1 ;op1 packed high
.bss op1_lsw,1 ;op1 packed low
.bss op2_hsw,1 ;op2 packed high
.bss op2_lsw,1 ;op2 packed low
mainstart
stm #initst0,st0
stm #initst1,st1
rsbx C16
ld #op1lm,dp
ld #op1valh,a ;load float number
stl a,op1_hsw
ld #op1vall,a
stl a,op1_lsw
ld #op2valh,a ;load float number
stl a,op2_hsw
ld #op2vall,a
stl a,op2_lsw
trap 2
;----------- conversion of floating point format - unpack ------- dld op1_hsw,a ;load OP1 to acc a
sfta a,8
sfta a,-8
bc op1_zero,AEQ ;if op1 is 0,jump to special case
sth a,-7,op1se ;store sign and exponent to stack
stl a,op1lm ;store low mantissa
and #07Fh,16,a ;mask off sign and exp to get high mantissa add #080h,16,a ;add implied 1 to mantissa
sth a,op1hm ;store mantissa to stack
dld op2_hsw,a ;load OP2 to acc a
sfta a,8
sfta a,-8
bc op2_zero,AEQ ;if op2 is 0,jump to special case
sth a,-7,op2se ;store sign and exponent to stack
stl a,op2lm ;store low mantissa
and #07Fh,16,a ;mask off sign and exp to get high mantissa add #080h,16,a ;add implied 1 to mantissa
sth a,op2hm ;store mantissa to stack
trap 2
;---------- judge the sign----------------
bitf op1se,#100h ;test the sign bit
bc testop2,NTC ;if is not negative jump to testop2
ld #0,a ;change the experssion to
dsub op1hm,a
dst a,op1hm ;store changed op1
testop2:
bitf op2se,#100h ;test the sign bit
bc compexp,NTC ;if is not negative jump to compexp
ld #0,a ;change the expression to
dsub op2hm,a
dst a,op2hm ;store changed op2
;--------- Exponent Comparison ------------
compexp:
ld op1se,a
and #00ffh,a ;mask off the sign bit
ld op2se,b
and #00ffh,b ;mask off the sign bit
sub a,b ;exp op2-exp op1 -> b
bc op1_gt_op2,BLT ;process op1 > op2
bc op2_gt_op1,BGT ;process op2 > op1
a_eq_b
dld op1hm,a
dadd op2hm,a ;add mantissa
bc res_zero,AEQ ;if result is zero process special case
ld op1se,b ;load exponent in preparation for normalizing
trap 2
normalize
sth a,rltsign ;Save signed mantissa on stack
abs a ;Create magnitude value of mantissa
sftl a,6 ;Pre–normalize adjustment of mantissa
exp a ;Get amount to adjust exp for normalization
nop
norm a ;Normalize the result
st t,rltexp ;Store exp adjustment value
add #1,b ;Increment exp to account for implied carry
sub rltexp,b ;Adjust exponent to account for normalization normalized
stl b,rltexp ;Save result exponent on stack
bc underflow,BLEQ ;process underflow if occurs
sub #0ffh,b ;adjust to check for overflow
bc overflow,BGEQ ;process overflow if occurs
sftl a,-7 ;Shift right to place mantissa for splitting stl a,rltlm ;Store low mantissa
and #07f00h,8,a ;Eliminate implied one
sth a,rlthm ;Save result mantissa on stack
;----------- Conversion of Floating Point Format- Pack --------- ld rltsign,9,a
and #100h,16,a ;Get the sign value
add rltexp,16,a ;Add the result exponent together
sftl a,7 ;shift the value to right place
dadd rlthm,a ;Add the result mantissa together
return_value
trap 2
b fs_start
op1_gt_op2
abs b ;if exp OP1 >= exp OP2 + 24 then return OP1 sub #24,b
bc return_op1,BGEQ
add #23,b ;restore exponent difference value
stl b,rltsign ;store exponent difference to be used as RPC dld op2hm,a ;load OP2 mantissa
rpt rltsign ;normalize OP2 to match OP1
sfta a,-1
bd normalize ;delayed branch to normalize result
ld op1se,b ;load exponentvalue to prep for normalization dadd op1hm,a ;add OP1 to OP2
op2_gt_op1
sub #24,b ;if exp OP2 >= exp OP1 + 24 then return OP1 bc return_op2,BGEQ
add #23,b ;Restore exponent difference value
stl b,rltsign ;Store exponent difference to be used as RPC dld op1hm,a ;Load OP1 mantissa
rpt rltsign ;Normalize OP1 to match OP2
sfta a,-1
bd normalize ;Delayed branch to normalize result
ld op2se,b ;Load exponent value to prep for normalization dadd op2hm,a ;Add OP2 to OP1
op1_zero:
return_op2:
bd return_value
dld op2_hsw,a ;Put OP2 as result into A
op2_zero:
return_op1:
dld op1hm,a ;Load signed high mantissa of OP1
bc op1_pos,AGT ;If mantissa is negative .
neg a ;Negate it to make it a positive value
addm #100h,op1se ;Place the sign value back into op1_se
op1_pos
sub #80h,16,a ;Eliminate implied one from mantissa
ld op1se,16,b ;Put OP1 back together in acc A as a result bd return_value
sftl b,7
add b,a
overflow
st #2,errno ;load error no
ld rltsign,16,a ;pack sign of result
and #8000,16,a
or #0ffffh,a ;result low mantissa
bd return_value
add #07f7fh,16,a ;result exponent underflow
st #1,errno ;load error no
b return_value
res_zero
bd return_value
sub a,a
nop
浮点数减法源程序fs1.asm:
.title "for test user program ... "
.mmregs
.global mainstart
.def fs_start
.ref fm_start,errno
op3valh .set 4150h ;floating point number 13.0 op3vall .set 0000h
op4valh .set 4140h ;floating point number 12.0 op4vall .set 0000h
initst0 .set 1800h ;set st0 initial number initst1 .set 2900h ;set st1 initial number .bss rlthm,1 ;result high mantissa
.bss rltlm,1 ;result low mantissa
.bss rltsign,1 ;ressult sigh
.bss rltexp,1 ;result exponent
.bss op3hm,1 ;op3 high mantissa
.bss op3lm,1 ;op3 low mantissa
.bss op3se,1 ;op3 sigh and exp
.bss op4se,1 ;op4 sigh and exponent .bss op4hm,1 ;op4 high mantissa
.bss op4lm,1 ;op4 low mantissa
.bss op3_hsw,1 ;op3 packed high
.bss op3_lsw,1 ;op3 packed low
.bss op4_hsw,1 ;op4 packed high
.bss op4_lsw,1 ;op4 packed low
fs_start
stm #initst0,st0 ;initialize st0 and st1
stm #initst1,st1
rsbx C16 ;insure long address for later
ld #op3lm,dp
ld #op3valh,a ;load floating
stl a,op3_hsw
ld #op3vall,a
stl a,op3_lsw
ld #op4valh,a ;load floating
stl a,op4_hsw
ld #op4vall,a
stl a,op4_lsw
;----------- conversion of floating point format - unpack ------- dld op3_hsw,a ;load op3 to acc a
sfta a,8
sfta a,-8
bc op3_zero,AEQ ;if op3 is 0,jump to special case
sth a,-7,op3se ;store sign and exponent to stack
stl a,op3lm ;store low mantissa
and #07Fh,16,a ;mask off sign and exp to get high mantissa add #080h,16,a ;add implied 1 to mantissa
sth a,op3hm ;store mantissa to stack
dld op4_hsw,a ;load op4 to acc a
sfta a,8
sfta a,-8
bc op4_zero,AEQ ;if op4 is 0,jump to special case
sth a,-7,op4se ;store sign and exponent to stack
stl a,op4lm ;store low mantissa
and #07Fh,16,a ;mask off sign and exp to get high mantissa add #080h,16,a ;add implied 1 to mantissa
sth a,op4hm ;store mantissa to stack
;---------- judge the sign----------------
bitf op3se,#100h ;test the sign bit
bc testop4,NTC ;if is not negative jump to testop4
ld #0,a ;change the experssion to
dsub op3hm,a
dst a,op3hm ;store changed op3
testop4:
bitf op4se,#100h ;test the sign bit
bc compexp,NTC ;if is not negative jump to compexp
ld #0,a ;change the expression to
dsub op4hm,a
dst a,op4hm ;store changed op4
;--------- Exponent Comparison ------------
compexp:
ld op3se,a
and #00ffh,a ;mask off the sign bit
ld op4se,b
and #00ffh,a ;mask off the sign bit
sub a,b ;exp op4-exp op3 -> b
bc op3_gt_op4,BLT ;process op3 > op4
bc op4_gt_op3,BGT ;process op4 > op3
a_eq_b
dld op3hm,a
dsub op4hm,a ;sub mantissa
ld op3se,b ;load exponent in preparation for normalizing normalize
sth a,rltsign ;save signed mantissa on stack
abs a ;create magnitude value of mantissa
sftl a,6
nop
exp a ;get amount to adjust exp for normalization
nop
norm a
st t,rltexp ;store exp adjustment value
add #1,b ;increment exp to account for normalization
sub rltexp,b ;adjust exponent to account for normalization normalized
stl b,rltexp ;save result exp
bc underflow,BLEQ ;process underflow if occurs
sub #0ffh,b
bc overflow,BGEQ ;process overflow if occurs
sftl a,-7 ;shift right to place mantissa for splitting stl a,rltlm ;store low mantissa
and #07f00h,8,a ;eliminate impiled one
sth a,rlthm ;save high mantissa
; trap 2
;----------- Conversion of Floating Point Format- Pack --------- ld rltsign,9,a ;put result sign to acc a
and #100h,16,a
add rltexp,16,a ;put result exp together ;
sftl a,7
dadd rlthm,a ;add mantissa together
return_value
nop
nop
nop
trap 2
b fm_start。