
程序代码:
;这是王爽《汇编语言》课程设计 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