|
kickout
高级用户
   
积分 667
发帖 135
注册 2002-10-25
状态 离线
|
『楼 主』:
一个在DOS屏幕下划出一个小屏幕的程序
[已使用 LLM 解释]
都是我以前练习时自己编得玩的。
==============
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
================
事隔多年,我也忘光了,自己编译一下试试就知道了。
LLM 解释
代码功能与核心机制
这段汇编程序的目标是在 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
修复后,程序可正常绘制窗口、控制光标,并在输入字符超出窗口右边界时自动上滚窗口内容。
|

================================= kickout
大功告成,打个Kiss!
|
|
2002-10-28 00:00 |
|
|
kickout
高级用户
   
积分 667
发帖 135
注册 2002-10-25
状态 离线
|
『第 2 楼』:
[已使用 LLM 解释]
这个和上面的差不多,但可以肯定还是有不同的,编译后对比一下试试就知道了
=====================
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
stack segment para stack'stack'
db 64 dup(?)
stack ends
clear macro
mov ah ,6
mov al ,18h
mov ch ,0
mov cl,0
mov dh,24
mov dl,79
mov bh,7
int 10h
endm
scroll macro cont
mov ah,6
mov al,cont
mov ch,luy
mov cl,lux
mov dh,rdy
mov dl,rdx
mov bh,00011111b
int 10h
endm
postc macro
mov ah,2
mov dh,cury
mov dl,curx
mov bh,0
int 10h
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 16h
cmp ah,4bh
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 sxy
cmp ah,01h
jz edd
cmp al,0dh
jnz eed
neew:
inc cury
mov ah,cury
cmp ah,rdy
jle no_change
scroll 1
dec cury
mov ah,cury
no_change:
dec lux
mov al,lux
mov curx,al
inc lux
eed: jmp disp
edd: ret
sxy: jmp setxy
disp:
mov ah,0ah
mov bh,0
mov cx,1
int 10h
inc curx
mov al,curx
cmp al,rdx
jng 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
=====================
LLM 解释
程序功能与核心机制
这段8086汇编程序实现了一个可自定义区域的文本滚动窗口(类似早期DOS的"小屏幕"效果),支持通过键盘调整窗口位置、输入文本并自动滚动。核心逻辑依赖BIOS视频中断int 10h的功能调用,分为以下模块:
1. 数据段定义
存储窗口的左上角(luy, lux)、右下角(rdy, rdx)坐标、窗口高度(cont)及当前光标位置(cury, curx)。默认窗口为第10-15行、30-40列的矩形区域。
2. 宏定义
-
clear:调用int 10h ah=6(上滚清屏),将整个屏幕(0-24行、0-79列)填充为黑底白字(bh=7)。
-
scroll:调用int 10h ah=6,对窗口区域进行上滚操作(al为滚动行数),填充行使用白底黑字(bh=70h)。
-
postc:调用int 10h ah=2,设置光标到(curx, cury)位置。
3. 主流程
-
初始化:设置数据段,清屏并绘制初始窗口。
-
键盘输入循环:通过
int 16h ah=0读取按键扫描码,处理方向键(调整光标位置)、F10键(调整窗口大小)和ESC键(退出)。
-
文本输入与滚动:输入字符时,若光标超出窗口右边界(
curx >= rdx),则窗口上滚1行,并将光标重置到窗口左边界(lux);若输入回车键(al=0dh),则光标换行并触发窗口滚动(若超出下边界)。
关键实现细节与问题
1. 窗口滚动机制
当输入字符超出窗口右边界或换行超出下边界时,通过scroll 1调用int 10h ah=6上滚窗口,自动覆盖最上面一行并在底部填充新行。这种方式依赖BIOS对视频缓冲区的直接操作,效率较高但仅支持文本模式。
2. 窗口大小调整(F10键)
通过光标位置设置窗口的右下角(若光标在初始窗口内)或左上角(若光标在初始窗口外),并重新计算窗口高度(cont = rdy - luy + 1)。调整后会清屏并重新绘制窗口。
3. 已知问题与历史局限性
-
方向键处理错误:左方向键判断中误将扫描码
4bh写成abh(应为cmp ah, 4bh),导致左方向键无法响应;这是典型的汇编编程笔误,当年因缺乏调试工具(如现代IDE的语法检查)容易出现。
-
回车键处理逻辑混乱:
disp模块中回车键处理分支(cmp al, 0dh)的代码跳转(jne eed)后,neew标签下的dec lux和inc lux是无效操作(相互抵消),且光标换行逻辑未正确处理窗口边界,可能导致光标位置异常。
-
未定义行为:宏
scroll中直接使用mov h,6(应为mov ah,6),这是语法错误(未定义h变量),会导致编译失败;当年汇编器(如MASM)对未定义符号的报错信息不明确,容易被忽略。
-
光标越界检查不完整:方向键处理中,光标移动到屏幕边缘时的换行逻辑(如左方向键到行首时跳到上一行末尾)未考虑窗口边界,可能导致光标移出窗口后无法正确触发滚动。
历史语境与合理性
该程序属于2000年前后DOS汇编编程的典型实践,利用BIOS中断实现基础的UI交互,反映了当时资源受限环境下的编程风格(依赖宏简化重复代码、直接操作硬件中断)。程序中的错误(如扫描码笔误、无效操作)是当年汇编开发中常见的问题,主要原因是缺乏高级调试工具和对BIOS中断参数的记忆误差。
后续跟帖中若有用户指出这些错误(如扫描码修正、无效操作删除),则是对程序的有效补充,体现了论坛互助调试的价值。
|

================================= kickout
大功告成,打个Kiss!
|
|
2002-10-28 00:00 |
|
|
随风顺
初级用户
 
积分 196
发帖 35
注册 2002-10-14
状态 离线
|
『第 3 楼』:
使用 LLM 解释/回答一下
大概浏览了一下代码
好像第一个是图形模式,第二个是文本模式
不过第一段程序
scroll macro
mov h,6
那块似乎有点问题,
是不是改成:
scroll macro cont
mov ah,6
我最近正好在准备汇编语言的学期考试,被BIOS中断那块搞得很是头疼
不知道kickout对这块熟不熟,不过看程序用到不少
多帮帮我哈,如果这回考试顺利过关的话我请客哦
|

http://ie.zzu.edu.cn
Email:Jathenal@mail.edu.cn
QQ:26165434 希望能和大家做个朋友 |
|
2002-10-28 00:00 |
|
|
柳飘逸
初级用户
 
积分 119
发帖 11
注册 2002-12-14
状态 离线
|
|
2002-12-14 00:00 |
|
|