MASM下AX=12h模式(640*480 16色VGA)显存读取异常排查
显存读取函数问题排查与修正
问题描述
已实现可正常运行的显存点绘制函数(坐标cx、dx),现编写读取指定坐标颜色值并返回至al(范围0-15)的函数vmemr,复用写函数的显存定位逻辑但未得到预期结果:
- 测试程序显示能检测到屏幕点,但存在约8像素的无响应区域,推测与
x/8的偏移计算有关 - 全屏绘制后,调试时无法在代码视图找到
A000内存段数据,无法进一步调试
函数代码:
vmemr PROC push ax push bx push cx push dx push di mov ax, 0A000h ; video memory start point mov es, ax ;offset=y*(640/8)+(x/8) mov ax, dx mov bx, 80 mul bx mov di, ax mov ax, cx mov bx, 8 div bx add di, ax ; di=offset mov al, es:[di] pop di pop dx pop cx pop bx pop ax ret vmemr ENDP
问题分析与解决
1. 核心错误:显存定位逻辑与视频模式不匹配+寄存器恢复覆盖结果
错误点拆解
- 视频模式偏移计算错误:你标注的
offset=y*(640/8)+(x/8)对应2色1位像素模式(每行80字节),但需求是返回0-15的颜色值,说明实际是16色4位像素模式。该模式下640宽的屏幕每行字节数为640*4/8=320,且每字节存储2个像素(高4位、低4位各一个),你的计算完全不符合该模式的存储规则,导致8像素的误差(同一字节内的8个像素被当成同一个字节处理)。 - 寄存器恢复覆盖结果:函数开头
push ax,结尾pop ax会把调用前的ax值恢复,直接覆盖掉读取到的颜色值al,等于白读取。
修正后的16色640模式读取函数
vmemr PROC ; 只保存会被修改的寄存器,不保存ax(避免覆盖返回值) push bx push cx push dx push di mov ax, 0A000h mov es, ax ; 计算行偏移:y * 320(16色640宽模式每行320字节) mov ax, dx mov bx, 320 mul bx mov di, ax ; 计算像素所在字节偏移与位位置 mov ax, cx mov bx, 2 div bx ; ax = x/2(字节偏移),dx = x%2(判断取高/低4位) add di, ax mov al, es:[di] ; 读取对应字节 test dx, dx ; x为偶数则取高4位,奇数取低4位 jz .read_high and al, 0Fh ; 保留低4位 jmp .read_done .read_high: shr al, 4 ; 高4位移至低4位,得到0-15的颜色值 .read_done: ; 恢复寄存器,不碰ax(al是返回值) pop di pop dx pop cx pop bx ret vmemr ENDP
2. 无法查看A000段数据的调试解决
- 切换调试器至实模式内存视图:现代调试器默认多为保护模式视图,需手动输入地址
0A000:0000定位显存段。 - 使用DOSBox等模拟器的内置调试命令:比如输入
d A000:0直接查看显存内容,无需依赖代码视图。 - 确认当前处于图形模式:只有在VGA图形模式下,
0A000h段才会映射到显存,文本模式下该段为无效数据。
内容的提问来源于stack exchange,提问作者user27789527
相关产品推荐
相关产品推荐

