第十二章 内中断
中断:cpu能接收到内部或外部的某种信息,cpu不再接着向下执行,而是转取处理这个特殊信息。
12.1 内中断的产生
cpu内部有下面情况发生将产生相应的中断信息。
1)除法错误,比如,执行div指令产生的除法溢出 (中断码 0)
2)单步执行 (1)
3)执行into指令 (4)
4)执行int指令 (int n)
cpu通过中断类型码来识别中断的来源。
12.2 中断处理程序
cpu收到中断信息后,需要中断信息处理程序。 对不同的中断信息编写不同的处理程序。根据中断类型码和中断向量表来定位中断处理程序
12.3 中断向量表
一张存放中断处理程序入口地址的列表。 中断向量表存放于内存中,其中放着256个中断源所对应的中断处理程序的入口
8086cpu默认的中断向量表存放于 0000:0000 ~ 0000:03FF
一个表项占用2个字(4个字节),高地址存放段地址,低地址存放偏移地址。
12.4 中断过程
cpu收到内部或外部中断以后会根据中断码寻找中断向量表中的中断处理程序的入口地址,并设置CS 和IP。 称为中断过程
以下是8086执行中断的过程:
1) 取得中断类型码:
2)标志寄存器的值入栈(pushf)
3)设置标志寄存器的第八位TF和第九位IF为0 TF=0, IF=0
4)CS的内容入栈 push CS
5)IP的内容入栈 push IP
6)从内存地址为中断码x4 和中断码x4+2 的两个字单元读取中断处理程序的入口地址并设置IP和CS IP = (N * 4) CS = (N*4 + 2)
12.5 中断处理程序和iret指令
1) 保存用到的寄存器
2)处理中断
3)恢复用到的寄存器
4)用iret指令返回
POP IP
POP CS
POPf
12.6 除法错误中断处理程序
屏幕上输出
Divide overflow
12.7 编程处理0号中断
编程:当发生除法溢出的时候,产生0号中断信息,从而引发中断过程。
0000:0000~0000:03FF 都是中断向量表。 但是为了脱离操作系统。这里使用0000:0200~0000:02ff的256个字节存放自己的程序。
1)编写可以显示“overflow!”的中断处理程序:do0:
2)将do0送入内存0000:0200处
3)将do0的入口地址0000:0200 存储在中断向量表的0号表项中
12.8 安装
assume cs:code
code segment
start: ; set es:di as target address 0000:0200h
mov ax, 0
mov es, ax
mov di, 200h
; set ds:si as source address cs:do0
mov ax, cs
mov ds, ax
mov si, offset do0
; set cx as the data length
mov cx, offset do0end - offset do0
; set the transport directive DF = 0 cld
cld
rep movsb
; set the IRQ table
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: jmp short do0start
db "overflow!"
; show the string "Overflow!"
do0start: mov ax, cs
mov ds, ax ; set ds:si to the string buffer
mov si, 202h ; the string will be move to 202h
mov ax, 0b800h
mov es, ax
mov di, 12 * 160 + 36 * 2 ; point to the center of the screen
mov cx, 9
s: mov al, [si]
mov es:[di], al
inc si
add di, 2
loop s
mov ax, 4c00h
int 21h
do0end: nop
code ends
end start
运行结果
12.11 单步中断
cpu中执行完一条指令后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。执行过程如下
1)取得中断类型码1
2)标志寄存器入栈,TF IF设为0
3)CS, IP入栈
4)(IP) = (1*4) (CS) = ( 1*4 + 2)
Debug在执行t指令时,将tf设为1,使得cpu工作于单步中断的方式下,在cpu执行完这条指令以后就会引发单步中断,执行单步中断的中断处理程序,所有寄存器中的内容被显示在屏幕上,并等待输入命令。
为了防止cpu处理单步中断陷入死循环,在进入单步中断处理程序之前TF会被设置为0.
为了单步跟踪程序的执行过程,提供了实现机制。
12.12 响应中断的特殊情况
在执行完向ss寄存器传送数据的指令后,即便是发生中断cpu也不会响应。因为ss:sp联合指向栈顶,对他们的设置应该连续完成。如果设置完ss以后cpu响应中断,要在栈中压入标志寄存器,cs和ip的值。(而此后sp会被改变)此时的栈顶是不正确的。所以cpu在执行设置完ss以后不响应中断。
实验 编写0号中断处理程序
assume cs:code
code segment
start: ; set es:di as target address 0000:0200h
mov ax, 0
mov es, ax
mov di, 200h
; set ds:si as source address cs:do0
mov ax, cs
mov ds, ax
mov si, offset do0
; set cx as the data length
mov cx, offset do0end - offset do0
; set the transport directive DF = 0 cld
cld
rep movsb
; set the IRQ table
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: jmp short do0start
db "divide error!", 0
; show the string "Overflow!"
do0start: mov ax, cs
mov ds, ax ; set ds:si to the string buffer
mov si, 202h ; the string will be move to 202h
mov ax, 0b800h
mov es, ax
mov di, 12 * 160 + 36 * 2 ; point to the center of the screen
s: mov al, [si]
cmp al, 0
je exit
mov es:[di], al
inc si
add di, 2
loop s
exit: mov ax, 4c00h
int 21h
do0end: nop
code ends
end start