实验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时。

自己选一个未被使用的中断码,实现一个中断例程,并调用测试。给出源码和运行测试截图。(选做 *)

如选做,请说明你使用的中断码,并描述你实现的这个中断例程的功能。

posted @ 2021-12-11 15:02  悬尘往  阅读(112)  评论(2编辑  收藏  举报