程序代码:
;这是王爽《汇编语言》课程设计 1 ;将实验7中的Power idea公司的数据以一定格式显示在屏幕上 ;作者ID:chaoc ;时间:21:14 2012/10/22~2012/10/24... assume cs:code,ss:stack stack segment dd 8 dup(0) stack ends Year segment;每个年份为4个byte db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995' Year ends ;.................................................................................................. Income segment;每年的收入为一个dword型数据,即4个字节 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000 dd 5937000 Income ends IncomeStr segment db 21 dup(' ');8个字符 字节 IncomeStr ends ;.................................................................................................. ;.................................................................................................. Employees segment;每年的员工人数为一个word型数据,即2个byte,此段占48个字节 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037 dw 5635,8226,11542,14430,15257,17800 Employees ends EmployeesStr segment db 21 dup(' ');5个字符 字节 此段占112个字节 EmployeesStr ends ;.................................................................................................. ;.................................................................................................. Perincome segment dw 21 dup(32) Perincome ends PerincomeStr segment db 21 dup(' ');3个字符,字节 PerincomeStr ends ;.................................................................................................. Lable segment db ' Year Income Employees Perincome' Lable ends code segment start: mov ax,stack mov ss,ax ; step0:计算人均收入 mov ax,Income ;把收入设为数据段ds +si mov ds,ax mov ax,Employees ;把员工人数设为扩展段es+di mov es,ax mov si,0 mov di,0 mov cx,21 loop0: push cx mov dx,ds:[si+2] mov ax,ds:[si] mov cx,es:[di] push dx push ax push cx call divdw mov es:[di+160],ax;把人均收入设为es段 es+di+160 add si,4 add di,2 pop cx loop loop0 ; step1:把Income段中的数据转为字符串保存到IncomeStr段。注意IncomeStr中的结果都是逆序的。 mov ax,Income;把Income设为数据段 ds+si mov ds,ax mov ax,IncomeStr;把IncomStr设为扩展段es+di mov es,ax mov si,0 mov di,0 mov cx,21 loop1: mov ax,ds:[si+2];依次将每个dword数据的高16位压栈 push ax mov ax,ds:[si];低16位 push ax push es ;存放转换结果字符的扩展段地址入栈 push di ;存放字符的偏移地址入栈 call dtoc add si,4 add di,8 loop loop1 ; step2:把Employees段中的数据转为字符串保存到EmployesStr段。注意EmployeesStr中的结果都是逆序的。 mov ax,Employees;把Employees设为数据段 ds+si mov ds,ax mov ax,EmployeesStr;把EmployeesStr设为扩展段es+di mov es,ax mov si,0 mov di,0 mov cx,21 loop2: mov ax,ds:[si];依次将每个word数据压栈 push ax push es ;存放转换结果字符的扩展段地址入栈 push di ;存放字符的偏移地址入栈 call wtoc add si,2 add di,5 loop loop2 ; step3:把Perincome段中的数据转为字符串保存到PerincomeStr段。注意PerincomeStr中的结果都是逆序的。 mov ax,Perincome;把Perincome设为数据段 ds+si mov ds,ax mov ax,PerincomeStr;把PerincomeStr设为扩展段es+di mov es,ax mov si,0 mov di,0 mov cx,21 loop3: mov ax,ds:[si];依次将每个word数据压栈 push ax push es ;存放转换结果字符的扩展段地址入栈 push di ;存放字符的偏移地址入栈 call wtoc add si,2 add di,3 loop loop3 ; step4:把IncomeStr,EmployeesStr,PerincomeStr段的数据翻转变为正序 ; step4.1把IncomeStr段的数据转为正序 mov ax,IncomeStr mov ds,ax mov si,0 mov ax,8 mov cx,21 step4loop1: push ds push si push ax call ReverseStr add si,8 loop step4loop1 ; step4.2把EmployeesStr段的数据转为正序 mov ax,EmployeesStr mov ds,ax mov si,0 mov ax,5 mov cx,21 step4loop2: push ds push si push ax call ReverseStr add si,5 loop step4loop2 ; step4.3把PerincomeStr段的数据转为正序 mov ax,PerincomeStr mov ds,ax mov si,0 mov ax,3 mov cx,21 step4loop3: push ds push si push ax call ReverseStr add si,3 loop step4loop3 ; step5:把数据显示到屏幕上,即把表格数据发送到显示缓冲区 ; step5.0在显示数据前先清屏 call clear ; step5.1把年份发送到显示缓冲区 mov ax,Year mov ds,ax mov si,0 ;要显示的字符首地址 mov dl,1 ;列号 mov dh,4 ;行号 mov bh,4 ;字符个数 mov bl,00000010B;颜色 mov cx,21 step5loop1: push dx push bx push ds push si call showstr inc dh add si,4 loop step5loop1 ; step5.2把总收入IncomeStr段的数据发送到显示缓冲区 mov ax,IncomeStr mov ds,ax mov si,0 ;要显示的字符首地址 mov dl,10 ;列号 mov dh,4 ;行号 mov bh,8 ;字符个数 mov bl,00000100B;颜色 mov cx,21 step5loop2: push dx push bx push ds push si call showstr inc dh add si,8 loop step5loop2 ; step5.3把员工人数即EmpoyeesStr段的数据发送显示缓冲区 mov ax,EmployeesStr mov ds,ax mov si,0 ;要显示的字符首地址 mov dl,20 ;列号 mov dh,4 ;行号 mov bh,5 ;字符个数 mov bl,00000001B;颜色 mov cx,21 step5loop3: push dx push bx push ds push si call showstr inc dh add si,5 loop step5loop3 ; step5.4把人均收入即PerincomeStr段的数据发送到显示缓冲区 mov ax,PerincomeStr mov ds,ax mov si,0 ;要显示的字符首地址 mov dl,30 ;列号 mov dh,4 ;行号 mov bh,3 ;字符个数 mov bl,00000101B;颜色 mov cx,21 step5loop4: push dx push bx push ds push si call showstr inc dh add si,3 loop step5loop4 ; step6:在数据的最前面显示栏目标签 mov ax,Lable mov ds,ax mov si,0 mov dl,0 mov dh,2 mov bl,00000010B mov bh,40 push dx push bx push ds push si call showstr ;主函数结束 mov ax,4c00h int 21h ;............................................................................................................................................................ ;............................................................................................................................................................ ;...........................................................上面是主程序..................................................................................... ;..........................................................下面是要调用的几个函数............................................................................ ;............................................................................................................................................................ ;............................................................................................................................................................ divdw: push bp push bx mov bp,sp mov cx,[bp+6];除数 mov ax,[bp+10];高16位 mov dx,0 div cx;现在AX中是高16位除n的商,DX中是余数 push ax;把高16位的除到得商保存到栈里 mov ax,[bp+8];现在dx中是高16位除到的余数,ax中是低16位 div cx mov cx,dx pop dx;现在dx中时高16除到得商,ax中是低16位除到得商,cx中是余数 pop bx pop bp ret 6 ;divdw函数结束 dtoc: push ax push bx push cx push ds push si push bp mov bp,sp mov dx,[bp+20];数据的高16位 mov ax,[bp+18];数据的低16位 mov ds,[bp+16];段地址 mov si,[bp+14];偏移地址 dtocs1: push dx push ax mov cx,10 push cx call divdw add cx,30H mov ds:[si],cl;把转换后的字符送到指定的数据区域 add si,1 mov cx,ax jcxz dtoctestagain;判断商的低16位是不是0 dtocs2: mov cx,10 jmp dtocs1 dtocwordsend: pop bp pop si pop ds pop cx pop bx pop ax ret 8 dtoctestagain: mov cx,dx;判断商的低16位后再判断商的高16位是不是0 jcxz dtocwordsend;如果都是0就跳到wordsend,准备跳除函数 jmp dtocs2;不是0回到前面继续执行 ;函数dtoc结束 wtoc: push ax push bx push cx push ds push si push bp mov bp,sp mov dx,0 ;数据的高16位 mov ax,[bp+18];数据的低16位 mov ds,[bp+16];段地址 mov si,[bp+14];偏移地址 wtocs1: push dx push ax mov cx,10 push cx call divdw add cx,30H mov ds:[si],cl;把转换后的字符送到指定的数据区域,转换后的字符只占据cl add si,1 mov cx,ax jcxz wtocwordsend mov cx,10 jmp wtocs1 wtocwordsend: pop bp pop si pop ds pop cx pop bx pop ax ret 6 ;wtoc函数结束 showstr: push ax push bx push cx push dx push ds push es push si push di push bp mov bp,sp mov dx,[bp+26];行号dh,列号dl mov bx,[bp+24];bl颜色值,bh个数 mov ds,[bp+22];段地址 mov si,[bp+20];偏移 mov di,0H;屏幕的偏移 ;接下来计算行号和列号带来的偏移di的初值 push bx;bx寄存器要用到 mov al,dh;开始计算行号带来的偏移 mov ah,0 mov bl,160 mul bl add di,ax;把计算行号带来的偏移值加到di上 mov al,dl;开始计算列号带来的偏移 mov ah,0 mov bl,2 mul bl add di,ax;把计算列号带来的偏移加到di上 pop bx;恢复bx的值 mov ax,0B800H;显示缓冲区的起始地址 mov es,ax mov ch,0 mov cl,bh ;把bh的值复制给cl用作循环次数 showstrloop: mov bh,ds:[si] ;这里bh为要显示的字符了 mov es:[di],bh mov es:[di+1],bl ;颜色值 inc si add di,2 loop showstrloop pop bp pop di pop si pop es pop ds pop dx pop cx pop bx pop ax ret 8 ;show_str ends ReverseStr: push ax push ds push si push cx push bp mov bp,sp mov ds,[bp+16];取得3个参数 mov si,[bp+14] mov cx,[bp+12] ReverseStrloop1:;把字符串取出来,存到栈中,再出栈实现顺序逆转 mov al,ds:[si] ;字符串中的字符是byte型。用word装住它再压栈 push ax inc si loop ReverseStrloop1 mov cx,[bp+12] ;由于cx和si的值在上面已经改变,现在须重新赋值 mov si,[bp+14] ReverseStrloop2: pop ax ;依次出栈,实现逆序 mov ds:[si],al inc si loop ReverseStrloop2 pop bp pop cx pop si pop ds pop ax ret 6 ;函数ReverseStr结束 clear: push ds push si push ax push cx mov ax,0B800H mov ds,ax mov si,0 mov cx,0FFFFH;25*80的缓冲区,2000个字符 clearloop: mov ax,0000011100100000b mov ds:[si],ax add si,2 loop clearloop pop cx pop ax pop si pop ds ret ;clear函数结束 code ends end start