太原理工大学微机原理实验报告课案
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
本科实验报告
课程名称:微机原理及应用
实验项目:
实验地点:
专业班级:机械xxx班学号:xxxxxxxxxx 学生姓名:xx
指导教师:
2016年12月28日
实验一汇编语言程序开发环境与程序调试一、实验要求和目的
1.熟悉在微机上编辑、汇编、连接、调试和运行汇编语言程序的过程,掌握PC 环境下命令行方式的特点。
2.熟悉汇编过程中一些常见出错信息。
3.熟悉程序调试的方法, DOS命令窗口的debug的常用命令。
二、实验内容
1、项目要求:在屏幕上显示字符串‘Hello,world!’。
2、程序设计思想:
运用DOS系统功能调用(INT 21H)的9号功能。
DOS系统功能调用的9号功能是显示字符串,它调用的参数DS:DX=串地址,且字符串以“$”结束。
程序流程图如图1-1:
图1-1 程序流程图
3、程序清单:
完整指令代码如下(简化段定义格式):
.model small ;定义程序的存储模式
.486 ;说明使用的80x86微处理器指令
.stack ;定义堆栈段
.data ;定义数据段
String db 'Hello, world!','$'
.code ;定义代码段
.startup ;程序执行开始
Mov ax, seg String ;把String的段地址送ax
Mov ds,ax ;ax送ds,ds取得string的段地址
mov dx,offset String ;String的偏移地址送dx
mov ah,9 ;字符串显示功能
int 21h ;DOS功能调用
mov ax,4c00h
int 21h ;返回DOS
.exit
end
三、结果与分析
指导教师:
年月
实验二内存数据的移动
一、实验要求与目的:
1、实验要求:编写程序实现把数据段的字符串数据移动到附加段中。
2、实验目的:通过项目学习汇编的数据传送指令和串处理类指令,巩固寻址方式,学
习汇编程序设计。
二、实验内容:
1、项目要求:把数据段中以dstring地址标号为开始地址的“hello world!”字符串移动到附加段以sstring地址标号为开始地址中去。
2、设计思想:从源串中取一个字符到AL中,然后把刚取到的字符放到目的串指定位置,重复这样的过程,把源串的字符取完为止。
程序流程如图2-1所示。
图2-1 程序流程图
3、程序设计清单:实现这样功能的程序方法很多,下面给出了实现这一功能的完整程序清单(完整段定义格式)。
方案一(无聊版):
采用的是loop指令,CX为循环次数,当CX为0时退出循环。
加入了换行指令。
用字符串常量’$’改变字符串,提前终止字符串的输出。
程序如下:
DSEG SEGMENT
dstring DB 'HELLO,WORLD!',33,33, '$' ;15个字节HELLO,WORLD!!!
dstring_1 db ' 数据段的字符串:' , '$' ;一定要加'$',表示一个字符串的结束
dstring_2 db ' 附加段的字符串:' , '$' ;在屏幕上显示的字符串DSEG ENDS
ESEG SEGMENT
sstring DB 15 DUP(?) ;附加段预留15个字节空间ESEG ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DSEG, ES:ESEG
start: MOV AX, DSEG ;程序开始执行的地方
MOV DS, AX ;将DSEG的段地址给ds
MOV AX, ESEG
MOV ES, AX ;将SSEG的段地址给es
LEA SI, dstring ;将dstring的首地址给si
LEA DI, sstring ;将sstring的首地址给di
MOV CX, 15 ;CX存放loop指令的循环次数
S: MOV AL, [SI]
MOV ES:[DI], AL
INC DI
INC SI
LOOP S
mov dX,offset dstring_1
MOV AH,09h
INT 21H ;输出字符串‘数据段的字符串:’
MOV DL,0AH ;输出换行
MOV AH,02H
INT 21H
mov dX,offset dstring
MOV AH,09h
INT 21H ;输出字符串:HELLO,WORLD!!!
MOV DL,0AH
MOV AH,02H
INT 21H ;输出换行
mov dX,offset dstring_2
MOV AH,09h
INT 21H ;输出字符串dstring_2
MOV DL,0AH
MOV AH,02H
INT 21H ;输出换行
mov al,'$'
mov es:[di-3],al ;将第二个'!'改成'$'以终止字符串的继续输出MOV AX,ES
MOV DS,AX ;将附加段的段地址附给数据段
mov dX,offset sstring
MOV AH,09h
INT 21H ;显示字符串HELLO,WORLD!注意不是!!!
MOV AX, 4C00H
INT 21H ;返回DOS
CODE ENDS ;代码段结束
END start ;程序结束
方案二:采用字符串操作指令movsb,执行[di]=[si]。
Si与di自动地址改变方向,由std,cld控制。
Cx作为计数器,前面应用rep指令重复。
程序如下:
DSEG SEGMENT
dstring DB 'HELLO,WORLD!','$' ;13个字节HELLO,WORLD!!! DSEG ENDS
ESEG SEGMENT
sstring DB 13 DUP(?) ;附加段留13个字节空间
ESEG ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DSEG, ES:ESEG
start: MOV AX, DSEG ;程序开始执行的地方
MOV DS, AX ;将DSEG的段地址给ds
MOV AX, ESEG
MOV ES, AX ;将SSEG的段地址给es
LEA SI, dstring ;将dstring的首地址给si
LEA DI, sstring ;将sstring的首地址给di
MOV CX, 13 ;CX存放rep指令的重复次数
cld ;将DF位清零,则di与si自增
rep movsb ;执行[di]=[si]
MOV AX,ES
MOV DS,AX ;将附加段的段地址附给数据段
mov dX,offset sstring
MOV AH,09h
INT 21H ;显示字符串HELLO,WORLD!!!
MOV AX, 4C00H
INT 21H ;返回DOS
CODE ENDS ;代码段结束
END start ;程序结束
方案三:采用是cmp与ja跳转指令来实现数据的移动。
程序如下:
DSEG SEGMENT
dstring DB 'HELLO,WORLD!', '$' ;13个字节HELLO,WORLD!!!
DSEG ENDS
ESEG SEGMENT
sstring DB 15 DUP(?) ;附加段留13个字节空间
ESEG ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DSEG, ES:ESEG
start: MOV AX, DSEG ;程序开始执行的地方
MOV DS, AX ;将DSEG的段地址给ds
MOV AX, ESEG
MOV ES, AX ;将SSEG的段地址给es
LEA SI, dstring ;将dstring的首地址给si
LEA DI, sstring ;将sstring的首地址给di
MOV CX, 13 ;CX存放循环次数
S: MOV AL, [SI]
MOV ES:[DI], AL
INC DI
INC SI
DEC CX
CMP CX,0
JA S
MOV AX,ES
MOV DS,AX ;将附加段的段地址附给数据段
mov dX,offset sstring
MOV AH,09h
INT 21H ;显示字符串HELLO,WORLD!
MOV AX, 4C00H
INT 21H ;返回DOS
CODE ENDS ;代码段结束
END start ;程序结束
附简化段定义格式如下:
.model small ;定义程序的存储模式
.486 ;说明使用的80X86微处理指令
.data ;定义数据段开始
dstring db 'hello,world!','$'
sstring db 13 dup(0) ;使用的同一个数据段
.code ;定义代码段
.startup ;程序开始执行的地方
mov ax,seg dstring ;=mov ax,@data
mov ds,ax ;将dstring的段地址附给ds
mov es,ax ;为了使用movsb指令,由于两个字符串都在数据段,所以令es=ds
lea si,dstring
lea di,sstring
mov cx,13 ;循环次数
cld
rep movsb
mov dx,offset sstring
mov ah,9
int 21h
mov ax,4c00h
int 21h
.exit
End
4、调试过程:(在win7x32下调试的方案二)
第1步:进入debug:命令debug+file.exe。
第2步:用r命令查看cpu寄存器内容,这一步基本没用。
看注意点即可
注意:此时并未给ds,es赋值,在ds,es赋值之前有ds=es,cs=ds+10h。
第3步:用U命令查看汇编指令。
直接暴力输入g 001a 也可,但只适用本程序。
第四步:用T命令执行一条机器指令。
这里了执行四次。
此时可以看到ds和es已经赋值了,此时来查看内存的内容。
注意cs没变。
第五步:用d命令查看内存的内容。
即查看DS:0 和ES:0输入d 0bc6:0和d 0bc7:0。
可以看出已经完成移动了。
三、结果与分析
没仔细去看为什么0bc6:0010处也有hello,world。
我调试过了发现还有,猜测可能与ss的栈有关。
四、拓展
用q命令退出debug。
用p命令一次执行完循环。
用g+偏移地址(ip),可以直接执行到上一条指令,即此时IP=ip。
教师点评:
指导教师:
年月日
实验三分支程序结构
一、实验要求与目的:
1、实验要求:掌握分支结构程序设计的基本方法;掌握无条件转移指令和条件转移指令的使用;掌握分支结构程序设计的两种基本结构的使用。
2、实验目的:通过分支程序的设计掌握结构化程序设计方法和常用算法设计。
二、实验内容:
1、项目要求:编写程序实现:在数据段中,有一个按从小到大顺序排列的无符号数组,其首地址存放在SI寄存器中,数组中的第一个单元存放着数组长度。
在key单元中有一个无符号数,要求在数组中查找是否存在[key]这个数,如找到,则使CF=0,并在DI中给出该单元在数组中的偏移地址;如未找到,则使CF=1。
2、设计思想:对于这个表格查找,可以使用顺序查找和折半查找的算法思想。
当然顺序查找程序简单,效率不高。
而折半查找程序复杂,效率高,但对查找数据要求有序。
本项目采用折半查找方式。
在一个长度为N的有序数组r中,查找元素k的折半查找算法可描述如下:
①初始化被查找数组的尾下标,low←1,high←n。
②若low>high,则查找失败,CF=1,退出程序;否则,计算中点mid←(low+high)/2。
③k与中点元素r[mid]比较。
若k= r[mid],则查找成功,结束程序;若k< r[mid],则转
步骤④;若k> r[mid],则转步骤⑤。
④低半部分查找(lower),high←mid-1,返回步骤(2),继续执行。
⑤高半部分查找(higher),low←mid+1,返回步骤(2),继续执行
3、程序清单(简化段定义格式):
.model small
.486
.stack
.data ;定义数据段开始
array db 13,45,49,54,66,78,83,85,89,94,99,123,233,245 key db 40
cg1 db 'find','$'
error1 db 'failed','$'
sstring db 12 dup(?)
.code
.startup
start: mov ax,@data ;加载数据
mov ds,ax
mov al,key ;查找关键词送AL
lea si,array ;把数组的首地址送SI
mov bl,array ;把数组元素个数送BL
mov bh,0 ;把数组元素个数送BX
inc si
main: cmp bx,0
jl error ;转到查找失败程序段
shr bx,1 ;bx除以2
cmp al,[bx+si] ;mid=bx+si
ja higher ;若大于,则转到高半部分
jb lower ;若小于,则转到低半部分
jmp cg ;转到查找成功,无条件转移指令higher: add si,bx ;高半部分
inc si
jmp main
lower: add si,0 ;低半部分
dec bx
jmp main
error: lea dx,error1 ;查找失败,lea取有效地址mov ah,09h ;字符串显示
int 21h
jmp s ;直接退出
cg: lea dx,cg1 ;查找成功
mov ah,09h ;字符串显示
int 21h
stc ;cf置0
mov di,[bx+si] ;di保存
s:
.exit
End
附完整段定义
DSEG SEGMENT
ARRAY DB 13,45,49,54,66,78,83,85,89,94,99,123,233,245
KEY DB 45
CG1 DB 'find','$'
ERROR1 DB 'failed','$'
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG
START: MOV AX,DSEG
MOV DS,AX
MOV AL,KEY
LEA SI,ARRAY
MOV BL,ARRAY
MOV BH,0
INC SI
MAIN: CMP BX,0
JL ERROR
SHR BX,1
CMP AL,[BX+SI]
JA HIGHER
JB LOWER
JMP CG
HIGHER: ADD SI,BX
INC SI
JMP MAIN
LOWER: ADD SI,0
DEC BX
JMP MAIN
ERROR: LEA DX,ERROR1
MOV AH,09H
INT 21H
CLC
JMP EXIT
CG: LEA DX,CG1
MOV AH,09H
INT 21H
STC
MOV DI,[BX+SI]
JMP EXIT
EXIT: MOV AX,4C00H
INT 21H
CSEG ENDS
END START
4、调试过程:此程序在计算中值(mid←(low+high)/2)采用了一些技巧。
在程序思想的描述上,应该计算出高端地址(high)和低端地址(low),再计算中间地址(mid)。
实际上我们需要的是中间地址(mid),没有必要一定要计算出高端地址和低端地址。
bx+si表示的是中值地址,cmp al,[bx+si] 这指令表示ax与中值进行比较。
本程序稍作修改,就可实现更广应用。
三、结果与分析
令key=45,输出结果如下:完整段代码输出结果:
指导教师:
年月日
实验四 循环程序结构
一、实验要求与目的
1、实验要求:掌握循环结构程序设计的基本方法;了解循环控制的方法(计数、条件和混合)。
2、实验目的:通过循环程序的设计掌握结构化程序设计方法和循环控制方法的设计。
二、实验内容
1、项目要求:编写程序实现1~100的累加和求算,结果送到SUM 单元中。
2、设计思想:如果循环次数是已知的,则采用计数控制方法。
这里计数法可以是正计数即从1计数到n(图4-1(a)所示);也可以是倒计数法即从n 计数到0(图4-1(b)所示)。
图4-1 累加和流程图
方案一:自减法,用的是LOOP 循环中CX 的自减。
程序如下:
.model small ;注意点与m 之间不能有空格 .486
.data ;定义数据段开始 sum dw ? .code .startup
mov ax,@data
mov ds,ax ;初始化数据段 mov ax,0 ;(ax)←0
mov cx,100 ;循环次数
S: add ax,cx ;求累加和
LOOP S
mov sum,ax ;最终结果送到SUM
mov ah,4ch
int 21h ;返回DOS
.exit
End
方案二(直观作死板)将结果显示在屏幕上
原理如下:
5050/1000= 商5 余数050
050/100= 商0 余数50
50/10= 商5 余数0
0/1= 商0 余数0
商加上30h即可得到相应数字的ASCII码,然后在调用DOS命令输出字符即可,汇编所有的字符输出都是ASCII码。
4,程序如下:
DA TA SEGMENT
STRING DB '1+2+3+4+5+...+99+100=$' ;输出字符串,$为结束符
DA TA ENDS
STACK SEGMENT
DB 16 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DA TA,SS:STACK,ES:DATA
START:
MOV AX,DATA
MOV DS,AX
mov dx,offset STRING
mov ah,9
int 21h ;输出字符串
mov ax,0
mov bx,0
mov cx,100 ;循环次数
S:
inc bx
ADD ax,bx
LOOP S ;实现从1加到100
MOV DX,0 ;除数1000要用16位寄存器存储,但5050用AX就可存储MOV BX,1000 ;除1000
DIV BX
PUSH DX ;余数在DX中,所以要将DX入栈
ADD AL,30H ;商值加48转换成ASCII码
MOV DL,AL ;DOS系统功能调用,显示
mov ah,02H
INT 21H
POP DX ;要将余数DX赋值给AX,以作下次除法
mov AX,DX ;除100
mov BL,100
div BL
PUSH AX ;余数在AX中,所以要将AX入栈
ADD AL,30H ;求ASCII值
mov dl,al ;DOS系统功能调用,显示
mov ah,2
int 21H
POP AX
mov aL,AH ;除10
MOV AH,0 ;由于余数只存在AL寄存器中所以要将AH寄存器清0 mov bL,10
div bL
PUSH AX
add al,30H ;求ASCII值
mov dl,al ;DOS系统功能调用,显示
mov ah,2
int 21H
POP AX
mov aL,AH ;除1
MOV AH,0 ;要将AH寄存器清0
mov bL,1
div bL
add al,30H ;求ASCII值
mov dl,al ;DOS系统功能调用,显示
mov ah,2
int 21H
MOV AX,4C00H
int 21h
code ends
end start
三、结果和分析
方案二输出结果:
方案二只适用于0-9999范围内,即最高加到140,如果要实现更高位位的话可以修改。
指导教师:
年月日
实验五子程序结构
一、实验要求与目的
1、实验要求:掌握子程序指令,了解子程序结构和子程序设计的基本方法。
2、实验目的:学习汇编的子程序结构和模块0。
化程序设计方法。
二、实验内容
1、项目要求:编写程序实现对一个无序排列的无符号数组排序。
数组的首地址存放在SI寄存器中,数组中的第一个单元存排序前后都存放着数组长度。
2、设计思想:对于这个排序问题,我们可以采用基本排序算法(如冒泡排序,简单选择排序,插入排序等),也可以采用高级排序算法(如堆排序,归并排序,快速排序等)。
为了使程序简单,本项目采用基本排序的冒泡排序。
简单选择排序的基本思想:对文件进行n-1趟排序,第i趟(i=1,2,...n-1)是在从i到n的n-i+1个记录中选择关键字最小(最大)的记录,并将它与第i个记录进行交换。
这里采用子程序结构,整个程序包括一个主程序和两个子程序,程序流程图如图5-1示。
(a)主程序
这三个子程序是:
XZPX:功能是对数组元素进行降序排序。
入口参数:采用寄存器SI传递参数。
用了寄存器:AX,BX,CX,DX
出口参数:无。
DISPLAY:功能是将数组元素输出在屏幕上显示。
入口参数:采用寄存器SI传递参数。
出口参数:无。
DIGITAL_DISPLAY:将数组元素中的数字显示在屏幕上。
你也可以定义显示字符串然后调用DOS命令,显示字符。
入口参数:采用寄存器SI传递参数。
调用的寄存器:AX,BX,DX
出口参数:无。
DATA SEGMENT
ARRAY DB 13,65,12,97,68,69,70,71,72,73,98,75,76,77
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX, DATA
MOV DS, AX
LEA SI,ARRAY
CALL DISPLAY ;显示原数字串
CALL XZPX ;大小排序
CALL DISPLAY ;显示排序后的数字串
JMP EXIT ;退出程序
XZPX PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSHF
MOV CL,[SI] ;数组元素个数读入CL中
MOV CH,0 ;CX保存数组元素个数
DEC CX
MOV BX,SI ;BX指向数组的第一个元素,即数组的个数字节
INC BX ;BX指向数组的第一个数字
MOV DX,0 ;DX用于循环计数
LOP1: MOV SI,DX ;DX送SI,用于定位,SI是用来循环比较的
MOV DI,DX ;用于交换
MOV AL,[BX+SI] ;AL用于存放最大数
INC SI ;用于SI的循环
LOP2: CMP AL,[BX+SI] ;比较
JAE GO ;AL大于等于跳转至GO
MOV AL,[BX+SI] ;否则,[bx+si]送AL
MOV DI,SI ;DI记下大元素在数组中的位置GO: INC SI ;继续增加SI作比较
CMP SI,CX
JB LOP2 ;直到一位比较完
MOV SI,DX ;SI重新定位,回初位置
XCHG [BX+SI],AL
XCHG [BX+DI],AL ;初位置元素SI与大元素交换
INC DX
CMP DX,CX
JB LOP1 ;直到所有的元素查找完
POPF
POP SI
POP DX
POP CX
POP BX
POP AX
RET
XZPX ENDP
DISPLAY PROC ;NEAR
PUSH AX
PUSH CX
PUSH DX
PUSH SI
PUSHF
MOV CL,[SI] ;循环次数
MOV CH,0
;INC CX
LOP3:
CALL DIGITAL_DISPLAY ;嵌套函数
MOV DL,32
MOV AH,2
INT 21H ;输出空格
INC SI
LOOP LOP3
MOV DL,0AH ;换行
MOV AH,02H
INT 21H
POPF
POP SI
POP DX
POP CX
POP AX
RET
DISPLAY ENDP
DIGITAL_DISPLAY PROC ;实现数字0-128的输出PUSH AX
PUSH DX
PUSH BX
MOV AL,[SI+1] ;除100,输出百位
MOV AH,0
MOV DX,0
MOV BX,100
DIV BX
CMP AL,0
JE S1 ;第一个数字不显示数字0
PUSH DX
ADD AL,30H ;数字加上30H转换成相应的ASCII MOV DL,AL ;DOS命令调用,字符显示
MOV AH,2
INT 21H
POP DX
S1:
MOV AX,DX ;除10
MOV DX,0
MOV BX,10
DIV BX
PUSH DX
ADD AL,30H
MOV DL,AL
MOV AH,2
INT 21H
POP DX
MOV AX,DX
MOV DX,0
MOV BX,1
DIV BX
ADD AL,30H
MOV DL,AL
MOV AH,2
INT 21H ;不需要保护现场了
POP BX
POP DX
POP AX
RET
DIGITAL_DISPLAY ENDP
EXIT: MOV AX,4C00H
INT 21H
CODE ENDS
END START
三、结果与分析
描述程序中子程序的参数传递:在XZPX子程序中,首先SI作为地址参数传给了BX,且AX用于存放最大数,CX用于存放数组长度,DX用于定位初位置和记录循环次数,把8个寄存器全用光了,所以后面采用基址加变址[BX+SI]的寻址方式。
这个程序只适用于0-128之间的排序,完全可以改进成0-65535之间排序。
四、问题讨论
如果将XZPX子程序中的JAE GO,改成JBE GO,在字符串的情况下可以实现ASCII值从低到高排序。
但我发现本程序却不能完美排序,好像最后两位交换出错了。
指导教师:
年月日。