《汇编语言》实验10 编写子程序
1. 显示字符串
显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行、列)、内容和颜色。
子程序描述
名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:(dh)=行号(取值范围0 ~ 24),(dl)=列号(取值范围0 ~ 79),(cl)=颜色,ds:si指向字符串的首地址
返回:无
回答
; 名称:show_str
; 功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
; 参数:(dh)=行号(取值范围0~24), (dl)=列号(取值范围0~79),
; (cl)=颜色,ds:si 指向字符串的首地址
; 返回:无
show_str:
push ax
push dx
push cx
push bx
; 计算指定行号的偏移地址
mov al,160
mov ah,0
mul dh
mov bx,ax
; 计算列号偏移地址
mov al,2
mov ah,0
mul dl
; 把列号偏移地址加到行号偏移地址中,保存在bx
add bx,ax
; 打印字符串
push es
push di
print_str:
; 把显存地址B800段地址放入ES段寄存器
mov ax,0B800H
mov es,ax
; di作为显存地址的字符列偏移地址,每个字符占2字节
mov di,0
; 先把cl中的颜色保存到al中,因为后面会用到cx做为跳转判断字符串是否结束
mov al,cl
print_str_put:
mov ch,[si] ; 把字符串放入ch,并把cl置为0
mov cl,0
jcxz ok ; 判断cx中的字符串是否为0,如果是说明字符串已结束,跳转到OK处
mov byte ptr es:[bx][di],ch
mov byte ptr es:[bx][di][1], al
add si,1 ; si作为字符串偏移地址
add di,2 ; di作为显存偏移地址
loop print_str_put
ok:
pop di
pop es
pop bx
pop cx
pop dx
pop ax
ret
; show_str
2. 解决除法溢出的问题
问题
前面读过,div指令可以做除法。当进行8位除法的时候,用al存储结果的商,ah存储结果的余数;进行16位除法的时候,用ax存储结果的商,dx存储结果的余数。可是,现在有一个问题,如果结果的商大于al或ax所能存储的最大值,那么将如何?
子程序描述
名称:divdw
功能:进行不会产生溢出的除法去处,被除数为dword型,除数为word型,结果为dword型。
参数:(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:(dx)=结果的高16位,(ax)=结果的低16位,(cx)=余数
公式:X/N = int(H/N)*65535 + [rem(H/N)*65535+L]/N
回答
; 名称:divdw
; 功能:进行不会溢出的除法运算,被除数为dword型,除数为word型,结果为dword型
; 参数:(ax)=dword型数据的低16位
; (dx)=dword型数据的高16位
; (cx)=除数
; 返回:(dx)=结果的高16位,(ax)=结果的低16位
; (cx)=余数
; 公式:X/N = int(H/N)*65536 + (rem(H/N)*65536+L)/N
divdw:
push bx
push ax ; 把ax中的被除数低位暂存 L
mov ax,dx ; 把dx放入低ax位计算 H/N
mov dx,0
div cx ; H/N 商在AX,余数在DX
mov bx,ax ; 暂存 H/N 商
; mov dx, dx ; 因为 rem(H/N)*65536 = rem(H/N)*10000H 即左移4位,所以上次余数在DX中不用动
pop ax ; 取出被除数低位 L
div cx ; 商在AX,余数在DX
; mov ax,ax ; 低位的商在ax中不变
mov cx,dx ; dx中的余数传送到cx中
mov dx,bx ; 高位计算的商传送到dx中
pop bx
ret
; divdw
3. 数值显示
问题
编程,将data段中的数据以十进制的形式显示出来。
data segment
dw 123,12666,1,8,3,38
data ends
子程序描述
名称:dtoc
功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。
参数:(ax)=word型数据 ,ds:si指向字符串的首地址
返回:无
回答
; 名称:dtoc
; 功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。
; 参数:(ax)=word型数据
; ds:si指向字符串的首地址
; 返回:无
dtoc:
push dx
push cx
push ax
push bx
mov bx,0
mov dx,0
push dx ; push进栈一个0值,用于在pop的时候判断是否已经到字符串尾部
dtoc_div_start:
mov dx,0
mov cx,10
call divdw
add cx,30H ; cx是余数,入栈
push cx
mov cx,dx ; 判断商的dx和ax是否都为0,如果是则结束
jcxz judge_ax
loop dtoc_div_start
judge_ax:
mov cx,ax ; 把ax放入cx,用于判断商为0时结束循环
inc cx
loop dtoc_div_start
dtoc_stack_to_data:
pop dx
mov byte ptr ds:[si][bx],dl
inc bx
mov cx,dx ; 把dx放入cx,用于判断dx为0时结束循环
inc cx
loop dtoc_stack_to_data
pop bx
pop ax
pop cx
pop dx
ret