【问题标题】:Set and reset keyboard Interrupt Service Routines in x86 real mode within DOS with Assembly在 DOS 中使用程序集在 x86 实模式下设置和重置键盘中断服务例程
【发布时间】:2017-08-07 00:28:12
【问题描述】:

如何在 DOS 中正确设置并重置键盘 ISR? (x86 汇编,实模式,16 位,带 TASM)

我有以下为键盘设置 ISR 的汇编代码。它应该做的就是每次按下一个键时打印一个句子,最多五次。然后它应该退出。

ISR 似乎安装正确。每次按下一个键(一次向下,一次向上)时,它会打印出一个句子。但是,似乎我错误地卸载了 ISR,因为在运行程序后我无法在 DOS 命令行中输入文本。

(由于目前收到的反馈,我已更新以下代码以在 ISR 中存储/恢复 DS、从端口 60h 读取并处理 EOI 调用。)

.model              small
.data

our_text            db      "Interrupt intercepted", 0dh, 0ah, "$"
old_int_seg         dw      0
old_int_off         dw      0
keyCount            dw      0
.code
.startup
                    cli
                    mov     ah, 035             ; get current keyboard int vector
                    mov     al, 09h             ; and save it, so we can restore it later
                    int     21h                 
                    mov     [old_int_off], bx   
                    mov     bx, es
                    mov     [old_int_seg], bx

                    mov     ax, cs
                    mov     ds, ax              ; load data segment with code segment 
                                                ;(the one we are in now)
                    mov     ah, 25h             ; Set Interrupt Vector Command
                    mov     al, 9               ; Interrupt to replace
                    lea     dx, ISR             ;load dx with our interrupt address
                    int     21h
                    sti

                    mov     ax,@data
                    mov     ds,ax
infinite:
                    mov     ax,keyCount[0]
                    cmp     ax,5
                    jl      infinite                ;check for 5 presses


                    cli                             ;restore old interrupt
                    mov     ax, [old_int_seg]
                    mov     ds, ax
                    mov     dx, [old_int_off]
                    mov     ah, 25h
                    mov     al, 09h
                    int     21h
                    sti

                    mov     ah,4Ch                  ; quit
                    mov     al,00h
                    int     21h

ISR                 proc    far
                                                    ; save old registers
                    push    ax
                    push    cx
                    push    dx
                    push    bx
                    push    sp
                    push    bp
                    push    si
                    push    di
                    push    ds

                    mov     ax,@data                ;print text
                    mov     ds,ax
                    xor     ah,ah
                    mov     ah, 9
                    lea     dx, our_text
                    int     21h

                    mov     ax,keyCount
                    inc     ax
                    mov     [keyCount],ax

                    in      al, 60h

                    ; send EOI to 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

                    pop     ds
                    pop     di
                    pop     si
                    pop     bp
                    pop     sp
                    pop     bx
                    pop     dx
                    pop     cx
                    pop     ax
                    iret
ISR                 endp     

我在恢复原始键盘 ISR 的方式上有什么问题?为什么我在运行程序后无法在 DOS 的命令提示符中输入任何内容?

【问题讨论】:

  • 您的键盘 ISR 必须从端口 0x60 读取一个字节,否则您将不会发生后续中断。您还必须向 PIC(可编程中断控制器)发送中断结束
  • 由于您更改了 DS,您的中断处理程序还应该保存和恢复 DS 的值,就像您可能修改的所有其他寄存器一样。跨度>
  • @MichaelPetch,感谢您的出色建议。我现在从 0x60 读取字节,向键盘和 PIC 发送 EOI 信号,并保存/恢复 DS。 (我已经更新了我的问题中的所有代码以反映这些更改。)该程序现在可以正常运行,除了一件小事:程序终止后我无法在 DOS 命令行中输入任何文本,所以我想我是没有正确恢复原始 ISR?
  • mov ah, 035 应该是 mov ah, 35h 。您调用了错误的软件中断并为向量获取了垃圾。另一个问题是此代码不正确:mov ax, [old_int_seg]mov ds, axmov dx, [old_int_off] 在读取不正确的偏移量之前更改 DS。应该是mov ax, [old_int_seg]mov dx, [old_int_off]mov ds, ax
  • 你太棒了!非常感谢你。既然您在 cmets 中给出了答案,那么我有什么方法可以为您提供答案吗?

标签: assembly keyboard interrupt-handling tasm x86-16


【解决方案1】:

如果有帮助的话,这里是我用 NASM

编码的用于 MS-DOS 的古老键盘处理程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Keyboard int 09 driver ver: 1.4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;keywait    wait for change from keyboard scancode >> ax
;keyadr     si<=adr of NAME of keycode in ax
;int09i     install int 09
;int09u     uninstall int 09
;int09      update tab press/pop status (0=pop,255=pressed) and key...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;key.ascii  ASCII key code      byte
;key.scan   tab key code        word
;key.name   adr of key name in tab  word
;key.tab0/1/2   scan(Byte) ,pressed/poped,ASCII,ASCIIZ
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Subroutines: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
keywait:mov ax,[cs:key.scan];wait for change from keyboard scancode >> ax
.l0:    cmp ax,[cs:key.scan]
    jz  .l0
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
keyadr: push    ax      ;si<=adr of NAME of keycode ax
    cmp ax,197+512      ;not if Pause or Break
    jz  .q0
    cmp ax,198+512
    jz  .q0
    and al,127
.q0:    lea si,[cs:key.tab0]
    cmp ah,0
    jz  .r0
    lea si,[cs:key.tab1]
    cmp ah,1
    jz  .r0
    lea si,[cs:key.tab2]
    cmp ah,2
    jz  .r0
    jmp .err
.r0:    xchg    al,ah
.l0:    mov al,[cs:si]
    add si,3
    cmp al,ah
    jz  .esc
    cmp al,255
    jz  .err
.l1:    mov al,[cs:si]
    inc si
    or  al,al
    jnz .l1
    jmp .l0
.err:   lea si,[cs:.errkey]
.esc:   pop ax
    ret
    db      1,0,'?'
.errkey:db  'Unknown key',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
int09i: pusha           ;install int 09
    push    es
    mov     al,9h
    mov     ah,35h
    int     21h
    mov     [cs:int09.vect],bx
    mov     [cs:int09.vect+2],es
    mov     al,9h
    mov     ah,25h
    lea     dx,[cs:int09]
    int     21h
    pop es
    popa
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
int09u: push    ds      ;uninstall int 09
    pusha
    mov     dx,[cs:int09.vect]
    mov     ax,[cs:int09.vect+2]
    mov     ds,ax
    mov     al,9h
    mov     ah,25h
    int     21h
    popa
    pop     ds
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Prerusenia: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
int09:  cli         ;keyboard
    pusha
    in  al,60h
    mov bx,[cs:key.stat]
    cmp bl,1
    jz  .r1
    cmp bl,2
    jz  .r2
.r0:    inc bl      ;level0 ... first byte of scan code
    cmp al,0E0h
    jz  .esc
    inc bl
    mov bh,5
    cmp al,0E1h
    jz  .esc
    sub ah,ah       ;normal code
    mov [cs:key.scan],ax
    sub bx,bx
    jmp .esc
.r1:    mov bx,2+256*2  ;level1 ... second byte of scan code
    cmp al,2Ah
    jz  .esc
    cmp al,46h
    jz  .esc
    cmp al,0AAh
    jz  .esc
    mov ah,1        ;extended1 code
    mov [cs:key.scan],ax
    sub bx,bx
    jmp .esc
.r2:    dec bh
    jnz .esc
    mov ah,2        ;extended2 code
    mov [cs:key.scan],ax
    sub bx,bx
.esc:   mov [cs:key.stat],bx
    mov ax,[cs:key.scan]
    call    keyadr
    mov ah,[cs:si-1]    ;ASCII
    mov [cs:key],ah
    mov [cs:key.name],si;NAME ADR
    and al,128
    jz  .keyp1
.keyp0: sub ax,ax
    mov [cs:si-2],al
    mov [cs:key],al
    mov [cs:key.scan],ax
    mov [cs:key.name],word key.tab0+3
    jmp .esc0
.keyp1: mov [cs:si-2],byte 255
.esc0:  in  al,61h      ;end of interrupt ...this is a must
    mov     ah,al
    or  al,80h
    out     61h,al
    xchg    al,ah
    out     61h,al
    mov     al,20h
    out     20h,al
    popa
    sti
    iret
.vect:  dw  0,0

key:
.ascii  db  0       ;ASCII
.scan   dw  0       ;low=key code ,hi=tab 0,1,2
.name   dw  0       ;adr of key NAME

.stat:  db  0,0     ;byte count of code,number of readed byte

;tables:    scancode low(hi is tab 0,1,2),pressed/poped,ASCII,name,0
.tab0:  db      0,0,' ','                 ',0   ;basic scan codes
    db      1,0,'?','Esc',0
    db  2,0,'1','1',0
    db      3,0,'2','2',0
    db      4,0,'3','3',0
    db      5,0,'4','4',0
    db      6,0,'5','5',0
    db      7,0,'6','6',0
    db      8,0,'7','7',0
    db      9,0,'8','8',0
    db  10,0,'9','9',0
    db      11,0,'0','0',0
    db      12,0,'-','-',0
    db      13,0,'=','=',0
    db      14,0, 8 ,'Backspace',0
    db      15,0, 9 ,'Tab',0
    db      16,0,'Q','Q',0
    db      17,0,'W','W',0
    db      18,0,'E','E',0
    db      19,0,'R','R',0
    db      20,0,'T','T',0
    db      21,0,'Y','Y',0
    db      22,0,'U','U',0
    db      23,0,'I','I',0
    db      24,0,'O','O',0
    db      25,0,'P','P',0
    db      26,0,'[','[',0
    db      27,0,']',']',0
    db      28,0, 13,'Enter',0
    db      29,0,'?','L-Ctrl',0
    db      30,0,'A','A',0
    db      31,0,'S','S',0
    db      32,0,'D','D',0
    db      33,0,'F','F',0
    db      34,0,'G','G',0
    db      35,0,'H','H',0
    db      36,0,'J','J',0
    db      37,0,'K','K',0
    db      38,0,'L','L',0
    db      39,0,';',';',0
    db      40,0,'"','"',0
    db      41,0,'~','~',0
    db      42,0,'?','L-Shift',0
    db      43,0,'\','\',0
    db      44,0,'Z','Z',0
    db      45,0,'X','X',0
    db      46,0,'C','C',0
    db      47,0,'V','V',0
    db      48,0,'B','B',0
    db      49,0,'N','N',0
    db      50,0,'M','M',0
    db      51,0,',',',',0
    db      52,0,'.','.',0
    db      53,0,'/','/',0
    db      54,0,'?','R-Shift',0
    db      55,0,'*','Num *',0
    db      56,0,'?','L-Alt',0
    db      57,0,' ','Space',0
    db      58,0,'?','Caps Lock',0
    db      59,0,'?','F1',0
    db      60,0,'?','F2',0
    db      61,0,'?','F3',0
    db      62,0,'?','F4',0
    db      63,0,'?','F5',0
    db      64,0,'?','F6',0
    db      65,0,'?','F7',0
    db      66,0,'?','F8',0
    db      67,0,'?','F9',0
    db      68,0,'?','F10',0
    db      69,0,'?','Num Lock',0
    db      70,0,'?','Scroll Lock',0
    db      71,0,'7','Num 7',0
    db      72,0,'8','Num 8',0
    db      73,0,'9','Num 9',0
    db      74,0,'-','Num -',0
    db      75,0,'4','Num 4',0
    db      76,0,'5','Num 5',0
    db      77,0,'6','Num 6',0
    db      78,0,'+','Num +',0
    db      79,0,'1','Num 1',0
    db      80,0,'2','Num 2',0
    db      81,0,'3','Num 3',0
    db      82,0,'0','Num 0',0
    db      83,0,'.','Num .',0
    db      84,0,'?','Alt-Prnscr',0
    db      87,0,'?','F11',0
    db      88,0,'?','F12',0
    db      255
.tab1:  db      28,0,'?','Num Enter',0  ;scan codes after E0h
    db      29,0,'?','R-Ctrl',0
    db      53,0,'/','Num /',0
    db      55,0,'?','System Request',0
    db      56,0,'?','R-Alt',0
    db      71,0,'?','Home',0
    db      72,0,'?','Up',0
    db      73,0,'?','Page Up',0
    db      75,0,'?','Left',0
    db      77,0,'?','Right',0
    db      79,0,'?','End',0
    db      80,0,'?','Down',0
    db      81,0,'?','Page Down',0
    db      82,0,'?','Ins',0
    db      83,0,'?','Del',0
    db  93,0,'?','Win F2',0
    db      255
.tab2:  db  55,0,'?','Print Screen',0   ;scan codes after E0h AAh E0h
    db      53,0,'?','Shift-Num /',0
    db      71,0,'?','Shift-Home',0
    db      72,0,'?','Shift-Up',0
    db      73,0,'?','Shift-Page Up',0
    db      75,0,'?','Shift-Left',0
    db      77,0,'?','Shift-Right',0
    db      79,0,'?','Shift-End',0
    db      80,0,'?','Shift-Down',0
    db      81,0,'?','Shift-Page Down',0
    db  82,0,'?','Shift-Insert',0
    db  83,0,'?','Shift-Delete',0
    db  197,0,'?','Pause',0
    db  198,0,'?','Break',0
    db  255
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Scan codes constants: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.esc    equ 1
.n1 equ 2
.n2 equ 3
.n3 equ 4
.n4 equ 5
.n5 equ 6
.n6 equ 7
.n7 equ 8
.n8 equ 9
.n9 equ 10
.n0 equ 11
.minus  equ 12
.equal  equ     13
.bckspc equ     14
.tab    equ     15
.q  equ     16
.w  equ     17
.e  equ     18
.r  equ     19
.t  equ     20
.y  equ     21
.u  equ     22
.i  equ     23
.o  equ     24
.p  equ     25
.enter  equ     28
.lctrl  equ     29
.a  equ     30
.s  equ     31
.d  equ     32
.f  equ     33
.g  equ     34
.h  equ     35
.j  equ     36
.k  equ     37
.l  equ     38
.lshift equ     42
.z  equ     44
.x  equ     45
.c  equ     46
.v  equ     47
.b  equ     48
.n  equ     49
.m  equ     50
.rshift equ     54
.lalt   equ     56
.space  equ     57
.caps   equ     58
.f1 equ     59
.f2 equ     60
.f3 equ     61
.f4 equ     62
.f5 equ     63
.f6 equ     64
.f7 equ     65
.f8 equ     66
.f9 equ     67
.f10    equ     68
.f11    equ     87
.f12    equ     88

.rctrl  equ 256+29
.ralt   equ 256+56
.home   equ 256+71
.up equ 256+72
.pgup   equ 256+73
.left   equ 256+75
.right  equ 256+77
.end    equ 256+79
.down   equ 256+80
.pgdown equ 256+81
.insert equ 256+82
.delete equ 256+83
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; End. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

【讨论】:

  • 谢谢。从那以后,我在 Michael Petch 的帮助下解决了这个问题,并为它创建了一个功能性 ISR(但忘记在这里发布我必须做的答案!)这让我可以轮询密钥而不是等待。当需要一次处理一个键时,您的代码肯定会派上用场,对吗?我仍然对 asm 感到陌生,但这就是我的样子。它看起来结构良好且易于使用,与我的第一个键盘处理程序不同。我希望我在开始时能把它拿回来。
  • @MarkInTheDark 此代码一次处理任意数量的键(受粗略的键盘硬件限制)。每个键都有自己的真/假状态,可以随时探测。我用它来玩游戏。如果我没记错的话,TASM 不知道像 .tab0 这样的本地标签,所以你需要移植到 TASM 样式。不确定那里是否有一些针对本地标签的指令(我的赌注是@),所以如果没有,那么所有标签都必须重命名为唯一的全局标签......但可能是更新的 TASM 编译器版本可以处理它我使用它年龄以前...
  • @MarkInTheDark 如果你有兴趣也可以看看What is the best way to move an object on the screen?这是我的TASM中的小型古代asm游戏
猜你喜欢
  • 2016-04-06
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-05
相关资源
最近更新 更多