2

プログラム用に作成したキーボード割り込みサービス ルーチン (キーを押すたびに "hello world" を出力する必要があります) が、dosbox で .exe を実行したときに 1 回しか発生しない理由がわかりません。コードは次のとおりです。

  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) を使用して、レジスタのプッシュとポップなど、いくつかのことを試しましたが、どれも機能しませんでした。「hello world」というメッセージが画面に表示されるため、ISR が少なくとも 1 回実行されることはわかっていますが、キーを押すたびに印刷されるはずで、なぜ印刷されないのかわかりません。

どうすればこれを解決できますか?

4

2 に答える 2

1

キーボードを「解放」して中断するには、いくつかの作業を行う必要があります。ここを見てください。最も簡単な方法は、独自のハンドラーの最後にある古い 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
于 2015-10-13T20:48:18.243 に答える
1

基本的に言えば、作業が完了した後にデフォルト ハンドラーを呼び出さない限り、完了したことを PIC (プログラマブル割り込みコントローラー) に通知する必要があります。デフォルト ハンドラーがこれを行い、EOI を送信します (終了の割り込み信号) を PIC(s) に送信します。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 (キーボード) ハンドラーです。登録関数は、関数のオフセットをinterrupt_handlers32 ビット アドレスのテーブル ( ) にコピーするだけです。私はフラット メモリ モードです (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
于 2015-10-14T14:07:58.760 に答える