2012-05-09 25 views
7

Tôi đã x86 lắp ráp như một sở thích vào tháng trước để tôi có thể chơi game trên các máy tính cũ 8086 như PCj và Tandy 1000, nhưng những cuốn sách tôi tìm thấy không chính xác dạy nhiều về chủ đề cụ thể đó. Trong khi một số dos và bios làm gián đoạn loại công việc, họ đang ở xa hoàn hảo.Làm cách nào để kiểm tra trạng thái khóa trong lắp ráp x86?

Vấn đề chính của tôi là đọc trạng thái bàn phím cho các phím nhấn mà không làm gián đoạn chương trình. Tôi tìm thấy một vài phương pháp, nhưng chúng rất hạn chế. INT 21h, AH 0Ch đọc phím bấm cuối cùng, nhưng theo kiểu ấn bản. Nó không chỉ đọc duy nhất một khóa tại một thời điểm, mà việc phát hiện hit giống như notepad khiến nó không thể biết được chìa khóa đã được giữ trong bao lâu. Tôi cũng đã thấy các tham chiếu đến các cổng 60h đến 64h trong khi Google di chuyển, nhưng đó chỉ là các tham chiếu. Các giải thích thực tế và mã làm việc hầu như không tồn tại. Hoặc có lẽ tôi chỉ là xấu khi sử dụng các công cụ tìm kiếm.

Điều tôi cần biết là liệu khóa có được giữ hay không. Giải pháp tốt nhất là có một bộ đệm/mảng của tất cả các phím bàn phím và đọc trạng thái của nó; 1 có nghĩa là nó xuống, 0 có nghĩa là nó không phải. Hoặc chỉ có quyền truy cập vào danh sách các phím cuối cùng đã bị tấn công và phát hành sẽ tốt đẹp (với một cách để xóa bộ đệm đó, tất nhiên). ai đó có thể chỉ cho tôi phương hướng đúng không?

Chỉnh sửa: Trước hết, tôi nên đề cập rằng tôi sử dụng Borland TASM. Bây giờ tôi đã biên soạn mã của bạn và nó hoạt động tốt và tất cả, mặc dù tôi gần như nhút nhát thừa nhận tôi không hiểu một nửa số đó. Tôi đã cố gắng để làm cho nó tương thích với TASM nhưng tất cả nó làm là tạo ra rác trên màn hình và đóng băng.

Đây là những gì tôi đã đưa ra;

.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 

Tôi không chắc chắn liệu tôi đã mã hóa quyền ngắt hay chưa. Và heck nếu tôi biết làm thế nào các cổng 060h - 064h làm việc.

+0

vấn đề chính của bạn là bạn đang làm một chương trình .EXE trong khi mã được cho là được biên dịch thành một chương trình .COM. Xem câu trả lời được cập nhật. –

+0

Làm việc với hệ điều hành Tetris thực hiện những gì bạn muốn: https://github.com/programble/tetrasm –

Trả lời

3

Đây là cách bạn có thể làm điều đó:

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

Chạy trong DOS/Win9x/NT/2K/XP/32-bit Vista/7 hoặc DosBox.

UPDATE: TASM phiên bản:

; 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

Trước hết, tôi nên đề cập đến việc tôi sử dụng Borland TASM. Bây giờ tôi đã biên soạn mã của bạn và nó hoạt động tốt và tất cả, mặc dù tôi gần như nhút nhát thừa nhận tôi không hiểu một nửa số đó. Tôi đã cố gắng để làm cho nó tương thích với TASM nhưng tất cả nó làm là tạo ra rác trên màn hình và đóng băng. – DieJay

+0

Có! Nó hoạt động! Tôi sửa đổi nó để cấu trúc phù hợp với dự án hiện tại của tôi và nó đã không phá vỡ được, vì vậy đó là chỉ là hoàn hảo. Tôi không hiểu chính xác chi tiết cách thức hoạt động (đối với các cổng anyway), nhưng miễn là nó có, tôi sẽ không phàn nàn. Cảm ơn rất nhiều! Bây giờ tôi có thể tạo trò chơi hành động theo thời gian thực! = D – DieJay

0

Thông thường cho các hệ thống cũ như người này sử dụng BIOS giống như một bộ chức năng thư viện được cung cấp sẵn, nơi những thứ như chức năng bàn phím chỉ được sử dụng nếu chúng thuận tiện. Trong trường hợp của bạn, các dịch vụ bàn phím BIOS không thuận tiện, vì vậy bạn không sử dụng chúng.

Thay vào đó, bạn muốn thay thế trình xử lý ngắt bàn phím BIOS bằng trình xử lý ngắt bàn phím của riêng bạn và thực hiện trình điều khiển bàn phím của riêng bạn. Bàn phím sử dụng IRQ1, bị ngắt 9. Bảng vectơ ngắt bắt đầu tại 0x0000: 0x0000 vì vậy bạn muốn lấy 4 byte tại 0x0000: 9 * 4 = 0x0000: 0x0024 và lưu trữ chúng ở đâu đó (để bạn có thể đặt mọi thứ trở lại để bình thường khi phần mềm của bạn thoát) và đặt địa chỉ (bù đắp rồi phân đoạn) của trình xử lý IRQ bàn phím của riêng bạn ở đó để thay thế.

Để viết trình điều khiển bàn phím của riêng bạn, bạn muốn bắt đầu bằng cách hiểu rằng có 2 phần cứng liên quan. Có chip điều khiển bàn phím (hoặc "bộ điều khiển PS/2") trong máy tính có đàm thoại (thông qua giao tiếp nối tiếp) với một con chip bên trong chính bàn phím.

Để biết thông tin trên chip điều khiển bàn phím, thấy cái gì đó như http://wiki.osdev.org/%228042%22_PS/2_Controller

Để biết thông tin trên chip bên trong bàn phím chính nó, nhìn thấy cái gì đó như http://wiki.osdev.org/PS/2_Keyboard

0

Ví dụ về bỏ phiếu bàn phím sử dụng cổng 60h và cổng 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 
Các vấn đề liên quan