MASM下VGA 12h模式(640*480 16色)显存绘点改色求助
解决VGA显存绘制不同颜色点的问题
你的代码只能显示白色点,核心问题有两个:一是固定修改单个显存平面的整字节,未针对目标像素的具体位操作;二是未根据颜色值控制多个位平面的读写。以下是具体分析和修正方案:
问题根源
- 未定位像素的具体位:你计算了显存字节偏移
di,但没处理像素在字节内的位位置,直接覆盖整个字节会导致同一字节内的8个像素被同时修改。 - 固定平面与颜色值:代码仅启用第1个位平面,且固定写入值
4,只能修改像素颜色的某一位,其他位保留原有显存数据(若原本为1则显示白色)。
VGA 16色模式(640x480,模式12h)中,每个像素由4个位平面(0-3)的对应位共同决定颜色,4位组合对应0-15共16种颜色(0=黑,15=白)。
修正后的代码
以下函数通过bl寄存器接收0-15的颜色码,绘制指定颜色的点:
vmem1 PROC mov ax, 0A000h ; 显存起始地址 mov es, ax ; 计算显存字节偏移: di = 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 是像素所在的显存字节偏移 ; 计算像素在字节中的位位置: 7 - (x % 8),字节最高位对应最左像素 mov ax, cx and ax, 7 ; ax = cx % 8 mov cl, al mov al, 80h ; 初始掩码为10000000b shr al, cl ; al = 目标位的掩码 mov ah, al ; 保存掩码到ah mov cx, bx ; cx = 传入的颜色值(bl) ; 遍历4个位平面(对应颜色的4位) mov dx, 3C4h ; VGA序列寄存器端口 mov si, 0 ; si = 当前平面索引(0-3) plane_loop: mov al, 2 ; 序列寄存器索引2:平面掩码 out dx, al inc dx mov al, 1 << si ; 仅启用当前平面 out dx, al dec dx ; 检查颜色的当前位是否为1 mov al, cl shr al, si and al, 1 jz clear_bit ; 位为0则清除对应位 set_bit: mov al, ah or es:[di], al ; 设置对应位 jmp next_plane clear_bit: mov al, ah not al and es:[di], al ; 清除对应位 next_plane: inc si cmp si, 4 jl plane_loop ret vmem1 ENDP
关键步骤说明
- 颜色参数:调用函数前将0-15的颜色码存入
bl,比如mov bl, 4对应红色,mov bl, 14对应黄色。 - 位掩码生成:通过
cx%8计算像素在字节内的位置,生成仅目标位为1的掩码,确保只修改目标像素,不影响同字节的其他像素。 - 位平面操作:遍历4个位平面,每个平面对应颜色的一位:
- 设置序列寄存器的平面掩码,仅允许当前平面读写;
- 根据颜色的对应位,决定是设置还是清除显存中的目标位。
内容的提问来源于stack exchange,提问作者user27789527
相关产品推荐
相关产品推荐

