汇编语言 第三版 王爽 课程设计1

大兔子大兔子 提交于 2020-01-31 02:26:09

课程设计1

题目要求

在这里插入图片描述
在这里插入图片描述

实验7

实验10

当然在做了课程设计1后 实验10中只有“数值显示”是比较成功的

分析

将数据存储在table中
('year summ nn ave ')
table格式(‘88484’)数字代表字节数 共32字节

大致步骤如下
1.传入字符
2.传入收入
人数为数据 需要转换为字符dtoc
dtoc过程中需要用到divdw但不是所有数据都需要
由于之前的经验不足 这次直接重写两个函数
divdw改为div_plus使之能够判断被除数是否需要进行32位除法
dtoc直接包含div_plus 并且参数更加明确 能够被直接调用
3.传入人数
4.计算人均收入传入
5.将数据以十进制显示在屏幕上show_str

那么重点问题就在第二步上 这里先给出代码

要注意子程序传入的参数若不是空闲寄存器需要入栈保存数值

dotc

功能

将dword或word数据转换为字符

参数

ax 高16位
dx 低16位
ds:[si] 空闲内存
返回si地址 便于后续的调用

dtoc:
	psi:
		push si
	re:	
		mov cx,0ah
		push bx
		call div_plus	;执行完后cx为余数 ax低位 dx高位
		pop bx
		add cx,30h
		mov ds:[si],cl
		inc si
		mov cx,ax	;判断最后一位
		jcxz finsh
	jmp short re
	
	finsh:
		mov cx,si	
		pop si		
		sub cx,si
		mov dx,si 
		s1:
			mov al,ds:[si]	;栈一次传一个字节
			push ax
			inc si
		loop s1
		mov cx,si
		sub cx,dx
		mov si,dx
		s2:
			pop ds:[si]
			inc si
		loop s2
		mov si,dx
	ret

div_plus

功能

判断被除数以进行32或16位除法 被除数位16位时返回dx为0

参数

ax 低16位
dx 高16位
cx 除数

返回

ax 低16位
dx 高16位
cx 余数

div_plus:
	push ax
	push cx
	mov cx,dx
	jcxz divd
	pop cx
	mov ax,dx
	mov dx,0
	div cx
	
	mov bx,ax	;商高位
	pop ax
	div cx
	mov cx,dx	;输出结果
	mov dx,bx
	
	div_ends:
	ret
	
	divd:
		pop cx
		pop ax
		div cx
		mov cx,dx
		mov dx,0
	jmp short div_ends

程序代码

assume cs:codesg,ds:datasg,es:table,ss:stack

datasg 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, 97479, 140417, 197514
	dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000

	dw 3, 7, 9, 13, 28, 38, 130, 220, 475, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
	dw 11542, 14430, 15257, 17800
	dw 16 dup(0)
datasg ends

table segment
	db 21 dup('year    summ        nn      ave ')
table ends

stack segment
	dw 16 dup(0)
stack ends

codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov ax,table
	mov es,ax
	mov ax,stack
	mov ss,ax
	mov sp,32
	mov bx,0
	mov cx,21
	mov dx,0
	mov si,0
	
	call s21
	
	mov ax,es
	mov ds,ax
	mov dh,3	;行
	mov dl,0
	mov cl,7h
	mov ch,0
	call show_list

	
	mov ax,4c00h
	int 21h
	
s21:
	push cx		;!!!!!!!!!!!!!!
	mov cx,4
	mov di,0
	
	s21_4_1:
		mov al,ds:[si]
		mov es:[bx+di],al
		inc si
		inc di
	loop s21_4_1
	
	call salary
	
	mov cx,2
	to_char:	;传入总收入和人数
		push si   ;!!!!!!!!!!!!!!
		jcxz avg
		mov si,0e0h			;空闲内存
		push cx  ;!!!!!!!!!!!!!!
		call clean
		
		call dtoc
		mov cx,4		
		s21_4_2:
			mov ax,ds:[si]
			mov es:[bx+di+4],ax
			
			add si,2
			add di,2
		loop s21_4_2
		
		pop cx		;line 68
		pop si		;line 53
		
		push cx
		call half
		mov cx,si
		mov si,ax
		
		mov ax,ds:[si+0a6h]
		mov si,cx
		pop cx
		
		mov dx,0h
		add di,4
		dec cx
		jmp short to_char
		
	avg:	;di 1c si 15
		call half
		
		mov cx,ax	;人数在ds占两个字节
		call salary
		mov si,cx
		div word ptr ds:[si+0a6h]
		mov dx,0
		mov si,0e0h
		call clean
		call dtoc
		
		mov ax,ds:[si]
		mov es:[bx+di],ax
		mov ax,ds:[si+2]
		mov es:[bx+di+2],ax
		pop si ;!!!!!!!!!!!!!!
	pop cx	;line 39
	add bx,20h
loop s21
ret

salary:	;求收入
	mov ax,ds:[si+50h]	;第一次结束为4
	mov dx,ds:[si+52h]
ret

show_list:
	mov ax,cx
	mov cx,21
	mov bx,0
	SL_21:
		push cx
		mov cx,31	;20h个数据是32 最后一个为0
		mov si,0
		
		SL_21_31:
			push cx
			mov cl,ds:[bx+si]
			jcxz space
		continue:
			inc si
			pop cx	;3数据循环
		loop SL_21_31
		
		mov cl,al
		inc dh
		mov si,bx
		push ax
		push bx
		call show_str
		pop bx
		pop ax
		add bx,20h
		
		pop cx	;行循环cx
		
	loop SL_21
ret

space:				;空数据替换空格
	push ax
	mov ax,20h
	mov ds:[bx+si],al
	pop ax
	jmp short continue	

dtoc:
	psi:
		push si
	re:	
		mov cx,0ah
		push bx
		call div_plus	;执行完后cx为余数 ax低位 dx高位
		pop bx
		add cx,30h
		mov ds:[si],cl
		inc si
		mov cx,ax	;判断最后一位
		jcxz finsh
	jmp short re
	
	finsh:
		mov cx,si	
		pop si		
		sub cx,si
		mov dx,si 
		s1:
			mov al,ds:[si]	;栈一次传一个字节
			push ax
			inc si
		loop s1
		mov cx,si
		sub cx,dx
		mov si,dx
		s2:
			pop ds:[si]
			inc si
		loop s2
		mov si,dx
	ret
		
div_plus:
	push ax
	push cx
	mov cx,dx
	jcxz divd
	pop cx
	mov ax,dx
	mov dx,0
	div cx
	
	mov bx,ax	;商高位
	pop ax
	div cx
	mov cx,dx	;输出结果
	mov dx,bx
	
	div_ends:
	ret
	
	divd:
		pop cx
		pop ax
		div cx
		mov cx,dx
		mov dx,0
	jmp short div_ends
	
show_str:
	mov ax,0b800h
	mov es,ax
	mov bh,dh
	mov bl,dl
	
	mov ax,0a0h
	mul bh	
	push si
	mov si,ax	;行
	
	mov ax,2
	mul bl	
	mov di,ax	;列
	
	add si,di
	mov bx,si
	pop si
	mov di,0

	s:	
		push cx
		mov cl,ds:[si]
		jcxz ok
		
		mov al,ds:[si]	;字符及属性
		pop cx
		mov ah,cl
		mov es:[bx+di],ax
		inc si
		add di,2
	jmp short s

	ok:
		pop cx
	ret

clean:	;使用ax si	8个字节取0 清空内存
	push ax
	push cx
	push si
	mov cx,8
	s_c:
		mov ax,0
		mov ds:[si],ax
		inc si
	loop s_c
	pop si
	pop cx
	pop ax
	ret
	
half:	;除2
	mov ax,si
	mov dx,0
	mov cx,2
	div cx
ret

codesg ends
end start

结果

在这里插入图片描述

问题

作为第一个综合性程序,水平不足 着实被难倒了。基本上一个小时写完10倍的时间debug。

1.主程序里call之前不要push 因为最后用到需要的某个值其实是执行call后push的ip

2.push pop对应着,写代码的时候就应该直接成对写出来 不然写着写着就混掉

3.在跳转里面的栈操作要注意执行了几次

4.调用子程序或者编写子程序时,对于在子程序中需要用到的reg应该提前push 调用完后即时pop,非常简单且必要的事情

5.代码长度超过jmp shotr最大字节256,解决这个问题可以用push ip 然后jmp far的操作,但是也可以把某一段改为子程序 然后调用,half salary clean子程序都是由s_21调用以减少内存

6.承接4 在写show_list的时候调用show_str忘记了虽然它不需要传入bx这个参数,但是用到了bx。也就是除了注意4外还有考虑该程序中某个寄存器是否和子程序中需要用到的寄存器冲突

7.在转换收入 人数时用一段空闲内存暂时存储 收入为16 两个字节 而人数为3 一个字节,后面传数据就不可避免的把6也当作人数传了过去,所以在调用空闲内存的时候需要确保其中没有其他数据干扰(子程序 clean) 就是初始化 当然各寄存器的初始化也不能忘

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!