程序集 – 使用自己的键盘中断`int 09h`处理程序时代码的奇怪行
我正在为univesity工作,我们需要创建一个简单的breakout / arkanoid克隆,它很顺利但是我发现了一个错误会删除屏幕上的所有内容,这个bug是随机的,但我怀疑它与我的DrawPaddle功能.也许你可以发现错误或了解为什么视频内存会这样做.
游戏必须使用16位ms-dos程序集完成,我使用NASM VAL Dosbox创建它,我用以下代码编译它: nasm -f obj test.asm val test.obj 游戏只是使用键盘箭头在固定屏幕上移动球拍,您也可以通过按下退出退出游戏. 这是一切都还好:https://puu.sh/yeKtG/affc912d4b.png,当程序溢出时它看起来像这样:http://puu.sh/yeKEy/caeef089d1.png或http://puu.sh/yeKJH/1106e1e823.png 我注意到奇怪的行为只发生在我移动桨时它会随机发生,例如现在我从程序中删除了几乎所有其他东西,它可能需要几次尝试来获取bug. 这是DrawPaddle代码: 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,02222211b 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],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,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,ax ;guardando el modo de video y aplicando el nuevo xor ax,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],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,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,9h int 21h mov al,0 mov ah,4ch int 21h 谢谢阅读!
您可以在键盘中断中修改cx而不保留它.
^^^这是答案(导致你的错误的原因),而不仅仅是一些建议 这里有一些建议如下: 在中断中有任何循环(动态延迟)也是错误的,中断应该尽可能快地进行. 我不记得从头部读取键盘的0x6X端口的正确方法(我只记得它有点棘手,让它完全正确),所以我不打算检查特定的输入/输出序列及其正确性. 但是如果你将在实际当前状态中设置XXXpressed中断,并且主循环将太慢,则可能看不到非常短的按键(因为输入没有被缓冲).对于像arkanoid clone一样的简单游戏,这是可以的,我根本不会被这个打扰,听起来像是正确的行为(你需要实际上非常快地把钥匙保持得这么短). 您还可以通过在中断代码处理程序附近保留一些数据空间(在iret之后将escpressed dw 0移动到代码部分中)来避免中断中的ds设置,然后将其用作mov word [cs:escpressed],1等.如果您实际上以更有效的方式设置内存标志和短中断代码(可以简化很多),那么使用cs的代价:内部中断寻址将低于ds设置. 你有多广泛地将slow 我确实检查了如何编写DOS键盘处理程序,所以这是我的建议(不幸的是我没有测试它,如果它工作): 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,al ; set "enable kbd" bit mov al,ah out 61h,al ; set original value back mov al,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 …然后在游戏代码中,要检查密钥的状态,你也必须使用cs: ... cmp byte [cs:escpressed],1 ... (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- windows – 从MSI文件中检索公共属性
- active-directory – 当您授予用户管理员访问权限时,SBS 20
- windows – 是否可以编写一个不会出现在打印屏幕上的应用程
- windows-server-2003 – 默认Windows共享的重要性
- windows – 什么是流程句柄?
- windows-server-2008 – Windows Server 2008上的管理工具中
- windows – 如何自动拒绝WSUS中的质量汇总更新
- windows-server-2012-r2 – 远程桌面网关MMC在“监控”下没
- windows-7 – 机器始终响应192.168.1.2 IP地址,该地址未在机
- windows-server-2008-r2 – 禁止,减慢或停止对RDP的大量登录