You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 13:53:23