在 16 位 ISA 总线环境下,VGA 显存访问并非简单地通过线性地址读写,而是一套涉及内存窗口映射、银行切换机制和索引式寄存器访问的复杂体系。理解这一体系的运作原理,对于编写低层图形代码、操作系统引导程序或复古游戏模拟器而言至关重要。
内存映射与分段窗口限制
VGA 显存被映射到系统物理地址空间的特定区域。在标准 VGA 配置下,显存窗口位于 0xA0000 至 0xAFFFF 范围,共 64KB。这一地址范围通过段寄存器访问:以 A000h 为段基址,0000h 至 FFFFh 为偏移量,即可直接寻址该窗口内的任意字节。对于 320×200 256 色模式(Mode 13h),这 64KB 恰好容纳整个帧缓冲 —— 每像素一字节,总计 64000 字节,剩余空间用于字符生成器等用途。
然而,64KB 的窗口限制很快成为瓶颈。当需要访问更大显存空间时(例如真彩色模式或分页操作),就必须在不同银行之间切换,使特定物理显存区域在窗口中可见。这种银行切换机制由 VGA 硬件内部的寄存器组控制,而非直接通过内存操作实现。
索引式寄存器访问:地址 / 数据端口对
VGA 控制器包含多个寄存器组,但 I/O 端口数量远少于寄存器数量,因此采用了索引式访问模式。每个寄存器组配备两个专用端口:地址端口用于指定目标寄存器的索引,数据端口用于读写该寄存器的值。
图形控制器寄存器组使用 0x3CE(地址端口)和 0x3CF(数据端口)。访问流程为:先将目标寄存器索引写入 0x3CE,然后对 0x3CF 进行读写操作。例如,访问图形模式寄存器(索引 0x05)的典型代码序列为:
mov dx, 3CEh ; 地址端口
mov ax, 0505h ; AL=索引, AH=值
out dx, ax ; 先写索引 05,再写数据
序列器寄存器组采用相同的模式,通过 0x3C4(地址)和 0x3C5(数据)访问。内存模式寄存器(索引 0x04)控制 Chain 4、奇偶模式和扩展内存等关键功能:
- Bit 3 (Chain 4):启用时,地址的最低两位用于选择显存平面,而非按字节序列寻址
- Bit 2 (Odd/Even):启用时,奇地址访问平面 0/2,偶地址访问平面 1/3
- Bit 1 (Extended Memory):禁用 64KB 模式,允许访问全部显存
CRT 控制器寄存器组则通过 0x3D4/0x3D5(彩色模式)或 0x3B4/0x3B5(单色模式)访问,用于配置扫描时序、显示起始地址和光标位置等。
杂项输出寄存器与内存映射选择
外部寄存器组中,杂项输出寄存器(Miscellaneous Output Register)是最关键的配置寄存器之一。该寄存器写入地址为 0x3C2,读取地址为 0x3CC—— 这种读写地址分离的设计是为了向后兼容 EGA 的只写寄存器。
该寄存器的 bit 3-2 控制显存映射窗口的位置:
| bit3 | bit2 | 内存区域 | 窗口大小 |
|---|---|---|---|
| 0 | 0 | A000h | 128KB |
| 0 | 1 | A000h | 64KB |
| 1 | 0 | B000h | 32KB |
| 1 | 1 | B800h | 32KB |
bit 0 (I/O Address Select) 则决定 CRT 控制器和其他端口的地址空间:设为 0 时选择单色适配器的 0x03Bx 地址范围,设为 1 时选择彩色适配器的 0x03Dx 地址范围。
写模式与银行切换的协同工作
在直接显存访问层面,图形控制器模式寄存器(索引 0x05)的 bit 1-0 定义了四种写模式:
- 模式 0:直接写入,数据经过旋转和 Set/Reset 处理后写入选定平面
- 模式 1:使用处理器锁存器作为写入数据
- 模式 2:字节的每一位写入对应平面(位平面填充模式)
- 模式 3:写入数据与位掩码进行 AND 操作,Set/Reset 用于所有平面
在实际银行切换场景中,软件通常需要:先通过序列器的内存模式寄存器配置地址解码方式,再通过图形控制器的 Map Mask 寄存器(索引 0x02,端口 0x3C4/0x3C5)选择要写入的显存平面,最后执行显存操作。切换银行时,修改相应寄存器的银行选择位即可将不同物理显存区域映射到 CPU 可见的窗口中。
工程实践:I/O 延迟与状态保护
由于 VGA 硬件响应速度跟不上高速 CPU 的 I/O 操作,寄存器访问之间必须插入适当延迟(I/O Fudge Factor)。延迟长度因具体硬件实现而异,不当的时序可能导致写入数据丢失或寄存器状态异常。
另一个工程实践要点是状态保护:修改任何寄存器前,应先读取当前值并保存,程序退出时恢复原始状态。这在图形程序可能被异常中断的场景下尤为重要。属性寄存器组(端口 0x3C0)通过内部触发器切换索引 / 数据模式,读取输入状态寄存器 #1(0x3DA)可重置触发器,但中断处理代码若在访问中途读取该端口,可能导致后续写入被误解释为索引操作,引发寄存器损坏。
VGA 显存银行切换与 I/O 端口寄存器寻址的复杂性,本质上反映了 16 位 ISA 时代的硬件资源约束与软件灵活性之间的权衡。掌握这些机制不仅有助于理解早期 PC 图形架构,也为现代系统程序员提供了宝贵的底层知识资产。
资料来源:VGA I/O Registers Documentation (osdever.net);FreeVGA Project (Stanford)
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。