实验10 编写子程序
这次实验需要编写三个子程序,通过它们来认识几个常见的问题和掌握解决这些问题的方法。
1.显示字符串
问题
子程序描述
提示
Solution
跟之前的文章的风格相似,都是用王爽老师原书中的描述,在完成第一个程序之前,需要稍微了解一下显存相关的内容:汇编语言:实验九 根据材料编程
了解了显存相关的知识,可以动手操作操作了,题目需要将字符串显示在特定的行列,如果学习过数据结构或者对二维数组较为了解,求解二维数组中R行C列的元素前面一共有多少个元素?一定知道这么一个计算方法:(R * nums + C),nums表示每一行元素的个数。
显存内存的分布也可以类比成二维数组,每一行一共有 80 个元素,每个元素占用 2 个字节,那么每一行占用了80 * 2 = 160字节,求解R行C列前面占用的空间就可以得到表达式:(R * 160 + C * 2 ) 字节。
实现代码
assume cs:code, ds:data
data segment
db 'Welcome to masm!',0
data ends
code segment
start:
mov dh, 10 ;行号 范围 0 ~ 24
mov dl, 3 ;列号 范围 0 ~ 79
mov cl, 2 ;颜色(取值范围0 ~ 79)
mov ax, data
mov ds, ax
mov si, 0;ds偏移
mov di, 0;es偏移
mov bl, cl ;bl保存需要改变的颜色
mov ax, 0B800H
mov es, ax;显存位置
mov al, dh
mov ah, 160
mul ah
add di, ax ;行空间
mov al, cl
mov ah, 2
mul ah
add di, ax ;列空间
call compare
mov ax, 4c00h
int 21h
compare:;调用子程序前的保存工作
push cx
push di
push si
show_str:
mov cl, ds:[si]
mov ch, 0H
jcxz ok ;循环结束
mov es:[di], cl
mov es:[di + 1], bl
add di, 2
inc si
jmp short show_str
ok:;调用完子程序之后的恢复工作
pop si
pop di
pop cx
ret
code ends
end start
运行
2.解决除法溢出的问题
问题
子问题描述
提示
Solution
问题主要用于解决除法溢出的问题。
程序不难,只是用于熟悉子程序结构、构建。
assume cs:code, ss:stack
stack segment
db 8 dup (0)
stack ends
code segment
start:
mov ax, stack
mov ss, ax
mov ax, 4240H ;被除数低位
mov dx, 000FH ;被除数高位
mov cx, 0AH ;除数
call divdw
mov ax, 4c00h
int 21H
divdw:
push ax ;将被除数低位压栈
mov ax, dx ;将被除数高位传入ax
mov dx, 0 ;进行高位除法
div cx ;ax / cx,公式中 H / N
mov bx, ax ;bx保存 int(H / N)
pop ax ;低数位出栈,此时dx中为rem(H / N),正好满足 [ rem(H / N) * 65536 + L]
div cx ;(dx * 16 + ax) / cx
mov cx, dx
mov dx, bx
ret
code ends
end start
3.数值显示
问题
子程序描述
提示
读者对本题应该非常熟悉,在《C语言程序设计》课程中应该完成过“打印一个数字的每位数字”,这道题其实也是那个经典的while循环,按照王爽老师的解析还是可以很轻松地完成的哦。
assume cs:code, ss:stack
stack segment
db 10 dup (0)
stack ends
data segment
db 10 dup (0)
data ends
code segment
start:
mov ax, 12666
mov bx, data
mov ds, bx
mov bx, stack
mov ss, bx
mov dx, 0
mov si, 0;计数器,表示共有多少位
mov di, 10 ;充当除数
call dtoc
mov dh, 8
mov dl, 3
mov cl, 2
call show
dtoc:
mov cx, ax
jcxz change ;如果ax已经是零,循环结束,将数据转移到ds:[x]
mov dx, 0
div di ;除10
push dx ;将余数压栈
inc si ;计数器加一
jmp short dtoc
change:
mov cx, si
mov di, 0 ;充当ds偏移
getAns: ;从栈中弹出数据,并加上30H
jcxz ok ;数据弹出完毕
pop ax
add ax, 30H
mov [di], ax
inc di
dec cx
jmp getAns
ok:
ret
show:
mov si, 0;ds偏移
mov di, 0;es偏移
mov bl, cl ;bl保存需要改变的颜色
mov ax, 0B800H
mov es, ax;显存位置
mov al, dh
mov ah, 160
mul ah
add di, ax ;行空间
mov al, cl
mov ah, 2
mul ah
add di, ax ;列空间
call compa
mov ax, 4c00h
int 21h
compa:;调用子程序前的保存工作
push cx
push di
push si
show_str:
mov cl, ds:[si]
mov ch, 0H
jcxz okk ;循环结束
mov es:[di], cl
mov es:[di + 1], bl
add di, 2
inc si
jmp short show_str
okk:;调用完子程序之后的恢复工作
pop si
pop di
pop cx
ret
code ends
end start