汇编语言第七章-第十章大实验总结

一、寻址方式在结构化数据访问中的应用(P172)

题目要求:Power idea 公司从1975年成立一直到1995年的基本情况如下。

图1 原始数据示例

数据汇编定定义如下:

data segment
;以下是表示21年的21个字符串
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以下表示21年公司总收入的21个dword型数据
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以下表示21年公司雇员人数的21个word型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends

tabel segment
db 21 dup('year sumn ne ?? ')
tabel ends

编程,将data段中的数据按如下格式写入到table段中,并计算21年中的人均收入(取整),结果也按照下面的格式保存在table段中。

图2 题目具体要求

汇编代码实现:

assume cs:codesg

data segment
;以下是表示21年的21个字符串
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以下表示21年公司总收入的21个dword型数据
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以下表示21年公司雇员人数的21个word型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends

tabel segment
db 21 dup('year sumn ne ?? ')
tabel ends

codesg segment
start: 
    mov ax,data
	mov ds,ax
    mov ax,tabel
	mov es,ax
    mov cx,21
	mov bx,0
	mov si,0
	mov di,0
    s:
	;存放公司年份
	mov ax,[bx]
	mov es:[di],ax
	mov ax,[bx+2]
	mov es:[di+2],ax
	;存放公司总收入
	mov ax,54h[bx]
	mov dx,56h[bx]
	mov es:5h[di],ax
	mov es:7h[di],dx
	;存放公司雇员人数
	mov ax,0a8h[si]
	mov es:0ah[di],ax
	;存放平均收入
	mov ax,54h[bx]
	mov dx,56h[bx]
	div word ptr ds:0a8h[si]
	mov es:0ch[di],ax
    ;更新下次循环的bx,si,di值,其中di标识目标地址tabel的行,
	;bx代表原始数据更新4个字节大小的数据(年份、总收入)
	;si代表原始数据更新2个字节大小的数据(雇员人数)
	add bx,4
	add si,2
	add di,16
	
	loop s
	mov ax,4c00H
	int 21H

codesg ends
end start

运行截图:

初始寄存器信息:

图3 初始寄存器信息

初始数据信息:

图4 初始年份信息

图5 初始总收入信息

图6 雇员信息

图7 tabel表(目的存储地址)初始状态存储信息

运行结束后tabel表信息:(debug时使用-p 可以运行到此次loop结束的地方)

图8 运行结束后tabel表信息

二、在屏幕中间分显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'(P188)别

编程所需的知识通过阅读、分析下面的材料获得。(从下向上阅读)

图9 书中提供的材料信息

汇编代码实现:

assume cs:codesg

data segment
;保存要显示的字符串信息
db 'welcome to masm!'
;保存输出字符串的属性信息(背景色、闪烁、高亮等)
;分别为绿色、绿底红色、白底蓝色
db 2,36,113
data ends

codesg segment
start: 
	mov ax,data
	mov ds,ax
	;保存显示缓冲区的段地址
	;从屏幕中间第十二行开始显示
    mov ax,0B878h
	mov es,ax
	;dx用于表示字符串的属性信息的偏移下标
	;dx每次更新时递增1
	mov dx,0
	mov cx,3
	;第一层循环输出三次
    s1:
		;si用于表示要输出字符的原始偏移下标
		;si每次递增1
		
		;di用于表示输出字符到缓冲区目的偏移下标
		;由于每个字符有一个字节的属性标识,所以每次递增2
		
		;es用于表示缓冲区每行起始的段地址
		;由于显示缓冲区每行可显示80个字符共160个字节
		;所以es每次更新时加10
		mov si,0
		mov di,0
		mov bx,cx
		mov cx,16
		;第二层循环输出整句话和属性标识到缓冲器
		s2:
		    ;将字符信息保存到al中
			mov al,[si]
			;将字符属性信息保存到ah中
			mov bp,bx
			mov bx,dx
			mov ah,10h[bx]
			mov bx,bp
			;将ax的值保存到指定缓冲器内存中
			mov es:40h[di],ax
			;更新si,di的值
			add si,1
			add di,2
		loop s2
		;更新es的值
		mov ax,es
		add ax,10
		mov es,ax
		;更新属性下标dx的值
		mov cx,bx
		add dx,1
	loop s1
	
	mov ax,4c00H
	int 21H

codesg ends
end start

运行结果:

图10 运行结果展示

三、编写子程序(P206)

(1)显示字符串

问题描述:显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,是调用者可以决定显示的位置(行、列)、内容和颜色

图11 显示字符串子程序描述

代码实现

assume cs:codesg

data segment
;保存要显示的字符串信息
db 'welcome to masm!',0
data ends

codesg segment
start: 
	mov dh,8            ;dh装行号(范围:1-25)
	mov dl,80           ;dl装列号(范围:1-80)[注:每超过80等于行号自动加1]
	mov cl,2            ;cl中存放颜色属性  
	mov ax,data
	mov ds,ax
	mov si,0
	call show_str
	
	mov ax,4c00H
	int 21H
	show_str:
	push cx
	push si
	s1:
	;判断字符是否为0,如果为0则直接返回
	mov bh,cl
	mov cl,[si]
	mov ch,0
	jcxz ok
	;es用于保存显示缓冲区的起始段地址
	mov ax,0B800h
	mov es,ax
	;将字符和字符属性信息保存到bx中
	mov cl,bh
	mov bl,[si]
	;如果dl大于80需更新行号
	mov ah,0
	mov al,dl
	mov dl,81
	div dl
	add dh,al
	mov dl,ah
	;根据行号更新es
	mov al,dh
	sub al,1
	mov ah,10
	mul ah
	mov di,es
	add ax,di
	mov es,ax
	;根据列号计算缓冲区索引,并保存到di中
	mov ah,0
	mov al,dl
    sub ax,1
	add ax,ax
	mov di,ax
	;将bx中的数据保存到缓冲区
	mov es:[di],bx
	;更新列号
	add dl,1
	;更新si
	add si,1
	jmp short s1
	ok:
	pop si
	pop cx
	ret

codesg ends
end start

运行结果:

图12 显示字符串子程序运行结果展示

(2)解决除法溢出的问题

具体问题描述如下:

图13 问题描述

图14 问题要求

代码实现:

assume cs:codesg

codesg segment
start: 
	mov ax,4240h ;数据低16位记作L
	mov dx,000Fh ;数据高16位记作H
	mov cx,0ah   ;除数记作N
	call divdw
	
	mov ax,4c00H
	int 21H
	
	divdw:
	;计算int(H/N)保存到si中和rem(H/N)保存在dx中 
	mov bx,ax
	mov ax,dx
	mov dx,0
	div cx
	mov si,ax
	mov ax,0
	;计算[rem(H/N)*65536+L]/N
	mov ax,bx
	div cx
	;将余数保存在cx中,将溢出(int(H/N)*65536)保存到dx中
	mov cx,dx
	mov dx,si

	ret

codesg ends
end start

运行结果:

图15 除法溢出结果显示

(3)数值显示

问题描述:编程,将data段中的数据以十进制的形式显示出来。

图16 数值显示子程序描述

代码实现:

assume cs:codesg

data segment
db 10 dup (0)
data ends

codesg segment
start: 
	mov ax,0 ;数据低16位记作L
	mov dx,1 ;数据高16位记作H
	mov bx,data 
	mov ds,bx
	mov si,0
	call dtoc
	
	mov dh,8
	mov dl,3
	mov cl,2
	call show_str
	
	mov ax,4c00H
	int 21H
	
	dtoc:
	push cx
	push si
	mov bx,10
	mov cx,ax
	add cx,dx
	s_div:
	;如果商为0则直接返回
	jcxz div_ok
	call divdw
	;将余数转化成对应字符的编码后保存
	add cx,30H
	mov [si],cl
	add si,1
	mov cx,ax
	add cx,dx
	jmp short s_div
	div_ok:
	mov cx,si
	sub cx,1
	jcxz revert_ok
	;翻转保存的字符串
	call revert 
	revert_ok:
	pop si
	pop cx
	ret
	
	divdw:
	push si
	push bx
    mov cx,10
	;计算int(H/N)保存到si中和rem(H/N)保存在dx中 
	mov bx,ax
	mov ax,dx
	mov dx,0
	div cx
	mov si,ax
	mov ax,0
	;计算[rem(H/N)*65536+L]/N
	mov ax,bx
	div cx
	;将余数保存在cx中,将溢出(int(H/N)*65536)保存到dx中
	mov cx,dx
	mov dx,si
    pop bx
	pop si
	ret
	
	revert:
	mov cx,0
	mov ax,si
	mov bl,2
	div bl
	mov ah,0
	mov cx,ax
	sub si,ax
	revert_s:
	mov di,cx
	mov dl,[si]
	mov bl,[di-1]
	mov [si],bl
	mov [di-1],dl
	add si,1
	loop revert_s
	ret
	
	
	show_str:
	push cx
	push si
	s1:
	;判断字符是否为0,如果为0则直接返回
	mov bh,cl
	mov cl,[si]
	mov ch,0
	jcxz ok
	;es用于保存显示缓冲区的起始段地址
	mov ax,0B800h
	mov es,ax
	;将字符和字符属性信息保存到bx中
	mov cl,bh
	mov bl,[si]
	;如果dl大于80需更新行号
	mov ah,0
	mov al,dl
	mov dl,81
	div dl
	add dh,al
	mov dl,ah
	;根据行号更新es
	mov al,dh
	sub al,1
	mov ah,10
	mul ah
	mov di,es
	add ax,di
	mov es,ax
	;根据列号计算缓冲区索引,并保存到di中
	mov ah,0
	mov al,dl
    sub ax,1
	add ax,ax
	mov di,ax
	;将bx中的数据保存到缓冲区
	mov es:[di],bx
	;更新列号
	add dl,1
	;更新si
	add si,1
	jmp short s1
	ok:
	pop si
	pop cx
	ret
	

codesg ends
end start

运行结果:

图18 数值显示的运行结果

四、课程设计

问题描述:将Power idea公司的数据按照下图所示格式在屏幕显示出来。

图19 问题描述

代码实现:

assume cs:codesg

data segment
;以下是表示21年的21个字符串
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以下表示21年公司总收入的21个dword型数据
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以下表示21年公司雇员人数的21个word型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends

tabel segment
db 21 dup('year sumn ne ?? ')
tabel ends

temp segment
db 10 dup (32)
temp ends

codesg segment
start: 
    mov ax,data
	mov ds,ax
    mov ax,tabel
	mov es,ax
    mov cx,21
	mov bx,0
	mov si,0
	mov di,0
    s:
	;存放公司年份
	mov ax,[bx]
	mov es:[di],ax
	mov ax,[bx+2]
	mov es:[di+2],ax
	;存放公司总收入
	mov ax,54h[bx]
	mov dx,56h[bx]
	mov es:5h[di],ax
	mov es:7h[di],dx
	;存放公司雇员人数
	mov ax,0a8h[si]
	mov es:0ah[di],ax
	;存放平均收入
	mov ax,54h[bx]
	mov dx,56h[bx]
	div word ptr ds:0a8h[si]
	mov es:0ch[di],ax
    ;更新下次循环的bx,si,di值,其中di标识目标地址tabel的行,
	;bx代表原始数据更新4个字节大小的数据(年份、总收入)
	;si代表原始数据更新2个字节大小的数据(雇员人数)
	add bx,4
	add si,2
	add di,16
	
	loop s
    
	;循环将es数据放入到显示缓冲区
	mov ax,es
	mov ds,ax
	mov dh,2         ;dh装行号(范围:1-25)
	mov cx,21
	mov ax,temp
	mov es,ax          ;临时存储数字转换成的字符串
	s2:
	push cx
	mov cx,2            ;显示颜色配置
	mov dl,20           ;dl装列号(范围:1-80)[注:每超过80等于行号自动加1] 
	;输出年份
	call show_str
	;输出公司总收入
	call clear
	add dl,10
	mov bx,dx
	mov dx,ds:[7h] ;要显示的数字
	mov ax,ds:[5h] ;要显示的数字
	mov di,0
	call dtoc
    call revert
	mov dx,bx
	mov ax,temp
	mov bx,ds
	mov ds,ax
	call show_str
	mov ds,bx
	
	;输出公司总雇员数
	call clear
	add dl,10
	mov bx,dx
	mov dx,0
	mov ax,ds:[0ah] ;要显示的数字
	mov di,0
	call dtoc
    call revert
	mov dx,bx
	mov ax,temp
	mov bx,ds
	mov ds,ax
	call show_str
	mov ds,bx
	
	;输出平均收入
	call clear
	add dl,10
	mov bx,dx
	mov dx,0
	mov ax,ds:[0ch] ;要显示的数字
	mov di,0
	call dtoc
    call revert
	mov dx,bx
	mov ax,temp
	mov bx,ds
	mov ds,ax
	call show_str
	mov ds,bx
	
	add dh,1
	pop cx
	mov ax,ds
	add ax,1
	mov ds,ax
	sub cx,1
	jcxz s2_ok
	jmp far ptr s2
	s2_ok:
	mov ax,4c00H
	int 21H
	
	
	show_str:
	push cx
	push di
	push bx
	push dx
	push es
	mov si,0
	s1:
	;判断字符是否为空格,如果为空格则直接返回
	mov bh,cl
	mov cl,[si]
	mov ch,0
	sub cl,32
	jcxz ok
	;es用于保存显示缓冲区的起始段地址
	mov ax,0B800h
	mov es,ax
	;将字符和字符属性信息保存到bx中
	mov cl,bh
	mov bl,[si]
	;如果dl大于80需更新行号
	mov ah,0
	mov al,dl
	mov dl,81
	div dl
	add dh,al
	mov dl,ah
	;根据行号更新es
	mov al,dh
	sub al,1
	mov ah,10
	mul ah
	mov di,es
	add ax,di
	mov es,ax
	;根据列号计算缓冲区索引,并保存到di中
	mov ah,0
	mov al,dl
    sub ax,1
	add ax,ax
	mov di,ax
	;将bx中的数据保存到缓冲区
	mov es:[di],bx
	;更新列号
	add dl,1
	;更新si
	add si,1
	jmp short s1
	ok:
	pop es
	pop dx
	pop bx
	pop di
	pop cx
	ret
	
	dtoc:
	push cx
	push dx
	push ds
	push bx
	mov bx,temp
	mov ds,bx
    mov cx,ax
	add cx,dx
	s_div:
	;如果商为0则直接返回
	jcxz div_ok
	call divdw
	;将余数转化成对应字符的编码后保存
	add cx,30H
	mov [di],cl
	add di,1
    mov cx,ax
	add cx,dx
	jmp short s_div
	div_ok:
	pop bx
	pop ds
	pop dx
	pop cx
	ret
	
	divdw:
	push si
	push bx
    mov cx,10
	;计算int(H/N)保存到si中和rem(H/N)保存在dx中 
	mov bx,ax
	mov ax,dx
	mov dx,0
	div cx
	mov si,ax
	mov ax,0
	;计算[rem(H/N)*65536+L]/N
	mov ax,bx
	div cx
	;将余数保存在cx中,将溢出(int(H/N)*65536)保存到dx中
	mov cx,dx
	mov dx,si
    pop bx
	pop si
	ret
	
	revert:
	push cx
	push dx
	push ds
	push bx
	mov dx,0
	mov cx,di
	sub cx,1
	jcxz revert_ok
	mov cx,temp
	mov ds,cx
	mov cx,0
	mov ax,di
	mov bl,2
	div bl
	mov ah,0
	mov cx,ax
	sub di,ax
	revert_s:
	mov si,cx
	mov dl,[si-1]
	mov bl,[di]
	mov [si-1],bl
	mov [di],dl
	add di,1
	loop revert_s
	revert_ok:
	pop bx
	pop ds
	pop dx
	pop cx
	ret
	
	clear:
	push dx
	push cx
	push bx
	mov cx,10
	mov dx,temp
	mov es,dx
	mov dl,32
	clear_s:
	mov bx,cx
	sub bx,1
	mov es:[bx],dl
	loop clear_s
	mov di,0
	pop bx
	pop cx
	pop dx

	ret
codesg ends
end start

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值