==============
dseg segment
cury db 0
curx db 0
luy db 10
lux db 30
rdy db 15
rdx db 40
cont db 5
dseg ends
clear macro
mov ah ,6
mov al ,0
mov ch ,0
mov cl,0
mov dh,24
mov dl,79
mov bh,7
int 10
endm
scroll macro
mov h,6
mov al,cont
mov ch,luy
mov cl,lux
mov dh,rdy
mov dl,rdx
mov bh,70h
int 10h
endm
postc macro
mov ah,2
mov dh,cury
mov dl,curx
mov bh,0
int 10
endm
;--------------------------------
cseg segment
assume cs:cseg,ds:dseg
main proc far
push ds
sub ax,ax
push ax
mov ax,dseg
mov ds,ax
clear
scroll cont
postc
input:
mov ah,0
int 16
cmp ah,abh
jnz no_left
cmp curx,0
jnz l1
cmp cury,0
jnz l3
jmp input
l1:
dec curx
jmp l5
l3:
dec cury
mov curx,79
l5:
postc
jmp input
no_left:
cmp ah,4dh
jnz no_right
cmp curx,79
jnz r1
cmp cury,24
jnz r3
jmp input
r1:
inc curx
jmp r5
r3:
inc cury
mov curx,0
r5:
postc
jmp input
no_right:
cmp ah,48h
jnz no_up
cmp cury,0
jz up1
dec cury
postc
up1:
jmp input
no_up:
cmp ah,50h
jnz no_down
cmp cury,24
jz d1
inc cury
postc
d1:
jmp input
no_down:
cmp ah,4fh
jz setxy
cmp ah,01
jnz disp
ret
disp:
mov ah,0ah
mov bh,0
mov cx,1
int 10h
inc curx
mov al,curx
cmp al,rdx
jl next
scroll 1
mov al,lux
mov curx,al
next:
postc
jmp input
setxy:
mov al,cury
mov bl,curx
cmp al,luy
jl s1
cmp bl,lux
jl s2
mov rdy,al
mov rdx,bl
jmp new
s1:
cmp bl,rdx
jle s3
jmp input
s2:
cmp al,rdy
jg s5
s3:
mov luy,al
mov lux,bl
new:
mov al,rdy
sub al,luy
inc al
mov cont ,al
clear
scroll cont
s5:
jmp input
main endp
;-----------------------------
cseg ends
end main
================
事隔多年,我也忘光了,自己编译一下试试就知道了。
Gemini 解答
代码功能与核心机制
这段汇编程序的目标是在 DOS 文本模式(默认 80×25 字符)下实现一个可调整大小的“小屏幕”(文本窗口),支持键盘控制光标移动、输入字符时窗口内滚动,以及通过特定按键修改窗口的位置/大小。其核心依赖 BIOS 中断
int 10h(视频服务)和int 16h(键盘服务)实现,属于典型的 DOS 字符界面交互程序。关键错误与当年常见误解
代码中存在两处编译级错误,这在当年文档不足或手写代码时容易出现:
scroll宏的寄存器错误:
宏内第一句为mov h,6,但 x86 汇编中没有名为h的寄存器,正确应为mov ah,6(int 10h的功能号需存入ah)。- 左移按键判断错误:
光标左移的按键扫描码判断为cmp ah,abh,实际方向键左移的扫描码是4Bh(十六进制),此处应为cmp ah,4Bh。核心逻辑解析
1. 数据段定义
dseg中存储窗口的位置(luy/lux为左上角行/列,rdy/rdx为右下角行/列)、光标位置(cury/curx)和窗口高度(cont)。2. 宏定义
clear:调用int 10h ah=6(上滚清屏),参数al=0表示清屏,bh=7为默认文本属性(黑底白字),清除整个屏幕(0行0列到24行79列)。scroll:本应为上滚窗口内容的宏,但因寄存器错误无法正常工作。修复后,int 10h ah=6会将luy-rdy行、lux-rdx列的区域上滚al行,bh=70h为窗口背景属性(白底黑字),实现“小屏幕”的视觉区分。postc:调用int 10h ah=2设置光标位置到cury/curx。3. 主流程
- 初始化后调用
clear清屏,再尝试调用scroll绘制窗口(因错误无法生效),最后定位光标。- 循环读取键盘输入(
int 16h ah=0阻塞读键):
- 方向键(左/右/上/下)控制光标移动,超出屏幕边界时换行或忽略。
- 按下
4Fh(推测为 F5 或其他功能键)时进入setxy逻辑,通过当前光标位置调整窗口的左上角或右下角坐标,并重新计算窗口高度cont。- 按下
01h(Esc 键扫描码)时退出程序。- 输入普通字符时,调用
int 10h ah=0Ah输出字符,若光标超出窗口右边界,则尝试滚动窗口(scroll 1)并重置光标到窗口左边界。当年的技术背景与限制
- 依赖 BIOS 中断是 DOS 程序的标准做法,但 BIOS 功能的参数要求严格(如寄存器使用),一旦出错会导致程序无响应或显示异常。
- 方向键扫描码的记忆误差是当年常见问题(如将
4Bh误写为abh),因缺乏实时调试工具(如现代 IDE 的断点),这类错误需通过“编译-运行-排查”循环解决。- 文本模式下的窗口滚动本质是字符缓冲区的移动,通过
int 10h ah=6实现比直接操作显存更简单,但灵活性较低(无法自定义滚动动画)。修复后的关键修改点
若要使程序正常运行,需修正两处错误:
; 错误1修复:scroll宏的寄存器 scroll macro mov ah,6 ; 替换 mov h,6 mov al,cont mov ch,luy mov cl,lux mov dh,rdy mov dl,rdx mov bh,70h int 10h endm ; 错误2修复:左移按键判断 no_left: cmp ah,4Bh ; 替换 cmp ah,abh jnz no_left修复后,程序可正常绘制窗口、控制光标,并在输入字符超出窗口右边界时自动上滚窗口内容。
大功告成,打个Kiss!


