文章目录
实验报告
课程名称:微处理器原理与应用
实验名称:CPUHomework4
【实验四】汇编程序编写与提高
1. 编写一个汇编程序,实现字符串的复制功能,并且将复制的字符串显示出来 (选做:倒序显示复制字符串)
流程图如下:
程序代码如下:
datas segment
string_a db 'The School of Information Science and Engineering Shandong University','$' ; 定义字符串
datas ends
ext segment ; 附加段
string_b db 100 dup(?) ; 开辟一个100字节的空间
ext ends
stacks segment
stacks ends
codes segment
assume cs:codes,ds:datas,ss:stacks,es:ext
start:
mov ax,datas ; 将datas的地址交给ds
mov ds,ax
mov ax,ext ; 将ext的地址交给es
mov es,ax
lea si, string_a ; 将string_a的地址交给si源变址寄存器
lea di, string_b ; 将string_b的地址交给di目的变址寄存器
mov cx, 72 ; 循环72次
std ; 方向标志位DF(Direction Flag)置1
rep movsb ; repeat move string byte
lea dx, string_b ; 将string_b的地址交给dx
mov ah, 9 ; 输出字符串
int 21h
mov ah,4ch ; 返回dos
int 21h
codes ends
end start
程序运行结果如下:
倒序显示流程图如下:
倒序显示代码如下:
datas segment
string_a db 'The School of Information Scinence and Engineering Shandong University','$'
datas ends
ext segment
string_b db 100 dup(?) ; 开辟一个100字节的空间
ext ends
stacks segment
stacks ends
codes segment
assume cs:codes, ds:datas, ss:stacks, es:ext
start:
mov ax, datas
mov ds, ax
mov ax, ext
mov es, ax
lea si, string_a
lea di, string_b
mov cx, 72
cld ; 方向标志位DF(Direction Flag)置0
rep movsb
lea dx, string_b
mov ah, 9 ; 输出字符串
int 21h
mov ah, 2 ; 回车换行
mov dl, 0dh
int 21h
mov ah, 2
mov dl, 0ah
int 21h
mov cx, 72
mov si, 69
loops:
mov dl, [si] ; 将si开始的第一个字符存入dl
mov ah, 2
int 21h ; 输出字符
dec si ; si减1, 从而实现倒序输出
loop loops
mov ah, 4ch
int 21h
codes ends
end start
程序运行结果如下:
2. 利用中断调用,在屏幕上显示1-9之间的随机数。中断号86H (使用定义法和DOS INT21法实现)
流程图如下:
datas segment
info db 0dh, 0ah, 'Random Number:', '$' ; 提示语句
dw 100 dup(?) ; 开辟100字的空间
datas ends
stacks segment stack
stacks ends
codes segment
assume ds:datas, ss:stacks, cs:codes
Random proc near
mov ah, 0
int 1ah ; 读取时钟滴答计数
mov ax, dx
mov dx, 0
mov bx, 10
div bx
add dl, 30h ; 将dl中的数据转换为对应的ASCII码
mov ah, 02h ; 输出数字
int 21h
ret
Random endp
start:
mov ax, datas
mov ds, ax
lea dx, info
mov ah, 9
int 21h
mov ax, 0 ; 设置中断向量(定义法)
mov ds, ax
cli
mov word ptr ds:[86h * 4], offset Random
mov word ptr ds:[86h * 4 + 2], seg Random
sti
int 86h ; 调用子程序
mov ah, 4ch
int 21h
codes ends
end start
程序运行结果如下:
INT 21法如下:
datas segment
info db 0dh, 0ah, 'New Random Number:', '$' ; 提示语句
dw 100 dup(?) ; 开辟100字的空间
datas ends
stacks segment stack
stacks ends
codes segment
assume ds:datas, ss:stacks, cs:codes
Random proc near
mov ah, 0
int 1ah ; 读取时钟滴答计数
mov ax, dx
mov dx, 0
mov bx, 10
div bx
add dl, 30h ; 将dl中的数据转换为对应的ASCII码
mov ah, 02h ; 输出数字
int 21h
ret
Random endp
start:
mov ax, datas
mov ds, ax
lea dx, info
mov ah, 9
int 21h
mov ax, stacks
mov ss, ax
mov ax, seg Random
mov ds, ax
mov dx, offset Random
mov al, 86h
mov ah, 25h
int 21h
int 86h ; 调用子程序
mov ah, 4ch
int 21h
codes ends
end start
程序运行结果如下:
3. 键盘输入10个学生的成绩,编写一个程序统计60-69分,70-79分,80-89分,90-99分以及100分的人数,分别存放在 Score6,Score7,Score8,Score9和Score10单元中
【输入10个学生的成绩如下】
65 98 78 82 88 95 72 62 90 100
流程图如下:
datas segment
info db 0dh, 0ah, 'Input ten scores:','$' ; 提示输入10个score
o_ten db 0dh, 0ah, 'The number of 100 is :', '$' ; 输出提示
o_nine db 0dh, 0ah, 'The number of 90 to 99 is :', '$'
o_eight db 0dh, 0ah, 'The number of 80 to 89 is :', '$'
o_seven db 0dh, 0ah, 'The number of 70 to 79 is :', '$'
o_six db 0dh, 0ah, 'The number of 60 to 69 is :', '$'
s_ten db 30h ; 初始化
s_nine db 30h
s_eight db 30h
s_seven db 30h
s_six db 30h
datas ends
stacks segment
db 100 dup(?) ; 开辟100字节的栈空间
stacks ends
codes segment
assume cs:codes, ds:datas, ss:stacks
start:
mov ax, datas
mov ds, ax
lea dx, info
mov ah, 9
int 21h
mov cx, 10
input:
mov ah, 1 ; 键盘录入并回显
int 21h
mov dl, al ; al = 输入字符
int 21h
call judge
mov dl, 32 ; 输出空格,使输入更加清晰
mov ah, 2 ; 显示输出, dl = 输出字符
int 21h
loop input
call output
mov ah, 4ch
int 21h
judge proc near
cmp dl, 31h ; dl与1的ASCII码比较
jz ten
cmp dl, 36h
jz six
cmp dl, 37h
jz seven
cmp dl, 38h
jz eight
cmp dl, 39h
jz nine
jmp fin
ten:
add [s_ten], 1
mov ah, 1
int 21h
jmp fin
six:
add [s_six], 1
jmp fin
seven:
add [s_seven], 1
jmp fin
eight:
add [s_eight], 1
jmp fin
nine:
add [s_nine], 1
jmp fin
fin:
ret
judge endp
output proc near
lea dx, o_ten
mov ah, 9
int 21h
mov dl, [s_ten] ; 输出100分的人数
mov ah, 2
int 21h
mov dl, 10 ; 输出空格
int 21h
lea dx, o_nine
mov ah, 9
int 21h
mov dl, [s_nine] ; 输出90-99的人数
mov ah, 2
int 21h
mov dl, 10
int 21h
lea dx, o_eight
mov ah, 9
int 21h
mov dl, [s_eight] ; 输出80-89的人数
mov ah, 2
int 21h
mov dl, 10
int 21h
lea dx, o_seven
mov ah, 9
int 21h
mov dl, [s_seven] ; 输出70-79的人数
mov ah, 2
int 21h
mov dl, 10
int 21h
lea dx, o_six
mov ah, 9
int 21h
mov dl, [s_six] ; 输出60-69的人数
mov ah, 2
int 21h
ret
output endp
codes ends
end start
程序运行结果如下:
【知识点】
标志寄存器PSW (程序状态字寄存器PSW)
标志寄存器PSW是一个16位的寄存器。它反映了CPU运算的状态特征并且存放某些控制标志。8086使用了16位中的9位,包括6个状态标志位和3个控制标志位
六个状态标志位
CF进位标志位:当执行一个加法(减法)运算时,最高位产生进位(或借位)时,CF为1,否则为0
ZF零标志位:若当前的运算结果为零,则ZF为1,否则为0
SF符号标志位:该标志位与运算结果的最高位相同。即运算结果为负,则SF为1,否则为0
OF溢出标志位:若运算结果超出机器能够表示的范围称为溢出,此时OF为1,否则为0。判断是否溢出的方法是:进行二进制运算时,最高位的进位值与次高位的进位值进行异或运算,若运算结果为1则表示溢出OF=1,否则OF=0
PF奇偶标志位:当运算结果的最低16位中含1的个数为偶数则PF=1否则PF=0
AF辅助进位标志位:一个加法(减法)运算结果的低4位向高4位有进位(或借位)时则AF=1否则AF=0三个控制标志位
用来控制CPU的操作,可以由程序进行置位和复位
TF跟踪标志:该标志位为方面程序调试而设置。若TF=1,8086/8088CPU处于单步工作方式,即在每条指令执行结束后,产生中断。
IF中断标志位:该标志位用来控制CPU是否响应可屏蔽中断。若IF=1则允许中断,否则禁止中断。
DF方向标志位:该标志位用来控制串处理指令的处理方向。若DF=1则串处理过程中地址自动递减,否则自动递增。
比较指令 CMP
格式: CMP A,B
功能: 两个操作数的相减,即从A中减去B,其结果会影响标志位,对标志位的影响与SUB指令相同。本条指令主要是用于配合条件转移指令使用。如JZ ZF=0时,跳转
**条件转移指令 **JE/JZ
格式: JE/JZ 标号
功能: ZF=1,转到指定地址执行
说明:
指令JE与JZ等价,它们是根据标志位ZF进行转移的指令
JE,JZ均为一条指令的两种助记符表示方法
CLD(CLear Direction flag):将标志寄存器Flag的方向标志位DF清零。在字串操作中使变址寄存器SI或DI的地址指针自动增加,字串处理由前往后
STD(SeT Direction flag):与CLD相反功能指令是STD,即将方向标志位DF置1。在字串操作中使SI或DI的地址指针自动递减,字串处理由后往前。STD用于将方向标志设置为1,使得Si和/或DI将自动递减到当其中一个字符串指令执行时指向下一个字符串元素。如果方向标志被设置,SI/DI对于字节字符串将减1,对于字符串将减2
**SI(source index)**源变址寄存器
DI(destination index)目的变址寄存器
SI和DI可以用来存放数据、地址,功能类似、用法类似、一般使用哪个都可以但在串处理指令中,SI用作隐含的源串地址,默认在DS中;
DI用做隐含的目的串地址,默认在ES中此时二者不能混用
si:指向要显示的字符
di:指向要存放的位置(目的空间)
字符串处理指令:是一种非数值处理指令,一般包括字符串传送、字符串转换(把一种编码的字符串转换成另一种编码的字符串)、字符串替换(把某一字符串用另一字符串替换)等。这类指令在文字编辑中对大量字符串进行处理
MOVSB即字符串传送指令,这条指令按字节传送数据。通过SI和DI这两个寄存器控制字符串的源地址和目标地址,比如DS:SI这段地址的N个字节复制到ES:DI指向的地址,复制后DS:SI的内容保持不变
中断是输入/输出程序中常用的控制方式,是指计算机暂停当前正在执行的程序而转去执行处理某事件的中断服务程序
当中断服务程序执行完毕,再恢复执行被暂时停止的程序
CLI汇编指令全称为Clear Interupt,该指令的作用是禁止中断发生,在CLI起效之后,所有外部中断都被屏蔽,这样可以保证当前运行的代码不被打断,起到保护代码运行的作用
STI汇编指令全称为Set Interupt,该指令的作用是允许中断发生,在STI起效之后,所有外部中断都被恢复,这样可以打破被保护代码的运行,允许硬件中断转而处理中断的作用
REP 指令即“重复前缀指令”, REP 前缀一次只能应用于一条字符串指令。要重复指令块,需要使用 LOOP 指令或其它循环结构。因此需要一个寄存器来控制串长度。这个寄存器就是CX,指令每次执行前都会判断CX 的值是否为0(为0 结束重复,不为0,CX 的值减1),以此来设定重复执行的次数
【实验心得】
这是微处理器原理与应用汇编的最后一次实验,这一次的心得也是之前所有汇编实验以及微处理器课程的总的体会
CPUHomework1.1的DOS方式以及Masm for Windows 集成实验环境的配置以及对Debug调试基本命令的学习为我之后的实验打下了基础,为我打开了汇编的大门
CPUHomework1.2让我更系统透彻地学习了Debug的六大功能,在此期间了解了CPU各种寄存器,内存以及程序运行之间的底层联系,同时也学会了许多基本的汇编程序指令,这次实验让我印象深刻,教会我只有不断地重复实践才能更快更好地掌握一系列汇编知识,正所谓纸上得来终觉浅,绝知此事要躬行
CPUHomework2.1则是对之前C语言学习的二进制原反补码的进一步理解,让我更多的角度去感受二进制的魅力
CPUHomework2.2 是分支程序实验和循环程序实验,对于分支语句和循环语句我们都已经很熟悉了,但是汇编语言的实现明显和绝大多数的高级语言不同,我们需要使用各种程序控制指令或者说是控制转移指令,有转移指令,循环控制指令,过程调用指令以及中断指令,这一次也为后面的程序编写打下了基础
CPUHomework3以及这次的CPUHomework4都是实战,在学习基础知识的基础上增加了程序逻辑设计的环节,让我们可以很好地体会到汇编语言编程的独特之处
在学习汇编的过程中遇到过许许多多的困难,但是如今的互联网为我们提供了许许多多的解决之道,汇编这个领域有许许多多的技术人的足迹也给我们这些初学者指引了前进的方向
最后,还是说咱痛并快乐着吧,这么课程的前半部分微处理器原理与汇编让我学到了许多,但更让我感受到的是自己的不足,我们唯一能做的就是继续努力!