马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 glider 于 2015-6-30 00:09 编辑
这个问题实质上很简单,只要把需求搞清楚,转化为思路,剩下的就是写代码和调试代码了。
我们先看题目的要求,有2个:
1. 读取data段中的字符,设置样式
2. 把设置好样式的字符,写入到指定位置的显存中
那么我们的初步思路就应该是这样的:
第一步,读取数据。读取data段中的数据,遇到0表示字符结束,这个应该不用再说了吧。
第二步,处理数据,即设置样式。添加了显示样式的数据占两个字节,所以在第一步中,我们最好把数据读到一个reg的低位中,然后在这一步里,把样式(在cl中)写入到reg的高位。这一步也没有什么难点。
第三步,写入显存。这是最关键的一步。把reg的内容显示在(dh)行、(dl)列,这个位置对应的内存地址,还需要我们自己去计算出来。显存所在的位置,实验9的题目介绍中已经详细说明了,这里不再缀述。
再要看上面的思路,读取数据、处理数据、写入数据可以放在一起,但是计算显示的位置,最好是单独拿出来,这样我们需要至少2个子程序:计算显示位置、把数据处理后显示出来;另外,主程序必不可少,它是整个程序的入口。我通常的写法是这样的:
main: 主程序,初始化参数
调用子程序sub1……
调用子程序sub2……
……
mov ax, 4c00h
int 21h
sub1: 子程序1
sub2: 子程序2
……
这个题目也不例外,看代码:assume cs:code
data segment
db 'welcome to masm!', 0
data ends
code segment
main: ;参数初始化
mov dh, 8 ;字符显示在哪一行
mov dl, 3 ;字符显示在哪一列
mov cl, 2 ;字符的样式
mov ax, data ;初始化数据段地址,数据地址用ds:[si]表示
mov ds, ax
mov si, 0
mov ax, 0b800h ;初始化显示位置的段地址,显示地址用es:[bx]表示
mov es, ax
call show_str ;调用在指定位置显示指定样式字符的方法
mov ax, 4c00h
int 21h
show_str: ;方法:在指定位置显示指定样式的字符
call addr ;调用方法:计算字符应该在哪个地址显示 参数1:行号dh,参数2:列号dl,计算结果存储在bx中
call show ;调用方法:将字符显示在计算好的位置 参数1:字符原地址ds:[si],参数2:字符显示位置es:[bx],参数3:字符样式cl
ret
show: push cx ;方法:读取数据段中的每一个字符,设置样式后,写入到显存中显示出来;参数1:字符原地址ds:[si],参数2:字符显示位置es:[bx],参数3:字符样式cl
push ax
s: mov ah, cl ;先把字符的样式从cl转存到ah
mov cl, [si] ;判断数据段是否读到0,如果读到0,从当前方法中返回
mov ch, 0
jcxz ok
mov al, cl ;把字符内容转存到al,这个时候ax中包含了字符的样式和内容
mov es:[bx], ax ;把字符内容和样式写入显存,显示到屏幕
inc si
add bx, 2
mov cl, ah ;把字符样式还原回cl中
jmp s
ok: pop ax
pop cx
ret
addr: push ax ;方法:计算字符应该在哪个地址显示; 参数1:行号dh,参数2:列号dl,计算结果存储在bx中
push dx ;计算方法:80(字)*2(byte/字)*行号dh(0~24) + 列号dl*2(byte/列)
mov al, 160
mul dh
mov dh, 0 ;把dh置为0,(dx) = (dl),这时候dx就是列号,方便与ax相加
add ax, dx ;因为每列2字节,所以列号要加两次
add ax, dx
mov bx, ax ;把计算好的字符显示位置的偏移地址,存到bx中
pop dx
pop ax
ret
code ends
end main
上面是我今天写的程序,时间太晚,明天还要早起上班,就不再优化了,各位如果有更好的思路,或者更优的处理方式,欢迎交流。重要表情发三遍:lol::lol::lol:
|