王爽《汇编语言》(第三版)实验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
posted @ 2018-08-23 15:13  nojacky  阅读(7789)  评论(3编辑  收藏  举报