Hotdry.

Article

16位实模式汇编与VGA模式13h:从BIOS中断到帧缓冲直写的复古图形编程

探索16位实模式下BIOS中断调用、VGA模式13h图形渲染与PIT定时器编程的复古系统编程技术栈,提供可直接运行的引导扇区代码骨架。

2026-05-24systems

在当代图形 API 动辄封装数千行抽象层的背景下,直接操作硬件的编程方式反而成为一种稀缺的技术体验。16 位实模式汇编配合 VGA 模式 13h,代表了一个极简却功能完整的图形编程切口 —— 仅用几十行代码就能让屏幕逐像素响应指令,这种 "所见即所得" 的掌控感是现代开发中难以复制的。

VGA 模式 13h 的技术定位

模式 13h(十六进制 0x13)是 1987 年随 IBM PS/2 推出的标准 VGA 图形模式,分辨率为 320×200 像素,支持 256 色调色板。其核心价值在于内存访问模型的简化:与 VGA 其他平面模式不同,13h 采用 "chunky" 线性布局,显存段地址固定在 0xA000,每个字节直接对应一个像素。这种设计牺牲了 VGA 256KB 显存中的 75%(仅 64KB 可寻址),换取了编程复杂度的断崖式下降。

进入该模式的标准方法是调用 BIOS 中断 10h,将 AX 寄存器设为 0x0013。这一调用在实模式下执行,意味着代码运行在 CPU 复位后的默认状态 —— 段寄存器与偏移地址直接映射物理内存,无需页表转换或特权级切换。

引导扇区骨架代码

一个可启动的最小 Demo 需要遵循引导扇区规范:代码加载至 0x7C00,最后两字节必须是 0xAA55 签名。以下骨架展示了从引导到清屏的完整流程:

[BITS 16]
org 0x7C00

start:
    ; 设置VGA模式13h
    mov ax, 0x0013
    int 0x10
    
    ; 配置显存段
    mov ax, 0xA000
    mov es, ax
    xor di, di          ; DI = 0,起始偏移
    
    ; 填充整个屏幕(320*200=64000字节)
    mov al, 0x0F        ; 白色(调色板索引15)
    mov cx, 64000
    rep stosb
    
hang:
    jmp hang            ; 挂起

times 510-($-$$) db 0
dw 0xAA55             ; 引导签名

这段代码展示了实模式编程的三个核心要素:BIOS 中断调用、段寄存器显存映射、以及字符串操作指令的批量写入。rep stosb在 64000 次迭代中每次将 AL 写入 ES:DI 指向的地址,实现整屏填充。

像素坐标计算与调色板操作

线性显存布局下,像素偏移量的计算公式为:offset = y * 320 + x。由于实模式缺乏乘法指令的硬件优化,实际代码通常用移位和加法组合实现:

; 计算(x,y)处的显存偏移
mov ax, [y_pos]
shl ax, 6           ; ax = y * 64
mov bx, [y_pos]
shl bx, 8           ; bx = y * 256
add ax, bx          ; ax = y * 320
add ax, [x_pos]     ; ax = y * 320 + x
mov di, ax
mov al, [color]
mov [es:di], al     ; 写入像素

调色板编程通过 VGA DAC 端口实现:向 0x3C8 写入颜色索引,再向 0x3C9 依次写入 R/G/B 分量(各 6 位,0-63 范围)。这种 18 位色深限制催生了 90 年代 Demo 场景中标志性的 "调色板动画" 技术 —— 通过快速循环修改调色板而非重绘像素,实现流畅的色彩流动效果。

PIT 定时器与中断处理

实模式下系统时钟由可编程间隔定时器(PIT)通道 0 驱动,默认频率约 18.2Hz。要突破这一限制实现更流畅的动画,需重新编程 PIT 计数器并挂接中断向量表中的 IRQ0 处理程序:

; 设置PIT频率(例如60Hz)
mov al, 0x36
out 0x43, al        ; 通道0,模式3
mov ax, 11931       ; 1193180 / 60 ≈ 19886,但需装入低字节
out 0x40, al
mov al, ah
out 0x40, al

中断处理程序需以iret返回,并注意保存 / 恢复寄存器状态。由于实模式没有内存保护,错误的段地址或栈操作会立即导致系统崩溃 —— 这正是此类编程的风险所在。

现代实践路径

在物理硬件上测试引导扇区代码已非必需。QEMU 配合-fda参数可直接加载二进制镜像,-vga std确保 VGA 兼容性。调试时可利用 GDB 远程调试协议,在int 0x10等关键指令处设置断点。

对于希望深入的学习者,建议遵循渐进路径:先实现静态图像渲染,再添加键盘输入(BIOS int 16h),最后引入定时器中断驱动动画。每个阶段都应验证在模拟器和实机(或旧 PC 兼容机)上的一致性。

局限与权衡

模式 13h 的 64KB 显存限制意味着无法直接实现双缓冲 —— 这是平滑动画的关键技术。变通方案包括:利用系统内存作为后缓冲,通过rep movsb批量复制到显存;或采用 "脏矩形" 局部更新策略。此外,320×200 的非方形像素(4:3 显示器上的像素宽高比为 1:1.2)要求图形资源在设计时预补偿拉伸。

实模式编程的本质限制在于 1MB 地址空间天花板和缺乏内存保护。任何指针错误都会立即体现为屏幕花屏或系统死锁,调试依赖经验与耐心。然而正是这种 "无护栏" 环境,迫使开发者建立对硬件行为的直觉理解 —— 这种理解在现代高级抽象下反而难以获得。

资料来源

  • Wikipedia: Mode 13h - VGA 256-color graphics mode technical reference
  • This Could Be Better: VGA Mode 13h in Assembly with Direct Memory Writes (2011)
  • OSDev Wiki: BIOS interrupt call documentation and VGA hardware specifications

systems

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com