32位保护文本模式下如何使用汇编实现换行打印
32位保护模式VGA文本模式汇编换行打印实现
之前操作无效的原因
VGA默认80×25文本模式的显存起始地址为0xb8000,每个字符占2字节:低字节存ASCII码,高字节存显示属性。直接修改0xb8000处的值仅会修改屏幕左上角第一个字符的内容,既没有更新当前打印位置的偏移,也没有调整VGA光标状态,自然无法实现换行效果。
换行实现核心逻辑
换行本质是将后续打印的起始位置移动到下一行行首,若当前已经在屏幕最后一行,还需要执行滚屏操作,核心步骤如下:
- 内存中维护两个全局状态值:
cursor_row(当前行号,范围0-24)、cursor_col(当前列号,范围0-79),所有打印操作都基于这两个值计算显存偏移 - 触发换行时,先将
cursor_col置0(回到行首),再将cursor_row加1(移动到下一行) - 判断
cursor_row是否等于25(超出最大行索引24):如果是则执行滚屏,将第124行的显存内容整体上移1行覆盖第023行,清空最后一行后将cursor_row重置为24 - 计算新位置的显存偏移:
显存偏移 = (cursor_row * 80 + cursor_col) * 2,后续字符从0xb8000 + 显存偏移位置开始写入 - 若需要显示硬件光标,通过
0x3D4、0x3D5端口更新VGA光标寄存器的值即可
32位汇编实现示例(NASM语法)
; 全局状态变量定义 cursor_row: db 0 cursor_col: db 0 vga_base: equ 0xb8000 vga_attr: equ 0x07 ; 默认黑底白字属性 ; 换行功能函数 print_newline: mov byte [cursor_col], 0 inc byte [cursor_row] cmp byte [cursor_row], 25 jl .update_hw_cursor ; 滚屏逻辑 .scroll: cld mov esi, vga_base + 80*2 ; 源地址:第1行起始位置 mov edi, vga_base ; 目的地址:第0行起始位置 mov ecx, 24*80 ; 共24行,每行80个字符单元,按4字节搬运 rep movsd ; 清空最后一行 mov ebx, vga_base + 24*80*2 mov ecx, 80 .clr_last: mov word [ebx], vga_attr << 8 | ' ' add ebx, 2 loop .clr_last mov byte [cursor_row], 24 ; 更新硬件光标 .update_hw_cursor: movzx ax, byte [cursor_row] mov bx, 80 mul bx movzx bx, byte [cursor_col] add ax, bx ; ax = 光标线性位置(行*80+列,非字节偏移) ; 写光标高8位 mov dx, 0x3D4 mov al, 0xE out dx, al mov dx, 0x3D5 mov al, ah out dx, al ; 写光标低8位 mov dx, 0x3D4 mov al, 0xF out dx, al mov dx, 0x3D5 mov al, al out dx, al ret
注意:如果不需要显示硬件闪烁光标,可以省略端口操作部分,但必须维护内存中的
cursor_row和cursor_col变量,否则后续打印无法定位到正确位置。
内容的提问来源于stack exchange,提问作者Markian
相关产品推荐
相关产品推荐

