• 汇编语言-15外中断


    外中断

    CPU在计算机系统中,除了能够执行指令,进行运算以外,还应该能够对外部设备进行控制,接收它们的输入,向它们进行输出。也就是说,CPU除了有运算能力外,还要有I/O(Input/Output,输入/输出)能力。比如,按下键盘上的一个键,CPU最终要能够处理这个键。在使用文本编辑器时,按下a键后,可以看到屏幕上出现“a"'是CPU将从键盘上输入的键所对应的字符送到显示器上的。

    接口芯片和端口

    PC系统的接口卡和主板上,装有各种接口芯片。这些外设接口芯片的内部有若干寄存器,CPU将这些寄存器当作端口来访问。
    外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。CPU还可以向外设输出控制命令,而这些控制命令也是先送到相关芯片的端口中,然后再由相关的芯片根据命令对外设实施控制。
    可见,CPU通过端口和外部设备进行联系。

    外中断信息

    当CPU外部有需要处理的事情发生的时候,比如说,外设的输入到达,相关芯片将向CPU发出相应的中断信息。CPU在执行完当前指令后,可以检测到发送过来的中断信息,引发中断过程,处理外设的输入。

    在PC 系统中,外中断源一共有以下两类:

    1. 可屏蔽中断

    可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF位的设置。当CPU检测到可屏蔽中断信息时,如果IF=l,,则CPU在执行完当前指令后响应中断,引发中断过程;如果IF=0,则不响应可屏蔽中断。

    2. 不可屏蔽中断

    不可屏蔽中断是CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。
    不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。则不可屏蔽中断的中断过程为:
    (1) 标志寄存器入栈,IF=O,TF=O:
    (2) cs、IP 入栈;
    (3) (IP)=(8),(CS)=(OAH) 。
    几乎所有由外设引发的外中断,都是可屏蔽中断。当外设有需要处理的事件(比如说键盘输入)发生时,相关芯片向CPU发出可屏蔽中断信息。不可屏蔽中断是在系统中有必须处理的紧急情况发生时用来通知CPU的中断信息。

    PC机键盘的处理过程

    键盘输入

    键盘上的每一个键相当于一个开关,键盘中有一个芯片对键盘上的每一个键的开关状态进行扫描。
    按下一个键时,开关接通,该芯片就产生一个扫描码,扫描码说明了按下的键在键盘上的位置。扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h。
    松开按下的键时,也产生一个扫描码,扫描码说明了松开的键在键盘上的位置。松开按键时产生的扫描码也被送入60h端口中。
    一般将按下一个键时产生的扫描码称为通码,松开一个键产生的扫描码称为断码。扫
    描码长度为一个字节,通码的第7位为0,断码的第7位为1,即:
    断码=通码+80h
    比如,g键的通码为22h,断码为a2h。

    引发9号中断

    键盘的输入到达60h端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU检测到该中断信息后,如果IF=1,则响应中断,引发中断过程,转去执行int9中断例程。

    执行int 9中断例程

    编写int 9 中断例程

    1.键盘产生扫描码;2.扫描码送入60h端口;3.引发9号中断;4.CPU执行int 9中断例程处理键盘输入。
    第1 、2 、3步都是由硬件系统完成的。能够改变的只有int 9中断处理程序。

    显示a~z

    assume cs:code
    
    stack segment
    	db 128 dup (0)
    stack ends
    
    code segment
    
    start: mov ax,stack
    		mov ss,ax
    		mov sp,128
    		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
    
    		mov ax,4c00h
    		int 21h
    
    	delay:push ax
    		push dx
    		mov dx,l000h  ;循环10000000h次,读者可以根据自己机器的速度调整循环次数
    		mov ax,0
    	s1: sub ax,1
    		sbb dx,0
    		cmp ax,0
    		jne s1
    		cmp dx,O
    		jne s1
    		pop dx
    		pop ax
    		ret
    code ends
    end start
    

    按下Esc键后改变颜色

    (1) 从60h端口读出键盘的输入;
    (2) 调用BIOS的int 9中断例程,处理其他硬件细节;
    (3) 判断是否为Esc的扫描码,如果是,改变显示的颜色后返回;如果不是则直接返回。

    1.从端口60h 读出键盘的输入

    in al,60h
    

    2.调用BIOS 的int 9中断例程

    int 9
    

    int 指令在执行的时候,CPU 进行下面的工作。
    (1) 取中断类型码n;
    (2) 标志寄存器入栈;
    (3) IF=0, TF=0;
    (4) cs 、IP入栈;
    (5) (IP)=((ds)16+0), (CS)=((ds)16+2)。

    第(4) 、(5)步和call dword ptr ds:[O] 的功能一样

    call dword ptr ds:[0] 的功能:
    (1) cs 、JP 入栈;
    (2) (IP)=((ds)16+0), (CS)=((ds)16+2) 。

    int 过程的模拟过程变为:

    (1) 标志寄存器入栈;
    (2) IF=0, TF=0:
    (3) call dword ptr ds:[0] 。

    对于(1) ,可用pushf 实现;

    对于(2) ,可用下面的指令实现:

    pushf
    pop ax
    and ah,11111100b  ;IF 和TF 为标志寄存器的第9位和第8位
    push ax
    popf
    

    则模拟int指令的调用功能,调用入口地址在ds:0 、ds:2中的中断例程的程序为:

    pushf    ;标志寄存器入栈
    
    pushf
    pop ax
    and ah, 11111100b
    push ax
    popf    ;IF=0, TF=0
    
    call dword ptr ds:[0]   ;CS、IP入栈;(IP)= ((ds)*16+0), (CS)= ((ds)*16+2)
    

    显示的位置是屏幕的中间,即第12行40列,显存中的偏移地址为:160 * 12+40 * 2 。所以字符的ASCII 码要送入段地址b800h, 偏移地址16012+402 处。段地址b800h,偏移地址160 * 12+40 * 2+1 处是字符的属性,只要改变此处的数据就可以改变在段地址b800h, 偏移地址160* 12+40* 2处显示的字符的颜色了。

    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
    
    		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]     ;将原来的int 9中断例程的入口地址保存在ds:0、ds:2单元中
    	
    		mov word ptr es:[9*4],offset int9
    		mov es:[9*4+2],cs     ;在中断向量表中设置新的int 9中断例程的入口地址
    	
    		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
    	
    		mov ax,O
    		mov es,ax
    	
    		push ds:[0]
    		pop es:[9*4]
    		push ds:[2]
    		pop es:[9*4+2]    ;将中断向量表中int 9中断例程的入口恢复为原来的地址
    	
    		mov ax,4c00h
    		int 21h
    	
    	delay:push ax
    		push dx
    		mov dx,1000h
    		mov ax,0
    	s1: sub ax,1
    		sbb dx,0
    		cmp ax,0
    		jne s1
    		cmp dx,0
    		jne s1
    		pop dx
    		pop ax
    		ret
    
    ;-----------以下为新的int 9 中断例程-----------------
        int9:push ax
            push bx
            push es
    
            in al,60h
    
            pushf
            pushf
            pop bx
            and bh, 11111100b
            push bx
            popf
            call dword ptr ds:[0]   ;对int 指令进行模拟,调用原来的int 9 中断例程
    
            cmp al,1
            jne int9ret
    
            mov ax,0bB00h
            mov es,ax
            inc byte ptr es:[160*12+40*2+1]   ;将属性值加1, 改变颜色
        int9ret:pop es
            pop bx
            pop ax
            iret
    
    code ends
    end start
    

    关于键盘的程序,因要直接访问真实的硬件,则必须在DOS 实模式下运行。在Windows 2000 的DOS 方式下运行,会出现一些和硬件工作原理不符合的现象。

    安装新的int 9中断例程

    (1) 改变屏幕的显示颜色

    改变从B8000H 开始的4000个字节中的所有奇地址单元中的内容,当前屏幕的显示颜色即发生改变。

    mov ax,0b800h
    mov es,ax
    mov bx,l
    mov cx,2000
    s:inc byte ptr es:[bx]
    add bx,2
    loops
    

    (2) 其他键照常处理
    可以调用原int 9中断处理程序,来处理其他的键盘输入。

    (3) 原int 9中断例程入口地址的保存

    因为在编写的新int 9中断例程中要调用原int 9中断例程,所以,要保存原int 9中断例程的入口地址。将地址保存在0:200单元处。

    (4) 新int 9 中断例程的安装

    将新的int 9 中断例程安装在0:204 处。

    assume cs:code
    
    stack segment
    	db 128 dup(0)
    stack ends
    
    code segment
    start: mov ax,stack
            mov ss,ax
            mov sp,128
    
            push cs
            pop ds
    
            mov ax,O
            mov es,ax
    
            mov si,offset int9    ;设置ds:si指向源地址
            mov di,204h    ;设置es:di 指向目的地址
            mov cx,offset int9end-offset int9    ;设置ex 为传输长度
            cld    ;设置传输方向为正
            rep movsb
    
            push es:[9*4]
            pop es:[200h]
            push es:[9*4+2]
            pop es:[202h]
    
            cli
            mov word ptr es:[9*4],204h
            mov word ptr es:[9*4+2],0
            sti
    
            mov ax,4c00h
            int 21h
    
    	int9:push ax
            push bx
            push cx
            push es
            
            in al,60h
            
            pushf
            call dword ptr cs:[200h]    ;当此中断例程执行时(CS)=O
            
            cmp al,3bh     ;Fl的扫描码为3bh
            jne int9ret
            
            mov ax,Ob800h
            mov es,ax
            mov bx,1
            mov cx,2000
         s: inc byte ptr es:[bx]
            add bx,2
            loop s
            
    	int9ret:pop es
            pop cx
            pop bx
            pop ax
            iret
            
    int9end:nop
    
    code ends
    end start
    

    总结

    CPU 对外设输入的通常处理方法:

    (1) 外设的输入送入端口;
    (2) 向CPU 发出外中断(可屏蔽中断)信息;
    (3) CPU检测到可屏蔽中断信息,如果IF=1, CPU在执行完当前指令后响应中断,执行相应的中断例程;
    (4) 可在中断例程中实现对外设输入的处理。

    端口和中断机制,是CPU 进行I/O 的基础。

    如果这篇文章对你有用,麻烦关注一下本人微信公众号,关注送福利哦~
    微信公众号二维码
    不定期安利各种插件,编程技巧,编程思想,欢迎交流~
  • 相关阅读:
    C#中如何求时间间隔?
    Ilist<T> 转换成 DataSet
    EditPlus 快捷键
    Array和ArrayList的异同点
    sql server 查询数据库中有多少个表
    jquery + Css 模式对话框
    paddingtop、margintop和top的区别
    JQuery之ContextMenu(右键菜单)
    关于TextBox的Enable与ReadOnly属性
    AjaxToollit 3.5 使用整理
  • 原文地址:https://www.cnblogs.com/aeolian/p/13297084.html
Copyright © 2020-2023  润新知