实验4 8086标志寄存器及中断
1. 实验任务1
使用任意文本编辑器,录入8086汇编源码task1.asm。
task1.asm
assume cs:code,ds:data
data segment
db 16 dup(0)
data ends
stack segment
db 128 dup(0)
top equ $+1
stack ends
code segment
start:
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,top
mov ax,0ffffh
add ax,1
;测试add对CF和ZF的影响
mov ax,1
add ax,1
;恢复测试之前的影响,即无进位
mov ax,0ffffh
inc ax
;测试inc对CF和ZF的影响
mov ah,4ch
int 21h
code ends
end start
其中:
add128是子程序子程序。
功能:实现计算两位128位数的加法
入口参数:
ds:si指向存储第一个128位数的存储空间(因为一个数128位,需要8个字节的连续空间)
ds:di指向存储第二个128位数的存储空间
出口参数:
加运算后的结果,保存在第一个数的存储空间中,即:ds:si开始的连续8个字节空间
在代码段种,调用add128实现对标号x和y处存储的两个128位数据相加,结果保存在x处的连续128个字
节中。
对程序进行汇编、链接,得到可执行程序task1.exe。在debug中调试程序,并回答问题。
1、line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?
add si 2 add di 2
更改指令前运算结果如下:

更改指令后的运算结果如下:

运算结果一致。
针对本体数据可以替换为改代码。
当需要用到进位制的时候不可用add指令,只能用inc指令。add会对CF标志寄存器造成影响,inc则不会。
如果本来应当是有进位的,CF的值为CY(1),但是做了add操作后CF会变成NC(0),会对后面的位数加法产生影响。所以不能使用add。
而inc指令并不影标志寄存器CF的值。
2、在debug中调试,观察数据段中做128位加之前,和,加之后,数据段的值的变化。
加之前数据段的值如下:

加之后数据段的值如下:

2. 实验任务2
使用任意文本编辑器,录入8086汇编源码task2.asm。
task2.asm
assume cs:code, ds:data
data segment
str db 80 dup(?);80个字节未初始化的内存空间
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0
s1:
mov ah, 1;int 21h中断的参数,表示输入单个字符
int 21h;调用中断例程
mov [si], al;将结果存入ds:[si]中
cmp al, '#';与'#'比对,影响标志寄存器ZF,运算结果为0表示相同,则ZF标志寄存器变为ZR
je next;if(al == '#'(ZF == ZR)) goto next
inc si;偏移地址加一
jmp s1;继续输入一个字符
next:
mov ah, 2;int 21h中断的参数,表示打印一个ASCII字符
mov dl, 0ah;换行
int 21h;调用中断例程
mov cx, si;将输入的字符的数量(不包括#)赋给cx寄存器
mov si, 0;将si寄存器置零
s2: mov ah, 2;int 21h中断的参数,表示打印一个ASCII字符
mov dl, [si];将ds:[si]出内存的值赋给dl
int 21h;调用中断例程
inc si;偏移地址+1
loop s2;循环,直到cx=0
mov ah, 4ch;int 21h中断的参数,表示回到DOS
int 21h;执行中断例程
code ends
end start
运行结果如下:

1、汇编指令代码line11-18,实现的功能是?
输入字符,将字符存保存在ds:[si]中,字符与‘#’比较,相同则跳转至next子程序,否则继续执行s1
2、汇编指令代码line20-22,实现的功能是?
调用中断程序并换行。
3、汇编指令代码line24-30,实现的功能是?
将输入的字符数量赋给寄存器cx,将ds:[si]的字符保存至显存区域实现字符打印。
3. 实验任务3
针对8086CPU,已知逻辑段定义如下:
data segment x dw 91, 792, 8536, 65521, 2021 len equ $ - x data ends
编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据
之间以空格间隔。
assume ds:data,cs:code,ss:stack data segment x dw 91, 792, 8536, 65521, 2021 len equ $ - x data ends stack segment dw 8 dup(?) stack ends code segment start: mov ax,data mov ds,ax mov ax,stack mov ss,ax mov sp,16 mov cx,len/2 ;数据是word型,数据个数是len/2 循环次数 print: mov ax,word ptr ds:[di] ;把数据放入al中 add di,2 push cx ;cx入栈,保存cx数值,子程序需要使用cx call printNumber ;调用子程序printNumber,打印字符 call printSpace ;调用子程序printSpace,打印空格 pop cx ;cx出栈,恢复cx的值 loop print mov ah,4ch int 21h ;子程序:printNumber ;功能:打印字符 ;入口参数:寄存器ax printNumber: mov bx,0 ;逐位获取数字 getChar子程序:每获取一位,然后压入栈中 getChar: mov bp,10 ;除10运算 mov dx,0 div bp; ;商在ax中,余数在dx中 push dx ;余数进栈 inc bx ;位数+1 mov cx,ax ;把商赋给cx inc cx loop getChar ;打印数字 mov cx,bx printEach: ;逐位打印字符 pop dx ;取出一位字符 add dl,30h mov ah,2 ;调用int 21h的2号子程序打印 int 21h loop printEach ret printSpace: mov ah,2 mov dl,20h int 21h ret code ends end start
程序运行结果如下:

4. 实验任务4
针对8086CPU,已知逻辑段定义如下:
data segment str db "assembly language, it's not difficult but tedious" len equ $ - str data ends
编写8086汇编源程序task4.asm,将data段中字符串里的小写字符转换成大写。
assume cs:code,ds:data
data segment
str db "assembly language, it's not difficult but tedious"
len equ $ - str
data ends
stack segment
db 8 dup(?)
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0
mov cx, len ; 参数:字符串长度存在cx中
call strupr ; 调用转换子程序
call printStr ; 调用打印子程序
mov ax, 4c00h
int 21h
; 子程序 strupr
; 功能: 将包含任意字符的字符串中的小写字母变成大写
; 入口参数
; (ds:si) 字符串首地址的段地址和偏移地址分别送至ds和si
; (cx) 字符串的长度
strupr:
push cx
push si ; 先保存两个寄存器的值
transform:
mov al, ds:[si] ; 取出一个字符
cmp al, 97 ; 判断ASCII码是否 >= 97
jl continue ; 小于97直接进入下次循环
cmp al, 122 ; 判断ASCII码是否 <= 122
jg continue ; 大于122直接进入下次循环
and al, 0dfh ; 小写转成大写,原理详见实验2
mov ds:[si], al ; 把转换后的字符送回data段
continue:
inc si ; 指针后移
loop transform ; 循环
pop si
pop cx ; 恢复寄存器的值
ret ; 返回
; 子程序 printStr
; 功能: 打印字符串
; 入口参数
; (ds:si) 字符串首地址的段地址和偏移地址分别送至ds和si
; (cx) 字符串的长度
printStr:
push cx ; 保存寄存器的值
push si
print: ; 打印字符循环
mov ah, 2
mov dl, ds:[si]
int 21h
inc si
loop print
pop si ; 恢复寄存器的值
pop cx
ret ; 返回
code ends
end start
程序运行结果如下:

5. 实验任务5
使用任意文本编辑器,录入8086汇编源码task5.asm。
task5.asm
assume cs:code, ds:data
data segment
str1 db "yes", '$'
str2 db "no", '$'
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ah, 1
int 21h
mov ah, 2
mov bh, 0 ;设置显示页为第0页
mov dh, 24 ;设置光标位置在第24行
mov dl, 70 ;设置光标位置在第70列
int 10h
cmp al, '7' ;把输入字符和7作比较
je s1 ;如果相等,跳转到s1处
mov ah, 9 ;调用int 21h的9号子程序显示str2
mov dx, offset str2 ;把str2的偏移量放到dx
int 21h
jmp over
s1: mov ah, 9 ;调用int 21h的9号子程序显示str1
mov dx, offset str1 ;把str1的偏移量放入dx
int 21h ;显示标号str1处的字符串 yes
over:
mov ah, 4ch
int 21h
code ends
end start
对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。
运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。
程序运行结果如下:

6. 实验任务6
本实验任务中,要求自行实现一个42号软中断
例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to
2049!"。
编译、链接task6_1、task6_2后运行得到结果如下

说明42号中断程序被成功调用。
实验总结
1、标志寄存器会被多数指令修改,如add、sub、jmp等,会对CF造成影响。而另一些,如inc不会对CF造成影响。因此在多位计算加法中不能使用add指令。
2、cmp指令会对两个操作数进行减法,然后将结果保存在标志寄存器中,有条件跳转指令则会根据标志寄存器的值进行判断和跳转。

浙公网安备 33010602011771号