任务: 将实验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运行结果: