我自己也想过一个子程序,但运行出来的结果是一些带颜色的表情包,实在是困惑,上网搜查到下面的结果:
这里面有几个地方是我之前没考虑到的:
1、设置显存范围时,我没考虑显示缓冲区与之前的内存设置上的不同,
偏移000~09f对应显示器上的第一行(80个字符占160个字节)
偏移0a0~13f对应显示器上的第二行
偏移140~1df对应显示器上的第三行
所以:第8行为8*160,注意行号减一,因为行号是从0开始;
同时在一行中:
00~01单元对应显示器上的第一列
02~03单元对应显示器上的第二列
04~05单元对应显示器上的第三列
所以:第三列为2*3,注意减二,因为行号是从0开始。
传值时,将上面直接用一个通用寄存器bx表示。
2、这道题有一个小技巧,即cx的使用,因为一个字符占两个字节的存储空间,低位字节存储ascii码,高位字节存储字符的属性。jcxz判断的是cx是否为0,所以可以先设置al存cl(题意中的颜色属性),将字符值送至cl,再传给低位字节。这样可以避免子程序内容用到栈(我用栈一直出错)。
- assume cs:code,ds:data
- data segment
- db 'Welcome to masm!',0
- data ends
- code segment
- start:
- mov dh,8 ;行号
- mov dl,3 ;列号
- mov cl,07h ;白色字
- mov ax,data
- mov ds,ax
- mov si,0 ;循环加入字
- call show_str
- mov ax,4c00h
- int 21h
- show_str:
- push cx ;保存用到的寄存器
- push si
- push es
- push di
- push bx
- mov ax,0b800h
- mov es,ax
- mov al,0a0h ;一行的总列数160字节
- dec dh ;行号减1,因为是从0开始的
- mul dh ;计算行开始偏移地址
- mov bx,ax
- mov al,2
- mul dl ;计算列
- sub ax,2 ;列也是从0开始,而且一个字符占两个字节
- add bx,ax ;求出开始位置
- mov di,0
- mov al,cl
- mov ch,0 ;高8位为0
- s:
- mov cl,ds:[si] ;判断是否到了字符结束
- jcxz ok
- mov es:[bx+di],cl
- mov es:[bx+di+1],al
- inc si
- add di,2
- jmp short s
- ok:
- pop bx
- pop di
- pop es
- pop si
- pop cx
- ret
- code ends
- end start