汇编语言(王爽) 课程设计一

课程设计一

思路
1 (子程序一) 首先调整要显示的区域的背景色
2 (子程序二) 将年份按照指定格式显示再屏幕上(这个子程序比较简单)
3 (子程序三) 将总收入dd(double word)和员工总数dw(define word)转化位字符串 并存入指定的代码段
每个字符串以数值0结尾,注意不是带引号的0 及’0’
以0为结尾来判断一个字符串是否结束 来决定是否需要换行
同时需要记录转化后所有的字符的总个数
4 (子程序四) 将指定段内的字符串按指定格式显示再屏幕
5 (子程序五) 计算每年员工平局收入
不足之处
1 开辟的三个数据段newdata1 newdata2 newdata3 大小是自己随意设定的值 浪费了很多空间
(MD 烧脑两周,总算搞完了,开始新的征程了 第十一章 走起…)

assume cs:codesg
data segment
	db '1975','1976','1977','1978','1979','1980','1981','1982','1983'			;注意这些数据在内存中就已经是二进制的数据了
	db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
	db '1993','1994','1995'
	dd 16,22,382,1356,2390,8000,16000,24486,50065,97497,140417,197514			;注意这些数据在内存中就还是二进制的数值 需要转化为字符串  dd  double word 占4个字节
	dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
	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
newdata1 segment
	db 4000 dup ('0')	;总收入字符数据域
newdata1 ends
newdata2 segment
	db 4000 dup ('0')	;员工总数字符域
newdata2 ends
newdata3 segment
	db 4000 dup ('0')	;员工总数字符域
newdata3 ends
codesg segment
start:					;整体思路为1 移动字符串同时转化为要显示的字符串 2 指定格式展示
		mov ax,data
		mov ds,ax
		call makeblack	;将显示区域置为黑色背景
		call showyear	;将年份按指定格式显示		
		call movsumnandne	;将总收入转化dd类型数据为字符并存入newdata段 这里是每转化一个就显示一个  如果连续存放到newdata段 无法判断字符的结束
		call movdiv			;计算每年的平均值 并转化为字符串从到指定的newdata段
	 
		mov ax,4c00h
		int 21h

		
;-------------------------movdiv start-------------------------------------------		
;功能 计算每年的员工平均收入 并将平均收入转化为字符串存到newdata3段  同时将newdata3段数据按指定格式显示到屏幕
movdiv:
		push cx
		push bx
		push ax
		push dx
		push es			;tdoc_dd会用到新的栈
		push ds
		push di
		
		mov bx,data
		mov ds,bx
		mov bx,newdata3	;将转换的字符串存到newdata3段	newdata3-096c
		mov es,bx		;es:[0]要存放的转化后字符串地址
		mov cx,21		;21年的总收入 循环21次
		mov bx,0		;ds:[84]指向数据的第二部分 总收入
		mov si,0		;使用si来 记录当前newdata1段的存放的数的起始地址,不能每次都从起始地址为0的地方存放 会覆盖原来数据
		mov di,0		;除数的索引
s9:		mov ax,ds:[bx+84]		;ax存低16位
		mov dx,ds:[bx+84+2]		;dx存高16位 注意这里是+2 因为dd占4个字节
		call divav				;调用子程序 计算平局值

		call tdoc_dd 		;将dd类型的平均收入转化为字符串 并存放到newdata段  参数 1、ax第16为  2、dx高16位	3、si newdata段的存放位置标	4、	di data段取数的位置	5、bx 将转化的字符串存放到新的数据段
		add bx,4			;一次循环占4个字节
		add di,2
		loop s9
		
		mov di,74			;屏幕显示的起始地址
		call showdoc		;注意si已经指向到了 newdata1段的末尾 无需再减2操作 将newdata1段转化的dd字符串 按指定的格式显示到屏幕

		pop di
		pop ds
		pop	es
		pop dx
		pop ax
		pop bx
		pop cx
		ret
;-------------------------movdiv end-------------------------------------------------		
	

;-------------------------divav start-------------------------------------------------
divav:	;计算平均值 不能除法溢出 结果高16位放到dx中 低16位放到ax中
		;push ax		;ax和dx的值需要作为tdoc_dd子程序的参数传入 所以不能还原位原来的值
		;push dx
		push bx
		push cx
		push di	
		push ds	
		
		push ax			
		push dx
		mov dx,0
		pop ax							;将dx值赋值给ax同时将dx置为0 防止除法溢出
		div word ptr ds:[di+168]		;ax存商 dx存放余数
		mov bx,ax						;暂存第一次的商 第一次的商就是最终结果的高十六位
		pop ax			
		div word ptr ds:[di+168]		;这时dx中存放了第一的余数最为第二次除法的高十六位  ax存商 dx存放余数
		mov dx,bx						;第一的结果存入到dx中 最终结果 dx存放高16为 ax存放低16为
		
		pop ds
		pop di
		pop cx
		pop bx
		;pop dx
		;pop ax
		ret
;-------------------------divav end-------------------------------------------------		
	

;-------------------------movsumnandne start-------------------------------------------
;功能 将总收入及员工总数转化为字符串存到newdata1和newdata2段 同时按指定格式显示到屏幕  
movsumnandne:
		push cx
		push bx
		push ax
		push dx
		push es			;tdoc_dd会用到新的栈
		push ds
		push di
		
		mov bx,data
		mov ds,bx
		mov bx,newdata1	;将转换的字符串存到newdata1段	newdata1-0778
		mov es,bx		;es:[0]要存放的转化后字符串地址
		mov cx,21		;21年的总收入 循环21次
		mov bx,84		;ds:[84]指向数据的第二部分 总收入
		mov si,0			;使用si来 记录当前newdata1段的存放的数的起始地址,不能每次都从起始地址为0的地方存放 会覆盖原来数据
s4:		mov ax,ds:[bx]		;ax存低16位
		mov dx,ds:[bx+2]			;dx存高16位 注意这里是+2 因为dd占4个字节
		call tdoc_dd				;调用子程序 将dd转化为字符串 并存放到newdata段  参数 1、ax第16为  2、dx高16位	3、si newdata段的存放位置标	4、	di data段取数的位置	5、bx 将转化的字符串存放到新的数据段
		add  bx,4					;一次循环占4个字节
		loop s4
		mov di,24			;屏幕显示的起始地址
		call showdoc		;注意si已经指向到了 newdata1段的末尾 无需再减2操作 将newdata1段转化的dd字符串 按指定的格式显示到屏幕
		
		mov bx,newdata2	;将转换的字符串存到newdata2段  newdata2-0872
		mov es,bx
		mov cx,21				;21年的员工总数 循环21次
		mov bx,168				;ds:[168]指向数据的第三部分 员工总数
		mov si,0					;使用si来 记录当前newdata2段的存放的数的起始地址,不能每次都从起始地址为0的地方存放 会覆盖原来数据
s5:		mov ax,ds:[bx]				;ax存低16位
		mov dx,0					;dx存高16位 注意这里是+2 因为dw占4个字节
		call tdoc_dd				;调用子程序 将dd转化为字符串 并存放到newdata段
		add  bx,2					;一次循环占2个字节
		loop s5
		mov di,50				;屏幕显示的起始地址
		call showdoc			;注意si已经指向到了 newdata2段的末尾 无需再减2操作 将newdata2段转化的dd字符串 按指定的格式显示到屏幕
		
		pop di
		pop ds
		pop	es
		pop dx
		pop ax
		pop bx
		pop cx
		ret				;子程序总收入显示完成
;-------------------------movsumnandne start-------------------------------------------			


;-------------------------tdoc_dd start-------------------------------------------
;参数 	1、ax低16为  2、dx高16位	3、si es:[si] newdata段的存放位置标	4、	di data段取数的位置	5、es将转化的字符串存放到新的数据段
;返回值 si要作为返回值使用 不能存放到栈中  因为再newdata1和newdata2段 时连续存放数据的
tdoc_dd:					;将ax和dx中数据 用取10的余数的方法转化位字符,注意除法的溢出问题
		push cx
		push bx
		push dx
		push ax
		push di 			;存放之要循环的总收入 员工总数 的位置  子程序中用来统计字符串的长度  
		push es				;es:[si] 用来指向存放 newdata1 newdata2段数据
		
		mov di,0
s6:		push ax			
		push dx
		pop ax				;dx中值放到ax中,做第一次的除法
		mov dx,0			;高16未置0防止除法溢出
		mov cx,10
		div cx				;dx存余数,ax存商
		mov bx,ax			;第一次的结果也就是商的高16位暂时保存到bx中
		pop ax				;从栈中去除低16位
		div cx				;dx存余数,ax存商
		mov cx,dx			;保存余数
		mov dx,bx			;将第一的结果从bx中去除放到dx中
		add cx,30h			;将余数转位数字,规律加30H
		push cx				;字符倒叙存放,出栈时正好正序为数字,注意这里实际上只有cl中有值 ch中值位0
		mov cx,ax			;判断商是否为0
		inc di				;长度统计
		jcxz  ok1			;商为0时跳出循环  而不是余数为0,结束子程序  
		jmp short s6		;正好dx存高16位,ax存低16位  形成一个循环	

ok1:	mov cx,di			;将得到的字符串正序存放,以0结尾 注意这里是以0结尾 不是'0' di字符串的长度
s7:		pop es:[si]			;字符串正序存放到newdata段
		add si,2			;一次占两个字节  这里的si需要覆盖主程序的si  因为下次再执行子程序时 newdata段的数据是连续存放的
		loop s7
		mov word ptr es:[si],0	;在newdata段的末尾加上0 表示结束  注意这里不是'0'
		add si,2			;必须要加2操作 让si指向末尾  且取数操作时  不需要减2来判断长度 本身就已经时 总长度了  需要加2防止 下一次存放时覆盖了末尾的0
		
		pop es
		pop di
		pop ax
		pop dx				;这里的出栈会和字符串数据有冲突,不能直接结束子方法
		pop bx
		pop cx
		ret					;子程序tdoc_dd结束  总收入显示完成	
;-------------------------tdoc_dd end----------------------------------------------		


;-------------------------showdoc start-------------------------------------------
;功能 显示newdata段的数据到屏幕上		
showdoc:					;需要两个判断 判断是否换行 判断是否到达末尾
		push es				;es:[0] 指向newdata1 或 newdata2的起始地址
		push ds
		push bx
		push di				;di 屏幕显示的起始地址
		push si				;si这时指向newdata段的末尾,程序结束时必须要还原si 这个很重要
		push cx
		push ax
		
		mov ax,di			;将屏幕显示的起始地址放到ax中 换行的时候需要重置di起始值
		push si				;用来判断是否到达newdata段的末尾
		mov bx,0b800h
		mov ds,bx

		mov bx,0			;行数
		mov cx,si			;cx先存newdata段字符串的总长度
		mov si,0			;newdata段的起始地址
s8:		pop cx				;这里取得值时刚才push si的值 优先判断是否到达newdata段的末尾,在判断是否需要换行  如果先判断换行 最后一次取数会越界
		jcxz ok3			;如果到达了newdata存放字符串数据末端 结束字符串,如果没有 取出当前位置的字符
		push cx
		mov cx,es:[si]	;取出一个字符,注意换行操作过程中di的值不能动
		jcxz ok4			;判断是否需要换行,到达一个字符串的结尾  需要取下一个字符串
		mov byte ptr ds:[bx+di],cl						;指定区域显示字符
		mov byte ptr ds:[bx+di+1],00001011b		;设置字体颜色为绿色高亮
		add di,2			;di的数值需要每次加2
		add si,2
		pop cx 
		sub cx,2			;已经取出一个数了 需要减少2个字节
		push cx
		jmp short s8
ok4:	add bx,160
		mov di,ax			;换行需要重置di为起始地址  注意不是以0起始的
		add si,2
		pop cx 
		sub cx,2			;换行表示一个字符串结束 newdata的指向也许要改变
		push cx
		jmp short s8
		
ok3:	pop ax
		pop cx
		pop si
		pop di
		pop bx
		pop ds
		pop es
		ret					;子程序showsumn结束	
;-------------------------showdoc end-------------------------------------------


;-------------------------showyear start-------------------------------------------			
showyear:
		push ax
		push si
		push bx
		push es
		push cx
		
		
		mov si,0
		
		mov cx,21
		mov ax,0b800h
		mov es,ax
		mov bx,0
		mov ax,data
		mov ds,ax
		
s3:		mov al,[si]							;取除第一个字
		mov byte ptr es:[bx],al		
		mov byte ptr es:[bx+1],00001011b	;设置字体颜色为绿色高亮  
		mov al,[si+1]						;取除第二个字
		mov byte ptr es:[bx+2],al			;取除第二个字		
		mov byte ptr es:[bx+3],00001011b
		mov al,[si+2]		
		mov byte ptr es:[bx+4],al			;取除第三个字
		mov byte ptr es:[bx+5],00001011b 
		mov al,[si+3]		
		mov byte ptr es:[bx+6],al			;取除第四个字
		mov byte ptr es:[bx+7],00001011b
		add si,4
		add bx,160							;第二行的起始地址160  每行80个字  160个字节
		loop s3

		pop cx
		pop es
		pop bx
		pop si
		pop ax
		ret											;子程序showyear结束  年份显示完成
;-------------------------makeblack end-------------------------------------------			


;-------------------------makeblack start-------------------------------------------		
makeblack:			;背景色黑白相间
		push cx
		push si
		push ax
		push ds
		push bx
		
		mov ax,0b800h
		mov ds,ax
		mov cx,10					;外层循环 循环10次 置为黑白相间
		mov bx,0
s1:		push cx						;放入栈中暂存这个数据
		mov cx,80					;25*160 共4000个字节
		mov si,0
		
		
s2:		mov byte ptr [bx+si],20h			;字符设置为空格
		mov byte ptr [bx+si+1],0000000b		;背景色设置为黑色
		mov byte ptr [bx+si+160],20h		;字符设置为空格
		mov byte ptr [bx+si+161],0000000b	;背景色设置为白色 01110000b
		add si,2
		loop s2
		
		add bx,320
		pop cx
		loop s1
		
		pop bx
		pop ds
		pop ax
		pop si
		pop cx
		ret				;子程序makeblack 背景色显示调整完毕
;-------------------------makeblack end-------------------------------------------			
codesg ends
end start			


最终效果如图,perfect!!!

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值