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

前端 未结 1 630
粉色の甜心
粉色の甜心 2020-12-11 08:45

I\'m working on an assignment for the univesity, we need to create a simple breakout/arkanoid clone, it is going pretty well but I found a bug that would delete everything o

相关标签:
1条回答
  • 2020-12-11 09:38

    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
            ...
    
    0 讨论(0)
提交回复
热议问题