汇编语言第四次实验
实验4 8086标志寄存器及中断
1. 实验任务1
验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。
在debug环境中,分别实践、观察:
① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?

答:有影响,因为FF + 1 后结果为0,则ZF标志位为ZR。因为FF + 1后产生了进位,CF的值为CY。
② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?

答:对ZF标志有影响,得到结果为0,ZF的值为ZR。对CF标志无影响,CF标志仍然是NC。
使用任意文本编辑器,录入8086汇编源码task1.asm。
task1.asm
assume cs:code, ds:data
data segment
x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h
y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, offset x
mov di, offset y
call add128
mov ah, 4ch
int 21h
add128:
push ax
push cx
push si
push di
sub ax, ax
mov cx, 8
s: mov ax, [si]
adc ax, [di]
mov [si], ax
inc si
inc si
inc di
inc di
loop s
pop di
pop si
pop cx
pop ax
ret
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中调试程序,并回答问题。
程序执行效果截图:

若使用
add si, 2
add di, 2
则结果不一定正确,因为add指令会对CF产生影响,而adc指令是进位加法。当add指令对CF产生影响后,必然对adc指令产生影响,导致结果出错。
2. 实验任务2
使用任意文本编辑器,录入8086汇编源码task2.asm。
1 assume cs:code, ds:data
2 data segment
3 str db 80 dup(?)
4 data ends
5
6 code segment
7 start:
8 mov ax, data
9 mov ds, ax
10 mov si, 0
11 s1:
12 mov ah, 1
13 int 21h
14 mov [si], al
15 cmp al, '#'
16 je next
17 inc si
18 jmp s1
19 next:
20 mov ah, 2
21 mov dl, 0ah
22 int 21h
23
24 mov cx, si
25 mov si, 0
26 s2: mov ah, 2
27 mov dl, [si]
28 int 21h
29 inc si
30 loop s2
31
32 mov ah, 4ch
33 int 21h
34 code ends
35 end start
对源程序task2.asm进行汇编、链接,得到可执行文件task2.exe。
运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结果。结合运
行结果,理解代码并回答问题:
① 汇编指令代码line11-18,实现的功能是?
s1部分的功能为:
读入键盘输入的字符,并将它们呈现在屏幕上,并将每个字符与“#”作比较,若等于“#”将跳转到next。
② 汇编指令代码line20-22,实现的功能是?
next部分的功能为:
将输出模式调整为输出dl中的值,0ah表示的值为创建新行。将si的值赋给cx,作为循环次数,将si置为0,表示回到字符串首位。
③ 汇编指令代码line24-30,实现的功能是?
s2部分的功能为:
将si作为地址指向的值,存入dl中,逐个输出。
3. 实验任务3
针对8086CPU,已知逻辑段定义如下:
data segment
x dw 91, 792, 8536, 65521, 2021
len equ $ - x
data ends
编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据之间以空格间隔。
要求:
编写子程序printNumber
- 功能:以十进制形式输出一个任意位数的整数(整数范围0 ~ 65535)
- 入口参数:寄存器ax(待输出的数据 --> ax)
- 出口参数:无
编写子程序printSpace
- 功能:打印一个空格
- 入口参数:无
- 出口参数:无
在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。
结果截图:

CODE:
assume cs:code, ds:data
data segment
x dw 91, 792, 8536, 65521, 2021
len equ $ - x
data ends
code segment
start:
mov ax, data
mov ds, ax
mov cx, 5
mov si, 0
s: mov ax,0
call printNumber
call printSpace
add si,2
loop s
mov ah, 4ch
int 21h
printNumber:
push cx;保存cx的值
mov cx,0
mov ax, ds:[si]
s1:
mov dx,0
mov bx, 10
div bx
push dx
inc cx;出栈的cx的值
cmp ax,0
jne s1
mov ah,2
s2: pop dx
or dx,30h;取ASCII码
int 21h
loop s2
pop cx;归还cx的值
ret
printSpace:
mov ah, 2
mov dl, ' '
int 21h
ret
code ends
end start
大致思路:针对每一个数字,如实验3那样,需要分解出每一位数字,使用到16位的除法。每次除完将数字存入栈中,保证输出为正常顺序。
注意点:
- cx的值在进入内循环之前要保存到栈中,最后还要出栈归还cx的值。
- 将除完的余数保存到栈中保证是正常的输出顺序。
4. 实验任务4
针对8086CPU,已知逻辑段定义如下:、
data segment
str db "assembly language, it's not difficult but tedious"
len equ $ - str
data ends
编写8086汇编源程序task4.asm,将data段中字符串里的小写字符转换成大写。
要求:
编写子程序strupr
功能:将包含任意字符的字符串中的小写字母变成大写
入口参数
(ds:si ) 字符串首地址的段地址和偏移地址分别送至ds和si
(cx) 字符串的长度
出口参数:无
在主体代码中,设置入口参数,调用strupr, 实现题目要求。
程序效果截图:

assume cs:code, ds:data
data segment
str db "assembly language, it's not difficult but tedious"
len equ $ - str
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si,0
mov cx,len
call strupr
inc si
mov ah, 4ch
int 21h
strupr:
mov byte ptr al,ds:[si]
cmp al,'a'
jb s1
cmp al,'z'
ja s1
and al,11011111b
s1:
push ax
mov ah, 2
pop dx
int 21h
inc si
loop strupr
ret
code ends
end start
大致思路:如果是字母,则与上11011111b,再输出。不是则直接跳到输出。
5. 实验任务5
使用任意文本编辑器,录入8086汇编源码task5.asm。
task5.asm
1 assume cs:code, ds:data
2
3 data segment
4 str1 db "yes", '$'
5 str2 db "no", '$'
6 data ends
7
8 code segment
9 start:
10 mov ax, data
11 mov ds, ax
12 ;输入
13 mov ah, 1
14 int 21h
15
16 mov ah, 2
17 mov bh, 0;页号
18 mov dh, 24;行号
19 mov dl, 70;列号
20 int 10h
21
22 cmp al, '7'
23 je s1
24 mov ah, 9
25 mov dx, offset str2;输出字符串的首字符的偏移地址,(已经设置过ds)
26 int 21h
27
28 jmp over
29
30 s1: mov ah, 9
31 mov dx, offset str1
32 int 21h
33 over:
34 mov ah, 4ch
35 int 21h
36 code ends
37 end start
功能:判断输入字符是否等于7。
6. 实验任务****6
实验任务1、2、3、5中使用了不少系统提供的中断例程。本实验任务中,要求自行实现一个42号软中断例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to 2049!"。
建议配合教材第12章学习理解并实践。
task6_1.asm:
assume cs:code
code segment
start:
; 42 interrupt routine install code
mov ax, cs
mov ds, ax
mov si, offset int42 ; set ds:si
mov ax, 0
mov es, ax
mov di, 200h ; set es:di
mov cx, offset int42_end - offset int42
cld
rep movsb
; set IVT(Interrupt Vector Table)
mov ax, 0
mov es, ax
mov word ptr es:[42*4], 200h
mov word ptr es:[42*4+2], 0
mov ah, 4ch
int 21h
int42:
jmp short int42_start
str db "welcome to 2049!"
len equ $ - str
; display string "welcome to 2049!"
int42_start:
mov ax, cs
mov ds, ax
mov si, 202h
mov ax, 0b800h
mov es, ax
mov di, 24*160 + 32*2
mov cx, len
s: mov al, [si]
mov es:[di], al
mov byte ptr es:[di+1], 2
inc si
add di, 2
loop s
iret
int42_end:
nop
code ends
end start
task6_2.asm:
assume cs:code
code segment
start:
int 42
mov ah, 4ch
int 21h
code ends
end start
中断
当计算机内部发生中断时:
- 根据中断信息获得中断类型码N
- 标志寄存器的值入栈
- 设置标志寄存器TF和IF为0(防止CPU执行中断程序时发生单步中断)
- push CS,push IP
- 将IP设为(N * 4),CS设为(N * 4 + 2)
编写中断程序:
- 将中断程序安装到相应位置
- 将程序位置安装到中断向量表中
- 书写中断程序
效果截图:

程序分析:
首先安装中断程序,即将写好的中断程序安装至0000:0200的地址。再将该中断程序的段地址和偏移地址,注册到es:[42 * 4]和es:[42 * 4 + 2]的位置(因为中断指令是42)。
int42部分 :表示的就是将“welcome to 2049”显示在桌面上。

浙公网安备 33010602011771号