内中断
1、内中断的产生
任何一个通用的CPU,都具备一种能力,可以在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或内部产生的一种特殊信息,并且可以立即对所接收到的信息进行处理。这种特殊的信息,我们可以称其为:中断信息。中断的意思是指,CPU不再接着(刚执行完的指令)向下执行,而是转去处理这个特殊信息。
中断信息可以来自CPU的内部和外部(内中断,外中断)
内中断:当CPU的内部有需要处理的事情发生的时候,将产生中断信息,引发中断过程。这种中断信息来自CPU的内部
8086CPU的内中断(下面四种情况将产生中断信息)
- 除法错误,比如,执行div指令产生的除法溢出;
- 单步执行;
- 执行 into指令;
- 执行 int指令。
中断信息中包含中断类型码,中断类型码为一个字节型数据,可以表示256种中断信息的来源(中断源)
上述的4种中断源,在8086CPU中的中断类型码如下。
- 除法错误:0
- 单步执行:1
- 执行into指令:4
- 执行int指令,该指令的格式为int n,指令中的n为字节型立即数,是提供给CPU的中断类型码。
2、中断处理程序、中断向量表、中断过程
中断处理程序
用来处理中断信息的程序被称为中断处理程序。
根据CPU的设计,中断类型码的作用就是用来定位中断处理程序。比如CPU根据中断类型码4,就可以找到4号中断的处理程序
中断向量表
中断向量就是中断处理程序的入口地址。中断向量表就是中断处理程序入口地址的列表
CPU用8位的中断类型码通过中断向量表找到相应的中断处理程序的入口地址
中断过程
中断过程的主要任务就是用中断类型码在中断向量表中找到中断处理程序的入口地址,设置CS和IP
简要描述如下
- 取得中断类型码N;
- pushf
- TF=0,IF=0 (为什么这样参考单步中断)
- push CS , push IP
- (IP)=(N * 4),(CS)=(N * 4 + 2)
硬件在完成中断过程后,CS:IP将指向中断处理程序的入口,CPU开始执行中断处理程序。
3、iret指令
CPU随时都可能执行中断处理程序,中断处理程序必须一直存储在内存某段空间之中
而中断处理程序的入口地址,即中断向量,必须存储在对应的中断向量表表项中。
中断处理程序的常规编写步骤:
- 保存用到的寄存器;
- 处理中断;
- 恢复用到的寄存器;
- 用
iret
指令返回。
iret 指令描述为:pop IP
pop CS
popf
iret 指令执行后,CPU回到执行中断处理程序前的执行点继续执行程序
4、除法错误中断的处理
1
2
3
|
mov ax, 1000h
mov bh, 1
div bh ;除法溢出错误
|
1、当CPU执行div bh时,发生了除法溢出错误,产生0号中断信息,从而引发中断过程,
2、CPU执行0号中断处理程序
3、系统中的0号中断处理程序的功能:显示提示信息“Divide overflow”后,返回到操作系统中。
编程实验
编程:编写0号中断处理程序do0,当发生除法溢出时,在屏幕中间显示“overflow!”,返回DOS。
1、0000:0200至0000:02FF的256个字节的空间所对应的中断向量表项都是空的,可以将中断处理程序do0传送到内存0000:0200处。
2、中断处理程序do0放到0000:0200
,再将其地址登记在中断向量表对应表项
- 0号表项的地址
0:0
。0:0
字单元存放偏移地址,0:2
字单元存放段地址
- 将do0的段地址0存放在
0000:0002
字单元中,将偏移地址200H存放在0000:0000
字单元
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
assume cs:code
code segment
start:
mov ax, cs
mov ds, ax
mov si, offset do0 ;设置ds:si指向源地址
mov ax, 0
mov es, ax
mov di, 200h ;设置es:di指向目的地址0000:0200
mov cx, offset do0end - offset do0 ;设置cx为传输长度 编译时给出do0部分代码长度
cld ;设置传输方向为正
rep movsb ;将do0的代码送入0:200处
mov ax, 0 ;设置中断向量表
mov es, ax
mov word ptr es:[0*4], 200h
mov word ptr es:[0*4+2], 0
mov ax,4c00h
int 21h
;do0程序的主要任务是显示字符串
do0: jmp short do0 start
db "overflow!"
do0start:
mov ax, cs
mov ds, ax
mov si, 202h ;设置ds:si指向字符串
mov ax, 0b800h
mov es, ax
mov di, 12*160+36*2 ;设置es:di指向显存空间的中间位置
mov cx, 9 ;设置cx为字符串长度
s: mov al, [si]
mov es:[di], al
inc si
add di, 1
mov al, 02h ;设置颜色
mov es:[di], al
add di, 1
loop s
mov ax, 4c00h
int 21h
do0end: nop
code ends
end start
|
5、单步中断
CPU在执行完一条指令之后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。单步中断的中断类型码为1
Debug是如何利用CPU所提供的单步中断的功能进行调试?如使用t命令查看寄存器状态
Debug提供了单步中断的中断处理程序,功能为显示所有寄存器中的内容后等待输入命令
在使用t命令执行指令时,Debug将TF设置为1,在CPU执行完这条指令后就引发单步中断,执行单步中断的中断处理程序,所有寄存器中的内容被显示在屏幕上,并且等待输入命令。
在进入中断处理程序之前,设置TF=0。从而避免CPU在执行中断处理程序的时候发生单步中断
6、int指令
int指令的格式为:int n
,n为中断类型码,它的功能是引发中断过程。
CPU执行int n指令,相当于引发一个n号中断的中断过程
在程序中使用int指令调用任何一个中断的中断处理程序(中断例程)
编写供应用程序调用的中断例程
实验1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
;求2 * 3456^2
assume cs:code
code segment
start:
mov ax, 3456 ;(ax)=3456
int 7ch ; 调用中断7ch的中断例程,计算ax中的数据的平方
add ax, ax
adc dx, dx ;存放结果,将结果乘以2
mov ax,4c00h
int 21h
code ends
end start
;编程:安装中断7ch的中断例程
;功能:求一word型数据的平方。
;参数:(ax) = 要计算的数据。
;返回值:dx、ax中存放结果的高16位和低16位。
assume cs:code
code segment
start:
mov ax,cs
mov ds,ax
mov si,offset sqr ;设置ds:si指向源地址
mov ax,0
mov es,ax
mov di,200h ;设置es:di指向目的地址
mov cx,offset sqrend - offset sqr ;设置cx为传输长度
cld ;设置传输方向为正
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4], 200h
mov word ptr es:[7ch*4+2], 0
mov ax,4c00h
int 21h
sqr:
mul ax
iret ;CPU执行int 7ch指令进入中断例程之前,标志寄存器、当前的CS和IP被压入栈
;在执行完中断例程后,应该用iret 指令恢复int 7ch执行前的标志寄存器和CS、IP的
sqrend: nop
code ends
end start
|
实验2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
;功能:将一个全是字母,以0结尾的字符串,转化为大写。
;参数:ds:si指向字符串的首地址。
;应用举例:将data段中的字符串转化为大写。
assume cs:code
data segment
db 'conversation',0
data ends
code segment
start: mov ax, data
mov ds, ax
mov si, 0
int 7ch
mov ax,4c00h
int 21h
code ends
end start
12345678910111213141516171819
assume cs:code
code segment
start:
mov ax,cs
mov ds,ax
mov si,offset capital
mov ax,0
mov es,ax
mov di,200h
mov cx,offset capitalend - offset capital
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0
mov ax,4c00h
int 21h
capital:
push cx
push si
change:
mov cl,[si]
mov ch,0
jcxz ok
and byte ptr [si],11011111b
inc si
jmp short change
ok:
pop si
pop cx
iret
capitalend:nop
code ends
end start
|
7、BIOS和DOS所提供的中断例程
在系统板的ROM中存放着一套程序,称为BIOS(基本输入输出系统)
BIOS中主要包含以下几部分内容
- 硬件系统的检测和初始化程序;
- 外部中断和内部中断的中断例程;
- 用于对硬件设备进行I/O操作的中断例程;
- 其他和硬件系统相关的中断例程。
程序员在编程的时候,可以用int 指令直接调用BIOS和DOS系统提供的中断例程,来完成某些工作。
和硬件设备相关的DOS中断例程中,一般都调用了BIOS的中断例程。
BIOS和DOS中断例程的安装过程
BIOS和DOS提供的中断例程是如何安装到内存中的呢?
1、开机后,CPU一加电,初始化(CS)= 0FFFFH,(IP)= 0,自动从FFFF:0单元开始执行程序。FFFF:0处有一条转跳指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。
2、初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。
注意,对于BIOS所提供的中断例程,只需将入口地址登记在中断向量表中即可,因为它们是固化到ROM中的程序,一直在内存中存在。
3、硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。从此将计算机交由操作系统控制。
4、DOS启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。
BIOS中断例程应用
一般来说,一个供程序员调用的中断例程中往往包括多个子程序,中断例程内部用传递进来的参数来决定执行哪一个子程序。
BIOS和DOS提供的中断例程,都用 ah 来传递内部子程序的编号。
编程:在屏幕的5行12列显示3个红底高亮闪烁绿色的“al。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
assume cs:code
code segment
;int 10h中断例程的"设置光标位置"功能
mov ah, 2;设置光标调用第10h号中断例程的2号子程序,功能为设置光标位置(可以提供光标所在的行号、列号和页号作为参数)
;设置光标到第0页,第5行,第12列
mov bh, 0;第0页
mov dh, 5;dh中放行号
mov dl, 12;dl中放列号
int 10h
;int10h中断例程的"在光标位置显示字符"功能。
mov ah,9 ;调用第10h号中断例程的9号子程序,功能为在光标位置显示字符
;提供要显示的字符、颜色属性、页号、字符重复个数作为参数
mov al,'a' ;字符
mov b1,11001010b ;颜色属性
mov bh,0 ;第0页
mov cx,3 ;字符重复个数
int 10h
code ends
end
|
bh中页号的含义:内存地址空间中,B8000H~BFFFFH
共32kB的空间,为80*25彩色字符模式的显示缓冲区。
一屏的内容在显示缓冲区中共占4000个字节。显示缓冲区分为8页,每页4KB(约4000B),显示器可以显示任意一页的内容。一般情况下,显示第0页的内容。也就是说,通常情况下,B8000H~B8F9FH中的4000个字节的内容将出现在显示器上。
DOS中断例程应用
int 21h
中断例程是DOS提供的中断例程,4ch
号功能,即程序返回功能
1
2
3
|
mov ah, 4ch ;调用第21h号中断例程的4ch号子程序,功能为程序返回,可以提供返回值作为参数
mov al, 0 ;返回值
int 21h
|
编程:在屏幕的5行12列显示字符串“Welcome to masm!”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
assume cs:code
data segment
db 'Welcome to masm', '$' ;“$”本身并不显示,只起到边界的作用
data ends
code segment
start: mov ah, 2 ;10号中断设置光标位置功能
mov bh, 0 ;第0页
mov dh, 5;dh中放行号
mov dl, 12 ;dl中放列号
int 10h
mov ax, data
mov ds, ax
mov dx, 0 ;ds:dx指向字符串的首地址data:0 (参数)
mov ah, 9 ;调用第21h号中断例程的9号子程序,功能为在光标位置显示字符串,可以提供要显示字符串的地址作为参数
int 21h
mov ax, 4c00h ;21号中断程序返回功能
int 21h
code ends
end start
|