微机原理实验3汇编语言程序设计.docx
《微机原理实验3汇编语言程序设计.docx》由会员分享,可在线阅读,更多相关《微机原理实验3汇编语言程序设计.docx(25页珍藏版)》请在冰豆网上搜索。
![微机原理实验3汇编语言程序设计.docx](https://file1.bdocx.com/fileroot1/2022-11/24/a9b64f02-2e5b-405a-81ad-f231b00e88f8/a9b64f02-2e5b-405a-81ad-f231b00e88f81.gif)
微机原理实验3汇编语言程序设计
微机原理实验3
实验设备:
LAB6000通用微控制器实验系统
实验用时10小时
一、实验内容:
汇编语言程序设计。
在了解8086/8088汇编语言后,编制并调试程序。
1.编制不恢复余数除法程序格式:
最高两位为符号位
2.按IEEE754格式编制32位浮点数与32位定点数相互转换程序子程序(两个子程序)
3.编制程序寻找100以内的质数,并从小到大排列。
4、编制8位(4字节)压缩BCD码加、减法程序。
5、编制8位(8字节)非压缩BCD码乘法和除法程序。
二、实验报告:
程序框图和源程序清单。
第一题必做,其余任选两个
第一题:
这道题可以按照老师所讲的不恢复余数除法的步骤,一步一步把书上的文字描述“翻译”成汇编语言。
1、执行第一次减法。
2、判断结果的正负,这里我们通过比较结果与0100h的大小关系来实现,结果大于等于0100h,说明结果小于0;结果小于0100h,说明结果大于0,最终会溢出,程序结束
3、如果上一次操作结果为正,则商1,被除数左移一位,减除数,跳转5
4、如果上一次操作结果为负,则商0,被除数左移一位,加除数,跳转5
5、判断上一次操作结果的正负
6、上面的第3,4,5步循环4次之后结束,如果最后一次操作结果小于0,则还要再左移一位,加除数。
这样就实现了8位除以4位的不恢复余数除法。
这道题的难点在于正确理解不恢复余数除法的步骤,和每一步的意义。
因为单纯翻译书上的内容很容易导致误解,只有真正理解了才能做出来。
这里比对一下自己最后梳理出来的1~6步,就会发现与书上所说的1~6步稍有不同,但是也是正确的。
程序流程图如下:
程序代码:
datasegment
Resultdb3dup(?
)
x2dw0021h
y2dw0040h
countdb0
signdw0h
dataends
;al保存被除数,bx第4~8位保存除数,ah,bh保存符号,即被除数为负,则ah=ffh,否则为0
;ax的第4~8位保存余数,dx的低4位保存商
codesegment
assumecs:
code,ds:
data
startprocnear
movax,data
movds,ax
movax,x2
movbx,y2
movcx,4
subax,bx
cmpax,0100h
jbjieshu
movdx,0;第一次为负
;shlax,1
shlax,1
addax,bx
bijiao:
cmpax,0100h
jbzheng;为正,跳转减法
;否则为负,执行加法
movsign,1
shldx,1;商0
addcount,1
cmpcount,4
jnbjieshu
shlax,1
addax,bx
jmpbijiao;进行下一次比较
zheng:
movsign,0
shldx,1
adddx,1
addcount,1
cmpcount,4
jnbjieshu
shlax,1
subax,bx
jmpbijiao
jieshu:
cmpax,0100h
jbendss
addax,bx
endss:
jmp$
codeends
endstart
第二题:
这道题的思路可以很快梳理清楚:
1、浮点数转定点数:
①确定符号,符号存入内存最高位,负数要取补②确定阶码③根据阶码值取相应数量的数构成整数部分(不要忘了浮点数中忽略了的最高位1)④剩余的部分是小数部分
2、定点数转浮点数:
①确定符号,存入内存最高位,负数要取补②确定阶码③忽略整数部分最高位1,其余部分存入内存④小数部分存入内存
思路即是这样。
难点在于处理的数据位数太多,超出了板子一次运算允许的最大范围。
这样就只能采取分步骤做,每做一步就把结果存入内存空间,之后内存空间左移若干位,为下一步骤存入数据腾出位置。
最终完成。
程序框图如下:
浮点数转定点数:
定点数转浮点数:
程序代码:
(先浮点转定点然后定点转浮点)
;将AX拆为三个BCD码,并存入Result开始的叁个单元
datasegment
;Resultdb3dup(?
)
xdd42c88000h
zhengshudb0;存整数部分,带符号,补码表示
xiaoshudb0;存小数部分,不带符号,原码表示
signdb0;保存符号
zhishudb0;保存阶码
countdb0;计数
tempdb0;
ctdb0;计数
dataends
codesegment
assumecs:
code,ds:
data
startprocnear
movax,data
movds,ax
movax,wordptrx;存低16位
movbx,42c8h;存高16位
shlbx,1
jbfu;负数,跳转到负数的处理部分
back:
;rclax,1;?
?
?
shlax,1
jbyi
jmpmain
yi:
addbx,1;程序结束后取消注释
jmpmain
main:
movzhishu,bh
shlbx,8
addbl,ah
shlax,8
subzhishu,7fh
movcl,zhishu
addbx,1
rolbx,cl
cmpsign,0
jaqufan
fuzhi:
movzhengshu,bl
movxiaoshu,bh
jmpnext
qufan:
;negbl
;subbh,1
;negbh
;addbl,80h
subah,bh
subal,bl
movbh,ah
movbl,al
jmpfuzhi
fu:
movsign,1
jmpback
next:
movax,0
movbx,0
movdx,0
movsign,0
moval,zhengshu
cmpzhengshu,80h
jbdayuling;低于跳转,是正数
movah,0ffh
movsign,1
movbx,0
subbx,ax
adddh,1
movax,bx
addah,80h
movbx,0
subbh,xiaoshu
shlax,1
jmphuiqu
dayuling:
movbh,xiaoshu;把取得的整数和小数部分分别存入段寄存器中
shlax,1
;jbfushu;判断是负数,把sign置为1
huiqu:
movcount,14
;movcount,6
jmpjishu
fushu:
movsign,1
jmphuiqu
jishu:
;rclal,1;从高到低一位一位的找,找到第一个1的时候,跳转,记下整数的位数
shlax,1
jbcunzheng
deccount
incct
jmpjishu
cunzheng:
addcount,7fh;求出偏移码
cmpsign,0
;jaqufu;取负值,高位为1
cmpcount,7h+7fh
;jataigao
movcl,count
movdl,cl;阶码存入dl
subcount,7fh
movcl,count
shldx,cl;dx左移,为整数部分存入做准备
;rolal,cl
rolax,cl
movtemp,al;
adddl,temp;整数最高7位(或少于7位)存入dx,之后ax就没有用了
movtemp,0
movcx,0
movax,0;到这里都还是对的
subct,7
movcl,ct
rolbx,cl;
movah,0ffh
shldx,cl;把dx剩下的最后几位腾出来,准备放入bx传递过来的数据
hehe:
shlal,1
addal,1
loophehe
subah,al
movtemp,bl
andtemp,al;把bl中由最高位移动过来的几位数保留下来
adddl,temp;然后存入dx剩下的空位中
andbl,ah;恢复bl
jmpjieshu;dx存高16位,bx存低16位
taigao:
shldx,7
rolax,7
movtemp,al
adddl,temp;整数最高7位存入dx,多出来的继续存入cx
movcl,temp-7
shrbx,cl;留出空间,把没存完的整数部分存进来
movtemp,ah
addbh,temp;整数部分全部存入,此时bx刚好保存了小数部分,完成
jmpjieshu
qufu:
adddh,1;把得到的浮点数编码存入dx中
jmpcunzheng
jieshu:
jmp$
codeends
endstart
第三题:
难度较小,只要用两层循环即可。
A循环是被检测数从1增加至100。
B循环是对每个被检测数,都要从2一直除到本身。
循环中不断地判定,如果出现了余数为0的情况,则跳出本次B,进入下一次A循环;如果直道一次B循环无跳出的执行完,都没有出现余数为0的情况,则这一个被检测数就是质数,把它存入内存单元。
程序框图:
程序代码:
;将AX拆为三个BCD码,并存入Result开始的叁个单元
datasegment
Resultdb30dup(?
)
xdd0c1c90000h
zhengshudb0;存整数部分,带符号,补码表示
xiaoshudb0;存小数部分,不带符号,原码表示
signdb0;保存符号
;zhishudb0;保存阶码
countdb0;计数
tempdb0;
ctdb1;计数
idb0;
dataends
codesegment
assumecs:
code,ds:
data
startprocnear
movax,data
movds,ax
movcx,99
movdx,0
movax,0
xunhuan:
incct;被检测的数
moval,ct;ct放在默认被除数的位置上
;jiance:
movi,2;i作除数,即因子
jiancea:
movbl,i
cmpbl,ct
jnbjixu;当i与ct相等时,认为找到了质数
divi
cmpah,0
jnaheshu;不高于跳转,表示余数为0,则是合数
movah,0
moval,ct;恢复做过除法的被检测数
addi,1
jmpjiancea;既没有发现余数为零的情况,i也比ct小,那么跳回检测分支的开头,重来
jixu:
;addcount,1
movbl,ct
mov[si],bl
;movresult,ct
addsi,1;不知道能不能像这样把地址的值直接加1,如果不行可以尝试对找到的质数计数count,然后每次存的时候用movresult+countct
;或许可以
heshu:
loopxunhuan;质数存在0400开始的连续空间里
jieshu:
jmp$
codeends
endstart
第四题:
本身句法结构不难,问题就是操作数位数过多,只能把操作数分割开,分别运算之后再组装在一起。
需要注意的是,分割开操作的时候要记录本位向高位的进位,同时考虑低位向本位的进位,这些数值,当一个部分的加法做完,转向下一个部分的加法时,一定要保存下来,带入下一次运算。
而减法则完全类似,把进位改为借位即可。
程序框图:
加法:
减法:
程序代码:
;将AX拆为三个BCD码,并存入Result开始的叁个单元
datasegment
Resultdb30hdup(?
)
x1dw0
x2dw0
;zhengshudb0;存整数部分,带符号,补码表示
;xiaoshudb0;存小数部分,不带符号,原码表示
signdb0;保存符号
;zhishudb0;保存阶码
countdb0;计数
tempdb0;
ctdb1;计数
idb0;
dataends
codesegment
assumecs:
code,ds:
data
startprocnear
movax,data
movds,ax
mov[si],5467h
mov[si+2],1234h
mov[si+10h],3716h
mov[si+12h],5438h
movax,0
movbx,0
movcx,4
jiafa:
jiancha:
addal,[si]
movbl,[si+10h]
addal,bl
;movcx,2
cmpal,9ah;看低8位是否对高8位有进位
jbjixu;低于跳转
subal,bl
addal,bl
addah,1;有进位,则高8位加1
movsign,1;把进位的标志也保存一下
jixu:
subal,bl
addal,bl
daa
mov[si+4],al
moval,ah
movah,0
addsi,1
loopjiancha
jianfa:
movcx,4
movax,0
movbx,0
;daa
;mov[si+2],al
;loopjiancha
subsi,4
mov[si+10h],5467h
mov[si+12h],1234h
mov[si],3716h
mov[si+2],5438h
jianchaa:
addal,[si]
movbl,[si+10h]
subal,bl;addal,bl
;movcx,2
cmpal,9ah;看低8位是否对高8位有借位
jbjixua;低于跳转
addal,bl;subal,bl
subal,bl;addal,bl
subah,1;addah,1;有借位,则高8位加1
movsign,1;把借位的标志也保存一下
jixua:
addal,bl;subal,bl
subal,bl;addal,bl
das
mov[si+8],al
moval,ah
movah,0
addsi,1
loopjianchaa
jmp$
codeends
endstart
第五题:
我只做了乘法部分。
仍然是面临操作数过大的问题。
我采用的是模拟手工竖式运算的方式,先取被乘数最低位,与乘数每一位分别相乘(考虑乘法进位),得到一行数;然后取被乘数次低位,与乘数每一位分别相乘,得到一行数,这一行比上一行高了一位;随后按照类似的方法,得到了8行数;最后,按竖式加法把每一列都按照BCD码的加法加起来(注意进位),得到的第9行数,就是乘法的结果。
程序框图:
(省略了最后的竖式加法部分,因为它就是BCD码加法运算,比较简单)
程序代码:
datasegment
Resultdb160hdup(?
)
x1dw0
x2dw0
signdb0;保存符号
countdb0;计数
tempdb0;
ctdw0;计数
idb0;
dataends
codesegment
assumecs:
code,ds:
data
startprocnear
movax,data
movds,ax
mov[si],0302h;low
mov[si+2],0606h
mov[si+4],0206h
mov[si+6],0701h;high
mov[di],0503h;low
mov[di+2h],0304h
mov[di+4h],0607h
mov[di+6h],0403h;high到这里没有问题
movcx,8
xiaocheng:
movax,0
movbx,0
addal,[si];之所以用add是因为难免低位会向高位进位,采用add的形式就可以把进位也存进来了
movbl,[di]
mulbl;此后直到下一个循环开始前bl不再参与这次乘法运算,可以再给它安排新的任务
aam
addsi,ct
addsi,di
add[si+11h],ah;乘法进位先存入结果的高一位
movah,0;然后把ah置0
movbl,[si+10h];先把结果的本位取出来,与al相加后再存回去,以免忽略
;结果与之前的进位相加后又产生的加法进位
addal,bl
aaa;非压缩BCD码的加法调整,调整后,ah中存放的是加法进位,
;这里加法进位是能直接加到结果高一位里去的,因为加法进位和乘法进位相加后不会再产生更高的进位了
add[si+11h],ah
mov[si+10h],al
;add[si+10h],al;本位存入结果的本位,这里又要考虑加法进位
subsi,ct
subsi,di
;moval,ah
incsi
cmpsi,8
jbxiaocheng
incdi
subsi,8
addct,10h
loopxiaocheng;理论上说到这里按竖式做的乘法已经一行一行的存进si起始的单元里了
subdi,8
adddi,10h
movax,0
movbx,0;到这里都是对的
movcx,8;下一个循环是要把竖式的值加起来
addsi,10h
movct,0
moval,[si]
xiaojiafa:
addsi,10h
movbl,[si]
addal,bl
aaa
loopxiaojiafa
movcx,8
mov[si],al
add[si+1],ah
subsi,80h
incsi
movax,0
movbx,0
moval,[si]
cmpct,16
jbxiaojiafa
jmp$
codeends
endstart
实验感想:
1、要敢于尝试。
开始接触的时候完全没有感觉。
它与C语言的编程风格迥然不同,很多地址空间是受限制的,比如不能直接读取、位数有限、有特定的功能,还有就是语言与自然语言差别很大。
这些陌生的概念积压在一起的时候就让人摸不着头脑。
借鉴以前学C语言的时候,我是从最短的开始,把书上的例程一个一个抄在编译环境里,然后单步执行,看每一步的变化。
这种方法既让我熟悉了每种功能语句的写法,也知道了语句的含义,看起来笨,实际上学得很快。
这次尝试我也是用了同样的办法。
抄了几个以后就开始凭着感觉写几个语句,然后执行以下,达到预期以后做个标记再往下写,慢慢的程序就写出来了。
2、细致。
我个人最容易出错的地方是搞不懂循环的次数,就比如说我要执行8次循环,cx的值该设为7还是8,这个问题我每次都要花点时间搞搞清楚。
做作业的时候也是经常因为多做了一次循环导致结果出错。
不过好处就是每次程序出错的时候我都知道该先从哪些地方找错误。