实验4 8086标志寄存器及中断
实验任务1
验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。
在debug环境中,分别实践、观察:
① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
均有影响
② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
对ZF有影响,对CF没有影响。
task1.asm源码
1 assume cs:code, ds:data 2 data segment 3 x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h 4 y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h 5 data ends 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, offset x 11 mov di, offset y 12 call add128 13 mov ah, 4ch 14 int 21h 15 add128: 16 push ax 17 push cx 18 push si 19 push di 20 sub ax, ax 21 mov cx, 8 22 s: mov ax, [si] 23 adc ax, [di] 24 mov [si], ax 25 inc si 26 inc si 27 inc di 28 inc di 29 loop s 30 pop di 31 pop si 32 pop cx 33 pop ax 34 ret 35 code ends 36 end start
其中: add128是子程序子程序。
功能:实现计算两位128位数的加法
入口参数:
ds:si指向存储第一个128位数的存储空间(因为一个数128位,需要8个字节的连续空间)
ds:di指向存储第二个128位数的存储空间
出口参数:
加运算后的结果,保存在第一个数的存储空间中,即:ds:si开始的连续8个字节空间
在代码段种,调用add128实现对标号x和y处存储的两个128位数据相加,结果保存在x处的连续128个字节中。
回答问题
line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?
1 add si, 2 2 add di, 2
不能,因为add对CF进位标识符有影响,可能影响最后结果。
在debug中调试,观察数据段中做128位加之前和加之后,数据段的值的变化。给出调试观察截图。
实验任务2
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
回答问题
运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结果。结合运行结果,理解代码并回答问题:
① 汇编指令代码line11-18,实现的功能是?
功能是从键盘读取一串以“#”结尾的字符串保存在数据段并跳转到next
② 汇编指令代码line20-22,实现的功能是?
输出换行符。
③ 汇编指令代码line24-30,实现的功能是?
输出之前存在数据段的字符串(不包含“#”)到屏幕上
说明:task2.asm中用到的两个DOS系统功能调用:
DOS系统功能调用int 21h的1号子功能
功能:从键盘上输入单个字符
入口参数:(ah) = 1
出口参数: (al)存放输入字符的ASCⅡ码
即:
1 mov ah, 1
2 int 21h ; (al) <-- 输入字符的ascⅡ码
DOS系统功能调用int 21h的2号子功能
功能:输出单个字符到屏幕上
入口参数:(ah) = 2, (dl) = 待输出的字符或其ascⅡ码
出口参数:无
即:
1 mov ah, 2
2 mov dl, ×× ; ××是待输出的字符,或,其ascⅡ码
3 int 21
实验任务3
针对8086CPU,已知逻辑段定义如下:
1 data segment 2 x dw 91, 792, 8536, 65521, 2021 3 len equ $ - x 4 data ends
编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据 之间以空格间隔。
要求:
- 编写子程序printNumber
- 功能:以十进制形式输出一个任意位数的整数(整数范围0 ~ 65535)
- 入口参数:寄存器ax(待输出的数据 --> ax)
- 出口参数:无
- 编写子程序printSpace
- 功能:打印一个空格
- 入口参数:无
- 出口参数:无 在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。
提示:
题目限定了数据范围是0 ~ 65535, 可以借助32÷16位的除法,无需考虑除法溢出问题。具体地:
1. 被除数 -> dx:ax,由于数据不超过65535,所以,每次寻址取数-> ax后,在子程序printNumber中做 除法时,dx设置为0即可。
2. 除以10,得到余数后,入栈并计数。重复这一过程,直至商为0。然后,循环出栈,并借助int 21h中 的2号子功能,实现输出。
3. 注意事项:① 数字和数字字符的区别,及,必要转换;② 寄存器使用冲突问题,可借助栈解决。具体 地,如内容不熟悉,请复习第10章。
task3.asm源码
1 assume cs:code, ds:data 2 data segment 3 x dw 91, 792, 8536, 65521, 2021 4 len equ $ - x 5 data ends 6 7 stack segment 8 dw 32 dup(0) 9 stack ends 10 11 code segment 12 start: 13 mov ax,data 14 mov ds,ax 15 mov cx,len/2 16 mov si,0 17 mov bx,10 18 19 mov ax, stack 20 mov ss, ax 21 mov sp, 32 22 23 s: mov ax,ds:[si] 24 call printNumber 25 call printSpace 26 inc si 27 inc si 28 loop s 29 30 mov ah, 4ch 31 int 21h 32 33 printNumber: 34 push cx 35 mov cx,0 36 jinzhan: 37 mov dx,0 38 div bx 39 push dx 40 inc cx 41 cmp ax,0 42 jz chuzhan 43 jmp jinzhan 44 45 chuzhan: 46 pop dx 47 add dl,30h 48 mov ah,2 49 int 21h 50 loop chuzhan 51 52 pop cx 53 ret 54 55 printSpace: 56 mov ah,2 57 mov dl,32 58 int 21h 59 ret 60 61 code ends 62 end start
运行测试截图
实验任务4
针对8086CPU,已知逻辑段定义如下:
1 data segment 2 str db "assembly language, it's not difficult but tedious" 3 len equ $ - str 4 data ends
编写8086汇编源程序task4.asm,将data段中字符串里的小写字符转换成大写。
要求: 编写子程序strupr
- 功能:将包含任意字符的字符串中的小写字母变成大写
- 入口参数 (ds:si ) 字符串首地址的段地址和偏移地址分别送至ds和si (cx) 字符串的长度
- 出口参数:无 在主体代码中,设置入口参数,调用strupr, 实现题目要求。
task4.asm源码
1 assume cs:code,ds:data 2 3 data segment 4 str db "assembly language, it's not difficult but tedious" 5 len equ $ - str 6 data ends 7 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 mov si, offset str 13 mov cx, len 14 call strupr; 15 mov ax, 4c00h 16 int 21h 17 18 strupr: 19 mov al, [si] 20 cmp al, 97 21 jb s 22 cmp al, 122 23 ja s 24 and al, 0dfh 25 mov [si], al 26 s:inc si 27 loop strupr 28 ret 29 code ends 30 end start
在debug中调试截图( call strupr 调用之前,数据段的值,以及,调用之后,数据段的值)
实验任务5
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 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
对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。
运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。
说明:task5.asm中,使用用到的DOS系统功能调用和BIOS中断例程
DOS系统功能调用int 21h的1号子功能
功能:从键盘上输入单个字符
入口参数:(ah) = 1
出口参数: (al)存放输入字符的ASCⅡ码
即:
1 mov ah, 1 2 int 21h ; (al) <-- 输入字符的ascⅡ码
DOS系统功能调用int 21h的9号子功能
功能:显示字符串
入口参数:(ah) = 9,(ds:dx) = 字符串的首地址的段地址和偏移地址
出口参数: 无 其它要求:字符串必须以$结束
即:
1 mov ah, 9 2 mov ds, ×× ; ××是待输出字符串所在段的段地址 3 mov dx, ×× ; ××是待输出字符串第一个字符的偏移地址 4 int 21h
BIOS中断例程int 10h的2号子功能
功能:设置光标位置
入口参数:(ah) = 2, (bh) = 页号(默认取0), (dh) = 行号, (dl) = 列号
出口参数:无
即:
1 mov ah, 2 2 mov bh, ×× ; ××是页号 3 mov dh, ×× 4 mov dl, ×× ; ××是列号 5 int 10h
程序运行测试截图(输入7,以及输入其他字符,运行结果截图)
程序的功能是?
判断输入的字符是否为7,是则输出yes,不是输出no。
实验任务6
实验任务1、2、3、5中使用了不少系统提供的中断例程。本实验任务中,要求自行实现一个42号软中断 例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to 2049!"。
建议配合教材第12章学习理解并实践。
task6_1.asm
1 assume cs:code 2 code segment 3 start: 4 ; 42 interrupt routine install code 5 mov ax, cs 6 mov ds, ax 7 mov si, offset int42 ; set ds:si 8 mov ax, 0 9 mov es, ax 10 mov di, 200h ; set es:di 11 mov cx, offset int42_end - offset int42 12 cld 13 rep movsb 14 ; set IVT(Interrupt Vector Table) 15 mov ax, 0 16 mov es, ax 17 mov word ptr es:[42*4], 200h 18 mov word ptr es:[42*4+2], 0 19 mov ah, 4ch 20 int 21h 21 int42: 22 jmp short int42_start 23 str db "welcome to 2049!" 24 len equ $ - str 25 ; display string "welcome to 2049!" 26 int42_start: 27 mov ax, cs 28 mov ds, ax 29 mov si, 202h 30 mov ax, 0b800h 31 mov es, ax 32 mov di, 24*160 + 32*2 33 mov cx, len 34 s: mov al, [si] 35 mov es:[di], al 36 mov byte ptr es:[di+1], 2 37 inc si 38 add di, 2 39 loop s 40 iret 41 int42_end: 42 nop 43 code ends 44 end start
task6_2.asm
1 assume cs:code 2 code segment 3 start: 4 int 42 ; 调用自己实现的42号软中断 5 mov ah, 4ch 6 int 21h 7 code ends 8 end start
对汇编源程序task6_1.asm进行汇编、链接,得到可执行程序task6_1.exe。运行task6_1.exe,实现将 42号中断处理程序安装到0:200开始的连续内存空间,并设置中断向量表,使得将来通过 int 42 ,系统 可以跳转到中断处理程序。
对汇编源程序task6_2.asm进行汇编、链接,得到可执行程序task6_2.exe。运行task6_2.exe。 两个程序正确编写、汇编、链接,运行后,预期结果如下:
- 通过此项实现任务,你对中断、软中断的理解
- 自己选一个未被使用的中断码,实现一个中断例程,并调用测试。给出源码和运行测试截图。(选做 *)
8086一共提供了256个中断,中断码为0~255,其中,有些保留作为系统用,有些未使用。可以自 行挑选一个未被使用的中断码,程时自己编写中断例程。
28H ~ 2EH DOS保留用(实验任务6中,使用的是42号中断码,即2AH)
30H ~ 3FH DOS保留用
60H ~ 6FH 用户保留
F1 ~ FFH 未使用
此部分书写内容:
通过此项实现任务,你对中断、软中断实现机制的理解
Ⅰ、中断可分为内中断(软中断)与外中断(硬中断),当CPU检测到中断信息,它将在不再接着刚执行完的指令向下执行,而是转去处理这个中断信息,即执行中断处理程序。
Ⅱ、CPU内部产生中断信息的可能情况有四种:(1)除法错误;(2)单步执行;(3)执行into指令;(4)执行int指令。
Ⅲ、中断信息中包含有标识中断源的类型码,用于从中断向量表中查找到中断处理程序的入口地址。
Ⅳ、对于8086PC机,中断向量表指定放在内存地址0处,其中一个表项占两个字,高地址字存放中断处理程序的段地址,低地址字存放偏移地址。存储N号中断源对于的中断处理程序入口的段地址的内存单元的地址为:4N+2,偏移地址的内存单元的地址为4N。
Ⅴ、中断过程可表示为:
(1)取得中断类型码N;
(2)pushf
(3)TF=0,IF=0 (防止陷入一直处理单步中断处理程序的第一条指令的死循环)
(4)push CS
(5)push IP
(6)(IP)=(N*4),(CS)=(N*4+2)
之后CPU开始执行中断处理程序,中断处理程序的执行过程可表示为:
(1)保存用到的寄存器;
(2)处理中断;
(3)恢复用到的寄存器;
(4)用iret指令返回。
Ⅵ、在有些情况下,CPU不会响应中断,如设置栈顶指针ss:sp时。
自己选一个未被使用的中断码,实现一个中断例程,并调用测试。给出源码和运行测试截图。(选做 *)
如选做,请说明你使用的中断码,并描述你实现的这个中断例程的功能。