assume cs:code ;年份 year segment db '1975','1978','1981','1984','1987','1990','1993','1995' year ends ;收入 income segment dd 16,1356,16000,97479,345980,1183000,3753000,5937000 income ends ;雇员 employee segment dw 3,13,130,778,2258,5635,14430,17800 employee ends table segment ;每列占9格,4列,8行 db 288 dup(' ') table ends code segment start: mov ax,table mov es,ax mov bx,0 ;定义年份的递增量 mov si,0 ;定义table的递增量 mov cx,8 ;循环添加8组数据到table中 loopyear: ;添加年份到table mov ax,year mov ds,ax mov al,[bx] mov es:[si],al mov al,[bx+1] mov es:[si+1],al mov al,[bx+2] mov es:[si+2],al mov al,[bx+3] mov es:[si+3],al add bx,4 ;增加偏移量 add si,36 loop loopyear mov bx,0 ;定义收入的递增量 mov si,0 ;定义table的递增量 mov cx,8 ;循环添加8组数据到table中 loopincome: ;转换收入为数字字符,添加到table中 push es push si mov ax,income mov es,ax ;由于转换用到ds,所以我们用es来暂时表示income mov ax,table mov ds,ax add si,9 ;从第9列开始保存收入 mov ax,es:[bx] mov dx,es:[bx+2] call ddtoc pop si pop es add bx,4 ;增加偏移量 add si,36 loop loopincome mov bx,0 ;定义收入的递增量 mov si,0 ;定义table的递增量 mov cx,8 ;循环添加8组数据到table中 loopemployee: ;转换雇员为十进制字符,添加到table中 push es push si mov ax,employee mov es,ax mov ax,table mov ds,ax add si,18 mov ax,es:[bx] call dtoc pop si pop es add bx,2 ;增加偏移量 add si,36 loop loopemployee mov bx,0 ;定义收入的递增量 mov si,0 ;定义table的递增量 mov di,0 ;雇员递增量 mov cx,8 ;循环添加8组数据到table中 loopaverage: ;计算人均收入,并且转换为十进制字符,添加到tabl push es push si mov ax,employee mov es,ax mov ax,income mov ds,ax mov ax,[bx] mov dx,[bx+2] div word ptr es:[di] ;商保存在ax中 mov dx,table mov ds,dx add si,27 call dtoc pop si pop es ;最后的空格保存为0表示这一行数据的结束,方便打印 mov ax,table mov es,ax mov dl,0 mov es:[si+35],dl add bx,4 ;增加偏移量 add si,36 add di,2 loop loopaverage mov dh,8 ;行号 mov dl,3 ;列号 mov cl,07h ;白色字 mov ax,table mov ds,ax mov si,0 ;循环加入字 mov bl,cl mov cx,8 loopprint: push bx push cx mov cl,bl call show_str pop cx pop bx ;让dh加1 mov al,dh mov ah,0 inc ax mov dh,al add si,36 loop loopprint mov ax,4c00h int 21h ;将word型数据转换为十进制字符串,ax是word型数据,ds:si指向字符串首地址 dtoc: push ax push di push cx push dx push si mov di,0 ;记录入栈多少次,就是有多少位数 s1: mov cx,10d ;除10 mov dx,0 div cx mov cx,ax ;如果商为0,那么求值完成 jcxz s2 add dx,30h push dx ;把求得的ACSII入栈 inc di jmp short s1 s2: add dx,30h ;最后一次也要记录 push dx inc di mov cx,di s3: pop ax mov [si],al ;ACSII码只占用了低8位 inc si loop s3 pop si pop dx pop cx pop di pop ax ret ;将dword型数据转换为十进制字符串,ax是dword型低16位,dx为高16位,ds:si指向字符串首地址 ddtoc: push ax push di push cx push dx push si mov di,0 ;记录入栈多少次,就是有多少位数 dds1: mov cx,10d ;除10 call divdw push cx mov cx,ax ;如果商为0,那么求值完成 add cx,dx ;低和高相加一下,看看是不是为0 jcxz dds2 pop cx add cx,30h push cx ;把求得的ACSII入栈 inc di jmp short dds1 dds2: pop cx add cx,30h ;最后一次也要记录 push cx inc di mov cx,di dds3: pop ax mov [si],al ;ACSII码只占用了低8位 inc si loop dds3 pop si pop dx pop cx pop di pop ax ret ;解决除法溢出问题,ax保存低16位,dx高16位,cx为除数, ;结果低16位保存在ax,高16保存在dx,余数保存在cx divdw: push bx push ax mov ax,dx ;int(H/N) mov dx,0 div cx mov bx,ax ;商暂存到bx,乘65536是高16位 pop ax ;取出ax作为低16位,上次计算的余数在dx中,刚好做为高16位 div cx mov cx,dx ;余数赋值给cx mov dx,bx ;dx赋值为上次暂存的bx pop bx ret ;dh保存行号,dl保存列号,cl颜色,ds:si指向首地址 show_str: push cx ;保存用到的寄存器 push si push es push di push bx push dx mov ax,0b800h mov es,ax mov al,0a0h ;一行的总列数160字节 dec dh ;行号减1,因为是从0开始的 mul dh ;计算行开始偏移地址 mov bx,ax mov al,2 mul dl ;计算列 sub ax,2 ;列也是从0开始,而且一个字符占两个字节 add bx,ax ;求出开始位置 mov di,0 mov al,cl mov ch,0 ;高8位为0 s: mov cl,ds:[si] ;判断是否到了字符结束 jcxz ok mov es:[bx+di],cl mov es:[bx+di+1],al inc si add di,2 jmp short s ok: pop dx pop bx pop di pop es pop si pop cx ret code ends end start