7

PCj や Tandy 1000 などの古い 8086 搭載コンピューターで動作するゲームを作成できるように、今年の 1 月に x86 アセンブリを趣味として取りましたが、見つけた本はその特定のトピックについてあまり教えてくれませんでした。一部の dos および bios 割り込みは、ある程度機能しますが、完全にはほど遠いものです。

私の主な問題は、プログラムを停止せずに、押されたキーのキーボードステータスを読み取ることです。いくつかの方法を見つけましたが、それらは非常に限られています。INT 21h、AH 0Ch は、最後に押されたキーを読み取りますが、テキスト編集方式です。一度に 1 つのキーしか読み取ることができないだけでなく、メモ帳のようなヒット検出により、キーが押されている時間を知ることができません。Google の旅行中にポート 60h から 64h への参照も見ましたが、それは単なる参照です。実際の説明と作業コードは事実上存在しません。あるいは、検索エンジンの使い方が下手なだけかもしれません。

私が知る必要があるのは、キーが押されているかどうかです。最善の解決策は、すべてのキーボード キーのバッファ/配列を用意し、その状態を読み取ることです。1 はダウンしていることを意味し、0 はダウンしていないことを意味します。または、最後にヒットしてリリースされたキーのリストにアクセスできるだけでもいいでしょう (もちろん、そのバッファをクリアする方法があれば)。誰かが私を正しい方向に向けることができますか?

編集:まず、Borland TASM を使用していることを言及する必要がありました。今、私はあなたのコードをコンパイルしました。私はその半分を理解していないことを認めるのはほとんど恥ずかしがり屋ですが、それはうまく機能します. TASMに対応させようとしたのですが、画面にガベージを作ってフリーズするだけです。

これが私が思いついたものです。

.MODEL TINY
.STACK 256

.DATA
kbdbuf DB 128 DUP (0)

msg1 db "Press and hold ESC", 13, 10, "$"
msg2 db "ESC pressed, release ESC", 13, 10, "$"
msg3 db "ESC released", 13, 10, "$"

.CODE
main PROC
    org 0100h
    mov ax, @data
    mov ds, ax

    xor     ax, ax
    mov     es, ax

    cli                         ; update ISR address w/ ints disabled
    push    word [es:9*4+2]     ; preserve ISR address
    push    word [es:9*4]
    lea si, irq1isr
    mov     word [es:9*4], si   ; requires a register
    mov     [es:9*4+2],cs
    sti

        mov     ah, 9
        lea     dx, msg1
        int     021h                ; print "Press and hold ESC"

    test1:
        mov     al, [kbdbuf + 1]    ; check Escape key state (Esc scan code = 1)
        or      al, al
        jz      test1               ; wait until it's nonzero (pressed/held)

        lea     dx, msg2
        int     021h                ; print "ESC pressed, release ESC"

    test2:
        mov     al, [kbdbuf + 1]    ; check Escape key state (Esc scan code = 1)
        or      al, al
        jnz     test2               ; wait until it's zero (released/not pressed)

        lea     dx, msg3            ; print "ESC released"
        int     021h

    cli                         ; update ISR address w/ ints disabled
    pop     word [es:9*4]       ; restore ISR address
    pop     word [es:9*4+2]
    sti

    ret

    irq1isr:
    push    ax bx

    ; read keyboard scan code
    in      al, 060h

    ; update keyboard state
    xor     bh, bh
    mov     bl, al
    and     bl, 07Fh            ; bx = scan code
    shr     al, 7               ; al = 0 if pressed, 1 if released
    xor     al, 1               ; al = 1 if pressed, 0 if released
    mov     [cs:bx+kbdbuf], al

    ; send EOI to XT keyboard
    in      al, 061h
    mov     ah, al
    or      al, 080h
    out     061h, al
    mov     al, ah
    out     061h, al

    ; send EOI to master PIC
    mov     al, 020h
    out     020h, al

    pop     bx ax
    iret
main ENDP

END main

割り込みを正しくコーディングしたかどうかもわかりません。そして、ポート 060h - 064h がどのように機能するかを知っているかどうか。

4

3 に答える 3

3

方法は次のとおりです。

; compile with NASM: nasm.exe -f bin kbd.asm -o kbd.com

bits 16
org 0x100

    xor     ax, ax
    mov     es, ax

    cli                         ; update ISR address w/ ints disabled
    push    word [es:9*4+2]     ; preserve ISR address
    push    word [es:9*4]
    mov     word [es:9*4], irq1isr
    mov     [es:9*4+2],cs
    sti

    call    test

    cli                         ; update ISR address w/ ints disabled
    pop     word [es:9*4]       ; restore ISR address
    pop     word [es:9*4+2]
    sti

    ret

test:
    mov     ah, 9
    mov     dx, msg1
    int     0x21                ; print "Press and hold ESC"

test1:
    mov     al, [kbdbuf + 1]    ; check Escape key state (Esc scan code = 1)
    or      al, al
    jz      test1               ; wait until it's nonzero (pressed/held)

    mov     dx, msg2
    int     0x21                ; print "ESC pressed, release ESC"

test2:
    mov     al, [kbdbuf + 1]    ; check Escape key state (Esc scan code = 1)
    or      al, al
    jnz     test2               ; wait until it's zero (released/not pressed)

    mov     dx, msg3            ; print "ESC released"
    int     0x21

    ret

irq1isr:
    pusha

    ; read keyboard scan code
    in      al, 0x60

    ; update keyboard state
    xor     bh, bh
    mov     bl, al
    and     bl, 0x7F            ; bx = scan code
    shr     al, 7               ; al = 0 if pressed, 1 if released
    xor     al, 1               ; al = 1 if pressed, 0 if released
    mov     [cs:bx+kbdbuf], al

    ; send EOI to XT keyboard
    in      al, 0x61
    mov     ah, al
    or      al, 0x80
    out     0x61, al
    mov     al, ah
    out     0x61, al

    ; send EOI to master PIC
    mov     al, 0x20
    out     0x20, al

    popa
    iret

kbdbuf:
    times   128 db 0

msg1 db "Press and hold ESC", 13, 10, "$"
msg2 db "ESC pressed, release ESC", 13, 10, "$"
msg3 db "ESC released", 13, 10, "$"

DOS/Win9x/NT/2K/XP/32 ビット Vista/7 または DosBox で実行します。

更新: TASM バージョン:

; file: kbdt.asm
; compile with TASM/TLINK:
;   tasm.exe kbdt.asm
;   tlink.exe /t kbdt.obj

.286

code segment use16
assume cs:code, ds:code, ss:code
org 100h

main:
    xor     ax, ax
    mov     es, ax

    cli                         ; update ISR address w/ ints disabled
    push    word ptr es:[9*4+2]     ; preserve ISR address
    push    word ptr es:[9*4]
    mov     word ptr es:[9*4], offset irq1isr
    mov     es:[9*4+2],cs
    sti

    call    test0

    cli                         ; update ISR address w/ ints disabled
    pop     word ptr es:[9*4]   ; restore ISR address
    pop     word ptr es:[9*4+2]
    sti

    ret

test0:
    mov     ah, 9
    mov     dx, offset msg1
    int     21h                 ; print "Press and hold ESC"

test1:
    mov     al, [kbdbuf + 1]    ; check Escape key state (Esc scan code = 1)
    or      al, al
    jz      test1               ; wait until it's nonzero (pressed/held)

    mov     dx, offset msg2
    int     21h                 ; print "ESC pressed, release ESC"

test2:
    mov     al, [kbdbuf + 1]    ; check Escape key state (Esc scan code = 1)
    or      al, al
    jnz     test2               ; wait until it's zero (released/not pressed)

    mov     dx, offset msg3     ; print "ESC released"
    int     21h

    ret

irq1isr:
    pusha

    ; read keyboard scan code
    in      al, 60h

    ; update keyboard state
    xor     bh, bh
    mov     bl, al
    and     bl, 7Fh             ; bx = scan code
    shr     al, 7               ; al = 0 if pressed, 1 if released
    xor     al, 1               ; al = 1 if pressed, 0 if released
    mov     cs:[bx+kbdbuf], al

    ; send EOI to XT keyboard
    in      al, 61h
    mov     ah, al
    or      al, 80h
    out     61h, al
    mov     al, ah
    out     61h, al

    ; send EOI to master PIC
    mov     al, 20h
    out     20h, al

    popa
    iret

kbdbuf      db 128 dup (0)

msg1 db "Press and hold ESC", 13, 10, "$"
msg2 db "ESC pressed, release ESC", 13, 10, "$"
msg3 db "ESC released", 13, 10, "$"

code ends

end main
于 2012-05-09T23:08:36.907 に答える
0

通常、このような古いシステムでは、BIOS は事前に提供された一連のライブラリ関数のように使用され、キーボード関数などは便利な場合にのみ使用されます。あなたの場合、BIOS キーボード サービスは便利ではないため、使用しません。

代わりに、BIOS キーボード割り込みハンドラーを独自のキーボード割り込みハンドラーに置き換えて、独自のキーボード ドライバーを実装する必要があります。キーボードは割り込み 9 である IRQ1 を使用します。割り込みベクトル テーブルは 0x0000:0x0000 から始まるため、0x0000:9*4 = 0x0000:0x0024 で 4 バイトを取得し、それらをどこかに保存します (元に戻すことができるようにします)。ソフトウェアが終了すると通常の状態になります) 代わりに、独自のキーボード IRQ ハンドラーのアドレス (オフセットの次にセグメント) をそこに置きます。

独自のキーボード ドライバーを作成するには、2 つのハードウェアが関係していることを理解することから始めます。コンピュータにはキーボード コントローラ チップ (または「PS/2 コントローラ」) があり、キーボード自体の内部にあるチップと (シリアル通信を介して) 通信します。

キーボード コントローラ チップの詳細については、http: //wiki.osdev.org/%228042%22_PS/2_Controller などを参照してください。

キーボード自体の内部のチップについては、http: //wiki.osdev.org/PS/2_Keyboard などを参照してください。

于 2012-05-09T22:44:19.227 に答える
0

ポート 60h とポート 64h を使用してキーボードをポーリングする例:

       cli            ; stop software-Interrupts
       mov  al, 2     ; stop IRQ 1
       out  21h, al
       sti
P1:
       in   al, 64h     ; get Status
       test al, 1       ;  is there something in the outputbuffer?
       jz  P1
       test al, 20h     ;  it is a byte from the PS2-Mouse?
       jnz  P1
       in   al, 60h     ; get a key
       cmp  al, 1       ;  Escape-key?
       jz  XRAUS        ; then goto end
;───────────────────────────────────────────────────────────────
       mov  si, OFFSET SONTAB  ; get the offsetaddress of our special-key table
       mov  cl, Extablen       ; lenght
XSUCH: cmp  al, [si]
       jz  XFOUND
       lea  si, [si+1]         ; instead of "inc si"
       dec  cl
       jnz XSUCH
;───────────────────────────────────────────────────────────────
       mov  si, OFFSET TASTTAB  ; get the offsetaddress of our key table
       mov  cx, tablen
       mov  bx, OFFSET TEXTTAB  ; our corresponding ASCII table
SUCH:  cmp  al, [si]
       jz  short FOUND
       lea  si, [si+1]
       dec  cx
       jnz SUCH
       jmp  P1
;───────────────────────────────────────────────────────────────
XRAUS: in   al, 60h ; clear outputbuffer
       cli
       xor  al, al  ; enable IRQ 1
       out  21h, al
       sti
       mov  ah, 1  ; clear buffer in the ram
       int  16h
; ...some more instructions
;───────────────────────────────────────────────────────────────
FOUND:  mov  si, tablen   ; Length
        sub  si, cx
        xor  ecx, ecx
        mov  cl, [bx+si]  ; get the ASCII from our table
;  ...some more instructions
;───────────────────────────────────────────────────────────────
XFOUND:
;  Tab,shift li.,shift re.,HOME,UP,LEFT,RIGHT,END,DOWN
        cmp  cl, 1       ; DOWN-key
        jnz short  ...   ; jump to next
        ....
        ....
        cmp  cl, 9       ; Tab-key
        jnz  P1
;  ...some more instructions
:------------------------Data area----------------------
TASTTAB DB 02h,03h,04h,05h,06h,07h,08h,09h,0Ah,0Bh,0Ch,0Dh
        DB 10h,11h,12h,13h,14h,15h,16h,17h,18h,19h,1Ah,1Bh,1Eh,1Fh
        DB 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Bh,2Ch,2Dh,2Eh,2Fh
        DB 30h,31h,32h,33h,34h,35h,39h
        DB 56h
tablen =  ($-TASTTAB)
TEXTTAB DB "1234567890ß'"     ; with some german letters inside
        DB "qwertzuiopü+as"
        DB "dfghjklöä^#yxcv"
        DB "bnm,.- "
        DB "<"
Textablen  =  ($-TEXTTAB)
;---------------------------------------------------------------------------
;  Tab,shift left.,shift rigth.,HOME,UP,LEFT,RIGHT,END,DOWN
;----------
SONTAB  DB 0Fh,2Ah,36h,47h,48h,4Bh,4Dh,4Fh,50h
Extablen  =  ($-SONTAB)
        DB 0,0,0 ; for data_alignment of following entries
于 2014-01-07T09:49:32.063 に答える