weird behaviour of code (corrupted draw) when using own keyboard interrupt `int 09h` handler

房东的猫 提交于 2019-11-28 12:35:03

You modify cx in your keyboard interrupt without preserving it.

^^^ this is the ANSWER (what is causing your bug), not just some advice


Here some advice is following:

Also it feels wrong to have any loop (dynamic delay) in interrupt, interrupts should proceed as fast as possible.

I can't recall from head what is correct way to read 0x6X ports of keyboard (I just recall it is a bit tricky, to have it fully correct), so I'm not going to check particular in/out sequence and its correctness.

But if you will set XXXpressed in interrupt by actual current state, and the main loop will be too slow, it may not see very short key presses (as the input is not buffered). For a simple game as arkanoid clone this is OK, and I wouldn't be bothered by this at all, sounds to me as correct behaviour (you would need to be actually incredibly fast to hold the key so short).

Also you can avoid ds setup in interrupt by reserving some data space near the interrupt code handler (moving escpressed dw 0 into the code part after iret), then using that everywhere as mov word [cs:escpressed], 1, etc. The total penalty for using cs: addressing inside interrupt would be lower than the ds setup, if you would actually set the memory flags in more efficient manner and short interrupt code (can be simplified a lot).

And it's sort of funny how extensively you use slow loop instruction for all main loops, but then in delay subroutine you do the faster dec cx jnz ... alternative.


And I did check in the end how to write DOS keyboard handler, so this is my suggestion (unfortunately I didn't test it, if it works):

segment mycode code

escpressed      db 0
leftpressed     db 0
rightpressed    db 0

KeybInt:
        cli
        push    ax      ;guardamos ax

        ; when IRQ1 is fired, int 9 is called to handle it and the input
        ; already waits on port 0x60, no need to validate IBF flag on 0x64

        in      al,60h ;obtenemos el codigo make o break de la tecla leida
        mov     ah,al
        and     al,0x7F ; AL = scan code without pressed/released flag
        shr     ah,7
        xor     ah,1    ; AH = 1/0 pressed/released

        cmp     al, 01h ;revisamos si es escape
        jne     .checkLeft
        mov     [cs:escpressed], ah
        jmp     .kbread
.checkLeft:
        cmp     al, 4bh ;revisamos si es la flecha izquierda
        jne     .checkRight
        mov     [cs:leftpressed], ah
        jmp     .kbread
.checkRight:
        cmp     al, 4dh ;revisamos si es la flecha derecha
        jne     .kbread
        mov     [cs:rightpressed], ah
.kbread:

        in      al, 61h
        mov     ah, al          ; store original value
        or      al, 10000000b
        out     61h, al         ; set "enable kbd" bit
        mov     al, ah
        out     61h, al         ; set original value back

        mov     al, 20h
        out     20h, al         ; send end-of-interrupt signal to 8259 IC

        pop     ax ;recuperamos ax
        sti        ; not needed in real x86 real mode, IRET restores flags
        iret       ; but explicit STI paired with CLI may help some VMs

... then in game code, to check state of key, you must use cs too:

        ...
        cmp     byte [cs:escpressed], 1
        ...
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!