汇编语言中的外中断——键盘事件

来源:互联网 发布:台湾人淘宝 编辑:程序博客网 时间:2024/05/16 11:47

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

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:codedata segment                                                                ;储存原int9的IP和CSdw 0, 0data endscode segmentstart:mov ax, 0                           ;将原int9的IP和CS放到data空间中mov ds, axmov ax, datamov es, axpush ds:[9*4]pop es:[0]push ds:[9*4 + 2]pop es:[2]mov ax, 0                           ;将新的int9中断的IP,CS写入中断向量表中mov ds, axmov word ptr ds:[9*4], offset do9hmov word ptr ds:[9*4 + 2], csmov ax, 0B800Hmov ds, axmov al, 'a'mov cl, 2s:mov ds:[10*160 + 8*2], almov byte ptr ds:[10*160 + 8*2 + 1], clcall delay                                    ;调用延时的子程序,方便显示cmp al, 'z'je s0inc aljmp ss0:mov al, 'a'jmp ssend:mov ax, 0                                    ;将原int9中断的IP,CS恢复mov ds, axmov ax, datamov es, axpush es:[0]pop ds:[9*4]push es:[2]pop ds:[9*4 + 2]mov ax, 4C00Hint 21Hdo9h:push axpush dxpush dsin al, 60H                                 ;从键盘端口读出键盘的输入mov dl, alpushf                                      ;模仿int指令,进行原int9的调用pushf                                      ;将标致寄存器的IF和TF置零pop axand ah, 11111100Bpush axpopfmov ax, data;保存下一条指令的IP和CSmov ds, axcall dword ptr ds:[0]cmp dl, 1                                   ;ESC的扫描码为1jne okjmp send                ;跳到循环外,不再执行循环指令ok:pop dspop dxpop axiretdelay:push dxpush axmov dx, 10Hmov ax, 0s1:sub ax, 1                                     ;-1的反码是65535sbb dx, 0                                     ;此时CF寄存器是1,则dx-1cmp ax, 0                                     ;内循环jne s1cmp dx, 0                                     ;外循环   jne s1pop axpop dxretcode endsend start

运行结果:



按下ESC键后的显示结果:



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

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

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

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

例:

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

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


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

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

在中断中:

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

这样就能跳出循环了

完整的代码:

assume cs:codedata segment                                                                ;储存原int9的IP和CSdw 0, 0data endscode segmentstart:mov ax, 0                           ;将原int9的IP和CS放到data空间中mov ds, axmov ax, datamov es, axpush ds:[9*4]pop es:[0]push ds:[9*4 + 2]pop es:[2]mov ax, 0                           ;将新的int9中断的IP,CS写入中断向量表中mov ds, axmov word ptr ds:[9*4], offset do9hmov word ptr ds:[9*4 + 2], csmov ax, 0B800Hmov ds, axmov al, 'a'mov cl, 2s:mov ds:[10*160 + 8*2], almov byte ptr ds:[10*160 + 8*2 + 1], clcall delay                                    ;调用延时的子程序,方便显示cmp al, 'z'je s0inc aljmp ss0:mov al, 'a'jmp ssend:mov ax, 0                                    ;将原int9中断的IP,CS恢复mov ds, axmov ax, datamov es, axpush es:[0]pop ds:[9*4]push es:[2]pop ds:[9*4 + 2]mov ax, 4C00Hint 21Hdo9h:push axpush dxpush dsin al, 60H                                 ;从键盘端口读出键盘的输入mov dl, alpushf                                      ;模仿int指令,进行原int9的调用pushf                                      ;将标致寄存器的IF和TF置零pop axand ah, 11111100Bpush axpopfmov ax, data;保存下一条指令的IP和CSmov ds, axcall dword ptr ds:[0]cmp dl, 1                                   ;ESC的扫描码为1jne okmov bp, sp                                  ;模拟jmp指令,跳出循环mov word ptr [bp + 6], offset sendok:pop dspop dxpop axiretdelay:push dxpush axmov dx, 10Hmov ax, 0s1:sub ax, 1                                     ;-1的反码是65535sbb dx, 0                                     ;此时CF寄存器是1,则dx-1cmp ax, 0                                     ;内循环jne s1cmp dx, 0                                     ;外循环   jne s1pop axpop dxretcode endsend start

效果是一样的

0 0