x86-16 MBR引导加载器中BIOS读字符宏仅生效一次问题排查
Pong游戏MBR引导加载器按键无响应问题排查与解决
问题分析
你的代码中按下‘s’键仅首次触发球拍绘制,后续无响应,核心问题出在宏的跳转逻辑和键盘输入处理两个方面:
宏的非法跳转截断后续代码
drawRacket宏的.fim1标签中使用jmp mainLoop,会直接跳出宏和moveDown函数,导致moveDown中更新playerPosition的代码完全无法执行——球拍位置从未改变,自然看不到后续移动效果。键盘缓冲区未清空
使用int 16h ah=01h仅检查键盘缓冲区是否有输入,不会读取/清空缓冲区。首次按下‘s’后,字符会一直留在缓冲区,后续每次检查都会重复触发moveDown,但因为位置未更新,视觉上无变化。
解决方案
1. 修复宏的跳转逻辑
将宏内的jmp mainLoop改为跳转到宏内部的结束标签,确保宏执行完毕后回到调用点继续执行后续代码:
%macro drawRacket 2 mov ah, 0ch ; 像素绘制模式 mov dx, %2 for1: mov bx, 32 ; 球拍高度 add bx, %2 cmp dx, bx ; 判断是否到达球拍底部 je .fim1 mov cx, %1 ; 球拍起始列 jmp .for2 .fim1: jmp .endMacro ; 跳转到宏结束标签,而非直接回主循环 ; 绘制单行像素的循环 .for2: mov bx, 8 ; 球拍宽度 add bx, %1 cmp cx, bx ; 判断是否到达球拍右侧 je .fim2 mov al, 0x0f ; 白色像素 mov ah, 0ch int 10h inc cx jmp .for2 .fim2: inc dx jmp for1 .endMacro: ; 新增宏结束标签 %endmacro
2. 修复键盘输入处理
检测到输入后,使用int 16h ah=00h读取字符以清空缓冲区,避免重复触发相同操作:
mainLoop: mov ah, 01h int 16h jz mainLoop ; 无输入则循环等待 ; 读取字符,清空键盘缓冲区 mov ah, 00h int 16h cmp al, 115 ; 's'键的ASCII码 je moveDown jmp mainLoop
3. 优化:清除旧球拍(可选)
每次移动前清除旧位置的球拍,避免画面叠加混乱。新增clearRacket宏,并在moveDown中先清旧再绘新:
; 清除指定位置的球拍(用黑色像素覆盖) %macro clearRacket 2 mov ah, 0ch ; 像素绘制模式 mov dx, %2 mov al, 0x00 ; 黑色像素 for1_clear: mov bx, 32 ; 球拍高度 add bx, %2 cmp dx, bx je .fim1_clear mov cx, %1 jmp .for2_clear .fim1_clear: jmp .endMacro_clear .for2_clear: mov bx, 8 ; 球拍宽度 add bx, %1 cmp cx, bx je .fim2_clear mov ah, 0ch int 10h inc cx jmp .for2_clear .fim2_clear: inc dx jmp for1_clear .endMacro_clear: %endmacro
修改moveDown函数:
moveDown: clearRacket 10, word[playerPosition] ; 清除旧位置球拍 mov ax, word[playerPosition] inc ax mov word[playerPosition], ax ; 更新位置 drawRacket 10, word[playerPosition] ; 绘制新位置球拍 jmp mainLoop
内容的提问来源于stack exchange,提问作者Deepak C
相关产品推荐
相关产品推荐

