8086汇编 课程设计1

本文详细指导如何使用汇编语言将Poweridea公司的历史数据,包括年份、收入和雇员数,按照特定格式在屏幕上显示,并涉及溢出处理和字符串转换子程序。通过C语言描述和汇编实现,展示了栈管理和寻址技巧的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

任务: 将实验7中的Power idea公司的数据按照下图所示的格式在屏幕上显示出来
在这里插入图片描述
在这个程序中,要用到我们前面学到的几乎所有的知识,注意选择适当的寻址方式和相关子程序的设计和应用。
另外,要注意,因为程序要显示的数据有些已经大于65535,应该编写一个新的数据到字符串转化的子程序,完成dword型数据到字符串的转化,说明如下。
在这里插入图片描述
在这个子程序中要注意除法溢出的问题,可以用在实验10中设计的子程序divdw来解决。
实验:
1.对于这个实验,还是可以先用C语言描述一遍
2.根据所学知识,用汇编语言将程序实现,特别注意栈的使用

C语言实现:

#include <stdio.h>
#include <stdlib.h>

struct table
{
	char year[4];
	int summ;
	short ne;
	short ave;
};

char years[21][4] = {'1', '9', '7', '5', '1', '9', '7', '6',
					 '1', '9', '7', '7', '1', '9', '7', '8',
					 '1', '9', '7', '9', '1', '9', '8', '0',
					 '1', '9', '8', '1', '1', '9', '8', '2',
					 '1', '9', '8', '3', '1', '9', '8', '4',
					 '1', '9', '8', '5', '1', '9', '8', '6',
					 '1', '9', '8', '7', '1', '9', '8', '8',
					 '1', '9', '8', '9', '1', '9', '9', '0',
					 '1', '9', '9', '1', '1', '9', '9', '2',
					 '1', '9', '9', '3', '1', '9', '9', '4',
					 '1', '9', '9', '5'};
//	years[i][j]	位置 --> ds:i * 4 + j

int summs[21] = {16, 22, 382, 1356, 2390, 8000, 16000, 24486,
				 50056, 97479, 140417, 197514, 345980, 590827,
				 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000};
//	summs[0]	位置 --> ds:84
short nes[21] = {3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001,
				 1442, 2258, 2793, 4037, 5635, 8226, 11542, 14430, 15257, 17800}; //	nes[0]		位置 --> ds:168
// short aves[21]; // 需要求的数

struct table T[21]; // T[i].year[0]	位置 --> es:i * 16
					// T[i].summ 	位置 --> es:i * 16 + 5
					// T[i].ne  	位置 --> es:i * 16 + 8
					// T[i].ave 	位置 --> es:i * 16 + 11(0bh)

// 题目要求: 将上面数据存入table表T中

// C语言描述
int main()
{
	for (int i = 0; i < 21; i++)
	{
		for (int j = 0; j < 4; j++)
			T[i].year[j] = years[i][j];
		T[i].ne = nes[i];
		T[i].summ = summs[i];		  // i * 16
		T[i].ave = summs[i] / nes[i]; // 32位数除以16位数
	}

	for (int i = 0; i < 21; i++)
	{
		for (int j = 0; j < 4; j++)
			printf("%c", T[i].year[j]);
		printf("\t%d", T[i].summ);
		printf("\t%d", T[i].ne);
		printf("\t%d\n", T[i].ave);
	}

	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
8086汇编实现:

assume cs:codesg,ds:datasg,ds:tablesg,ss:stacksg

stacksg segment
	dw 16 dup (0)		;16字节的内存作为栈段
stacksg ends

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'
	;以上是表示21年的21个字符串,起始地址datasg:0

	dd 16,22,382,1356,2390,8000,16000,24486,50056,97479,140417,197514
	dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
	;以上是表示21年公司收入的21个dword型数据,起始地址datasg:84

	dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
	dw 11542,14430,15257,17800
	;以上是表示21年公司雇员人数的21个word新数据,起始地址datasg:168
	;数据段总大小210字节
datasg ends

tablesg segment
	db 21 dup ('year summ ne ?? ')
				;|0123456789abcdef|
				;|year summ ne ?? |
				; 0    5 7  a  d
tablesg ends

str segment				;用于临时存放字符型数据
	db ' ' dup (8)
str ends

codesg segment

start:	mov ax,stacksg
		mov ss,ax

		mov ax,datasg
		mov ds,ax
		mov ax,tablesg
		mov es,ax
		call in_table			;将数据存入table表, 参数ds段数据存放在es段

		mov ax,tablesg
		mov ds,ax				;table表段地址
		call show_table			;显示ds段的内容, 参数ds段数据转成字符显示在显存上

		mov ax,4c00h
		int 21h
;main函数结束

;show_table功能:	将table变中的数据打印在屏幕上
;		   参数:	ds->table表的段地址
;		   返回:	无
show_table:

		mov dx,0				;开始在0行0列
		mov ax,0007h			;黑底白字
		mov bp,0				;bp确定好是table中的第几条信息
		mov cx,21				;table表共21行数据
	show_table_s:
		push cx					;循环次数入栈
		push dx					;行列信息入栈
		push ax					;字体属性入栈

		call str_ini			;初始化年份字符串
		mov ax,str
		mov es,ax				;str字符串的段地址
		mov cx,4
		mov si,0
	year_to_str:
		mov al,ds:[bp+si]
		mov es:[si],al
		inc si
		loop year_to_str		;将年份信息复制到str中
		pop cx					;字体
		pop dx					;行列
		call show_str			;显示年份

		call str_ini
		add dl,8				;列数+8
		push dx
		push cx
		mov ax,ds:[bp+5]
		mov dx,ds:[bp+7]
		call dtoc				;将summ数值转成字符串存放在str中
		pop cx
		pop dx
		call show_str			;显示summ

		call str_ini
		add dl,8
		push dx
		push cx
		mov dx,0
		mov ax,ds:[bp+0ah]
		call dtoc
		pop cx
		pop dx
		call show_str			;显示ne

		call str_ini
		add dl,8
		push dx
		push cx
		mov dx,0
		mov ax,ds:[bp+0dh]
		call dtoc
		pop cx
		pop dx
		call show_str			;显示ave

		;一行所有信息显示完后
		add bp,16
		mov ax,cx				;暂时存下字体color属性
		inc dh					;行数+1
		mov dl,0				;列数设为0
		pop cx					;循环次数出栈
		loop show_table_s
		ret
;show_table函数结束

;dtoc功能: 	将16进制数转成10进制数的字符形式, 暂时存放在str段中
;	 参数: 	dx->原数据高16位, ax->原数据低16位
;  	 返回:	无
dtoc:	push ds

		mov bx,str
		mov ds,bx

		mov si,0
	dtoc_s0:
		mov cx,10				;除数设为10
		call divdw
		push cx					;余数入栈
		inc si
		mov cx,ax
		add cx,dx				;cx判断商是否为0
		jcxz dtoc_s0_ok
		jmp short dtoc_s0
	dtoc_s0_ok:					;处理完最高位数字后
		mov cx,si
		sub si,si
	dtoc_s1:
		pop bx
		add bx,'0'
		mov ds:[si],bl
		inc si
		loop dtoc_s1
		pop ds
		ret
;dtoc函数结束


;divdw功能:	32位数除以16位数,防止溢出
;	  参数:	dx,ax->(32位数), cx->(除数16位)
;	  返回:	dx,ax->(商32位), cx->(余数16位)
divdw:	push ax			;先将低16位入栈保存
		mov ax,dx
		sub dx,dx
		div cx			;计算H/N以及H%N, 得到的H/N(ax)就是最终结果的高16位
		pop bx			;取出L
		push ax			;最终结果的高16位入栈
		mov ax,bx
		div cx			;计算结果的低16位商放在ax
		mov cx,dx		;将结果的余数放在cx
		pop dx			;将结果的高16位放在dx
		ret
;divdw函数结束


;str_ini功能:	将str段字符串赋值为化为8个空格
;		参数:	无
;	    返回:	无
str_ini:
		push ax
		push bx
		push cx
		push es
		mov ax,str
		mov es,ax
		mov bx,0
		mov cx,8
	ini:mov byte ptr es:[bx],' '
		inc bx
		loop ini			;将str数据全部设为' '(空格)
		pop es
		pop cx
		pop bx
		pop ax
		ret
;str_ini函数结束


;show_str功能:	显示str段的内容在屏幕上
;		 参数:	dh->首字符行数, dl->首字符列数, cl->字符color属性
;	     返回:	无
show_str:
		push dx
		push cx
		push ds			;table表的ds暂时入栈
		mov ax,str
		mov ds,ax
		mov al,0ah
		mul dh
		add ax,0b800h
		mov es,ax		;获取具体行的段地址
		mov bh,0
		mov bl,dl
		add bl,dl		;es:bx定位地址显示字符
		mov si,0
		mov dl,cl		;dl存储要显示的color

		mov cx,8
	show_str_s:
		mov al,ds:[si]
		mov es:[bx],al			;设置字符
		mov es:[bx+1],dl		;设置color
		inc si
		add bx,2
		loop show_str_s

	show_str_ok:
		pop ds
		pop cx
		pop dx
		ret
;show_str函数结束


;in_table功能:	将data段数据填入表table中
;		 参数: 	ds->data数据段地址, es->table表段地址
;	     返回:	无
in_table:
		mov bp,0 				;用于table表寻址,每次循环自增16
		mov si,0 				;用于数据中summ寻址,每次循环自增4
		mov di,0 				;用于数据中ne寻址,每次循环自增2
		mov cx,21
	in_table_s:
		push cx
		mov bx,si  				;用于数据中year寻址
		push si
		mov si,0
		mov cx,4
	in_table_s0:
		mov al,ds:[bx+si]
		mov es:[bp+si],al
		inc si
		loop in_table_s0
		pop si
								;以上循环实现将年份信息存入table表中

		mov ax,ds:[di+168]
		mov es:[bp+0ah],ax		;table表存入ne
								;C语言描述中的T[i].ne = nes[i]

		mov ax,ds:[si+84]		;双字型数据的低16位
		mov dx,ds:[si+86]		;双字型数据的高16位
		mov es:[bp+5],ax
		mov es:[bp+7],dx		;table表存入summ
								;C语言描述中的T[i].summ = summs[i]

		div word ptr es:[bp+0ah]
		mov es:[bp+0dh],ax		;除法计算,table表存入ave
								;C语言描述中的T[i].ave = summs[i] / nes[i];

		add bp,16
		add si,4
		add di,2
		pop cx
		loop in_table_s
		ret
;in_table函数结束

codesg ends
end start

DosBox运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值