内中断

关于中断信息:
    如果cpu在执行完当前正执行的指令后,检测到了中断信息,将不会执行接下来的指令,而是立即处理中断信息;
    中断信息可以来自cpu内部和外部;
来自cup内部的中断信息称为内中断;
 
1.内中断的产生
8086cpu产生内中断信息的情况:
    1】除法错误;比如执行div指令产生的除法溢出
    2】单步执行
    3】执行into指令
    4】执行int指令
 
中断源:
    cpu需要知道中断信息的来源,以此来区别不同的中断信息;
    中断信息中包含有中断类型码;
    中断类型码为一个字节型数据,可表示256种中断信息来源;
    例如:四种内中断对应的中断类型码
        除法错误    ->0
        单步执行    ->1
        执行into指令    ->4
        int n    ->n
 
2.处理中断信息
1)中断处理程序
cpu收到中断信息后,需要对中断信息进行处理;
用来处理中断信息的程序称为中断处理程序;
一般来说,要对不同的中断信息编写不同的中断处理程序;
 
2)中断向量表
中断信息中包含8位的中断类型码;
需要通过中断类型码来找到对应的中断处理程序;
cpu用8位中断类型码通过中断向量表找到相应的中断处理程序入口地址;
也就是说:中断向量表就是中断处理程序的入口地址列表;
 
cpu在处理中断时,必需找到中断向量表;
在8086cpu机器中,中断向量表存放在内存0处;
内存地址:0000:0000~0000:03FF,之间1024个内存单元中用来存放中断向量表;
一个表向存放一个中断向量,即中断处理程序的入口地址;
一个表项占两个字;
高地址字存放段地址,低地址字存放偏移地址;
 
3)中断过程
在处理中断时,cup硬件会自动完成下面的过程:
    1】通过中断类型码查看中断向量表;
    2】找到对应的表项,从而确定中断处理程序的入口地址;
    3】将cs:ip设为表项中对应的值,以此来让cpu执行中断处理程序;
cpu完成该过程的工作称为中断过程;
 
4)处理中断信息的流程
8086cpu在收到中断信息后,将执行下面的流程:
    1】从中断信息中获取中断类型码n;
    2】标志寄存器的值入栈;
    3】标志寄存器第8位TF、第9位IF置0;
    5】CS的值入栈;
    6】IP的值入栈;
    7】cs的值设为4*n,ip的值设为4*n+2;
完成该流程后,cpu开始执行中断处理程序;
 
3.关于中断处理程序
由于cpu随时可能会检测到中断信息;
也就是说中断处理程序随时可能执行;
因此,中断处理程序必须一直储存在一段内存空间中;
中断处理程序的入口地址必须储存在中断向量表中;
 
中断处理程序的编写:
    1】保存用到的寄存器
    2】处理中断
    3】恢复用到的寄存器
    4】用iret指令返回
 
iret指令
iret
作用:
    调用中断处理程序前,需要将标志寄存器、cs、ip的值入栈;
    当执行完后,需要将这些值出栈还原;
    iret指令就用来做这件事;
相当于:
    pop ip
    pop cs
    popf
iret指令执行完后,cpu回到中断处理程序执行前的执行点,继续向下执行;
 
4.编写0号中断的处理程序
1)分析
0号中断对应的是除法溢出;
当发生除法溢出时,cpu做如下工作:
    1】取得中断类型码,也就是0;
    2】标志寄存器入栈、TF和IF置0;
    3】cs和ip入栈;
    4】cs和ip的值设为中断向量表中的值,即:cs=4*0,ip=4*0+2;
cs:ip会指向中断处理程序,也就是cpu会开始执行中断处理程序;
编写中断处理程序do0;
do0做如下操作:
    相关处理;打印错误信息;返回dos;
 
因为除法溢出随时可能发生,因此do0随时可能被调用;
为了让do0一直存在于内存中,do0需要放在其他程序用不到的内存区域;
为了方便,可以将do0放在0000:0200处;
理由如下:
    0000:0000~0000:03ff是系统存放中断向量表的区域,因此一般不会被其它程序修改;
    8086支持256个中断但实际上,系统要处理的中断数远小于该值,也就是说,该段内存很多都是没被使用的;
    do0程序不会占用太大的内存空间;
 
通过分析,我们需要做如下工作:
    1】编写中断处理程序do0;
    2】将do0送入内存0000:0200处;
    3】将do0的入口地址,也就是0000:0200存放在中断向量表的0号表项中;
 
总的来说,要编写一个汇编程序,实现如下功能:
    1】安装do0    ->主要是将do0代码复制到0000:0200处,可以用rep movsb指令来实现;
    2】实现do0    ->主要是打印错误提示信息,也就是将字符串送入到内存地址b8000处;
 
2)实现
中断处理程序:
assume cs:code
 
code segment
    start:    mov ax,code
            mov ds,ax
            mov si,offset do0    ;ds:si指向do0用来做串传送
            
            mov ax,0
            mov es,ax
            mov di,200h            ;es:di指向0000:0200h
            
            cld                    ;标志位df置0,正向传送,也就是传送一个字节后si、di加1
            mov cx,offset do0end-offset do0    ;由编译器来计算do0的字节数,编译器可以用+-*/来计算
            rep movsb
            
            mov ax,0            ;设置中断向量
            mov es,ax
            mov word ptr es:[0*4],200h
            mov word ptr es:[0*4+2],0
            
            mov ax,4c00h        ;返回dos
            int 21h
            
    do0:    jmp short do0Start    ;为了字符串不被其它程序覆盖,也需要放在db0中
            db "hello world!",0
            
    do0start:mov ax,cs
            mov ds,ax
            mov si,202h            ;ds:si指向字符串,也就是do0执行后要打印的字符串
            
            mov ax,0b800h
            mov es,ax
            mov di,12*160+36*2    ;在12行的中间输出,由编译器来做数学运算
            
        s:    mov ch,0
            mov cl,byte ptr[si]
            jcxz ed                ;如果遇到0就跳出循环
            mov al,[si]
            mov ah,02h            ;黑底绿字
            mov es:[di],ax
            inc si
            add di,2
            loop s
            
        ed:    nop    
            iret
            mov ax,4c00h        ;do0结束后返回dos
            int 21h
    do0end:    nop                    ;标记do0结束,用来让编译器计算do0的字节数        
    
code ends
end start
测试用的除法溢出程序:
assume cs:code
code segment
    start:    mov ax,1000h
            mov bh,01h
            div bh
            mov ax,4c00h
            int 21h
code ends
end start
 
测试结果:
可以看到发生除法溢出后,输出了“hello world!”,表示执行了自定义的中断处理程序;
 
5.单步中断
单步中断类型码为1;
单步中断产生:
    在cpu执行完一条指令后,如果检测到标志寄存器的TF标志位的值为1,则产生单步中断;
 
1)debug与单步中断
debug 的 t 命令用来单步调试程序;
当t命令执行时,debug将TF标志位置1;
cpu检测到单步中断;
执行中断处理程序1,作用是显示所有寄存器的内容、并且等待命令输入;
 
2)关于进入中断处理程序前的TF置0
当tf=1时,cpu执行完当前指令后进入中断;
单中断处理程序也是由一条条指令组成;
如果在执行中断处理前tf=1,则在执行一条中断处理指令后将再次引发单步中断;
以此类推,会造成死循环;
为了避免这种情况,在进入中断处理程序之前,中断过程会将tf置0;
 
6.响应中断的特殊情况
一般情况下,cpu在执行当前指令后,如果检测到中断信息就会立即响应中断;
但有些情况下例外;
例如:执行完向ss寄存传送数据的指令后,即使发生中断cpu也不会响应;
原因:
    ss:sp指向栈顶;
    在中断过程中,需要将cs:ip压入栈;
    此时ss改变了,但sp还没变,ss:sp指向的不是正确的栈顶,将引起错误;
因此,在设置ss:sp时应该将设置sp的指令紧接设置ss的指令;
mov ax,1000h
mov ss,ax
mov sp,0
而不应该
mov ax,1000h
mov ss,ax
mov ax,200
mov sp,0
 
 
 
posted @ 2019-07-16 17:38  L丶银甲闪闪  阅读(323)  评论(0编辑  收藏  举报