设计子程序
子程序一:在指定的位置,用指定的颜色,显示一个用0结束的字符串
举例:在屏幕的8行3列,用绿色显示data段中的字符串
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 mov ax,0b800h mov es,ax ;显示缓冲区段地址 mov al,dh mov bl,0a0h ;用于计算第八行的首地址 dec al mul bl ;首地址在ax中 mov bx,ax ;存在bx寄存器内 mov dh,0 mov di,dx ;用于计算列地址 dec di add di,di ;列地址就在di寄存器中 mov al,cl s: mov cl,ds:[si] ;取出字符,要判断cx是否为0 mov ch,0 jcxz ok ;终止指令跳转的条件 mov dl,ds:[si] ;取出字符 mov es:[bx+di],dl ;将字符送入显示缓冲区中 mov es:[bx+di+1],al ;设置字符属性 inc si ;data段的地址偏移+1 add di,2 ;显是缓冲区段地址+2 jmp short s ;指令跳转 ok: pop si ;恢复主程序中寄存器的值 pop cx pop dx ret ;子程序返回 code ends end start
运行结果:(不知明原因,第一行会被吃掉,因此实际显示是在第七行)
子程序二:
功能:解决除法溢出问题
应用举例:计算1000000/10(F4240/0AH)
返回: (dx) = 结果的高16位,(ax)=结果的低16位,(cx)=余数
结果:(dx) =0001H, (ax)=86A0H,(cx)=0
公式:
H:X的高16位
L:X的低16位
N:除数
X/N = int(H/N)*65535 + [rem(H/N*65535)+L]/N
(对公式的理解很重要!!!我看了半天,才看懂了)
assume cs:code code segment start: mov ax,4240h ;存放被除数(dword类)的低16位地址 mov dx,000fh ;存放被除数(dword类)的高16位地址 mov cx,0ah ;存放除数 call divdw divdw: push ax ;把ax(即低16位地址先存入栈中,之后要用到) mov ax,dx ;对高16位地址进行16位除法 mov dx,0 div cx mov bx,ax ;bx的值为int(H/N),将除法所得商移入bx中 pop ax ;取出低16位地址
div cx ;对低16位地址进行16位除法,结果的低16位商位于ax寄存器中 mov cx,dx ;将余数移入cx中 mov dx,bx ;将结果的高16位商移入dx中 ret code ends end start
运行结果:
子程序设计三:
功能:将word型数据转变为表示十进制数据的字符串,字符串以0结尾
应用举例:将12666以十进制的形式在屏幕的8行3列,用绿色显示出来(显示时调用子程序一)
assume cs:code data segment db 10 dup(0) ;保存字符串的内存地址段 data ends code segment start: mov ax,12666 mov bx,data mov ds,bx mov si,0 call dtoc ;调用子程序 mov ax,4c00h int 21h dtoc: mov bx,10 ;bx为除数 mov dx,0 div bx ;对ax进行16位除法 mov cx,ax ;商保存在cx中,用于结束除法的继续,当商为0时,代表所有余数已求出 add dx,30h ;利用十进制对应的ascii码=十进制数值码+30H,得出字符并存在寄存器dx中 push dx ;将字符结果保存在栈中,因为余数结果相对于本身字符的顺序是逆序,因此我们要利用栈来逆序 add si,1 ;记录除的次数,也就是字符的个数 jcxz s1 ;若cx即商为0,则调到s1处 jmp short dtoc ;循环除法 s1: mov bl,0 mov ds:[si],bl ;在data段的即将放入字符的末尾,将0存入 mov cx,si ;将字符的个数存取cx中 mov si,0 ;si寄存器表示data段的偏移地址 s2: pop ds:[si] ;取出放在栈中的数据 add si,1 ;偏移地址+1 loop s2 ;循环 mov dh,8 ;显示字符串 mov dl,3 mov cl,2 mov si,0 call show_str ret show_str: push dx push cx push si mov ax,0b800h mov es,ax mov al,dh mov bl,0a0h dec al mul bl mov bx,ax mov dh,0 mov di,dx dec di add di,di mov al,cl s: mov cl,ds:[si] mov ch,0 jcxz ok mov dl,ds:[si] mov es:[bx+di],dl mov es:[bx+di+1],al inc si add di,2 jmp short s ok: pop si pop cx pop dx ret code ends end start
运行结果:(还是一样,第一行显示的会被吃掉,所以实际在第七行)