汇编实验十(王爽)

设计子程序

子程序一:在指定的位置,用指定的颜色,显示一个用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

运行结果:(还是一样,第一行显示的会被吃掉,所以实际在第七行)

 

posted @ 2020-05-23 00:03  jane_315  阅读(431)  评论(0编辑  收藏  举报