8086 Assembly INT 9h:键盘ISR实现

时间:2016-09-30 02:44:32

标签: assembly x86-16

我正在尝试在按下某个键时覆盖默认中断。 这是我的代码:不要调用kbd_handler并更改'port60' 我该如何解决这个问题?您认为是什么导致了它?

 MAIN SEGMENT PUBLIC                        
         ASSUME CS:MAIN, DS:DATA

         MOV AX, MAIN   ; Set up the Data Segment address
         MOV DS, AX
         mov bx, 9 * 4 ;find the int 9

         mov dx, word ptr [bx]
         push dx
         mov dx, word ptr [bx] + 2    
         push dx


         mov ax, DATA
         mov DS, ax
         mov es, ax

         ;mov bx, 09h * 04h
        mov bx, 9 * 4 ;find the int 9 
         cli                    ; disable an interrupt
         mov word ptr [bx],  offset kbd_handler ; load your keyboard ISR
         mov word ptr [bx] + 2, seg kbd_handler ;
         sti                    ;enable interrupts      

    TEST_2 :
        call printc
        call delay_cx
        jmp test_2

         mov ax, MAIN
         mov dx, ax

         mov bx, 09h * 04h ;find the int 9

         cli ; disable interrupt
         pop dx
         mov word ptr [bx], dx ;back to normal address
         pop dx
         mov word ptr [bx]+2, dx
         sti ; enalbe interrupts  

         MOV AH, 4CH                        ;
         INT 21H                  

    PUBLIC    kbd_handler

    kbd_handler PROC    NEAR
         push ax
         push bx
         push cx
         push dx                                          
         push sp
         push bp
         push si
         push di

         in al, 64h
         test al, 01h

         ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
         in al, 60h
         mov byte ptr ds:[port60], al   
         ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

         mov al, 20h
         out 20h, al

         pop di
         pop si
         pop bp
         pop sp
         pop dx
         pop cx
         pop bx
         pop ax    
         IRET
    kbd_handler ENDP

    PRINT PROC NEAR
        CLD ; 
    PRINT_1 :
        MOVSB
        MOV AL, DL
        STOSB
        LOOP PRINT_1
        RET
    PRINT ENDP

    delay_cx proc   near            ; 
    delay_1:        
        push    cx          ; 
        mov cx, 50          ; 
    delay_2:
        loop    delay_2         ; 
        pop cx          ; 
        loop    delay_1         ;
        ret             ; 
    delay_cx    endp


    PRINTC PROC NEAR
        MOV AL, port60
        MOV DL, AL
        MOV AH, 02H
        INT 21H
        RET
    PRINTC ENDP

    MAIN ENDS

    DATA SEGMENT
        msg1 db 'Press and hold ESC'
        msg2 db 'ESC pressed, release ESC'
        msg3 db 'ESC released'
        kbdbuf      db 128 dup (0)
        port60    db    '1'
    DATA ENDS

    END  

1 个答案:

答案 0 :(得分:2)

您的代码中发现了几个错误:

  • 要检索和恢复中断向量,您需要将所选的段寄存器设置为零。 Michael Petch也发了同样的话。因此,让我们使用ES段注册。

    ...
    xor dx, dx
    mov es, dx
    mov dx, word ptr es:[bx]
    ...
    
  • 当您在堆栈中保存中断向量时,您必须以相反的顺序恢复它!你已反过来做过了。

  • 在新的处理程序中,您只能直接使用CS段寄存器作为覆盖。

    in al, 60h
    mov byte ptr cs:[port60], al 
    
  • 推送/弹出您不打算更改的寄存器没用。此外,push sppop sp始终是还原的。

  • 由于您的主程序循环使用无条件跳转,因此将恢复正常的代码永远不会运行。

    TEST_2 :
     call printc
     call delay_cx
     jmp test_2
    
     mov ax, MAIN  <-- You're code will never get here!
     mov dx, ax
    
  • 当您使用call delay_cx时,仍需要将CX寄存器设置为合适的值。

我看到你的程序仍在进行中。很多临时代码不再使用了。删除不需要的东西,以免在可读性方面松动 看看你写的信息,我敢建议你以某种方式划分这些信息。

msg1 db 'Press and hold ESC',13,10,0
msg2 db 'ESC pressed, release ESC',13,10,0
msg3 db 'ESC released',13,10,0