Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 使用自己的键盘中断'int 09h'处理程序时代码的奇怪行为(损坏的绘图)_Assembly_Nasm_Dos_X86 16 - Fatal编程技术网

Assembly 使用自己的键盘中断'int 09h'处理程序时代码的奇怪行为(损坏的绘图)

Assembly 使用自己的键盘中断'int 09h'处理程序时代码的奇怪行为(损坏的绘图),assembly,nasm,dos,x86-16,Assembly,Nasm,Dos,X86 16,我正在为大学做一项任务,我们需要创建一个简单的breakout/arkanoid克隆,它进行得很顺利,但我发现了一个会删除屏幕上所有内容的bug,这个bug是随机的,但我怀疑它与我的Drawpail功能有关。也许你可以发现这个bug,或者知道视频内存为什么会这样做 游戏必须使用16位ms dos汇编完成,我正在使用NASM+VAL+Dosbox创建它,我使用以下工具编译它: nasm -f obj test.asm val test.obj 游戏只需使用键盘箭头在固定屏幕上移动挡板,您也可以按

我正在为大学做一项任务,我们需要创建一个简单的breakout/arkanoid克隆,它进行得很顺利,但我发现了一个会删除屏幕上所有内容的bug,这个bug是随机的,但我怀疑它与我的Drawpail功能有关。也许你可以发现这个bug,或者知道视频内存为什么会这样做

游戏必须使用16位ms dos汇编完成,我正在使用NASM+VAL+Dosbox创建它,我使用以下工具编译它:

nasm -f obj test.asm
val test.obj
游戏只需使用键盘箭头在固定屏幕上移动挡板,您也可以按escape退出游戏

这是在一切都还正常的时候:当程序溢出时看起来是这样的:或者

我注意到这种奇怪的行为只会在我移动划桨时发生,而且它会随机发生,例如,现在我从程序中删除了几乎所有其他内容,可能需要几次尝试才能得到错误

这是抽桨代码:

DrawPaddle:
    push di
    mov di, [paddleposition]
    mov cx, 5 ;the paddle will be 5 pixels tall
.p0:
    push cx
    mov cx, paddlesize
.p1:
    mov byte [es:di], bl
    inc di
    loop .p1
    add di, screenweight - paddlesize
    pop cx
    loop .p0
    pop di
    ret
这是完整的代码,它使用键盘处理程序读取输入,并使用320x200x256直接写入视频内存

BITS 16

stacksize       EQU 0200h

;Constantes
;Direccion de inicio de la memoria de video
videobase       EQU 0a000h

;Definicion de colores
black           EQU 0
green           EQU 00110000b

;Screen data
screenweight    EQU 320


;Paddle data
startx      EQU 140
starty      EQU 170
paddlesize      EQU 40
paddlecolor     EQU 00101010b 

;Paddle movement limits
leftlimit       EQU starty * screenweight + 1 + 10 + 1
rightlimit       EQU ((starty + 1) * screenweight) - paddlesize - 10 - 1

segment mystack stack
    resb stacksize
stacktop:   

segment mydata data

;Variables
escpressed  dw 0
leftpressed     dw 0
rightpressed    dw 0
oldintseg       resw 1
oldintoff       resw 1
originalVideoMode resb 1
paddleposition  resw 1

segment mycode code
;Subrutinas

KeybInt:
        push    ds ;guardamos ds:ax       
        push    ax              

        mov ax, mydata ;los re-inicializamos
        mov ds, ax          

        cli

.getstatus:
        in      al, 64h
        test    al, 02h
        loopnz  .getstatus ;esperando a que el puerto esté listo

        in      al,60h ;obtenemos el codigo make o break de la tecla leida

        cmp     al, 01h ;revisamos si es escape
        jne     .revEsc 
        mov     word [escpressed], 1
        jmp     .kbread
.revEsc:
        cmp     al, 81h ;revisamos si el escape fue soltado
        jne     .revIzq
        mov     word [escpressed], 0
        jmp     .kbread
.revIzq:
        cmp     al, 4bh ;revisamos si es la flecha izquierda
        jne     .revDer
        mov     word [leftpressed], 1
        jmp     .kbread
.revDer:
        cmp     al, 4dh ;revisamos si es la flecha derecha
        jne     .revIzq2
        mov     word [rightpressed], 1
        jmp     .kbread
.revIzq2:
        cmp     al, 0cbh ;si se solto la flecha izquierda
        jne     .revDer2
        mov     word [leftpressed], 0
        jmp     .kbread
.revDer2:
        cmp     al, 0cdh ;o la derecha
        jne     .kbread
        mov     word [rightpressed], 0
        jmp     .kbread
.kbread:
        in      al, 61h     
        or      al, 10000000b
        out     61h, al            
        and     al, 01111111b                     
        out     61h, al                      
        mov     al, 20h
        out     20h, al               

        sti 

        pop     ax ;recuperamos ds:ax       
        pop     ds
        iret

DrawStage:
    push di
    push bx
    ;movemos el cursor a la posicion 10,10
    ;que seria en realidad 10*320+10
    mov di, (10 * screenweight) + 10
    ;ahora repetiremos esto 320-20 veces
    mov cx, 300
.h1:
    mov byte [es:di], green
    inc di
    loop .h1

    mov di, (190 * screenweight) + 10
    ;ahora repetiremos esto 320-20 veces
    mov cx, 301
.h2:
    mov byte [es:di], green
    inc di
    loop .h2    

    ;ahora volveremos al primer punto
    ;y dibujaremos hacia abajo
    mov di, (10 * screenweight) + 10
    ;y lo repetiremos 200-20 veces
    mov cx, 180
.v1:
    mov byte [es:di], green
    add di, screenweight
    loop .v1

    mov di, (10 * screenweight) + 310
    mov cx, 180
.v2:
    mov byte [es:di], green
    add di, screenweight
    loop .v2

    pop bx
    pop di
    ret

;Rutina para dibujar el palo
;Recibe en bl el color del mismo
DrawPaddle:
    push di
    mov di, [paddleposition]
    mov cx, 5 ;the paddle will be 5 pixels tall
.p0:
    push cx
    mov cx, paddlesize
.p1:
    mov byte [es:di], bl
    inc di
    loop .p1
    add di, screenweight - paddlesize
    pop cx
    loop .p0
    pop di
    ret

Delay1:
    mov dx, 4
    sub dx, 3
.pause1:
    mov cx, 6000
.pause2:
    dec cx
    jne .pause2
    dec dx
    jne .pause1
    ret

..start:
    mov ax, mydata
    mov ds, ax
    mov ax, mystack
    mov ss, ax
    mov sp, stacktop

    ;guardando el manejador actual
    mov ah, 35h
    mov al, 9h
    int 21h
    mov [oldintseg], es
    mov [oldintoff], bx

    ;instalando el manejador nuevo
    mov ax, mycode
    mov es, ax
    mov dx, KeybInt
    mov ax, cs
    mov ds, ax
    mov ah, 25h
    mov al, 9h
    int 21h

    ;restaurando el segmento de datos
    mov ax, mydata
    mov ds, ax

    ;guardando el modo de video y aplicando el nuevo
    xor ax, ax
    mov ah, 0fh
    int 10h
    mov [originalVideoMode], al
    mov ah, 00h
    mov al, 13h
    int 10h
    ;coordenada de inicio para el palo
    mov ax, (screenweight * starty) + startx
    mov word [paddleposition], ax
    mov ax, videobase
    mov es, ax

    call DrawStage
    mov bl, paddlecolor
    call DrawPaddle
    jmp .main

.main:
    call Delay1

    ;leemos las entradas
    cmp word [escpressed], 1
    je .dosexit
    cmp word [rightpressed], 1
    je .movRight
    cmp word [leftpressed], 1
    je .movLeft
    jmp .main
.movRight:
    mov bl, black
    call DrawPaddle
    cmp word [paddleposition], rightlimit
    je .ending
    inc word [paddleposition]
    jmp .ending
.movLeft:
    mov bl, black
    call DrawPaddle
    cmp word [paddleposition], leftlimit
    je .ending
    dec word [paddleposition]
    jmp .ending
.ending:    
    mov bl, paddlecolor
    call DrawPaddle
    jmp .main

.dosexit:
    ;restaurando el modo de video original
    mov ah, 00h
    mov byte al, [originalVideoMode]
    int 10h

    ;restaurando el manejador de teclado original
    mov dx, [oldintoff]
    mov ax, [oldintseg]
    mov ds, ax
    mov ah, 25h
    mov al, 9h
    int 21h
    mov al, 0
    mov ah, 4ch
    int 21h

谢谢你的阅读

在键盘中断中修改
cx
,而不保留它

^^^这是答案(是什么导致了你的bug),而不仅仅是一些建议


以下是一些建议:

此外,在中断中使用任何循环(动态延迟)也是错误的,中断应该尽可能快地进行

我记不起什么是读取键盘0x6X端口的正确方法(我只记得完全正确有点棘手),所以我不打算检查特定的
in/out
序列及其正确性

但是,如果您将按实际当前状态在中断中设置
XXXpressed
,并且主循环速度太慢,则可能看不到很短的按键(因为输入没有缓冲)。对于arkanoid clone这样一个简单的游戏来说,这是可以的,我一点也不会为此烦恼,在我看来,这是正确的行为(你需要非常快才能把钥匙握得这么短)

此外,您还可以通过在中断代码处理程序附近保留一些数据空间(将
esccpressed dw 0
移动到
iret
之后的代码部分),然后将其用作
mov word[cs:esccpressed],1
,从而避免在中断中设置,等等。如果您实际以更有效的方式设置内存标志并缩短中断代码(可以大大简化),那么使用
cs:
内部中断寻址的总惩罚将低于
ds
设置

有趣的是,您对所有主循环的使用都非常广泛,但在
延迟
子例程中,您执行的是更快的
dec cx
jnz…
备选方案


最后我确实检查了如何编写DOS键盘处理程序,因此这是我的建议(不幸的是,如果它有效,我没有测试它):

。。。然后在游戏代码中,要检查钥匙的状态,也必须使用
cs

        ...
        cmp     byte [cs:escpressed], 1
        ...

您好,谢谢您的回复,这是一个关于保护cx的好电话,我没有任何问题,因为这一点,但它仍然是很好的建议。键盘中断工作正常,我现在对优化部分不太感兴趣,因为这个橙色屏幕上的死亡错误让我很困扰,我已经完成了游戏,但是由于错误随机出现,你无法完成游戏,我不知道为什么会发生“键盘中断工作正常”-实际上,我正在检查一些文档,您的处理程序完全错误,端口64h的初始读取可能完全错误。。。哦,您不知道损坏的
cx
是如何导致橙色屏幕的-o。。。这是一个中断,它将在执行例如
mov-cx、pallesize
之后,将
cx
设置为
0
,因此下一个
循环。p1
将运行65536次。(相反,您的绘图例程是100%正常和正确的,没有错误,可以优化,但它们是正确的)。。所以这不是建议,而是答案。如果你不明白,问我更多,解释什么:)既然你提到了,这就是原因(cx),我很感激你花了这么多时间看我的代码,我有这个错误大约3天了,然后继续使用这个游戏,现在我有一些空闲时间,我想把它拉出来,谢谢!PS:我也会检查你提到的其他事情,但稍后会:P@cobolatrix我添加了我对中断代码的尝试(还将数据标志移动到
cs
段中,因此您也必须修复游戏代码,以便对新标志作出反应)。但实际上我并没有运行它,但它应该可以工作。。。。是的,应该……:)(你现在可能明白了,这些东西是多么脆弱)我可以确认代码工作正常,这就是关于汇编的事情,你可以用各种方式做事情,甚至可以用很多方式做错事,再次感谢!
        ...
        cmp     byte [cs:escpressed], 1
        ...