精华内容
下载资源
问答
  • 木工数控机床CPU非正常中断浅谈.pdf
  • 网络异常断开原因主要那些呢?归纳起来主要以下两种: 1、客户端程序异常。  对于这种情况,我们很好处理,因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常(就是WinSock2中的10054异常...

    网络异常断开原因主要有那些呢?归纳起来主要有以下两种:

    1、客户端程序异常。

      对于这种情况,我们很好处理,因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常(就是WinSock2中的10054异常)。只要在服务端处理这个异常就可以了。

    2、网络链路异常。

      如:

    网络异常断开原因主要有那些呢?归纳起来主要有以下两种:

    1、客户端程序异常。

      对于这种情况,我们很好处理,因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常(就是WinSock2中的10054异常)。只要在服务端处理这个异常就可以了。

    2、网络链路异常。

      如:网线拔出、交换机掉电、客户端机器掉电。当出现这些情况的时候服务端不会出现任何异常。那我们该怎么办呢?

      我们知道,TCP有一个连接检测机制,就是如果在指定的时间内(一般为2个小时)没有数据传送,会给对端发送一个Keep-Alive数据报,使用的序列号是曾经发出的最后一个报文的最后一个字节的序列号,对端如果收到这个数据,回送一个TCP的ACK,确认这个字节已经收到,这样就知道此连接没有被断开。如果一段时间没有收到对方的响应,会进行重试,重试几次后,向对端发一个reset,然后将连接断掉。

      在Windows中,第一次探测是在最后一次数据发送的两个小时,然后每隔1秒探测一次,一共探测5次,如果5次都没有收到回应的话,就会断开这个连接。但两个小时对于我们的项目来说显然太长了。我们必须缩短这个时间。那么我们该如何做呢?我要利用Socket类的IOControl()函数。我们来看看这个函数能干些什么:

     

    使用   IOControlCode   枚举指定控制代码,为   Socket   设置低级操作模式。  

    命名空间:System.Net.Sockets  
    程序集:System(在   system.dll   中)  

    语法  

    C#  
    public   int   IOControl   (  
    IOControlCode   ioControlCode,  
    byte[]   optionInValue,  
    byte[]   optionOutValue  
    )  


    参数  
    ioControlCode  
    一个   IOControlCode   值,它指定要执行的操作的控制代码。  

    optionInValue  
    Byte   类型的数组,包含操作要求的输入数据。  

    optionOutValue  
    Byte   类型的数组,包含由操作返回的输出数据。  

    返回值  
    optionOutValue   参数中的字节数。  

    如:
    socket.IOControl(IOControlCode.KeepAliveValues,   inOptionValues,   null);
    我们要搞清楚的就是inOptionValues的定义,在C++里它是一个结构体。我们来看看这个结构体:

    struct   tcp_keepalive  {  
            u_long     onoff;   //是否启用Keep-Alive
            u_long     keepalivetime;   //多长时间后开始第一次探测(单位:毫秒)
            u_long     keepaliveinterval;   //探测时间间隔(单位:毫秒)
    };

    在C#中,我们直接用一个Byte数组传递给函数:

    uint   dummy   =   0;
    byte[]   inOptionValues   =   new   byte[Marshal.SizeOf(dummy)   *   3];
    BitConverter.GetBytes((uint)1).CopyTo(inOptionValues,   0);//是否启用Keep-Alive
    BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues,   Marshal.SizeOf(dummy));//多长时间开始第一次探测
    BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues,   Marshal.SizeOf(dummy)   *   2);//探测时间间隔

    具体实现代码:

                    public   static   void   AcceptThread()
                    ...{
                            Thread.CurrentThread.IsBackground   =   true;
                            while   (true)
                            ...{
                                    uint   dummy   =   0;
                                    byte[]   inOptionValues   =   new   byte[Marshal.SizeOf(dummy)   *   3];
                                    BitConverter.GetBytes((uint)1).CopyTo(inOptionValues,   0);
                                    BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues,   Marshal.SizeOf(dummy));
                                    BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues,   Marshal.SizeOf(dummy)   *   2);
                                    try
                                    ...{
                                            Accept(inOptionValues);
                                    }
                                    catch   ...{   }
                            }
                    }

                    private   static   void   Accept(byte[]   inOptionValues)
                    ...{
                            Socket   socket   =   Public.s_socketHandler.Accept();
                            socket.IOControl(IOControlCode.KeepAliveValues,   inOptionValues,   null);
                            UserInfo   info   =   new   UserInfo();
                            info.socket   =   socket;
                            int   id   =   GetUserId();
                            info.Index   =   id;
                            Public.s_userList.Add(id,   info);
                            socket.BeginReceive(info.Buffer,   0,   info.Buffer.Length,   SocketFlags.None,   new   AsyncCallback(ReceiveCallBack),   info);
                    }

     

    展开全文
  • 向量中断向量中断的区别

    千次阅读 2011-02-14 21:50:00
      向量中断 向量中断 向量中断向量中断的区别  推荐向量中断就是不同的中断有不同的入口地址,向量中断就只有一个入口地址,进去了再判断中断标志来识别具体是哪个中断。向量中断...

    今天被一个年轻小伙用这个问题给问倒了, 特记下来以示警记!!

     

    向量中断 非向量中断
    向量中断与非向量中断的区别
         推荐向量中断就是不同的中断有不同的入口地址,非向量中断就只有一个入口地址,进去了再判断中断标志来识别具体是哪个中断。向量中断实时性好,非向量中断简单
         向量中断控制器VIC具有32个中断请求输入,可将其编程分为3类,FIQ,向量IRQ和非向量IRQ。
         FIQ(fast interrpt request)快速中断请求要求具有最高优先级。如果分配给FIQ的请求多于一个,VIC将中断请求相或后向ARM处理器产生FIQ信号。当只有一个中断被分配为FIQ时可实现最短的FIQ等待,但如果分配给IFIQ级的中断多于1个,FIQ服务程序需要读取FIQ状态寄存器来识别产生中断请求的FIQ中断源!向量IRQ具有中等优先级。该级别可分别32个请求中断的16个。32个请求种的任意一个都可分配到16个向量IRQ slot中的任意一个,其中slot0具有最高优先级非向量IRQ的优先级最低

    向量中断 非向量中断
         向量者,矢量也,即指方向,门路。
         向量中断------由硬件提供中断服务程序入口地址;
         非向量中断------由软件件提供中断服务程序入口地址;
     
         向量中断模式用于RESET、NMI、异常处理。当向量中断产生时,控制器直接将PC赋值,如跳到0x0000000d处,而在0x0000000d地址处通常放置ISR服务程序地址LDR PC, =ISR_HANDLER。
         非向量中断模式,有一个寄存器标识位,跳转到统一的函数地址,此函数通过判别寄存器标识位和优先级关系进行中断处理。向量中断模式是当CPU读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址函数中,节省了中断处理时间提高了中断处理速度。例如 ADC 中断的向量地址为0xC0,则在0xC0处放如下代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会自动跳转到HandlerADC函数中处理中断。
          非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将INTPND寄存器中对应标志位置位,然后跳转到位于0x18处的统一中断函数中;该函数通过读取INTPND寄存器中对应标志位来判断中断源,并根据优先级关系再跳到对应中断源的处理代码中处理中断。


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shi_869160/archive/2010/09/16/5888321.aspx

     

     
     
     
    向量中断就是不同的中断有不同的入口地址,非向量中断就只有一个入口地址,进去了在判断中断标志来识别具体是哪个中断。向量中断实时性好,非向量中断简单

    向量中断控制器VIC具有32个中断请求输入,可将其编程分为3类,FIQ,向量IRQ和非向量IRQ。
    FIQ(fast interrpt request)快速中断请求要求具有最高优先级。如果分配给FIQ的请求多于一个,VIC将中断请求相或后向ARM处理器产生FIQ信号。当只有一个中断被分配为FIQ时可实现最短的FIQ等待,但如果分配给IFIQ级的中断多于1个,FIQ服务程序需要读取FIQ状态寄存器来识别产生中断请求的FIQ中断源!
    向量IRQ具有中等优先级。该级别可分别32个请求中断的16个。32个请求种的任意一个都可分配到16个向量IRQ slot中的任意一个,其中slot0具有最高优先级
    非向量IRQ的优先级最低
    1. 中断优先级不同: 非向量中断比向量中断要低(向量中断则比FIQ优先级低);
    2. 两者的设置方式不同:非向量中断只需要通过VICDefVectAddr来设置ISR地址,然后在VIC控制器中使能外设中断即可;而向量中断配置时,先选择为IRQ中断,然后分配中断通道(即优先级。此为IRQ内部的优先级,不同于FIQ、IRQ与非向量中断三者的优先级意义),再在VICVectAddrx 中设置ISR地址,最后使能向量中断。
    3. 中断响应异同:响应过程两者皆是由VIC硬件来控制,用户软件不用干预。共同点是,当中断产生,处理器进入IRQ模式,并将对应的ISR地址保存寄存器的值,复制到VICVectAddr寄存器中,PC根据此地址进行跳转,执行相应ISR程序。而区别如下:
    a. 非向量中断:ISR地址由VICDefVectAddr复制到VICVectAddr,如果有多路非向量中断,在确定是哪路中断产生时,要通过VICIRQStatus寄存器来查询;
    b. 向量中断:ISR地址由VICVectAddrx复制到VICVectAddr,如果有多路向量中断,在同时产生中断时,处理器响应的是具有最高优先级的IRQ中断。
    4. 中断服务程序编写:两者没有差异。中断处理完毕后,皆要先清除中断标志,再对VICVectAddr执行写操作,以更新中断优先级,正常响应下一次中断。
     对于三星S3C440b处理器,是必须要定义中断向量表的,并将中断向量表放置在最初的位置。Samsung的ARM7处理器一般不使用非向量中断的,使用向量中断。在中断源产生中断之后,处理器会自动根据中断源来将正确的中断向量地址赋给PC。所以,我们必须在启动代码中事先设置好中断向量表,为使用的中断设置相应的中断服务函数。当PC指针指向中断源唯一对应的中断向量处之后,就会跳转到相应的中断处理函数。

     

     

    展开全文
  • 中断

    千次阅读 2013-10-31 11:54:00
    中断是一种使CPU中止正在执行的程序而转去处理特殊事件的操作。这些引起中断的事件称为...一般称为硬件中断或外中断,由程序中安排的中断指令INT产生的中断,或由CPU的某些错误结果产生的中断称为软件中断或内中断
    中断是一种使CPU中止正在执行的程序而转去处理特殊事件的操作。这些引起中断的事件称为中断源,它们可能是来自外部设备的输入/输出请求,也可能是计算机的一些异常事故或其它内部原因。由外设控制器或协处理器(8087/80287)引起的中断 一般称为硬件中断或外中断,由程序中安排的中断指令INT产生的中断,或由CPU的某些错误结果产生的中断称为软件中断或内中断。

      8086/8088的中断源如动画所示。图中引线端标示的数字为系统分配的中断类型号。


      连到CPU的非屏蔽中断(NMI)是为电源错、内存或I/O总线的奇偶等异常事件的中断保留的,它不受中断允许标志IF的屏蔽,而且在整个系统中只能有一个非屏蔽中断,其中断类型号为2。

      外部设备的中断是通过Intel 8259A可编程中断控制器(PIC)连到主机上。CPU通过一组I/O端口控制8259A,而8259A则通过INTR管脚给CPU传送中断信号。多个8259A PIC可以树形结构连在一起,从而使大量的外部设备顺序连接到CPU的中断系统上。外部设备和8259A PIC的连法是由设计人员规定好的,这种外中断类型的分配由硬件连线实现,因而软件不能对其修改。动画中外设与8259A PIC的连法是80X86的标准连法。内中断不是由连线接到硬件上的,中断20H到3FH用于调用DOS功能例行程序,其它中断号小于20H或大于3FH的中断,用于调用IBM PC ROM BIOS或一些应用软件,这些内容在以后的章节中将要陆续讲到。

      中断是CPU和外部设备进行输入/输出的有效方法。这种输入/输出方式一直被大多数计算机所采用,它可以避免因反复查询外部设备的状态而浪费时间,从而提高了CPU的效率。

    8.3.1 8086的中断分类

     
    8.3.1.1 软件中断
     
      软件中断又称为内中断,它通常由三种情况引起:
      (1) 由中断指令INT引起。
      (2) 由于CPU的某些错误而引起。
      (3) 为调试程序(DEBUG)设置的中断。
      

      单步是 一种很有用的调试方法。当标志位TF置为1时,每条指令执行后,CPU自动产生类型号为1的中断-单步中断。产生单步中断时,CPU同样自动地将 FLAGS、CS和IP的内容保存入栈,然后清除TF、IF,于是,当进入单步中断处理程序后,就不是处于单步方式了,它将按正常方式运行中断处理程序。 在单步处理程序结束时,原来的FLAGS从堆栈中取回,又把CPU重新置成单步方式。
      
      使用单步中断可以一条指令一条指令地跟踪程序的流程,观察CPU每执行一条指令后,各个寄存器及有关存储单元的变化,从而指出和确定产生错误的原因。

      断点中断也是供DEBUG调试程序使用的,通常调试程序时,把程序按功能分成几段,然后每段设一个断点。当CPU执行到断点时便产生中断,这时程序员可以检查各寄存器及有关存储单元的内容。
      在上述内中断中,INT指令和INTO指令产生的中断,以及除法错中断都不能被禁止,并且比任何外部中断的优先权都高
    1. 中断指令INT引起的内中断
     
        CPU执行完一条INT n指令后,会立即产生中断,并且调用系统中相应的中断处理程序来完成中断功能,中断指令的操作数n指出中断类型号。

      例如,我们要对存储器的容量进行测试,可在程序中安排一条中断指令:
        
         INT 12H
      
      当CPU执行这条指令时,立即产生了一个中断,并从中断向量表的0:48H开始的四个字节单元中取出段地址和偏移地址,然后转去执行相应的中断处理程序以完成对存储器的测试,返回调用程序后,AX寄存器中的数据即为存储器的大小。
      
      INT指令可以指定0~0FFH中的任何类型号。除系统占用的类型号之外,用户还可利用为用户保留的类型号扩充新的中断处理功能。

      2. 处理CPU某些错误的中断
       
       (1) 除法错中断,中断类型号为0。
       在执行除法指令时,若发现除数为0或商超过了寄存器所能表达的范围,则立即产生一个类型为0的中断。

       (2) 溢出中断,中断类型号为4。
       INTO指令专门用来处理溢出中断,下例为测试加法溢出的指令:
       
       ADD AX,VALUE
       INTO

      如果溢出标志OF置1,指令INTO可中断发生溢出的算术操作,如OF为0,则INTO指令不产生中断,CPU继续运行原程序。溢出中断处理程序的主 要功能是打印出一个出错信息,在处理程序结束时,不返回原程序继续运行,而是把控制交给操作系统。

      3. 为调试程序(DEBUG)设置的中断

      (1) 单步中断,中断类型号为1。

      (2) 断点中断,中断类型号为3。
      断点可以设置在程序的任何地方,设置断点实际上是把一条断点指令INT 3插入程序中,CPU每执行到断点处的INT3指令便产生一个中断。

    8.3.1.2 硬件中断

       硬件中断来自处理机的外部条件,如I/O设备或其它处理机等,以完全随机的方式中断现行程序而转向另一处理程序。硬件中断又称为外中断。
      
      硬件中断主要有两种来源,一种是非屏蔽中断(NMI),另一种是来自各种外部设备的中断。由外部设备的请求引起的中断也称为可屏蔽中断。

      微型计算机配置的外部设备一般有硬磁盘(DISK),软磁盘(FLOPPY DISK),显示器(CRT)和各种打印机(LINE PRINTER)等。这些外部设备通过8259A可编程中断控制器和CPU相连,8259A可编程中断控制器可接收来自外设的中断请求信号,并把中断源的中断类型号送CPU,如果CPU响应该外设的中断请求,就自动转入相应的中断处理程序。

      从外设发出中断请求到CPU响应中断,有两个控制条件是起决定性作用的:

      (1) 该外设的中断请求是否屏蔽,这个条件由8259A的中断屏蔽寄存器控制;中断屏蔽寄存器的某位为0表示允许某种外设中断请求,某位为1表示某种外设的中断请求被屏蔽(禁止)。
      (2) CPU是否允许响应中断,这由标志寄存器(FLAG)中的中断允许位IF控制。如果IF=0,CPU就禁止响应任何外设的中断,如果IF=1,则允许CPU响应外设的中断请求。有两条指令能设置和清除IF位。
      STI 设置中断允许位(IF=1)
      CLI 清除中断允许位(IF=0)
    中断屏蔽寄存器的I/O端口地址是21H,它的8位对应控制8个外部设备(见图8.4(a)),通过设置这个寄存器的某位为0或为1来允许或禁止某外部设备的中断。某位为0表示允许某种外设中断请求,某位为1表示某种外设的中断请求被屏蔽(禁止)。
      
      例如,只允许键盘中断,可设置如下中断屏蔽字:
      MOV AL, 11111101B
      OUT 21H, AL
      
      如果系统重要新增设键盘中断,则可用下列指令实现:
      IN AL, 21H
      AND AL, 11111101B
      OUT 21H, AL

      在编写中断程序时,应在主程序的初始化部分设置好中断屏蔽寄存器,以确定允许用中断方式工作的外部设备。

      外部设备向CPU发出中断请求,CPU是否响应还与标志寄存器中的中断标志位IF有关。如果IF=0,CPU就禁止响应任何外设的中断,也就是 说,CPU将不会产生中断来处理外设的请求。如果IF=1,则允许CPU响应外设的中断请求, 允许CPU响应外设的中断请求(IF=1)也叫做开中断,反之叫做关中断(IF=0)。

      我们已经知道,当任何类型的中断发生时,当前的FLAGS要保存入栈,然后清除IF位进入中断处理程序。如果允许在一个中断处理程序的执行过程中发生 硬中断,则必须用一条STI指令开中断。当执行到中断返回指令IRET,又取出FLAGS先前的值,其中IF为1,CPU将允许硬中断再次发生。



    非屏蔽中断 是一种特殊的硬件中断,它和IF标志位无关。非屏蔽中断的类型号为2,CPU不能禁止非屏蔽中断。

      对非屏蔽中断, CPU总会响应的,所以非屏蔽中断主要用于一些紧急的意外处理,如电源掉电等。另外计算机内部的实时钟希望能不停地计时,所以也可以把非屏蔽中断提供给实时钟。

      中断结束命令是由中断命令寄存器中的中断结束位(5位)控制的。当EOI位为1时,当前正在处理的中断请求就被清除。

      结束硬件中断用下面的指令:
      MOV AL, 20H
      OUT 20H, AL
      在一次中断处理结束之前,还应给8259A可编程中断控制器的中断命令寄存器发出中断结束命令 (End Of Interrupt -- EOI)。中断命令寄存器的I/O端口地址为20H(见图8.4(b)),它的各控制位可动态地控制中断处理过程,其中L2-L0三位指定IR0-IR7 中具有最低优先级的中断请求。6位(Set Level)和7位(Rotate)控制IR0-IR7的中断优先级的顺序。5位(EOI)是中断结束位,当EOI位为1时,当前正在处理的中断请求就被 清除,所以在中断处理完成后,必须把中断结束位置为1,否则以后将屏蔽掉对同级中断或低级中断的处理。当然在必要的时候,在中断处理程序中也可利用EOI 命令清除当前的中断请求,使得在中断处理的过程中又能响应同级和低级中断。

          
    图8.4 中断屏蔽寄存器和中断命令寄存器   
     


    8.3.2 中断向量表

      中断向量表是各类型中断处理程序的入口地址表。

      各类型中断处理程序的段地址和偏移地址在中断向量表中按中断类型号顺序存放,因此每类中断向量的地址可由中断类型号乘以4计算出来。

       动画以BIOS中断INT 4AH为例,表示出中断操作的5个步骤:
      (1) 取中断类型号
      (2) 计算中断向量地址
      (3) 取中断向量,偏移地址送IP,段地址送CS
      (4) 转入中断处理程序
      (5) 中断返回到INT指令的下一条指令
    我们给每种中断都安排一个中断类型号。80x86中断系统能处理256种类型的中断,类型号为 0-0FFH。如图8.3所示的中断源,系统时钟的中断类型为08,键盘为09,软中断中的除法错误的中断类型为0,等等。每种类型的中断都由相应的中断 处理程序来处理,中断向量表就是各类型中断处理程序的入口地址表。
     
                  
    图8.5 中断向量表         
             
      我们知道存储器的低1.5K字节,地址从0段0000 ~ 5FFH为系统占用,其中最低的1K字节,地址从0000 ~ 3FFH存放中断向量。中断向量表中的256项中断向量对应256种中断类型,每项占用四个字节,其中两个字节存放中断处理程序的段地址(16位),另两 个字节存放偏移地址(16位)。因为各处理程序的段地址和偏移地址在中断向量表中按中断类型号顺序存放(如图8.5所示),所以每类中断向量的地址可由中 断类型号乘以4计算出来。例如,报警中断的中断类型为4AH,它的中断向量地址为4AH*4=128H,即128H、129H两字节存放的是报警中断处理 程序的偏移地址,12AH、12BH两字节存放的是报警中断处理程序的段地址,取出段地址和偏移地址放入CS和IP,CPU就可以转入相应的中断处理程 序。

      采用向量中断的方法,大大加快了中断处理的速度,因为计算机可直接通过中断向量表转向相应的处理程序,而不需要CPU去逐个检测和确定中断原因。  
    表8.2列出了80X86各类型中断在中断向量表中的地址。
      例8.4 使用DOS功能调用存取中断向量
     
      为中断类型N设置中断向量的程序:
    MOV AX, 0
    MOV ES, AX    ;set to base interrupt vectors
    MOV BX, N * 4   ;offset of type N interrupt
    MOV AX, OFFSET INTHAND
    MOV ES:WORD PTR [BX], AX  ;set addr of INTHAND
    MOV AX, SEG INTHAND
    MOV ES : WORD PTR[BX+2], AX
    ...
    INHAND:  ;interrupt processing routine
    ...
    IRET

       
               表8.2 中断向量表地址分配

    地 址    中断类型号
    0 - 7F     0 - 1F     BIOS中断向量
    80 - FF    20 - 3F    DOS中断向量
    100 - 17F   40 - 5F  扩充BIOS中断向量
    180 - 19F   60 - 67    用户中断向量
    1A0 - 1BF   68 - 6F    保留

    地址    中断类型号
    1C0 - 1DF  70 - 77   I/O设备中断向量
    1E0 - 1FF  78 - 7F    保留
    200 - 3C3  80 - FD    BASIC
    3C4 - 3FF  F1 - FF    保留

       用 户可以利用保留的中断类型号扩充自己需要的中断功能,对新增加的中断功能要在中断向量表中建立相应的中断向量。如果新的中断功能只供自己使用,或用自己编 写的中断处理程序代替系统中的某个中断处理功能时,要注意保存原中断向量。在设置自己的中断向量时,应先保存原中断向量再设置新的中断向量,在程序结束之 前恢复原中断向量。

      实际上,我们在检查或设置任何中断向量时,总是避免直接使用中断向量的绝对地址,而是使用DOS功能调用(21H)存取中断向量。

      存取中断向量的DOS功能调用
     
      
    设置中断向量
        把由AL指定的中断类型的中断向量DS : DX放在中断向量表中
      预置:AH = 25H
         AL = 中断类型号
         DS : DX = 中断向量
      执行:INT 21H

      取中断向量
        把由AL指定的中断类型的中断向量从中断向量表中取到ES : BX中
      预置:AH = 35H
         AL = 中断类型号


      执行:INT 21H
      返回时送:ES : BX = 中断向量


       
    例8.4  
         
    ...
          MOV    AL, N          ;type N interrupt
          MOV    AH, 35H         ;get interrupt vector
          INT    21H
          PUSH    ES            ;save the old base and
          PUSH    BX           ; offset of interrupt N
          PUSH   DS
          MOV    AX, SEG INTHAND
          MOV    DS, AX          ;base of INTHAND in DS
          MOV    DX, OFFSET INTHAND   ;offset in DX
          MOV    AL, N          ;type N
          MOV    AH, 25H        ;set interrupt vector
          INT    21H
          POP    DS
          ...
          POP    DX           ;restore the old offset
          POP    DS           ; and base of interrupt
          MOV    AL, N          ;type N
          MOV    AH, 25H        ;set interrupt vector
          INT    21H
          RET               ;return
         
    ;
     INTHAND: ...                ;interrupt processing routine
          ...
          IRET

    8.3.3 中断过程

      当中断发生时,由中断机构自动完成下列动作:
      1. 取中断类型号N
      2. 标志寄存器(FLAGS)内容入栈
      3. 当前代码段寄存器(CS)内容入栈
      4. 当前指令计数器(IP)内容入栈
      5. 禁止硬件中断和单步中断(IF=0, TF=0)
      6. 从中断向量表中取4*N的字节内容送IP,取4*N+2中的字节内容送CS
      7. 转中断处理程序
     
      中断过程如动画所示

      中断发生的过程很像我们所熟悉的子程序调用,不同的是在保护中断现场时,除了保存返回地址CS:IP之外,还保存了标志寄存器FLAGS的内容。因为 标志寄存器记录了中断发生时,程序指令运行的结果特征,当CPU处理完中断请求返回原程序时,要保证原程序工作的连续性和正确性,所以中断发生时的 FLAGS内容也要保存起来。另一个不同点是,在中断发生时,CPU还自动清除了IF位和TF位,这样设计的目的是使CPU转入中断处理程序后,不允许再 产生新的中断,如果在执行中断处理程序的过程中,还允许外部的中断,可通过STI指令再把IF置为1。

      编写中断处理程序和编写子程序一样,所使用的汇编语言指令没有特殊限制,只是中断程序返回时使用IRET指令。这条指令的工作步骤和中断发生时的工作 步骤正好相反。它首先把IP、CS和FLAGS的内容出栈,然后返回到中断发生时紧接着的下一条指令

    8.3.4 中断优先级和中断嵌套

      1.中断优先级
      8086规定中断的优先级次序为:



      可屏蔽中断的优先权又分为八级,按图8.3的连接,在正常的优先级方式下,定时器的优先级最高,键盘其次,打印机的优先权最低。


     
     在 8086系统中,有软件中断、硬件中断等多个中断源,当多个中断源同时向CPU请求中断时,CPU应如何处理呢?办法是我们给各种中断源事先安排一个中断 优先级次序,当多个中断源同时申请中断时,CPU先比较他们的优先级(Priority),然后从优先级高到优先级低的次序来依次处理各个中断源的中断请 求。

      在8.3节中我们已经提到8259A的中断命令寄存器(图8.4)的6位和7位能控制各中断请求端的优先次序。在正常的优先级方式下,优先级次序是:
      IR0,IR1,IR2,IR3,IR4,IR5,IR6,IR7

      在发出一个EOI命令时,7位(R)和6位(SL)有四种组合,其含义如下:
      R SL
      0  0  正常优先级方式
      0  1  清除由 L2 - L0指定的中断请求
      1  0  各中断优先级依次左循环一个位置
      1  1  各中断优先级依次循环到由L2 - L0指定的中断请求到达最低优先级位置上。

      硬件中断的优先级次序一般在正常优先级方式下(R=0,SL=0),但在必要的情况下,设置中断命令寄存器能改变IR0-IR7的优先级次序,例 如,IR0-IR7原为正常的优先级次序,现在要使IR4成为最低级的中断请求,则给端口20H送命令码:11100100,即 R=1,SL=1,EOI=1,L2L1L0=100,这样,各中断优先级就依次循环到IR4为最低优先级的位置上:
      IR5,IR6,IR7,IR0,IR1,IR2,IR3,IR4,IR5

      如果再送一个命令码:10100000,则优先级次序再向左循环一个位置,成为:
      IR6,IR7,IR0,IR1,IR2,IR3,IR4,IR5

      在下面的描述中,如无特别说明,中断优先级是指正常方式下的中断优先级。



      2.中断嵌套
      中断嵌套是指正在运行的中断处理程序,又被其它中断源中断的情况。

      一个正在执行的中断处理程序,在开中断(IF=1)的情况下,能被优先级高于它的中断源中断,但如果要被同级或低级的中断源中断,则必须发出EOI命令,清除正在执行的中断请求,才能响应同级或低级的中断。


      80X86没有规定中断嵌套的深度(中断程序又被中断的层次),但在实际使用时,多重的中断嵌套要受到堆栈容量的限制,所以在编写中断程序时,一定要考虑有足够的堆栈单元来保存多次中断的断点及各寄存器的内容。

      首先,CPU响应优先级高的IR2,转去处理IR2的中断处理程序。进入IR2处理程序后,IF被置为1。当IR1的中断请求到达后,因IR1的优先 级高于IR2,CPU就立即中断IR2的程序,转去执行IR1的处理程序。在IR1处理程序中,由指令发出了EOI命令,结束了IR1的中断请求。返回 IR2处理程序后,同样由于发出EOI命令清除了IR2的中断请求,所以在较低级的中断请求IR4到达后,即转向处理IR4的中断请求。在IR4处理程序 的执行过程中,IR3的中断请求到达,当判断IF已被置为1,则又中断了IR4的程序,转去执行IR3的程序。在IR3程序中,也发出了开中断指令 (STI)和中断结束命令(EOI),最后IRET指令使其返回到IR4程序,IR4在返回IR2之前也发出了EOI命令,结束了IR4的中断请求。

      IR2中断请求在前面已被清除,所以IR4执行完后,IR2继续执行直到返回主程序。

      中断嵌套举例:
      该动画的例子是在正常优先级方式下,优先级中断和中断嵌套发生时的处理过程。该例子假定在主程序的执行过程中,IR2和IR4的中断请求同时发生, 而后IR1的中断请求又到达,最后IR3的中断请求也到达。

    多级8259A 中断系统:
      硬件中断的扩充使用多级的8259A系统。在多级中断系统中,从属的8259A连接到主8259A的哪一端上,它就具有那一端的中断优先级别,如图8.6所示。


      在图8.6的连接方式下,各中断请求端的优先级排列顺序如下:


      对于主8259A和从属8259A的中断屏蔽寄存器,禁止相应端中断请求的原理和单级8259A是一样的。


    8.3.5 中断处理程序
     
      通过前面几节对中断的介绍,我们对如何编写中断程序已经有一些了解了,现在把它们归纳在一起就更清楚了。

      左面是主程序为响应中断所作的准备工作以及硬件(包括CPU和外设接口)自动完成的动作:


      中断处理程序的编写方法和标准子程序很类似,下面是编写中断处理子程序的步骤,请注意与子程序编写的一些不同之处。

      


      至此,CS和IP寄存器取得了中断处理程序的段地址和偏移地址,CPU就把控制转给中断处理程序。

      这里要注意的是设备发到CPU的中断请求信号在时间上是随机的,只要未被屏蔽的设备本身的状态是准备好或空闲的,它就会向CPU请求中断,如果此时 CPU正在执行一条指令,那么就要等这条指令执行完后,才响应中断。对加封锁的指令(如LOCK MOV AX, BX)应看作为一条指令处理;对加重复前缀的串指令(如REP MOVSB),也要作为一个整体来处理,但不是把串操作全部重复执行完,而是执行一次重复和串指令即可响应中断。对MOV指令和POP指令,如果处理对象 是段寄存器时,那么本条指令执行完后,接着再执行一条指令才响应中断。对开中断指令STI和中断返回指令IRET,也是要在STI或IRET指令执行完 后,再执行一条指令才响应中断。以上是几种特殊情况,对一般指令,只要一条指令的执行周期结束即可响应中断。  

      (1) 保存寄存器内容
      (2) 如允许中断嵌套,则开中断(STI)
      (3) 处理中断
      (4) 关中断 (CLI)
      (5) 送中断结束命令(EOI)给中断命令寄存器
      (6) 恢复寄存器内容
      (7) 返回被中断的程序(IRET)

      进入中断处理程序时,IF和TF已经被清除,这样在执行中断处理程序的过程中,将不再响应其它外设的中断请求,如果这个中断处理程序允许其它设备中 断,则需用STI指令把IF位置1。中断结束命令(EOI)在程序的什么地方发出,这要看程序员是否要求在其处理过程中允许同级或低级中断。一般设备希望 一次中断的处理过程最好是完整的,所以只在中断处理结束之前发出EOI命令。

      处理中断部分是中断处理程序的主体部分,它要完成的任务是各种各样的,这与实际应用有关。如果它的任务是处理某种错误的,一般要求显示输出一系列出错 信息。如果它是对一个I/O设备进行服务的,就按其端口地址接收或发送一个单位(字节或字)的数据。要注意的是CPU产生一次中断,I/O设备只完成一个 字节(或字)的输入/输出,所以中断处理程序所用的指针变量或数据变量一般应设置存储单元来保存。

    8.3.6 中断程序举例

      例8.5 编写一个中断处理程序,要求在主程序运行过程中,每隔10秒响铃一次,同时在屏幕上显示出信息“The bell is ring!”

     在系统定时器(中断类型为8)的中断处理程序中,有一条中断指令 INT 1CH,时钟中断每发生一次(约每秒中断18.2次)都要嵌套调用一次中断类型1CH的处理程序。在ROM BIOS例程中,1CH的处理程序只有一条IRET指令,实际上它并没有做任何工作,只是为用户提供了一个中断类型号。如果用户有某种定时周期性的工作需 要完成,就可以利用系统定时器的中断间隔,用自己设计的处理程序来代替原有的1CH中断程序。

      1CH作为用户使用的中断类型,可能已被其它功能的程序所引用,所以在编写新的中断程序时,应作下述工作:
      (1) 在主程序的初始化部分,先保存当前1CH的中断向量,再置新的中断向量。
      (2) 在主程序的结束部分恢复保存的1CH中断向量。

     
    Purpose: ring and display a message every 10 seconds.
      ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      ;eg8-5.asm
      ;Purpose: ring and display a message every 10 seconds.
      ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

         .model small
    ;-------------------------------------------------------------------------
         .stack
    ;-------------------------------------------------------------------------
         .data
      count   dw   1
      msg    db   'The bell is ringing!', 0dh, 0ah, '$'
    ;-------------------------------------------------------------------------
         .code
    ; Main   program
      main    proc far
      start:
      mov    ax, @data   ;allot data segment
      mov    ds, ax

    ; save old interrupt vector
      mov    al, 1ch    ;al<=vector number
      mov    ah, 35h    ;to get interrupt vector
      int    21h      ;call DOS
      push   es       ;save registers for restore
      push   bx
      push   ds

    ;set new interrupt vector
      mov    dx, offset ring  ;dx<=offset of procedure ring
      mov    ax, seg ring    ;ax<=segment of procedure ring
      mov    ds, ax       ;ds<=ax
      mov    al, 1ch      ;al<=vector#
      mov    ah, 25h      ;to set interrupt vector
      int    21h        ;call DOS

      pop ds            ;restore ds
      in     al, 21h      ;set interrupt mask bits
      and    al, 11111110b
      out    21h, al
      sti

       mov    di, 20000
    delay: mov si, 30000
    delay1:dec si
       jnz    delay1
       dec   di
       jnz   delay

    ;restore old interrupt vector
       pop    dx        ;restore registers
       pop    ds
       mov   al, 1ch      ;al<=vector#
       mov    ah, 25h      ;to restore interrupt
       int   21h        ;call DOS

       mov    ax, 4c00h     ;exit
       int   21h
    main endp


    ring proc   near
       push   ds         ;save the working registers
       push   ax
       push   cx
       push   dx

       mov    ax, @data     ;allot data segment
       mov    ds, ax
       sti


    ;siren if it is time for ring
      dec    count       ;count for ring interval
      jnz    exit        ;exit if not for ring time

      mov    dx, offset msg   ;dx<=offset of msg
      mov    ah, 09h      ;to display msg
      int    21h        ;call DOS

      mov    dx, 100      ;dx<=turn on/off times(100)
      in     al, 61h      ;get port 61h
      and    al, 0fch      ;mask bits 0,1


    sound:
      xor    al, 02       ;toggle bit 1
      out    61h, al      ;output to port 61h
      
    mov    cx, 1400h     ;value of wait

    wait1:
      loop   wait1
      dec    dx        ;control turn on/off 10 times
      jne    sound
      mov    count, 182    ;control ring interval delay(10s)


    exit:
      cli
      mov    al,20h      ;set EOI
      mov    20h,al
      pop    dx        ;restore the reg.
      pop    cx
      pop    ax
      pop    ds
      iret            ;interrupt return
    ring endp

    ;-------------------------------------------------------------------------
      end start          ;end assemble

    例8.6 在配置了键盘输入(中断类型09)和打印机输出(中断类型0FH)两种外部设备的8086中断系统中,要求从键盘上接收字符,同时对32字节的输入缓冲区进行测试,如果缓冲区已满,则键盘挂起(禁止键盘中断输入),由打印机输出一个提示信息。

      键盘和打印机分别由中断屏蔽寄存器(21H)的1位和7位控制。键盘的输入寄存器端口地址为60H,控制寄存器的端口地址为61H。打印机输出寄存器的端口地址为378H,打印机控制寄存器的端口地址为37AH。

      在这种特定情况下,只要求打印机在键盘输入缓冲区满了后,打印出提示信息,因此它可以在屏蔽键盘中断的同时,设置打印机的中断屏蔽位。另外,在中断处 理程序中用到的一些指针及计数值要保存在指定的存储单元中,每次进入中断,取出指针及计数值,退出中断时,再把修改后的指针及计数值保存起来。


      这个中断程序包括以下几部分:
      MAIN 初始化部分,保存09和0FH的原中断向量,设置新的中断向量。主程序用有限循环来模拟。主程序结束时,恢复原中断向量。
      KBDINT 键盘中断处理程序。接收按键的扫描码并保存在缓冲区中,如果输入的字符数超过32,则屏蔽键盘中断,允许打印机中断,并调用INIT-PRT子程序初始化打印机。
      INIT-PRT初始化打印机,启动适配器,发出选通信号。
      PRTINT 打印机中断处理程序。按照指针取出打印机字符送到输出寄存器,发出选通信号。
      DISPLAY-HEX 用十六进制显示AL中的代码。

    Purpose: accept keyboard input and print messages on the printer 
      ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      ;eg8-6.asm
      ;Purpose: accept keyboard input and print messages on the printer
      ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


         .model tiny
    ;-------------------------------------------------------------------------
         .stack
    ;-------------------------------------------------------------------------
         .data
      old_ip09   dw ?
      old_cs09    dw ?
      old_ip0f   dw ?
      old_cs0f    dw ?
      count     dw ?
      buffer     db 20h dup(' ')
      buf_p     dw ?
      start_msg   db 0ah, 0dh, 'RUN', 0ah, 0dh, '$'
      end_msg    db 0ah, 0dh, 'END', 0ah, 0dh, '$'
      full_msg    db 0ah, 0dh, 'Buffer full!$'

    ;-------------------------------------------------------------------------
         .code
    ; Main   program
      main    proc far
    start:
      mov    ax, @data           ;ds<=data segment
      mov    ds, ax

    ; initialize
      lea    ax, buffer          ;buf_p<=buffer address
      mov    buf_p, ax
      mov    count, 0           ;count<=0

    ; save old interrupt 09h
      mov    al, 09h            ;al<=vector#
      mov    ah, 35h            ;to get interrupt vector
      int    21h              ;call DOS
      mov    old_cs09, es          ;save registers for restore
      mov    old_ip09, bx
      push    ds               ;save ds


    ;set new interrupt 09h
      lea    dx, kbdint           ;dx<=offset of procedure kbdint
      mov    ax, seg kbdint        ;ax<=segment of procedure kbdint
      mov    ds, ax            ;ds<=ax
      mov    al, 09h            ;al<=intrrupt number
      mov    ah, 25h            ;to set interrupt vector
      int    21h              ;call DOS
      pop    ds               ;restore ds

    ;set keyboard interrupt mask bits
      in     al, 21h
      and    al, 0fdh
      out    21h, al

    ;save old interrupt 0fh
      mov    al, 0fh            ;al<=vector#
      mov    ah, 35h            ;to get interrupt vector
      int    21h               ;call DOS
      mov    old_cs0f, es          ;save registers for restore
      mov    old_ip0f, bx
      push    ds               ;save ds

    ;set new interrupt 0fh
      lea    dx, prtint           ;dx<=offset of procedure prtint
      mov    ax, seg prtint         ;ax<=segment of procedure prtint
      mov    ds, ax            ;ds<=ax
      mov    al, 0fh            ;al<=vector#
     
      mov    ah, 25h            ;to set interrupt vector
      int    21h              ;call DOS
      pop    ds              ;restore ds

      mov    ah, 09h            ;print start message
      lea    dx, start_msg
      int    21h
      
      sti
      mov    di,20000            ;main process
    mainp: mov   si,30000
    mainp1:dec  si
      jnz    mainp1
      dec    di
      jnz    mainp

      mov    ah, 09h            ;print end msg of main process
      lea    dx, end_msg
      int    21h

      cli
    ;restore old interrupt 09h
      push    ds              ;save ds
      mov    dx, old_ip09          ;ds:dx<=old handler address
      mov    ax, old_cs09
      mov    ds, ax
      mov    al, 09h            ;al<=vector#
      mov    ah, 25h            ;to restore interrupt vector
      int    21h              ;call DOS
      pop    ds               ;restore ds

    ; restore old interrupt 0fh
      push   ds               ;save ds
      mov    dx, old_ip0f          ;ds:dx<=old address
      mov    ax, old_cs0f
      mov    ds, ax
      mov    al, 0fh            ;al<=vector#
      mov    ah, 25h            ;to restore interrupt
      int    21h              ;call DOS
      pop    ds              ;restore ds

    ; enable keyboard interrupt
      in    al, 21h
      and    al, 0fdh

    ; enable keyboard interrupt
      in     al, 21h
      and    al, 0fdh
      out    21h, al

      sti
      mov   ax, 4c00h
      int   21h
    main endp


    ;-----------------------------------------------------
    ; Interrupt Handler kbd
    ;  Purpose: fill buffer until full when substituted for interrupt 09h
      kbdint proc near
      push   ax            ; save registers

      push   bx

      cld                ;direction: forward
      in    al, 60h         ;read a character
      push   ax            ;save it
      in    al, 61h          ;get the control port
      mov    ah, al          ;save the value in ah
      or    al, 80h          ;reset bits for kbd
      out    61h, al         ;send out
      xchg   ah, al          ;restore control value
      out    61h, al          ;kdb has been reset

      pop   ax            ;restore scan code
      test   al, 80h          ;press or release?
      jnz    return1         ;ignore when release

      mov    bx, buf_p        ;bx<=buffer pointer
      mov    [bx], al         ;store in buffer
      call   display_hex        ;display in hex
      inc    bx            ;move pointer
      inc    count          ;count characters
      mov    buf_p, bx        ;save the pointer

    check:
      cmp    count, 20h ;judge whether full
      jb    return1
      in    al, 21h
      or    al, 02          ;mask kdb bits
      and   al, 7fh         ;enable prt bits
      out   21h, al
      call   init_prt         ;initiate printer

    return1:
      cli
      mov   al, 20h         ;end of interrupt
      out    20h, al

    ;restore registers
      pop   bx
      pop   ax
      iret               ;interrupt return
    kbdint endp

    ;------------------------------------------------------------------------

    ; Interrupt Handler prtint
    ; Purpose: print characters when substituted for interrupt 0fh
      prtint proc near
      push   ax            ;save registers
      push   bx
      push   dx

      mov    bx, buf_p        ;bx<=buffer pointer
      mov    al, [bx]         ;get from buffer
      mov    dx, 378h         ;printer data port
      out    dx, al          ;output a character

      push   ax            ;save ax
      mov    dx, 37ah         ;printer control port
      mov    al, 1dh          ;al<=control code
      out    dx, al          ;send out
      jmp    $+2           ;slight delay
      mov    al, 1ch          ;al<=control code
      out    dx, al          ;send out
      pop    ax            ;restore ax

      inc    bx            ;move pointer
      mov    buf_p, bx        ;save the pointer
      cmp    al, 0ah         ;end of message?
      jnz    return2
      in     al, 21h         ;disable printer
      or    al, 80h         ; interrupt
      out    21h, al

    return2:
      mov    al, 20h         ;end of interrupt
      out    20h, al

      pop    dx            ;restore registers
      pop    bx
      pop    ax
      iret                ;interrupt return
    prtint endp

    ;------------------------------------------------------------------------

    ; Procedure init_prt
      init_prt proc near
      push    ax            ;save registers
      push   bx
      push   dx

      cli
      lea    bx, full_msg       ;bx<=offset of full_msg
      mov    buf_p, bx         ;save full_msg address

      mov    dx, 378h         ;printer data port
      mov    al, 0dh         ;CR
      out    dx, al          ;output a character

      mov    dx, 37ah         ;printer control port
      mov    al, 1dh         ;al<=control code
      out    dx, al          ;send out
      jmp    $+2            ;slight delay
      mov    al, 1ch          ;al<=control code
      out    dx, al          ;send out

      pop    dx            ;restore registers
      pop    bx
      pop    ax

      ret
    init_prt endp
    ;------------------------------------------------------------------------


    display_hex proc   near       ;display char with hex
        push     ax 
        push     cx
        push     dx
        mov     ch, 2       ;number of digits
        mov      cl, 4
    nextb:
        rol      al, cl      ;highest of bits to lowest
        push     ax
        mov     dl, al
        and     dl, 0fh     ;mask off left digit

       or      dl, 30h     ;convert to ASCII
        cmp     dl, 3ah
        jl      dispit
        add      dl,7h       ;digit is A to F

    dispit:
        mov      ah, 2       ;display character
        int     21h
        pop     ax
        dec      ch        ;done 2 digits?
        jnz      nextb      ;not yet
        mov      ah, 2
        mov     dl,','      ;display ','
        int      21h
        pop      dx
        pop     cx
        pop      ax
        ret              ;return from display_hex
    display_hex endp

    ;------------------------------------------------------------------------
        end start



    例8.7 除数为0时的软件中断(类型0)处理程序
      此程序分成两个主要部分:初始化部分和中断处理部分。


      初始化部分(Init)设置新的0型中断向量,显示一条信息,然后完成终止和驻留后退出程序。这种特殊的退出是用INT 21H的功能31H,它将保留程序所占的内存,从而使这些内存单元不被以后的应用程序破坏。

      中断处理程序(Zdiv)在发生一个被零除中断时接收控制。中断处理程序先保存有关寄存器的值,然后打印出信息询问用户是退出程序(Quit)还是继 续(Continue)。若键入"C"要求继续执行程序,则处理程序恢复所有寄存器并执行IRET返回主程序(显示一个标记符#),当然此时除法的操作结 果应是无效的。若键入"Q"要求退出,则从处理程序直接返回DOS(无标记符显示)。这里返回DOS,是用INT 21H的功能4CH,该功能是唯一不依赖于任何段寄存器内容的终止功能,例如,CS寄存器不必指向PSP所在的段。该功能的另一个优点是能在AL中返回一 个表明程序是否正常终止的出口代码。系统出口代码的含义为:00 - 正常终止;01 - 用Ctrl-C终止;02 - 严重设备错误引起终止;03 - 用功能调用31H终止。左侧是处理除数为0错误的中断处理程序清单。

    Purpose: zero_division handler  
      ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      ;eg8-7.asm
      ;Purpose: zero_division handler
      ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


         .model small
    ;-------------------------------------------------------------------------
         .stack
    ;-------------------------------------------------------------------------
         .code
    ; Main program
    main    proc   near
    ;reset  interrupt  vector 0
          lea   dx, zdiv    ;set interrupt vector
          mov   ax, seg zdiv
          mov   ds, ax
          mov   al, 0     ;interrupt number
          mov   ah, 25h     ;to reset interrupt vector
          int   21h       ;call DOS

    ;print introduction message
          mov   ax, @code    ;ds<=code segment
          mov   ds, ax
          mov   dx, ok_msg   ;print introduction
          mov   ah, 9
          int   21h

    ;simulate zero_division condition
          mov   ax, 1
          mov   dl, 0
          div   dl

    ; display '# 'after return from interrupt handler zdiv
          mov   ah, 2      ;to display a character
          mov   dl, '#'     ;dl<='#'
          int   21h       ;call DOS

    ;exit and reside in memory
          mov   ah, 31h     ;to exit and reside
          mov   al, 0     ;return code: 0
          mov   dx, ((prog_len+15)/16)+16   ;dx<=memory paragraph

    ; for residence
          int   21h      ;call DOS
    main endp





    ;-------------------------------------------------------------------------
    ; Interrupt Handler zdiv
    zdiv   proc   far
         push   ax    ;save registers
         push   bx
         push   cx
         push   dx
         push   si
         push   di
         push   bp
         push   ds
         push   es
         sti

    prt_warn:
         mov   ax, @code
         mov   ds, ax
         mov   dx, offset warn_msg   ;print warning
         mov   ah, 9
         int   21h


    input:
         mov   ah, 1           ;to accept keyboard input
         int    21h           ;call DOS
         cmp    al, 'c'          ;judge whether 'c'
         je    continue
         cmp    al, 'q'         ;judege whether 'q'
         je    exit

         mov    dx, offset beep      ;beep when illegal input
         mov    ah, 09
         int    21h
         jmp   prt_warn


    exit:
         mov    ax, 4cffh
         int    21h
    continue:
         mov    dx, offset crlf      ;print CR & LF
         mov    ah, 09
         int   21h
         cli


         pop    es            ;restore registers
         pop    ds
         pop    bp
         pop   di
         pop   si
         pop   dx
         pop   cx
         pop   bx
         pop    ax
         iret               ;interrupt return
    zdiv   endp

    ;------------------------------------------------------------------------

    ; Data area
    ok_msg  db 0dh, 0ah, 'Zero-division Handler installed!'
         db 0dh, 0ah, '$'
    warn_msg db 'Zero-division detected, ', 07h
         db 'Continue or Quit(c/q)?$'
    beep   db 07h, '$'
    crlf   db 0dh, 0ah, '$'
    prog_len equ $-main


    ;------------------------------------------------------------------------
         end main

    【本章小结】

     
    1. 程序直接控制I/O的方式:
      这是一种使用I/O指令直接在端口级上进行数据传送的编程方式,这种方式有时需要查询外设的状态,如果外设处于准备好或空闲状态,则CPU通过接口中 的数据寄存器进行输入或输出,如果外设没有准备好或是忙状态,CPU就查询等待,不再作有效的工作。

      2. 中断程序的设计方法:
      对于要求以中断方式工作的I/O设备,它们的中断类型已由硬件连线确定(如图8.3)。主程序为中断所做的准备工作如下:
      (1) 保存原中断向量(INT 21H的35H功能),设置新的中断向量(INT 21H的25H功能);
      (2) 设置设备的中断屏蔽位(仅对可屏蔽中断);
      (3) 设置CPU的中断允许位(开中断);
      (4) 在主程序结束前,恢复原中断向量。

      主程序完成了上述准备工作后,I/O设备即以完全随机的方式产生中断。当CPU响应了中断请求,中断系统将自动完成以下工作:
      (1) CPU接收外设的中断类型号;
      (2) 当前的FLAGS、CS、IP的内容入栈保存;
      (3) 清除IF、TF;
      (4) 根据中断类型号取出中断向量送CS和IP;
      (5) 转中断处理子程序。

      中断处理子程序的编写方法:
      (1)保存工作寄存器内容;
      (2)如允许中断嵌套,则开中断(STI);
      (3)处理中断任务;
      (4)关中断 (CLI);
      (5)送中断结束命令(EOI)给中断命令寄存器(仅对硬件中断);
      (6)恢复工作寄存器内容;
      (7)返回被中断的程序(IRET)。

    <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
    阅读(1458) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~
    评论热议
    展开全文
  • 输入输出中断时当外部设备或通道操作正常结束或发生某种错误时发生的中断。例如:I/O传输出错、I/O传输结束等。 2、 外中断 对某中央处理机而言,他的外部通道式装置所引起的中断称为外部中断。 例如:时钟中断...

    按中断功能分类:

    1、 输入输出中断

    • 输入输出中断时当外部设备或通道操作正常结束或发生某种错误时发生的中断。例如:I/O传输出错、I/O传输结束等。

    2、 外中断

    • 对某中央处理机而言,他的外部非通道式装置所引起的中断称为外部中断。

    例如:时钟中断、操作员控制台中断、多机系统中CPU到CPU的通信中断。

    3、 机器故障中断

    • 当机器发生故障时所产生的中断叫硬件故障中断。例如:电源故障、通道与主存交换信息是主存储错、从主存取指令出错、取数据错、长线传输时的奇偶校验错等。

    4、程序性中断

    • 在现行程序执行过程中,发现了程序性的错误或出现了某些程序的特定状态而产生的中断称为程序性中断。这些程序性错误有定点溢出、十进制溢出、十进制数错、地址错、用户态下用核态指令、越界、非法操作等。程序的特定状态包括逐条指令跟踪、指令地址符合跟踪、转态跟踪、监视等。

    5、访管中断

    • 对操作系统提出某种需求(如请求I/O传输、建立进程等)时所发出的中断称为访管中断。

    补充:

    一般中断按功能、中断方式、终端来源分类

    按中断方式分类

    1、强迫性中断

    2、自愿中断

    按中断来源分类

    1、中断

    2、俘获

    展开全文
  • ubuntu 解决非正常关闭apt-get的锁

    千次阅读 2017-10-13 14:48:48
    E: 无法锁定管理目录(/var/lib/dpkg/),是否其他进程正占用它? 我们执行如下命令, 删除锁定的文件 $ sudo rm -rf /var/cache/apt/archives/lock $ sudo rm -rf /var/lib/dpkg/lock 此时, 我们...
  • 检查非正常断开的tcp连接

    万次阅读 2011-01-18 16:54:00
    连接的对端非正常关闭,这包括对端设备掉电,程序崩溃,网络被中断等.这种情况是不能也无法通知对端的,所以连接会一直存在,浪费国家的资源.tcp协议栈个keepalive的属性,可以主动探测socket是否可用,不过这个属性的...
  • 每个中断状态位,每个中断/事件都独立的触发和屏蔽设置。 STM32F407的22个外部中断为: EXTI线0~15:对应外部IO口的输入中断。 EXTI线16:连接到PVD输出。 EXTI线17:连接到RTC闹钟事件。
  • Linux 中断中断处理浅析

    万次阅读 多人点赞 2019-01-17 14:15:09
    中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的 CPU 暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序。...
  • 在一次非正常关机,即没有关闭服务(例如断电等)就关机,重启Hadoop成功,但是重启HBase后,HMaster和HRegionServer重启失败 注 :此时的现象是,执行完start-hbase.sh后马上jps,是能看能这两个进程的,但是过一会...
  • linux中断编程、中断基础介绍

    千次阅读 2017-11-16 19:47:23
    中断基础介绍中断就是CPU正常运行期间,由于内、外部事件引起的CPU暂时停止正在运行的程序,去执行该内部事件或外部事件的引起的服务中去,服务执行完毕后再返回断点处继续执行的情形。中断的意义极大提高CPU运行...
  • 这篇博文记录一个VMWare虚拟机非正常关闭后无法启动的解决方案。 我们中心的网站部署在一个Windows XP的虚拟机上,但是由于电源问题,那台虚拟机所在的实体物理机总是重启,时候就会导致虚拟机系统还没有正常...
  • STM32的中断和事件

    万次阅读 2017-07-12 18:53:36
    1. 中断和异常的区别1.1 中断是指系统停止当前正在运行的程序转而其他服务,可能是程序接收了比自身高优先级的请求,或者是人为设置中断中断属于正常现象。 1.2 异常是指由于cpu本身故障、程序故障或者请求服务...
  • 中断详解

    千次阅读 2018-10-24 01:28:04
    1.中断的基本概念 程序中断是指在计算机执行现行程序的过场中,出现某些急需处理的异常情况或特殊请求,CPU暂停中断现行程序,而专区对这些异常情况或特殊情况进行处理,在处理完毕后CPU又自动返回到现行程序的断点...
  • linux中断--中断嵌套&中断请求丢失

    千次阅读 2014-04-14 20:06:04
    在linux内核里,如果驱动在申请注册中断的时候没有特别的指定,do_irq在做中断响应的时候,是开启中断的,如果在驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被...
  • 首先,要明确什么叫“非中断保存”。熟悉Fragment的开发人员都知道,Fragment是依附于Activity的。当Activity销毁时,Fragment会随之销毁。而当Activity配置发生改变(如屏幕旋转)时候,旧的Activity会被销毁,然后...
  • 连接的对端非正常关闭,这包括对端设备掉电,程序崩溃,网络被中断等.这种情况是不能也无法通知对端的,所以连接会一直存在,浪费国家的资源. tcp协议栈个keepalive的属性,可以主动探测socket是否可用,不过这个...
  • 多线程中断机制

    万次阅读 热门讨论 2017-08-18 12:02:55
    一个线程在未正常结束之前, 被强制终止是很危险的事情. 因为它可能带来完全预料不到的严重后果,比如会带着自己所持有的锁而永远的休眠,迟迟不归还锁等。 在当前的api中,Thread.suspend、Thread.stop等方法都被...
  • 首先看下 UTF-8 编码 C2 A0 代表的含义:https://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=dec 翻译过来就是:半角非中断空格 这是什么鬼? 长这样,你看到了吗?我没看到
  • 向量中断就是不同的中断有不同的入口地址(类似于51中的中断,不同的中断对应着不同的入口地址),向量中断就只有一个入口地址(中断地址),进去了再进行判断,通过中断标志来识别具体是哪个中断。向量中断实时性...
  • UBUNTU 解决非正常关闭APT-GET的锁

    千次阅读 2017-05-26 12:48:08
    在ubuntu的命令行窗口中使用apt-get命令安装程序, 命令未执行完的情况下关闭窗口或使用Ctrl+C来结束命令。...E: 无法锁定管理目录(/var/lib/dpkg/),是否其他进程正占用它? 我们执行如下命令, 删
  • 中断中断处理程序

    千次阅读 2013-11-02 00:58:20
    在学习网络接口驱动的时候,已经接触过中断中断处理程序了,这里在具体的说一说有关中断中断处理程序的相关知识点. ...比如说,当敲打键盘时,键盘控制器会发送一个中断,通知os健按下. 中断本质上来
  • linux中断--内核中断编程

    千次阅读 2014-04-14 19:24:44
    Linux中断内核编程 前言 在前面分析了中断的基本原理后,就可以写一个内核中断程序来体验以下,也可以借此程序继续深入来了解内核中断的执行过程 一.内核中断程序: 我们还是来看一看成程序: 在看程序之前,要熟悉...
  • 处理控制台程序的正确退出操作,命令行参数的获取和使用。
  • 7.4.2 程序中断方式

    千次阅读 2016-09-22 17:21:05
    1.中断的基本概念 程序中断是指在计算机执行现行程序的过场中,出现某些急需处理的异常情况或特殊请求,CPU暂停中断现行程序,而专区对这些异常情况或特殊情况进行处理,在处理完毕后CPU又自动返回到现行程序的断点...
  • ARM Linux中断机制分析

    万次阅读 2013-02-21 14:46:04
    ARM Linux中断机制分析 ——以用户模式产生irq中断为例 以下代码基于内核linux2.6.38.3(trimslice官网下载) 本文主要分析ARM发生中断时的处理流程,以在usr态发生IRQ为例,即usr—>irq为例讨论。       1.内核...
  • linux中断--中断原理分析

    千次阅读 2014-04-14 18:48:28
    中断之原理篇 前言: 中断是计算机发展中一个重要的技术,它的出现很大程度上解放了CPU,提高了CPU的执行效率。 在中断出现之前,CPU对IO采用的是轮询的方式进行服务,这使的CPU纠结在某一个IO上,一直在等待它的...
  • 中断处理

    千次阅读 2012-05-07 20:29:02
    16. 中断处理 上一页     下一页 16. 中断处理 16.1. 概述 对于中断和异常的定义在ULK中的第4章中给予了非常明确的定义。中断通常分为同步中断和异步中断: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 134,674
精华内容 53,869
关键字:

属于非正常中断的有