内中断
中断源 : 中断类型码N(8位) –>N号中断向量–>中断向量表(内存0000:0~0000:03FF,每项两个字,放中断处理程序的入口地址,即段地址(4N)+偏移地址(4N+2))
除法错误(溢出) : 0
单步执行 : 1 –>每执行一条指令后,都检查TF=1则中断
执行into指令 : 4
执行int指令 : int n –>引发n号中断
中断过程:
1.取得中断码
2.保存标志寄存器
3.设置标志寄存器的8位TF=0,9位IF=0(防止CPU在执行中断时发生单步中断)
4.保存CS和IP(用于返回)
5.取得入口地址,设置IP(中断类型码*4)和CS(中断类型码*4+2)的值
6.硬件自动完成中断
编程处理除法中断(0)
功能:发生中断时在屏幕中间显示“overflow!”
1、0000:0200~0000:02FF的256个字节的空间是空的,写入中断程序;
2、入口地址(偏移地址)=0*4,段地址=0*4+2,将入口地址放入中断向量表。
assume cs:code
code segment
start://将中断程序写入一块空地方
mov ax,cs //设置ds:si指向原地址
mov ds,ax
mov si,offset do0
mov ax,0 //设置es:di指向要写入的地址0000:0200
mov es,ax
mov di,200h
mov cx,offset do0end-offset do0 //传输长度
cld //传输方向为正
rep movsb
//将中断程序的入口地址0:200写入中断向量表项0:0
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 //在程序中分一块空间存放数据“overflow!”防止被覆盖
db "overflow!"
do0start:mov ax,cs //设置ds:si指向字符串,“overflow!”的地址为0:202
mov ds,ax
mov si,202h
mov ax,0b800h //设置es:di指向显存的中间位置
mov es,ax
mov di,12*160+36*2
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
编程处理int n调用中断
(int指令:保存标志寄存器、CS、IP入栈 ,配合 iret指令:出栈IP、CS、标志寄存器 )
(分两个程序,一个程序调用中断,一个程序安装中断)
功能:用int 7ch中断例程完成LOOP指令
//调用中断的程序
assume cs:code
code segment
start:mov bx,offset s-offset se //bx保存转移地址,在两个程序间传递
mov cx,80
s:...(循环体)
int 7ch //调用7ch处中断程序
se:nop(只是起标记作用)
mov ax,4c00h
int 21h
//安装中断到7ch处
...(将中断写入一块空地)
...(将中断程序的入口点写入中断向量表项0:7ch)
lp:push bp
mov bp,sp
dec,cx
jcxz lpret
add [bp+2],bx
lpret:pop bp
iret
引发7ch中断,保存CS和IP入栈(CS的值=s的段地址;IP的值=se的偏移地址)–>进入lp,第一句push bp
这时栈中的情况如下图:
继续执行:
mov bp,sp–>bp指向栈顶,
add [bp+2],bx–>bp+2指向se的偏移地址,bx=s-se,所以se+s-se=s,将bp+2处修改成了s的偏移地址
iret出栈IP和CS,从标号s处开始执行指令
int n调用系统提供的中断例程
BIOS(基本输入输出系统,在系统板的ROM中):包含I/O操作的中断例程,一个包含多个子程序(用ah选择子程序的编号)
DOS(操作系统):也有中断例程–>mov ax,4c00h int 21h(调用第21h号中断例程的4ch号子程序)
外中断
分类:
1.可屏蔽中断。若IF=1,则CPU执行完当前指令后,相应中断。若IF=0,则不响应。
2.不可屏蔽中断。中断类型码为2。
编写int 9中断例程(处理键盘输入,键盘有操作就引发int 9中断)
1.按下一个键,对应一个通码;放开一个键,对应一个断码。断码=通码+80h
2.通码或断码–>60端口–>BIOS引发9号中断–>扫描码(通码/断码)+字符码(a~z)写入键盘缓冲区,状态字节(shift、ctrl等)写入状态内存区
3.用别的指令模拟int指令的中断过程
1.取得中断码
2.保存标志寄存器
pushf
3.设置标志寄存器的TF=0,9位IF=0
pop ax
and ah,11111100b //标志寄存器的第9位和第8位
push ax
popf
4.保存CS和IP(用于返回)
5.取得入口地址,设置IP(中断类型码*4)和CS(中断类型码*4+2)的值
call dword ptr ds:[0]
6.硬件自动完成中断
功能:在屏幕中间依次显示a~z,在显示过程中,按下esc后,改变显示的颜色
分析:改变了esc键对应的功能,也就是改变了int9中断
assume cs:code
stack segment
db 128 dup (0)
stack ends
data segment //用来保存原入口地址
dw 0,0
data ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,128
**********************************************************
保存int9原入口地址,在中断向量表中写入本int9中断的入口地址 *
mov ax,data *
mov ds,ax
*
mov ax,0 *
mov es,ax
*
push es:[9*4] *
pop ds:[0] *
push es:[9*4+2] *
pop ds:[2] *
*
mov word ptr es:[9*4],offset int9 *
mov es:[9*4+2],cs *
***********************************************************
//在屏幕上依次显示a~z
mov ax,0b800h
mov es,ax
mov ah,'a'
s:mov es:[160*12+40*2],ah
call delay
inc ah
cmp ah,'z'
jna s
********************************************************
恢复int9原入口地址,恢复键盘的功能
mov ax,0
mov es,ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
*********************************************************
mov ax,4c00h
int 21h
//循环延时。空循环100000h次,为了延长字母显示的时间
delay:push ax
push dx
mov dx,10h//高8位
mov ax,0//低8位
s1:sub ax,1
sbb dx,1
cmp ax,0
jne s1
cmp dx,0
jne s1
pop dx
pop ax
ret
//按下esc键变颜色
int9:push ax
push bx
push es
in al,60h(从60端口读入键盘的输入)
pushf(模拟调用int9中断)
pushf
pop bx
and bh,11111100b
push bx
popf
call dword ptr ds:[0]
cmp al,1(判断是否按下了esc键,esc键的通码为1)
jne int9ret
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*12+40*2+1](字符的属性,改变数值则变颜色)
int9ret:pop es
pop bx
pop ax
iret
code ends
end start
编写int 16h中断例程(读取键盘缓冲区)
引发int 16h中断–>读取键盘缓冲区第一个字单元–>扫描码(高8位)送入ah,字符码(低8位)送入al–>已经读取的从缓冲区删除–>循环(若缓冲区空,则等待)
功能:
1.字符串输入,同时显示在屏幕上;能删除已有的字符(用栈存字符串)
2.输入回车后,结束输入(输入回车时在字符串上加0)
字符串输入
用int 13h中断例程(读写磁盘)
给出面号(0~n)、磁道号(0~n)、扇区号(1~n)
读取0面0道1扇区的内容
mov al,1(读取的扇区数量)
mov ch,0(磁道号)
mov cl,1(扇区号)
mov dl,0(驱动器号,软盘从0开始,硬盘从80h开始)
mov dh,0(磁头号,软盘即面号)
mov ah,2(2表示读取,3表示写入)
int 13h
读取成功,ah=0;读取失败,ah=出错代码