汇编语言(七)--中断程序设计
本文最后更新于:2019年6月26日 晚上
概览:中断的概念、分类,CPU如何得知中断,中断的过程,中断向量表,自定义中断
中断的概念和分类
中断就是指CPU在执行指令的过程中,收到了中断请求,于是终止正在执行的程序去处理中断,处理完之后返回被终止的程序继续执行。
中断分为两大类:软件中断(内中断)与硬件中断(外中断)
软件中断
中断指令 int n。
·比如DOS功能 INT 21HCPU遇到了某些运算错误。
除法错中断(中断类型号 0):执行除法指令时,若发现除数为0或超过了寄存器所能表达的范围,则立即产生一个类型为0的中断。(自己写的div 0之后运行就会卡住)
溢出中断(中断类型号 4):若溢出标志OF置1,由中断指令INTO来处理发生溢出的中断操作;若OF为0,则INTO指令不产生中断,CPU继续运行原程序。debug程序时设置的中断。
单步中断(中断类型号 1):在DEBUG下执行T命令(或P命令)时,陷阱标志TF置为1,CPU自动产生类型为1的单步中断。产生单步中断时,CPU自动地将PSW、CS和IP的内容入栈保存,然后清除TF、IF。
断点中断(中断类型号 3):断点中断也是供DEBUG调试程序使用的。在调试程序时,当CPU执行到断点时便产生中断(G命令),这时显示出各寄存器及相关标志,可以查看寄存器或存储单元的内容。设置断点实际上是把一条断点指令INT 3插入到程序中,CPU每执行到断点处的INT 3指令,便产生一个中断。
硬件中断
硬件中断是由输入/输出外设发出中断请求引起的中断。
不可屏蔽中断。
通常是遇到故障时,比如电源故障、奇偶检验错、I/O通道校验错等紧急情况时系统自动产生的。
这些不可屏蔽中断请求信号会接到CPU的NMI引脚上,不可屏蔽中断的中断类型号为2。
NMI (Non Maskable Interrupt)——不可屏蔽中断(即CPU不能屏蔽)无论状态寄存器中 IF 位的状态如何,CPU收到有效的NMI必须进行响应。可屏蔽中断。
可屏蔽中断是键盘、显示器、打印机、磁盘、串行口/并行口等外设发出的。由于可屏蔽中断种类较多,各种处理要求不一样,因此系统专门用8259中断控制器来管理这些中断。
可屏蔽是指可以使用软件设置允许或者禁止CPU进行响应。因为除了本身是否发出中断请求之外,该请求是否执行还要看CPU的IF标志的控制。
不可屏蔽中断CPU必须立刻响应,而可屏蔽中断可以选择响应或者不响应,或者按照优先级排序处理。
典型的非屏蔽中断源的例子是电源掉电,一旦出现,必须立即无条件地响应,否则进行其他任何工作都是没有意义的。
典型的可屏蔽中断源的例子是打印机中断,CPU对打印机中断请求的响应可以快一些,也可以慢一些,因为让打印机等待儿是完全可以的。
CPU处理中断
80X86系统中所有的中断请求都会有与之相对应的中断处理子程序。CPU响应中断之后会跳转到中断处理子程序,执行完之后会回到原来程序执行的断点处继续执行。
中断类型
80X86系统一共提供了256个中断类型,类型号为0–FFH。
但是系统只使用了一部分类型号。
中断向量与中断向量表
CPU要跳转执行中断处理子程序就需要知道它存放在那里,有入口地址才能够跳转执行。这个入口地址称之为中断向量(段地址+偏移地址)。
中断向量表,80X86系统建立的保存中断向量的地址区域,位于内存最低地址区中0号单元开始的1KB单元之中。
一个中断向量占用2个字即四个字节,高字单元根据放段地址,低字单元放偏移地址。
由于从0号单元开始,根据中断类型号码,乘以四就可以得到内存向量。
中断优先级
内部中断优先级最高,其次是非屏蔽中断,优先级最低的是单步中断。
CPU中断过程
中断响应条件。
(1) 当前的指令周期结束;
(2) 采样到有效的中断请求信号;
(3) 如果是可屏蔽中断请求INTR,检查中断允许标志IF是否为1,即中断开放;
(4) CPU正在执行的程序不是中断服务程序,或者是中断优先级较低的中断服务程序。
此外,特殊情况CPU不会响应中断。
(1) 当执行到STI指令时,CPU不会马上响应中断。STI指令是开中断指令,要求在开放中断后再执行后续的一条指令后才能响应中断;
(2) IRET指令是中断子程序返回指令,它也要求再执行一条后续指令后才能响应中断。这样做的目的是保护系统能够正常运行;
(3)当执行MOV SS,AX指令,即向SS段寄存器传送数据时,即使发生了中断,CPU也不会响应;直到本条执行完后,接着再执行一条指令才响应中断。
所以遇到非屏蔽中断时,这些特殊情况怎么做???中断响应过程。
(1)首先将标志寄存器FLAGS压入堆栈,将陷阱标志TF存入暂存器;
(2)将IF和TF清零;
(3)将正在运行程序的断点的CS和IP压入堆栈;
(4)从中断向量表中取出中断向量高两个字节的内容送入CS,取出低两个字节的内容送到IP;
(5)转到相应中断源的中断服务程序入口,执行中断处理服务程序。
简单来说:就是先保护现场,然后更换CS:IP的内容,执行。中断处理。
即执行中断处理子程序。
中断之中可以嵌套中断,如果新的中断优先级高于现在处理的中断,CPU就会转去执行新的中断。中断返回。
中断子程序的结尾为IRET。即中断返回,恢复现场。
将保存在堆栈中断点的偏移地址和段地址弹出,修改IP和CS寄存器;再把保存在堆栈中的PSW各标志位弹到FLAGS寄存器中,然后返回到被中断的程序去继续执行。
在中断发生时,CPU自动清除了IF位和TF位。使执行中断处理过程中,避免再次发生外部中断的干扰。
定制自己的中断程序
步骤
- 保护现场
- STI 开中断指令(IF=1)
- 处理中断
- CLI 关中断指令(IF=0)
- 恢复现场
- IRET 指令,返回被中断的程序
从应用程序进入中断子程序时,IF、TF都被清除,此时CPU在中断子程序中不会再响应其他的外部中断请求。
但如果这个中断子程序允许被打断或者优先级不高的话,设计中断子程序时就要开放中断标志,允许被打断。
IRET指令和RET指令都是返回原调用程序,但是IRET指令还要弹出保存的标志寄存器的值。
中断的设置
设置中断向量。
DOS中断INT 21H的25H号功能。将DS:DX中的中断向量写入中断向量表。
DS存储中断子程序名的段地址,DX存储中断子程序名的偏移地址。AH=25H
AL=中断类型号码
DS:DX=中断向量
INT 21H取出中断向量。
DOS中断INT 21H的35H号功能。从中断向量表中取出中断向量放入ES:BX。
ES存储中断子程序名的段地址,BX存储中断子程序名的偏移地址。AH=35H
AL=中断类型号码
INT 21H中断驻留。
特殊的退出程序,在退出前保留程序占用的内存,使得程序的内存不会被其他程序占据或覆盖,从而让此中断程序驻留在内存,从而其他程序也可以调用此中断。AH=31H
AL=0;表示返回码
DX=驻留程序的长度
INT 21H附:驻留程序的长度
中断子程序
mail proc far ;中断子程序名
smail: ;子程序开始标号
…… ;子程序内容
iret
smaisl:nop ;标号的结尾,Nop表示无操作的意思。
mail endp
故驻留程序的长度为:DX=smaisl-smail+16。两个标号名字不同,最后记得+16.
案例:7ch号功能,显示一段字符
;7ch号中断处理程序的功能是在屏幕上输出自己的班级,班级序号,学号,姓名。
;例如:1706 1 20177004 xuhaoyong
;并在另外一个程序程序中调用7ch号中断。
data segment
mess db 0ah,0dh,'1701 5 20170000 colourso $'
mess1 db 0ah,0dh,'Trigger interrupt, display information $'
mess2 db 0ah,0dh,'Continue or Quit(c/q): $'
data ends
stack segment stack
db 256 dup(?)
stack ends
code segment
assume cs:code,ds:data
start:
;mov ax,data
;mov ds,ax
;主程序
main proc far
mov ax,seg show
mov ds,ax ;将子程序的段地址给ds
mov dx,offset show;偏移地址
mov ah,25h
mov al,7ch ;中断类型号
int 21h ;写入中断向量表
;调用7ch号中断
con:
mov ax,data
mov ds,ax
mov dx,offset mess1
mov ah,9
int 21h ;输出
int 7ch
mov dx,offset mess2
mov ah,9
int 21h ;输出
mov ah,1
int 21h
cmp al,'c'
je con
;退出的话将子程序中断驻留
mov ah,31h
mov al,0
mov dx,showend-showstart+16
int 21h
mov ah,4ch
int 21h
main endp
;中断子程序
show proc far
showstart:
sti;开中断
mov ax,data
mov ds,ax
mov dx,offset mess
mov ah,9
int 21h ;输出
cli ;关中断
iret
showend:nop
show endp
code ends
end start
向量表的位置:7ch *4h = 1f0h。故在0000:01f0处查看int 7ch的中断向量表。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!