《汇编语言》王爽——第十章,课程设计1

在这个程序中,要用到前10章几乎所有的知识。(书中原话)

课程设计的需求:

将之前实验7的数据在屏幕上展示出来

如图所示:                                      该图也是我的程序展示图

 

分析:

首先需要展示四大块内容,分别是:

1.年份(字符串数据,可以直接展示,不需要转化字符串)

2.收入(dword数据,需要先转化为字符串,再进行展示)

3.雇员(word数据,需要先转化为字符串,再进行展示)

4.人均收入(word数据,需要先转化为字符串,再进行展示)

接着,该以怎样的方式展示?

这里我选择一次展示一整列的数据,因为这样数据类型是一样的,比较好把握.

那么就是说按照四块内容分别展示四次,每次展示21个数据

分析完毕。

(这个程序最头疼的还是定位地址和寄存器冲突的问题,所以我把数据分成多个数据段,并且在每个小程序开始前面存储好即将使用的寄存器就解决了这个问题)

开始之前我们需要确定需要的几个小程序

1.展示小程序showptr,前面实验10写过

2.word数据转化字符串小程序dtoc,前面实验10写过

3.除法溢出问题解决小程序divdw,前面实验10写过

4.dword数据转化为字符串小程序dtoc2,没写过,需要自己写

那么先把没写过的小程序写出来:
原理和word数据转化字符串是一样的,只不过变成了双字的数据类型

代码如下,该程序将实现转化并且将12345678展示出来:

assume cs:code,ds:data,ss:stack
data segment
db 20 dup(0)
data ends
stack segment
dw 20 dup(0)
stack ends 

code segment
start:
mov bx,data
mov ds,bx
mov bx,stack
mov ss,bx
mov sp,40

mov ax,614eh
mov dx,0bch
mov si,0

call dtoc_2 	;将dword型数据转变成十进制字符串,字符串以0结尾,存放于data段

mov dh,12
mov dl,64
mov cl,02h
mov si,0
call showptr ;显示字符串 dh是行,dl是列,cl是颜色,ds:si指向字符串首地址

mov ax,4c00h
int 21h




;dword转化10进制字符串 字符串以0结尾 
;参数 ax 低16,dx 高16, ds:si 指向字符串首地址
dtoc_2:
push ax
push bx
push cx
push dx
push di
push si


mov di,0 ;计数器置0

dtoc2_s0:
mov cx,10;除数为10
call divdw   ;做dword除法 dx存放高16位结果 ax存放低16位结果 cx存放余数


add cx,30h ;余数加30h
push cx    ;存放ascii码,入栈
inc di     ;计数器加1
;判断商是否为0,此时的商是32位的结果,需要将商相加一下
mov cx,ax 
add cx,dx ;如果相加之后结果为0就说明商为0了
jcxz dtoc2_ok
jmp short dtoc2_s0 ;跳转回去继续做除法直到商为0

dtoc2_ok:
;inc di 
mov cx,di  ;计数器存进cx做循环
;inc cx 
dtoc2_s2:
pop ds:[si];出栈 弹出到data空间
inc si     ;指针后移
loop dtoc2_s2    ;结束循环表示出栈成功
;归还寄存器
pop si 
pop di
pop dx 
pop cx 
pop bx 
pop ax 
ret

divdw:
;ax存放被除数低16 dx存放被除数高16 cx存放除数
		push ax 
		
		mov ax,dx ;取出高16位
		
		mov dx,0
		
		div cx    ;int()H/N 商结果存放ax,余数结果存放dx
		
		mov bx,ax ;存放高16位结果
		
		pop ax    ;取出低16位
		
		div cx    ;L/N  商ax 余数dx 
		
		mov cx,dx ;存储余数
		
		mov dx,bx ;存储低16位
			
        ret
		
showptr: ;将用到的寄存器统统存储一遍,后续结束小程序时全部返还
push di
push dx
push cx
push si 
push ds 
push es
push ax


show:
;将字符串显示在屏幕上,dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
;1.首先计算显存位置
sub dh,1  		;dh减一
mov al,dh 		;做乘法运算
mov ah,160
mul ah   		;行数减一乘以160 最后将结果ax加上dl即可
mov dh,0
add ax,dx 		;ax此时存放写入的地址位置
mov di,ax 		;作为显存指针使用
mov ax,0b800h
mov es,ax		;将显存地址写入es

;2.确定颜色属性
mov dh,cl 		;将颜色属性赋值高位过去

;3.写入字符串,ds:si指向字符串首地址,需要将字符串存放到dl中
show0:
;这里要利用jcxz了
mov ch,0
mov cl,ds:[si]
jcxz show_ok 
mov dl,ds:[si] 	;获取字符串字节
mov es:[di],dx  ;将dx写入到es:[di]中去 也就是显存地址
inc si 			;字符串指针后移
add di,2		;显存地址后移
jmp short show0 ;跳转回去

show_ok:;出口
pop ax
pop es 
pop ds 
pop si 
pop cx 
pop dx 
pop di 
ret
		code ends 
		end start

效果图:

 

小程序搞定之后,就可以写代码了.

数据段要先安排好:

我把这些数据分成了五段,分别是:

年份段year

收入段income

雇员段workers

人均收入段per_income

最后就是展示数据段show_data

我在年份数据段里面,每个年份后面加上0作为标识符,因为年份数据段是不需要转化的.

year segment
;21年的21个字节
db '1975',0,'1976',0,'1977',0,'1978',0,'1979',0,'1980',0,'1981',0,'1982',0,'1983',0
db '1984',0,'1975',0,'1986',0,'1987',0,'1988',0,'1989',0,'1990',0,'1991',0,'1992',0
db '1993',0,'1994',0,'1995',0
year ends 
income segment
;21年的21收入双字
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
income ends 
workers segment
;21年的21个字 雇员数目
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
workers ends 
per_income segment
;21年的人均收入
dw 5,3,42,104,85,210,123,111,105,125,140,136,153,211,199,209,224,239,260,304,333
per_income ends

show_data segment
dd 256 dup(0)
show_data ends

在写这个程序之前,我并没有头脑发热直接往下撸,而是在先写出展示每块的测试小程序,分别实现展示,最后组合进来的.

完整代码:

assume cs:code
year segment
;21年的21个字节
db '1975',0,'1976',0,'1977',0,'1978',0,'1979',0,'1980',0,'1981',0,'1982',0,'1983',0
db '1984',0,'1975',0,'1986',0,'1987',0,'1988',0,'1989',0,'1990',0,'1991',0,'1992',0
db '1993',0,'1994',0,'1995',0
year ends 
income segment
;21年的21收入双字
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
income ends 
workers segment
;21年的21个字 雇员数目
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
workers ends 
per_income segment
;21年的人均收入
dw 5,3,42,104,85,210,123,111,105,125,140,136,153,211,199,209,224,239,260,304,333
per_income ends

show_data segment
dd 256 dup(0)
show_data ends
 
stack segment
dd 256 dup(0)
stack ends 

code segment
start:
mov bx,stack
mov ss,bx 
mov sp,1024

;首先展示年份,由于年份直接就是字符串,所以不需要转化
mov ax,year
mov ds,ax
mov dh,3  ;从第3行开始
mov dl,20  ;第20列开始

mov si,0
mov cx,21
s001:
push cx
mov cl,1Ah
call showptr
inc dh  ;行数+1
inc si 
pop cx 
loop s001 
;
;
;
;
;
;年份展示完毕,展示收入,需要转化dword数据
mov bx,show_data
mov ds,bx
mov bx,income
mov es,bx
mov si,0
mov bx,0
mov cx,21 ;21次循环
s011: 	;先将数据转化为10进制字符串到show_data段之中
mov ax,es:[bx]
mov dx,es:[bx].2
add bx,4 ;指向下一个双字
call dtoc_2 	;将dword型数据转变成十进制字符串,字符串以0结尾,存放于data段
inc si 
loop s011
 
mov dh,3  ;行数仍然为3
mov dl,40 ;列数变为40
mov si,0
mov cx,21
s012: ;从show_data段开始展示
push cx 
mov cl,1Ah
call showptr ;显示字符串 dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
inc dh 
inc si
pop cx 
loop s012
;
;
;
;
;
;收入展示完毕,展示雇员数目,dw数据 需要转化为字符串数据再进行展示
mov bx,show_data
mov ds,bx
mov bx,workers 
mov es,bx
mov si,0
mov bx,0
mov cx,21 ;21次循环
s021: 	;先将数据转化为10进制字符串到show_data段之中
mov ax,es:[bx]
add bx,2 ;指向下一个字
call dtoc 	;将word型数据转变成十进制字符串,字符串以0结尾,存放于data段
inc si 
loop s021
 
mov dh,3  ;行数仍然为3
mov dl,60 ;列数变为60
mov si,0
mov cx,21
s022: ;从show_data段开始展示
push cx 
mov cl,1Ah
call showptr ;显示字符串 dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
inc dh 
inc si
pop cx 
loop s022
;
;
;
;
;
;雇员数展示完毕,展示人均收入数目
mov bx,show_data
mov ds,bx
mov bx,per_income 
mov es,bx
mov si,0
mov bx,0
mov cx,21 ;21次循环
s031: 	;先将数据转化为10进制字符串到show_data段之中
mov ax,es:[bx]
add bx,2 ;指向下一个字
call dtoc 	;将word型数据转变成十进制字符串,字符串以0结尾,存放于data段
inc si 
loop s031
 
mov dh,3  ;行数仍然为3
mov dl,80 ;列数变为80
mov si,0
mov cx,21
s032: ;从show_data段开始展示
push cx 
mov cl,1Ah
call showptr ;显示字符串 dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
inc dh 
inc si
pop cx 
loop s032
mov ax,4c00h
int 21h
;
;
;
;
;
;转化小程序
dtoc:
push ax
push bx
push cx
push dx
push di


mov bx,10;除数为10
mov di,0 ;计数器置0

s0:
mov dx,0 ;被除数高位置0
div bx   ;做除法 dx存放余数 ax存放商


add dx,30h ;余数加30h
push dx    ;存放ascii码,入栈
inc di     ;计数器加1
;判断商是否为0
mov cx,ax 
jcxz dtoc_ok
jmp short s0 ;跳转回去继续做除法直到商为0

dtoc_ok:
;inc di 
mov cx,di  ;计数器存进cx做循环
;inc cx 
s2:
pop ds:[si];出栈 弹出到data空间
inc si     ;指针后移
loop s2    ;结束循环表示出栈成功
;归还寄存器

pop di
pop dx 
pop cx 
pop bx 
pop ax 
ret
;
;
;
;
;
;转化小程序2
dtoc_2:
push ax
push bx
push cx
push dx
push di



mov di,0 ;计数器置0

dtoc2_s0:
mov cx,10;除数为10
call divdw   ;做dword除法 dx存放高16位结果 ax存放低16位结果 cx存放余数


add cx,30h ;余数加30h
push cx    ;存放ascii码,入栈
inc di     ;计数器加1
;判断商是否为0,此时的商是32位的结果,需要将商相加一下
mov cx,ax 
add cx,dx ;如果相加之后结果为0就说明商为0了
jcxz dtoc2_ok
jmp short dtoc2_s0 ;跳转回去继续做除法直到商为0

dtoc2_ok:
;inc di 
mov cx,di  ;计数器存进cx做循环
;inc cx 
dtoc2_s2:
pop ds:[si];出栈 弹出到data空间
inc si     ;指针后移
loop dtoc2_s2    ;结束循环表示出栈成功
;归还寄存器
pop di
pop dx 
pop cx 
pop bx 
pop ax 
ret
;
;
;
;
;
;除法小程序
divdw:
;ax存放被除数低16 dx存放被除数高16 cx存放除数
		push ax 
		
		mov ax,dx ;取出高16位
		
		mov dx,0
		
		div cx    ;int()H/N 商结果存放ax,余数结果存放dx
		
		mov bx,ax ;存放高16位结果
		
		pop ax    ;取出低16位
		
		div cx    ;L/N  商ax 余数dx 
		
		mov cx,dx ;存储余数
		
		mov dx,bx ;存储低16位
			
        ret

;
;
;
;
;
;展示小程序
showptr: ;将用到的寄存器统统存储一遍,后续结束小程序时全部返还
push di
push dx
push cx
push ds 
push es
push ax


show:
;将字符串显示在屏幕上,dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
;1.首先计算显存位置
sub dh,1  		;dh减一
mov al,dh 		;做乘法运算
mov ah,160
mul ah   		;行数减一乘以160 最后将结果ax加上dl即可
mov dh,0
add ax,dx 		;ax此时存放写入的地址位置
mov di,ax 		;作为显存指针使用
mov ax,0b800h
mov es,ax		;将显存地址写入es

;2.确定颜色属性
mov dh,cl 		;将颜色属性赋值高位过去

;3.写入字符串,ds:si指向字符串首地址,需要将字符串存放到dl中
show0:
;这里要利用jcxz了
mov ch,0
mov cl,ds:[si]
jcxz ok 
mov dl,ds:[si] 	;获取字符串字节
mov es:[di],dx  ;将dx写入到es:[di]中去 也就是显存地址
inc si 			;字符串指针后移
add di,2		;显存地址后移
jmp short show0 ;跳转回去

ok:;出口
pop ax
pop es 
pop ds 
pop cx 
pop dx 
pop di 
ret
code ends
end start 

  • 1
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值