assembly - 8086 assembly INT 9h : keyboard ISR implementation

标签 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  

最佳答案

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

  • 要检索和恢复中断向量,您需要将您选择的段寄存器设置为零。迈克尔·佩奇也发表了同样的言论。因此,让我们使用 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
    
  • 当您使用calldelay_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

关于assembly - 8086 assembly INT 9h : keyboard ISR implementation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39782865/

相关文章:

assembly - x86中如何从中断处理程序中获取中断号?

assembly - 为什么要向标准输出设备写入这么多字节?

assembly - 如何从 DOS 中的标准输入读取字符以便重定向工作?

c++ - 汇编程序任务 - 数组的最小值和最大值

assembly - TASM 中的 "Near jump or call to different CS"错误

assembly - x86 汇编中的 cmpsb 问题

c - linux内核一步一步

ios - 在 Mac/Windows 上为 iPhone 编译 ARM .s

assembly - 加载引导加载程序的第二阶段并启动它

x86-16 - RCR 和 ROR 有什么区别?