外部中断编写int 09h

汇编语言中的外中断和内中断差不多

1、取中断类型码n

2、标致寄存器入栈,IF=0,TF=0

2、CS、IP入栈

3、(IP)=(n*4),(CS)=(n*4+2)

但是外中断和内中断的中断类型码的来源不同,所以第一步肯定是不一样的,其他相同

下面来讲一下键盘事件下的处理方式

只要有键盘事件发生,就会触发int 9,这个int 9是硬件扫描过程,其实就是CPU对按键的IO口进行扫描的过程

这里问题就出现了,因为键盘事件发生必定会引发int 9,所以如果要对按按键后进行处理的话,需要将中断程序写在int 9中,但是如果需要扫描键盘的按键,就必须要调用BIOS提供的int 9

解决这种冲突的办法就是先将BIOS提供的int 9的IP和CS储存起来,用模拟int指令的方式来调用原来的int 9,当然新建的int 9需要将其入口的IP和CS放到向量表中

任务:显示a~z,按下ESC结束

代码:

assume cs:code
 

data segment                                                                ;储存原int9的IP和CS
    dw 0, 0
data ends
 
code segment
 
    start:                                
                                        mov ax, 0                           ;将原int9的IP和CS放到data空间中
                                        mov ds, ax
                                        mov ax, data
                                        mov es, ax
                                        push ds:[9*4]
                                        pop es:[0]
                                        push ds:[9*4 + 2]
                                        pop es:[2]
                                        
                                        mov ax, 0                           ;将新的int9中断的IP,CS写入中断向量表中
                                        mov ds, ax
                                        mov word ptr ds:[9*4], offset do9h
                                        mov word ptr ds:[9*4 + 2], cs
                                        
                                        mov ax, 0B800H
                                        mov ds, ax
                                        mov al, 'a'
                                        mov cl, 2
                                s:        mov ds:[10*160 + 8*2], al
                                        mov byte ptr ds:[10*160 + 8*2 + 1], cl
                                        
                                        call delay                                    ;调用延时的子程序,方便显示
                                        
                                        cmp al, 'z'
                                        je s0
                                        inc al
                                        jmp s
                                        
                                s0:        mov al, 'a'
                                        jmp s
                                        
                                send:    mov ax, 0                                    ;将原int9中断的IP,CS恢复
                                        mov ds, ax
                                        mov ax, data
                                        mov es, ax
                                        push es:[0]
                                        pop ds:[9*4]
                                        push es:[2]
                                        pop ds:[9*4 + 2]
                                        mov ax, 4C00H
                                        int 21H
                                        
                        do9h:            push ax
                                        push dx
                                        push ds
                                        
                                        in al, 60H                                 ;从键盘端口读出键盘的输入
                                        mov dl, al
                                        
                                        pushf                                      ;模仿int指令,进行原int9的调用
                                        
                                        pushf                                      ;将标致寄存器的IF和TF置零
                                        pop ax
                                        and ah, 11111100B
                                        push ax
                                        popf
                                        
                                        mov ax, data                                ;保存下一条指令的IP和CS
                                        mov ds, ax
                                        call dword ptr ds:[0]
                                        
                                        cmp dl, 1                                   ;ESC的扫描码为1
                                        jne ok
                                        jmp send                ;跳到循环外,不再执行循环指令
                                        
                                ok:        pop ds
                                        pop dx
                                        pop ax
                                        iret
                                        
                        delay:            push dx
                                        push ax
                                        
                                        mov dx, 10H
                                        mov ax, 0
                                s1:        sub ax, 1                                     ;-1的反码是65535
                                        sbb dx, 0                                     ;此时CF寄存器是1,则dx-1
                                        cmp ax, 0                                     ;内循环
                                        jne s1
                                        cmp dx, 0                                     ;外循环   
                                        jne s1
                                        
                                        pop ax
                                        pop dx
                                        ret
                                        
code ends        
end start

运行结果:


按下ESC键后的显示结果:

为了避免在修改int 9的IP和CS时就发生外部中断,那么会让中断的地址混乱,所以可以改进一下程序

指令:cli:设置IF=0,屏蔽中断

            sti:设置IF=1,不屏蔽中断

将这两条指令分别加在修改入口地址的前后,那么就可以避免上面说的那种情况了

例:

cli                                 ;设置IF=0,屏蔽中断
mov ax, 0                           ;将新的int9中断的IP,CS写入中断向量表中
mov ds, ax
mov word ptr ds:[9*4], offset do9h
mov word ptr ds:[9*4 + 2], cs
sti                                 ;设置IF=1,不屏蔽中断

这样就避免了在修改IP,CS时发生外部中断

这里还有个问题,这里的jmp是有范围的,如果在程序中超出了jmp的范围,那么就不能完美的跳出程序了,为了解决这个问题,还需要模拟利用中断模拟jmp指令,让jmp指令的范围得到扩充

因为进入到外部中断时,会将CS和IP入栈,只要改变一下IP,在跳回程序后,就能跳到指定的位置

在中断中:

mov bp, sp                                  ;模拟jmp指令,跳出循环
                                        mov word ptr [bp + 8], offset send

这样就能跳出循环了
完整的代码:

assume cs:code
 
data segment                                                                ;储存原int9的IP和CS
    dw 0, 0
data ends
 
code segment
 
    start:                                
                                        mov ax, 0                           ;将原int9的IP和CS放到data空间中
                                        mov ds, ax
                                        mov ax, data
                                        mov es, ax
                                        push ds:[9*4]
                                        pop es:[0]
                                        push ds:[9*4 + 2]
                                        pop es:[2]
                                        
                                        mov ax, 0                           ;将新的int9中断的IP,CS写入中断向量表中
                                        mov ds, ax
                                        mov word ptr ds:[9*4], offset do9h
                                        mov word ptr ds:[9*4 + 2], cs
                                        
                                        mov ax, 0B800H
                                        mov ds, ax
                                        mov al, 'a'
                                        mov cl, 2
                                s:        mov ds:[10*160 + 8*2], al
                                        mov byte ptr ds:[10*160 + 8*2 + 1], cl
                                        
                                        call delay                                    ;调用延时的子程序,方便显示
                                        
                                        cmp al, 'z'
                                        je s0
                                        inc al
                                        jmp s
                                        
                                s0:        mov al, 'a'
                                        jmp s
                                        
                                send:    mov ax, 0                                    ;将原int9中断的IP,CS恢复
                                        mov ds, ax
                                        mov ax, data
                                        mov es, ax
                                        push es:[0]
                                        pop ds:[9*4]
                                        push es:[2]
                                        pop ds:[9*4 + 2]
                                        mov ax, 4C00H
                                        int 21H
                                        
                        do9h:            push ax
                                        push dx
                                        push ds
                                        
                                        in al, 60H                                 ;从键盘端口读出键盘的输入
                                        mov dl, al
                                        
                                        pushf                                      ;模仿int指令,进行原int9的调用
                                        
                                        pushf                                      ;将标致寄存器的IF和TF置零
                                        pop ax
                                        and ah, 11111100B
                                        push ax
                                        popf
                                        
                                        mov ax, data                                ;保存下一条指令的IP和CS
                                        mov ds, ax
                                        call dword ptr ds:[0]
                                        
                                        cmp dl, 1                                   ;ESC的扫描码为1
                                        jne ok
                                        mov bp, sp                                  ;模拟jmp指令,跳出循环
                                        mov word ptr [bp + 6], offset send
                                        
                                ok:        pop ds
                                        pop dx
                                        pop ax
                                        iret
                                        
                        delay:            push dx
                                        push ax
                                        
                                        mov dx, 10H
                                        mov ax, 0
                                s1:        sub ax, 1                                     ;-1的反码是65535
                                        sbb dx, 0                                     ;此时CF寄存器是1,则dx-1
                                        cmp ax, 0                                     ;内循环
                                        jne s1
                                        cmp dx, 0                                     ;外循环   
                                        jne s1
                                        
                                        pop ax
                                        pop dx
                                        ret
                                        
code ends        
end start



https://blog.csdn.net/qq_23880193/article/details/43274599 
 

猜你喜欢

转载自blog.csdn.net/weixin_42149196/article/details/84000865