[汇编语言]实验10 编写子程序

    选择打赏方式

这个实验10检验的是是否会用寄存器储存相关参数,灵活CALL子程序实现功能。


1.显示字符串
问题
显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行、列)、内容和颜色。
子程序描述
名称:show_str功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:(dh)=行号(取值范围0-24),(dl)=列号(取值范围0-79),
(cl)=颜色,ds:si指向字符串的首地址返回:无
应用举例:在屏幕的8行3列,用绿色显示data段中的字符串。

代码:

assume cs:code,ds:data,ss:stack
 
data segment
db 'welcome to masm!',0
data ends
 
stack segment
dw 8 dup (0)        ;定义一个栈段,防止溢出,貌似不定义也没什么问题。
stack ends
 
code segment       
   
    show_str:     
        ;寄存器压入堆栈
        push dx
        push cx
        push ds
        push si
        ;引入附加段寄存器存储0b800h
        mov ax,0b800h    ;屏幕显示缓冲区开始页(第0页)
        mov es,ax
     
        ;计算行偏移
        mov al,160     
        mul dh     ;行数
        mov bx,ax
       
        ;计算列偏移
        mov al,2
        mul dl     ;列数
     
        ;累加行列偏移
        add bx,ax            
        
        ;将颜色值cl赋值给al寄存器,以便腾出CX寄存器做jcxz判断
        mov al,cl
        
        ;进入循环,条件为CX=0
         s: mov cl,[si] 
             jcxz ok       
             ;条件成立后执行
                mov dx,[si]     ;字符存入DX寄存器
                mov es:[bx],dx  ;写入字符到显示缓冲区
                mov es:[bx+1],al    ;写入颜色到显示缓冲区
                inc si  ;下一个字符偏移
                add bx,2    ;下一个缓冲区偏移
                loop s
 
            ok:    
    ;           ;寄存器弹出堆栈
                pop si
                pop ds
                pop cx
                pop dx
ret


start:  
    mov dh,8    ;欲写入行号
mov dl,3    ;欲写入列号
    mov cl,2    ;欲写入颜色值
    
    ;定义数据区
mov ax,data
mov ds,ax   ;ds指向数据段
    mov si,0    ;字符首位置
        
    ;调用show_str
call show_str
 
mov ax,4c00h
int 21h
 
code ends
end start


效果:

1.gif


2.解决除法溢出

子程序描述
名称:divdw功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
参数:(ax)=dword型数据的低16位(dx)=dword型数据的高16位
(cx)=除数
返回:(dx)=结果的高16位,(ax)=结果的低16位(cx)=余数
应用举例:计算1000000/10(F4240H/0AH)mov ax,4240Hmov dx,000FH mov cx,OAHcall divdw结果:(dx)=0001H,(ax)=86A0H,(Cx)=0提示
给出一个公式:
X:被除数,范围:[0,FFFFFFFF]
N:除数,范围:[0,FFFF]
H:X高16位,范围:[0,FFFF]L:X低16位,范围:[0,FFFF]
intO:描述性运算符,取商,比如,int(38/10)=3
rem):描述性运算符,取余数,比如,rem(38/10)=8公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]N这个公式将可能产生溢出的除法运算:X/N,转变为多个不会产生溢出的除法运算。公式中,等号右边的所有除法运算都可以用div指令来做,肯定不会导致除法溢出。


代码:

assume cs:code,ds:data,ss:stack
 
data segment
db 'welcome to masm!',0
data ends
 
stack segment
dw 8 dup (0)        ;定义一个栈段,防止溢出,貌似不定义也没什么问题。
stack ends
 
code segment       
   
    divdw:     
    ; X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N   
    ;这个公式中的*65536代表高16位,+连接高低16位,而不是数学中的加法运算符

    
        ;寄存器压入堆栈
        push dx
        
        ;计算H/N    结果的高16位
        mov ax,dx   ;将高16位的值赋值给AX寄存器 
        mov dx,0    ;DX寄存器置0,高16位置0,当作低16位计算
        div cx  ;此时AX=(int)H/N,DX=(rem)H/N
        
        ;存储结果并pop出被除数的低16位L
        mov bx,ax
        pop ax     
        
        ;计算L/N    结果的低16位
        ;此时高16位为(rem)H/N(之前的DX)
        ;实际上是计算[rem(H/N)*65536+L]/N
        ; +代表了高16位和低16位组合形成一个dword类型。
        div cx   
        
        ;存储结果
        mov cx,dx
        mov dx,bx           
        
ret


start:  
    mov ax,4240h  ;L    被除数低16位
    mov dx,000fh  ;H    被除数高16位    
    mov cx,0ah    ;N    除数    

    ;调用divdw
call divdw
 
mov ax,4c00h
int 21h
 
code ends
end start

3.数值显示

子程序描述
名称:dtoc功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。
参数:(ax)=word型数据
ds:si指向字符串的首地址
返回:无
应用举例:编程,将数据12666以十进制的形式在屏幕的8行3列,用绿色显示出来。在显示时我们调用本次实验中的第一个子程序show_str。


代码:

assume cs:code,ds:data,ss:stack
 
data segment
   db 10 dup (0)    ;初始化10个字节
data ends
 
stack segment
dw 8 dup (0)        ;定义一个栈段,防止溢出,貌似不定义也没什么问题。
stack ends
 
code segment       
   
    show_str:     
        ;寄存器压入堆栈
        push dx
        push cx
        push ds
        push si
        ;引入附加段寄存器存储0b800h
        mov ax,0b800h    ;屏幕显示缓冲区开始页(第0页)
        mov es,ax
     
        ;计算行偏移
        mov al,160     
        mul dh     ;行数
        mov bx,ax
       
        ;计算列偏移
        mov al,2
        mul dl     ;列数
     
        ;累加行列偏移
        add bx,ax            
        
        ;将颜色值cl赋值给al寄存器,以便腾出CX寄存器做jcxz判断
        mov al,cl
        
        ;进入循环,条件为CX=0
         s: mov cl,[si] 
             jcxz ok       
             ;条件成立后执行
                mov dx,[si]     ;字符存入DX寄存器
                mov es:[bx],dx  ;写入字符到显示缓冲区
                mov es:[bx+1],al    ;写入颜色到显示缓冲区
                inc si  ;下一个字符偏移
                add bx,2    ;下一个缓冲区偏移
                loop s
 
            ok:    
    ;           ;寄存器弹出堆栈
                pop si
                pop ds
                pop cx
                pop dx
ret
    
    
    dtoc:     
        ;寄存器压入堆栈
        push ax
        push bx
        push cx
        push si
        ;初始化除法运算
        mov si, 0       ;偏移地址置零
        mov bx, 10      ;除数=10
             
        ;开始循环取余
        mod: 
            mov dx, 0       ;余数置0
            div bx          ;AX/BX 
            mov cx, ax      ;将除法运算结果的商赋值给cx,用于条件判断 
            ;进入循环,条件为CX=0  
            jcxz last       ;判断cx是否为0?或商为零?
                add dx, 30H     ;将每个位的数字转换成ASCII码值  余数+30H
                push dx         ;将ASCII码值压栈保存,利用栈先进后出实现倒序
                inc si        
                jmp short mod

  

        last:    ;当除法的商为0,没有余数可供倒序,转换结束
            add dx, 30H     ;将数字转换成ASCII码
            push dx         ;将字符值压栈
            inc si          
            ;将栈中数据倒序写入内存data段中 
            mov cx, si      ;(si)=字符串共几个字符,设置循环计数器cx。
            mov si, 0
            s2:  
                pop ds:[si]     ;弹栈,并写入data内存段。
                inc si
                loop s2
          
        
            exit:    
    ;           ;寄存器弹出堆栈
                pop si
                pop cx
                pop bx
                pop ax
ret

start:   
    mov ax,data       
    mov ds,ax  
    mov ax, 12666       ;欲显示的数字     
    mov si, 0           ;将ds:si指向data内存段

        call dtoc           ;调用dtoc子程序
    mov dh,8    ;欲写入行号
mov dl,3    ;欲写入列号
    mov cl,2    ;欲写入颜色值
    mov ch,0    ;ch寄存器置0 
    
    ;定义数据区
mov ax,data
mov ds,ax   ;ds指向数据段
    mov si,0    ;字符首位置
        
    ;调用show_str
call show_str
 
mov ax,4c00h
int 21h
 
code ends
end start


效果:

2.gif



版权声明:若无特殊注明,本文皆为《 8964CN 》原创,转载请保留文章出处。
本文链接:[汇编语言]实验10 编写子程序 http://www.8964cn.net/?post=40
正文到此结束

热门推荐

发表吐槽

你肿么看?

你还可以输入 250 / 250 个字

嘻嘻 大笑 可怜 吃惊 害羞 调皮 鄙视 示爱 大哭 开心 偷笑 嘘 奸笑 委屈 抱抱 愤怒 思考 日了狗 胜利 不高兴 阴险 乖 酷 滑稽

评论信息框

吃奶的力气提交吐槽中...


既然没有吐槽,那就赶紧抢沙发吧!