2012-05-09 3 views
7

Ich nahm x86 Assembly als Hobby im vergangenen Januar, so dass ich Spiele machen konnte, die auf alten 8086 betriebenen Computern wie dem PCj und Tandy 1000 funktionieren würden, aber die Bücher, die ich fand, lehren nicht gerade viel über dieses spezielle Thema. Während einige Dos und Bios die Arbeit unterbrechen, sind sie bei weitem nicht perfekt.Wie überprüft man den Status der Tasten in der x86-Baugruppe?

Mein Hauptproblem ist das Lesen des Tastaturstatus für gedrückte Tasten, ohne das Programm zu stoppen. Ich habe ein paar Methoden gefunden, aber sie sind sehr begrenzt. INT 21h, AH 0Ch liest die zuletzt gedrückte Taste, jedoch in Textausgabe. Es liest nicht nur jeweils nur einen Schlüssel, aber die Notizblock-ähnliche Treffererkennung macht es unmöglich zu wissen, wie lange der Schlüssel gehalten wurde. Ich habe während meiner Google-Reisen auch Hinweise auf die Ports 60h bis 64h gesehen, aber das sind nur Referenzen. Tatsächliche Erklärungen und Arbeitscode sind praktisch nicht existent. Oder vielleicht bin ich so schlecht im Umgang mit Suchmaschinen.

Was ich wissen muss ist, ob eine Taste gedrückt gehalten wird oder nicht. Die beste Lösung wäre, einen Puffer/ein Array aller Tastaturtasten zu haben und seinen Zustand zu lesen; 1 bedeutet, es ist down, 0 bedeutet, dass es nicht ist. Oder einfach Zugang zu einer Liste der letzten Schlüssel, die getroffen und freigegeben wurden, wäre nett (mit einer Möglichkeit, diesen Puffer zu löschen, natürlich). Kann mir jemand in die richtige Richtung zeigen?

Edit: Zunächst einmal sollte ich erwähnt haben, dass ich Borland TASM verwende. Jetzt habe ich deinen Code kompiliert und es funktioniert super und alle, auch wenn ich fast schüchtern bin zuzugeben, dass ich die Hälfte davon nicht verstehe. Ich habe versucht, es mit TASM kompatibel zu machen, aber es wird nur Müll auf dem Bildschirm erzeugt und eingefroren.

Hier ist, was ich gefunden habe;

.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 

Ich bin mir nicht sicher, ob ich sogar den Interrupt richtig codiert habe. Und wenn ich weiß wie die Ports 060h - 064h funktionieren.

+0

Ihr Hauptproblem ist, dass Sie ein .EXE-Programm während machen Der Code soll zu einem .COM-Programm kompiliert werden. Siehe die aktualisierte Antwort. –

+0

Arbeiten Tetris OS, das tut was Sie wollen: https://github.com/programmable/tetrasm –

Antwort

3

Hier ist, wie Sie es tun können:

; 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, "$" 

Führen Sie es in DOS/Win9x/NT/2K/XP/32-Bit Vista/7 oder DosBox.

UPDATE: TASM Version:

; 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 
+0

Zunächst einmal sollte ich erwähnt haben, dass ich Borland TASM verwenden. Jetzt habe ich deinen Code kompiliert und es funktioniert super und alle, auch wenn ich fast schüchtern bin zuzugeben, dass ich die Hälfte davon nicht verstehe. Ich habe versucht, es mit TASM kompatibel zu machen, aber es wird nur Müll auf dem Bildschirm erzeugt und eingefroren. – DieJay

+0

Ja! Es klappt! Ich habe es so modifiziert, dass die Struktur zu der meines aktuellen Projekts passt und es ist noch nicht kaputt gegangen, das ist einfach perfekt. Ich verstehe nicht genau, wie das funktioniert (für die Ports sowieso), aber solange es so ist, werde ich mich nicht beschweren. Vielen Dank! Jetzt kann ich Actionspiele in Echtzeit machen! = D – DieJay

0

In der Regel für alte Systeme wie diese verwendet Menschen das BIOS ein bisschen wie eine vor-bereitgestellten Reihe von Bibliotheksfunktionen, wo Dinge wie Tastaturfunktionen nur verwendet werden, wenn sie bequem sind. In Ihrem Fall sind die BIOS-Tastatur-Dienste nicht bequem, also verwenden Sie sie nicht.

Stattdessen möchten Sie den Interrupt-Handler des BIOS-Keyboards durch einen eigenen Interrupt-Handler für die Tastatur ersetzen und Ihren eigenen Tastaturtreiber implementieren. Die Tastatur verwendet IRQ1, das ist Interrupt 9. Die Interrupt-Vektortabelle beginnt bei 0x0000: 0x0000, also möchten Sie die 4 Bytes bei 0x0000: 9 * 4 = 0x0000: 0x0024 abrufen und sie irgendwo speichern (damit Sie Dinge zurückstellen können) Wenn Ihre Software beendet wird, geben Sie stattdessen die Adresse (Offset und Segment) des eigenen IRQ-Handlers für die Tastatur ein.

Um Ihren eigenen Tastaturtreiber zu schreiben, möchten Sie zunächst damit beginnen, dass es 2 Hardwareteile gibt. Im Computer befindet sich der Tastatur-Controller-Chip (oder "PS/2-Controller"), der (über serielle Kommunikation) mit einem Chip in der Tastatur selbst kommuniziert.

Informationen auf der Tastatur-Controller-Chip finden Sie so etwas wie http://wiki.osdev.org/%228042%22_PS/2_Controller

Informationen auf dem Chip im Inneren der Tastatur selbst, sehen so etwas wie http://wiki.osdev.org/PS/2_Keyboard

0

Beispiel für das Abfragen des Tastaturanschluss 60h und 64h-Port mit:

 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 
Verwandte Themen