编程:
在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串:“welcome to masm!”
程序分析:
1)在内存中定义并初始化一个字符串:“welcome to masm!”(这个在数据段中定义就可以,使用db)
2)由材料提示(这里是8位的二进制的组合,形成一个属性)
属性字节的格式:
7 6 5 4 3 2 1 0
BL(闪烁) R(背景) G(背景) B(背景) I(高亮) R(前景) G(前景) B(前景)
知道: 绿色属性:00000010B==02H
绿底红色:00100100B==24H
白底蓝色:01110001B==71H
也就是说02H如果存储在显示缓冲区中的奇数内存单元时,它显示的字符是绿色的。
3)80x25的彩色字符模式显示缓冲区结构:
内存地址空间中,B8000H~BFFFH共32KB的空间,为80x25的彩色字符模式显示缓冲区,向这个地址写入数据,写入的内容会立即出现在显示器上,在80x25的彩色字符模式下,显示器可以显示25行,每行80个字符,每个字符可以有256种属性(背景色、前景色、闪烁、高亮等组合信息)
这样,一个字符在显示缓冲区就要占两个字节,分别存放字符的ASCII码和属性,80x25模式下,一屏的内容在显示缓冲区共占4000个字节。显示缓冲区分为8页,每页4KB, 显示器可以显示任一页的内容,一帮情况下,显示第0页的内容,也就是说通常情况下,B8000H~B8F9FH中的4000个字节的内容将出现在显示器上
在一页显示缓冲区中:
偏移000~09F是显示的第一行(80个字符共160个字节)
偏移0A0~13F是显示的第二行
偏移140~1DF是显示的第三行
依此类推,可知,偏移F00~F9F对应显示器上的第25行
题目中由于需要让此字符串(共三行,显示在屏幕中间),共有每页共有25, 故行数应该是在11、12、13行。那么它们的偏移地址的首地址是多少?0640H、06e0H、0780H。(粗略计算,实际上屏幕是多少行也不完全固定的。此处我们不重新计算段地址了,段地址还是B800H,只计算偏移地址。)
"welcome to masm!"字符串有16个字符,也就是说它在显示内存区域中所占空间为32个字节。每行有80个字符显示,那么它在中间显示的话,取中显示,应该在0-159字节中间的第64-96字节(40~60H);也就是在列上偏移40(开始)
行和列的偏移地址确定了。我们就可以试着输出第一行,它的偏移地址是:0640H+0040H=0680H(1664)。我们使用debug在B800:640H处写内存,发现实验成功了。如图。
可以看出在显示缓冲区中偶地址存放字符,奇地址存放字符的颜色属性
其它剩余2行的偏移地址,我们按照159-31=128计算,即(bx)=(bx)+128.
字符串和字符的属性是存储在内存的data段中的,如何从内存中将它们(每个字节)取出,然后通过寄存器中转,然后写入到指定的显示缓冲区内(也是内存单元),并指定每个字符的属性(在奇数位置)。
(es)= (data);(ds)= 0B800H,中转寄存器为ax(按要求将它们分开为2个8位寄存器)。
由于在屏幕上输出3行“welcome to masm!”,故外循环3次来输出3行,每次一行输出。此为外循环。使用栈来存储CX的状态。
内循环:将字符和字符属性按照顺序写入到显示缓冲区内。
源代码如下:
assume cs:codesg
data segment
db 'welcome to masm!'
db 02h, 24h, 71h
data ends
stack segment
db 8 dup(0)
stack ends
codesg segment
start:mov ax, data
mov es, ax
mov di, 0
mov ax, 0B800h
mov ds, ax
mov bx, 1664
mov si, 16
;建栈,并初始化栈顶
mov ax, stack
mov ss, ax
mov sp, 0
mov cx, 3
s:push cx
mov cx, 16
output:mov al, es:[di]
mov ah, es:[si]
mov [bx], ax
inc di
add bx, 2
loop output
pop cx
add bx, 128;偏移量为128字节
mov di, 0
inc si
loop s
mov ax, 4100h
int 21h
codesg ends
end start
输出如图:
也可以把每一行输出的偏移量保存在数据段data中,利用偏移量来取出