王爽《汇编语言》(第三版)实验10解析
1、显示字符串
assume cs:code
data segment
db 'welcome to masm!',0
data ends
code segment
start: mov dh,8
mov dl,3
mov cl,2
mov ax,data
mov ds,ax
mov si,0
call show_str
mov ax,4c00h
int 21h
show_str: push dx
push cx
push si ; 保护子程序寄存器中用到的寄存器
; 由于主程序的限定
; 这里由CPU自动为我们分配栈空间
mov di,0 ;显示缓存区中的偏移量
mov bl,dh
dec bl ; bl-1才是真正的行,因为行号从0开始计数
mov al,160
mul bl ; 每行160字节 用 行数*每行偏移量 得到目标行的偏移量
mov bx,ax ; mul bl之后,乘积存储在ax中,这里要转存入bx中
mov al,2 ; 列的偏移量为2,两个字节代表一列!!!
mul dl ; 与行偏移量同理
add bl,al ;将列偏移量与行偏移量相加,得到指定位置的偏移量。
mov ax,0b800h
mov es,ax ;指定显示缓存区的内存位置
mov al,cl ; 由于后面jcxz语句的判断要用到cx,所以我们要将
; cl(颜色)先存下来。
s: mov ch,0
mov cl,ds:[si] ;首先将当前指向字符串的某个字符存入cx中
jcxz ok ; 如果cx为0,则转移到ok标号执行相应代码
mov es:[bx+di],cl ;将字符传入低地址
mov es:[bx+di+1],al ; 将颜色传入高地址
add di,2 ; 列偏移量为2
inc si ; 字符串的偏移量为1
loop s ; 不为0,继续复制
ok: pop dx
pop cx
pop si ; 还原寄存器变量
ret ; 结束子程序调用
code ends
end start
2、解决除法溢出的问题
这里要注意,把一个数放在了dx,高位寄存器中,那么就相当于 65536。
例如:int(H/N)65536 就相当于把int(H/N)放在了dx中。
divdw:
;先计算高位,再计算低位。低位先入栈
push ax ; 先将低位数据入栈,因为后面的div需要占用ax寄存器
mov ax,dx ; 将被除数(X的高16位)放入被除数的低16位ax中
mov dx,0 ; 将被除数的高十六位dx清零
div cx ; int(H/N), 存入ax(商)中,rem(H/N)存入dx(余数)中
mov bx,ax ; 临时保存ax
pop ax ; 取出先前入栈的X的低位
div cx ; L\N
mov cx,dx ; 余数保存在cx里
mov dx,bx ; dx保存的是最终结果的高位
3、数值显示
投机取巧之法,不过相对简单。
assume cs:code
data segment
db 10 dup (0)
data ends
stack segment
dw 8 dup(0)
stack ends
code segment
start: mov ax,12666
mov bx,data
mov ds,bx
mov bx,stack
mov ss,bx
mov sp,10h
mov si,0
call dtoc
mov dh,8
mov dl,3
mov cl,2
call show_str
mov ax,4c00h
int 21h
dtoc: push ax
push bx
push si
mov bx,10
mov si,0
s0:
mov dx,0
div bx ; ax/bx
add dx,30h ; 余数加30
push dx ; 入栈
mov cx,ax ; 商-->cx
inc si ; 记录循环次数
inc cx ; 当商为0时,也要加 1 ,方便loop判断
loop s0 ; 首先 cx = cx -1,再判断 cx 是否为0
mov cx,si ; cx 为循环次数
mov si,0 ; si 指向 ds:[0]
s1:
pop ds:[si] ; 将栈中转化好了的数据放到内存中
inc si
loop s1
pop si
pop bx
pop ax
ret
show_str: push dx
push cx
push si ; 保护子程序寄存器中用到的寄存器
; 由于主程序的限定
; 这里由CPU自动为我们分配栈空间
mov di,0 ;显示缓存区中的偏移量
mov bl,dh
dec bl ; bl-1才是真正的行,因为行号从0开始计数
mov al,160
mul bl ; 每行160字节 用 行数*每行偏移量 得到目标行的偏移量
mov bx,ax ; mul bl之后,乘积存储在ax中,这里要转存入bx中
mov al,2 ; 列的偏移量为2,两个字节代表一列!!!
mul dl ; 与行偏移量同理
add bl,al ;将列偏移量与行偏移量相加,得到指定位置的偏移量。
mov ax,0b800h
mov es,ax ;指定显示缓存区的内存位置
mov al,cl ; 由于后面jcxz语句的判断要用到cx,所以我们要将
; cl(颜色)先存下来。
s: mov ch,0
mov cl,ds:[si] ;首先将当前指向字符串的某个字符存入cx中
jcxz ok ; 如果cx为0,则转移到ok标号执行相应代码
mov es:[bx+di],cl ;将字符传入低地址
mov es:[bx+di+1],al ; 将颜色传入高地址
add di,2 ; 列偏移量为2
inc si ; 字符串的偏移量为1
loop s ; 不为0,继续复制
ok: pop dx
pop cx
pop si ; 还原寄存器变量
ret ; 结束子程序调用
code ends
end start