内中断的产生

当CPU的内部有什么事情发生的时候,将产生需要马上处理的中断信息呢?对于8086CPU,当CPU内部有下面的情况发生的时候,将产生相应的中断信息。

  • 除法错误,比如,执行div指令产生的除法溢出:
  • 单步执行:
  • 执行into指令:
  • 执行int指令。

    中断处理程序

    CPU在收到中断信息后,应该转去执行该中断信息的处理程序。我们知道,若要8086CPU执行某处的程序,就要将CS:IP指向它的入口(即程序第一条指令的地址)。可见首要的问题是,CPU在收到中断信息后,如何根据中断信息确定其处理程序的入口。CPU的设计者必须在中断信息和其处理程序的入口地址之间建立某种联系,使得CPU根据中断信息可以找到要执行的处理程序。

    中断向量表

  • 中断向量表,就是中断程序入口地址的列表
  • 中断向量表在内存中存放,其中包含256个中断程序所对应的入口

    中断过程

    CPU收到中断信息后,要对中断信息进行处理,首先将引发中断过程。硬件在完成中断过程后,CS:P将指向中断处理程序的入口,CPU开始执行中断处理程序。

    有一个问题需要考虑,CPU在执行完中断处理程序后,应该返回原来的执行点继续执行下面的指令。所以在中断过程中,在设置CS:P之前,还要将原来的CS和P的值保存起来。在使用cl指令调用子程序时有同样的问题,子程序执行后还要返回到原来的执行点继续执行,所以,call指令先保存当前CS和IP的值,然后再设置CS和P。

  1. 取得中断类型码
  2. 标志寄存器的值入栈(中断过程会改变标志,所以先保存原来的值)
  3. 设置标志寄存器的第八位TF(陷阱标志)和第九位IF(中断标志)为零

    设置TF = 0很重要,否则不停产生单步中断不断循环,TF置为0不允许单步中断了

  4. cs内容入栈,ip内容入栈
  5. 从内存地址为中断类型码 4和中断类型码 4+2的两个字单元中读取中断处理程序的入口地址设置IP和CS。

    中断程序和iret指令

    常规步骤:
  • 保存用到的寄存器
  • 处理中断
  • 恢复寄存器
  • 用iret返回

    入栈顺序为:标志寄存器、CS、IP
    出栈顺序为:IP、CS、标志寄存器

    除法错误中断

    1
    2
    3
    mov ax,1000h
    mov bh,1
    div bh
  • 显示提示信息“Divide overflow”,并返回操作系统编写中断处理
  • 设置es:di指向目的地址
  • 设置ds:si指向源地址
  • 设置cx的值
  • 设置传输方向(std为逆向,cld为正向)
  • rep movsb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    mov ax,cs
    mov ds,ax
    mov si,offset do0 ;设置es:di指向目的地址

    mov ax,0
    mov es,ax
    mov di,200h ;设置ds:si指向源地址

    mov cx,offset do0end-offset do0 ;设置cx的值为传输长度(-)减号

    cld ;设置传输方向(std为逆向,cld为正向)

    rep movsb

    int指令

    int指令格式: int n,n为中断类型码,引发中断过程
    cpu执行int指令的过程:
  1. 取中断类型码n
  2. 标志寄存器入栈,IF=0,TF=0
  3. CS,IP入栈
  4. IP=(N 4),CS=(N 4+2)
    例如
    1
    2
    3
    4
    mov ax,0b800h		;电脑显存的地址
    mov ex,ax
    mov byte ptr es:[12*160+40*2] ;显示在中间位置

    端口

    从CPU的角度,将这些寄存器都当作端口,对它们进行统一编址,从而建立了一个统一的端口地址空间。每一个端口在地址空间中都有一个地址。
    CPU可以直接读写以下3个地方的数据。
  5. CPU内部的寄存器:
  6. 内存单元:
  7. 端口。

    端口的读写

    在访问端口的时候,CPU通过端口地址来定位端口。因为端口所在的芯片和CPU通过总线相连,所以,端口地址和内存地址一样,通过地址总线来传送。在PC系统中,CPU最多可以定位64KB个不同的端口。则端口地址的范围为0~65535。
    对端口的读写不能用movpushpop等内存读写指令。端口的读写指令只有两条:inout,分别用于从端口读取数据和往端口写入数据。
    访问内存与端口比较
  • 访问内存
    1
    mov ax,ds:[8]
  1. cpu通过地址线将地址信息8发出
  2. cpu通过控制线发出内存读命令,选择存储器芯片并通知他,将要从中读取数据
  3. 储存器将8号单元中的数据通过数据线送入cpu
  • 访问端口
    1
    in al,60h
  1. cpu通过地址线将地址信息60发出
  2. cpu通过控制线发出端口读命令,选择端口所在的芯片并通知他,将要从中读取数据
  3. 端口所在的芯片将8号单元中的数据通过数据线送入cpu
    :::warning
    inout指令中,只能用ax或al来存放端口读入的数据或要发送到端口的数据
    :::

    CMOS RAM芯片

  4. 包含一个实时钟和一个有128个存储单元的RAM存储器(早期的计算机为64个字节)。
  5. 该芯片靠电池供电。所以,关机后其内部的实时钟仍可正常工作,RAM中的信息不丢失。
  6. 128个字节的RAM中,内部实时钟占用0~ 0dh单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时BIOS程序读取。BIOS也提供了相关的程序,使我们开机的时候配置CMOS的系统信息
  7. 该芯片内部有两个端口,端口地址为70h和71h。CPU通过这两个端口来读写CMOS RAM.
  8. 70h为地址端口,存放要访问的CMOS RAM单元的地址;71h为数据端口,存放从选定的CMOS RAM单元中读取的数据,或要写入到其中的数据。可见,CPU对CMOS RAM的读写分两步进行,
    比如,读CMOS RAM的2号单元:
    ①将2送入端口70h;
    ②从端口71h读出2号单元的内容。

    shl和shr指令

    shl(逻辑左移)
  9. 将一个寄存器或内存单元中的数据向左移位;
  10. 将最后移出的一位写入CF中;
  11. 最低位用0补充。
    1
    2
    3
    mov al,10000010B;
    shl al,1 ;将al的数据向左移一位
    (al)=00000010B,ZF=1 ;将移出的写入zf中低位用零补充

    如果执行的次数大于1,则次数要放入cl中

    1
    2
    3
    4
    mov al,10001000B
    mov cl,3
    shl al,cl
    执行后(al)=01000000B,ZF=0
    :::
    shr(逻辑右移)
    它和shl所进行的操作刚好相反。
  12. 将一个寄存器或内存单元中的数据向右移位:
  13. 将最后移出的一位写入CF中;
  14. 最高位用0补充。
    1
    2
    3
    mov al,10000010B;
    shr al,1 ;将al的数据向左移一位
    (al)=01000001B,ZF=0 ;将移出的写入zf中高位用零补充
    :::warning no-icon
    如果执行的次数大于1,则次数要放入cl中
    1
    2
    3
    4
    mov al,10001100B
    mov cl,3
    shr al,cl
    执行后(al)=00010001B,ZF=1
    :::

    CNOS RAM存储时间

    在CMOS RAM中,存放着当前的时间:年、月、日、时、分、秒。这6个信息的长
    度都为1个字节,存放单元为:
    秒:0 分:2 时:4 日:7 月:8 年:9
    这些数据以BCD码的方式存放。
    在屏幕中间显示月份
    1
    2
    3
    mov al,8
    out 70h,8 ;读取内存8号的数据
    in al,71h ;显示内存8号的数据

    外中断

    外中断源有两类
    :::info no-icno
    可屏蔽中断
    :::
    可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF位的设置。当CPU检测到可屏蔽中断信息时,如果IF=1,则CPU在执行完当前指令后响应中断,引发中断过程;如果IF=0,则不响应可屏蔽中断。
    我们回忆一下内中断所引发的中断过程:
  15. 取中断类型码n;
  16. 标志寄存器入栈,IF=0,TF=0:
  17. CS、IP入栈;
  18. (IP)=(n 4),(CS)=(n 4+2)
    可屏蔽中断所引发的中断过程,除在第1步的实现上有所不同外,基本上和内中断的中断过程相同。因为可屏蔽中断信息来自于==CPU外部==,中断类型码是通过[数据总线送入CPU]{.yellow}的;
    而内中断的中断类型码是在[CPU内部产生的]{.yellow}。
    现在,我们可以解释中断过程中将IF置为0的原因了。将IF置0的原因就是,在进入中断处理程序后,禁止其他的可屏蔽中断。当然,如果在中断处理程序中需要处理可屏蔽中断,可以用指令将IF置1.8086CPU提供的设置F的指令如下:
    1
    2
    sti  ,设置IF=1;
    cli ,设置IF=0。
    :::info no-icno
    不可屏蔽中断
    :::
    不可屏蔽中断是CPU==必须响应==的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。则不可屏蔽中断的中断过程为:
  19. 标志寄存器入栈,IF=0,T℉=0:
  20. CS、IP入栈;
  21. (P)=(8),(CS)=(0AHD。
    几乎所有由外设引发的外中断,都是可屏蔽中断。当外设有需要处理的事件(比如说键盘输入)发生时,相关芯片向CPU发出可屏蔽中断信息。不可屏蔽中断是在系统中有必须处理的紧急情况发生时用来通知CPU的中断信息。

    接口芯片和端口

    外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。CPU还可以向外设输出控制命令,而这些控制命令也是先送到相关芯片的端口中,然后再由相关的芯片根据命令对外设实施控制。可见,[CPU通过端口和外部设备进行联系。]{.yellow}

    键盘的处理过程

    按下一个键时,开关接通,该芯片就产生一个[扫描码]{.blue},扫描码说明了按下的键在键盘上的位置。扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h。松开按下的键时,也产生一个扫描码,扫描码说明了松开的键在键盘上的位置。松开按键时产生的扫描码也被送入60h端口中。一般将
    [按下一个键时产生的扫描码称为通码,松开一个键产生的扫描码称为断码]{.yellow}。
    [断码=通码+80h]{.label .info}