王爽《汇编语言》(第三版)实验10解析

1、显示字符串

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     ; 保护子程序寄存器中用到的寄存器
                        ; 由于主程序的限定
                        ; 这里由CPU自动为我们分配栈空间
                        
            
            mov di,0    ;显示缓存区中的偏移量
            mov bl,dh   
            dec bl      ; bl-1才是真正的行,因为行号从0开始计数
            mov al,160  
            mul bl      ; 每行160字节 用 行数*每行偏移量 得到目标行的偏移量
            mov bx,ax   ; mul bl之后,乘积存储在ax中,这里要转存入bx中
            mov al,2    ; 列的偏移量为2,两个字节代表一列!!!
            mul dl      ; 与行偏移量同理
            add bl,al   ;将列偏移量与行偏移量相加,得到指定位置的偏移量。
            
            mov ax,0b800h
            mov es,ax   ;指定显示缓存区的内存位置
            
            mov al,cl   ; 由于后面jcxz语句的判断要用到cx,所以我们要将
                        ; cl(颜色)先存下来。
     s:     mov ch,0
            mov cl,ds:[si] ;首先将当前指向字符串的某个字符存入cx中
            jcxz ok         ; 如果cx为0,则转移到ok标号执行相应代码
            mov es:[bx+di],cl   ;将字符传入低地址
            mov es:[bx+di+1],al ; 将颜色传入高地址
            add di,2    ; 列偏移量为2
            inc si      ; 字符串的偏移量为1
            loop s      ; 不为0,继续复制
    
    ok:     pop dx      
            pop cx
            pop si      ; 还原寄存器变量
            ret         ; 结束子程序调用
code ends
end start

2、解决除法溢出的问题

这里要注意,把一个数放在了dx,高位寄存器中,那么就相当于 65536。
例如:int(H/N)
65536 就相当于把int(H/N)放在了dx中。

divdw:
    ;先计算高位,再计算低位。低位先入栈
    push ax     ; 先将低位数据入栈,因为后面的div需要占用ax寄存器
    mov ax,dx   ; 将被除数(X的高16位)放入被除数的低16位ax中
    mov dx,0    ; 将被除数的高十六位dx清零
                
    div cx      ; int(H/N), 存入ax(商)中,rem(H/N)存入dx(余数)中
    mov bx,ax   ; 临时保存ax
      
    pop ax      ; 取出先前入栈的X的低位
 
    div cx      ; L\N
    mov cx,dx   ; 余数保存在cx里
    mov dx,bx   ; dx保存的是最终结果的高位

3、数值显示

投机取巧之法,不过相对简单。

assume cs:code

data segment
        db 10 dup (0)
data ends

stack segment
    dw 8 dup(0)
stack ends

code segment
start:  mov ax,12666
        mov bx,data
        mov ds,bx
        mov bx,stack
        mov ss,bx
        mov sp,10h
        mov si,0
        call dtoc

        mov dh,8
        mov dl,3
        mov cl,2
        call show_str
        
        mov ax,4c00h
        int 21h

dtoc:    push ax
        push bx
        push si
        mov bx,10
        mov si,0
    
  s0:    
        mov dx,0
        div bx      ; ax/bx
        add dx,30h  ; 余数加30
        push dx     ; 入栈
        mov cx,ax   ; 商-->cx
        inc si      ; 记录循环次数
        inc cx      ; 当商为0时,也要加 1 ,方便loop判断
        loop s0     ; 首先 cx = cx -1,再判断 cx 是否为0
    
        mov cx,si   ; cx 为循环次数  
        mov si,0    ; si 指向 ds:[0]
  s1:    
        pop ds:[si] ; 将栈中转化好了的数据放到内存中
        inc si
        loop s1

        pop si
        pop bx
        pop ax
        ret
    

show_str:   push dx
            push cx
            push si     ; 保护子程序寄存器中用到的寄存器
                        ; 由于主程序的限定
                        ; 这里由CPU自动为我们分配栈空间
                        
            
            mov di,0    ;显示缓存区中的偏移量
            mov bl,dh   
            dec bl      ; bl-1才是真正的行,因为行号从0开始计数
            mov al,160  
            mul bl      ; 每行160字节 用 行数*每行偏移量 得到目标行的偏移量
            mov bx,ax   ; mul bl之后,乘积存储在ax中,这里要转存入bx中
            mov al,2    ; 列的偏移量为2,两个字节代表一列!!!
            mul dl      ; 与行偏移量同理
            add bl,al   ;将列偏移量与行偏移量相加,得到指定位置的偏移量。
            
            mov ax,0b800h
            mov es,ax   ;指定显示缓存区的内存位置
            
            mov al,cl   ; 由于后面jcxz语句的判断要用到cx,所以我们要将
                        ; cl(颜色)先存下来。
     s:     mov ch,0
            mov cl,ds:[si] ;首先将当前指向字符串的某个字符存入cx中
            jcxz ok         ; 如果cx为0,则转移到ok标号执行相应代码
            mov es:[bx+di],cl   ;将字符传入低地址
            mov es:[bx+di+1],al ; 将颜色传入高地址
            add di,2    ; 列偏移量为2
            inc si      ; 字符串的偏移量为1
            loop s      ; 不为0,继续复制
    
    ok:     pop dx      
            pop cx
            pop si      ; 还原寄存器变量
            ret         ; 结束子程序调用
    
code ends
end start

转载于:https://www.cnblogs.com/nojacky/p/9523904.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值