【问题标题】:8086 Assembly keyboard ISR implementation8086 组装键盘 ISR 实现
【发布时间】:2015-10-13 20:14:44
【问题描述】:

我不明白为什么我为我的程序编写的键盘中断服务例程(每次按一个键时都应该打印“hello world”)只在我在 dosbox 上执行 .exe 时发生一次。 代码如下:

  NAME keyb

PILE    SEGMENT STACK
    db      20 dup ('LA PILE ')
PILE    ENDS


DONNEE SEGMENT
message db "Hello wolrd !$"
DONNEE ENDS

PROGRAMME SEGMENT
ASSUME CS:PROGRAMME , DS:DONNEE, ES:NOTHING, SS:PILE
debut:

    mov ax,DONNEE
    mov ds,ax

    cli

    xor ax,ax
    mov es, ax ; load ES with segment address of interrupt pointer table
    mov bx, 24h ; load BX with interrupt type
    mov word ptr es:[bx], OFFSET SUBR ; isr address
    mov word ptr es:[bx]+2, SEG SUBR ; isr segment
    mov ax, 01h
    sti

BOUCLE: jmp BOUCLE

SUBR PROC NEAR
    cli
    mov ah,9
    mov dx,OFFSET message
    int 21h
    sti

    IRET
SUBR ENDP

PROGRAMME ENDS

    END debut

我尝试了一些方法,例如使用另一个中断(系统时钟 08h)推送和弹出寄存器,但都没有奏效。 我知道 ISR 至少运行一次,因为屏幕上出现了“hello world”消息,但是每次我按下一个键时它都会打印出来,我不知道为什么它不打印。

我该如何解决这个问题?

【问题讨论】:

    标签: assembly keyboard interrupt x86-16 isr


    【解决方案1】:

    你必须做一些工作来“释放”键盘和中断。看看here。最简单的方法是在您自己的处理程序末尾跳转到旧的 IRQ 处理程序:

    NAME keyb
    
    PILE    SEGMENT STACK
        db      20 dup ('LA PILE ')
    PILE    ENDS
    
    DONNEE SEGMENT
    message db "Hello wolrd !$"
    oldvec dw 0, 0
    DONNEE ENDS
    
    PROGRAMME SEGMENT
    ASSUME CS:PROGRAMME , DS:DONNEE, ES:NOTHING, SS:PILE
    debut:
    
        mov ax,DONNEE
        mov ds,ax
    
        cli
    
        xor ax,ax
        mov es, ax ; load ES with segment address of interrupt pointer table
        mov bx, 24h ; load BX with interrupt type
    
        ; Store the old IRQ vector
        mov ax, es:[bx]
        mov oldvec, ax
        mov ax, es:[bx+2]
        mov oldvec + 2, ax
    
        mov word ptr es:[bx], OFFSET SUBR ; isr address
        mov word ptr es:[bx]+2, SEG SUBR ; isr segment
        mov ax, 01h
        sti
    
    BOUCLE: jmp BOUCLE
    
    SUBR PROC NEAR
        push ax
        push dx
    
        mov ah,9
        mov dx,OFFSET message
        int 21h
    
        pop dx
        pop ax    
    
        jmp dword ptr [oldvec]
    SUBR ENDP
    
    PROGRAMME ENDS
    
    END debut
    

    【讨论】:

      【解决方案2】:

      基本上,除非您在完成工作后调用默认处理程序,否则您必须告诉 PIC(可编程中断控制器)您已完成 - 默认处理程序会为您执行此操作 - 发送EOI(中断信号结束)到 PIC。 PIC 不会再次触发中断,直到你告诉它你已经完成了当前的中断。

      在 32 位保护模式下执行此操作的代码如下所示。请注意,我对所有 IRQ 使用通用处理程序,只是将其交给适当注册的用户回调函数。我都包括了。

      首先,通用 IRQ 处理程序

      irq_handler:
          push    ebp
          mov     ebp, esp
          add     ebp, 8
      
      
          mov     eax, [ebp +registers_t.int_no]
      
          cmp     eax, IRQ7                   ; this just dumps spurious IRQ7 interrupts
          je      .irqHandlerDone
      
          cmp     eax, IRQ8                   ; if it's IRQ0 - IRQ7, the first controller fired the int, otherwise the slave controller did
          jb      .slaveResetDone
      .resetSlave:
          mov     al,20H      ; send End-Of-Interrupt signal
          out     0xA0,al     ; to the 8259 _slave_ Programmable Interrupt Controller
      .slaveResetDone:
      .resetMaster:
          mov     al, 0x20    ; send End-Of-Interrupt signal
          out     0x20, al    ; to the 8259 master Programmable Interrupt Controller
      
          mov     eax, [ebp + registers_t.int_no]
          shl     eax, 2                              ; x4
          mov     esi, interrupt_handlers
          add     esi, eax                            ; esi --> interrupt_handlers[int_no]
          cmp     dword [esi], 0
          je      .irqHandlerDone
      
          call    [esi]
      .irqHandlerDone:
          pop     ebp
          ret
      

      接下来,IRQ1(键盘)处理程序。注册函数只是简单地将函数的偏移量复制到一个 32 位地址的表 (interrupt_handlers) 中。 我处于平面内存模式(4GB 可寻址,ES 已经拥有可写数据段的段选择器。0xB8000 + 79*2 只是指向 80x25 模式3 文本屏幕右上角的字符)

      ; keyboard IRQ handler
      irq1Handler:
          push    ebp
          mov     ebp, esp
          add     ebp, 8+4
      
          in      al, 0x60
          mov     bl, al
          mov     byte [port60], al
      
          in      al, 0x61
          mov     ah, al
          or      al, 0x80
          out     0x61, al
          xchg    ah, al
          out     0x61, al
      
          and     bl, 0x80
          jnz     .done
      
          pusha
          ;mov        al, [port60]
          ;call   outputChar
      
          mov     edi, 0xB8000 + 79*2
          mov     al, [port60]
          mov     [es:edi], al
      
          popa
      .done:  
          pop     ebp
          ret
      port60  db  0
      

      代码来自 James M 的教程,这里:http://www.jamesmolloy.co.uk/tutorial_html/5.-IRQs%20and%20the%20PIT.html

      在 OSDev.org - http://wiki.osdev.org/Main_Page 上可以阅读很多关于硬件接口的信息

      更新: 这是一个在 DosBox 中运行的 16 位 ISR。

      ;-----------------------------------------------------
      ; handles int 0x09
      ;-----------------------------------------------------
      keyhandler:
          cli
          pusha
          in al, 0x60                     ; get key data
          mov bl, al                      ; save it
          mov byte [port60], al
      
          in al, 0x61                     ; keybrd control
          mov ah, al
          or al, 0x80                     ; disable bit 7
          out 0x61, al                    ; send it back
          xchg ah, al                     ; get original
          out 0x61, al                    ; send that back
      
          mov al, 0x20                    ; End of Interrupt
          out 0x20, al                    ;
      
          and bl, 0x80                    ; key released
          jnz done                        ; don't repeat
      
          mov al, [port60]
          ;
          ; do something with the scan-code here
          ;
      done:
          popa
          iret
      port60    db    0        ; where we'll store the scan-code
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-27
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        • 2017-01-01
        • 1970-01-01
        相关资源
        最近更新 更多