《汇编语言》课程设计1
任务
将实验7中的Power idea公司的数据按照图10.2所示的格式在屏幕上显示出来。
回答
assume cs:code,ds:data
data 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'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,25257,17800
data ends
data_str segment
db 16 dup (0)
data_str ends
code segment
start:
call clear_screen
start_i:
mov dh,0
mov cx,21
print_row_start:
call print_row
inc dh
loop print_row_start
loop start_i
mov ax,4c00h
int 21h
; 名称: print_row
; 功能: 打印一行记录
; 参数: (dh)=行号
print_row:
push es
push bx
push ds
push si
push dx
push cx
mov bx,data
mov es,bx
mov bx,data_str
mov ds,bx
print_row_year:
; 计算年份偏移地址
mov ax,4
mul dh
; ds:si 指向保存字符串的地址
mov si,0
; 把原数据复制到ds:si,一次操作2字
mov bx, ax
mov ax, es:[bx]
mov ds:[si],ax
mov ax, es:[bx][2]
mov ds:[si][2],ax
mov ds:[si][4],0
; 打印字符
mov dl,1
mov cl,31
call show_str
print_row_amount:
; 计算收入偏移地址
mov ax,4
mul dh
; ds:si 指向保存字符串的地址
mov si,0
push ax ; 收入地址入栈,用于后面计算人均收入
push dx
mov bx, ax
mov ax, es:84[bx]
mov dx, es:84[bx][2]
call dtoc
pop dx
; 打印字符
mov dl,11
mov cl,31
call show_str
print_row_count:
; 计算人员偏移地址
mov ax,2
mul dh
; ds:si 指向保存字符串的地址
mov si,0
push ax ; 人员地址入栈,用于后面计算人均收入
push dx
mov bx, ax
mov ax, es:168[bx]
mov dx, 0
call dtoc
pop dx
; 打印字符
mov dl,25
mov cl,31
call show_str
print_row_avg:
; 计算人均收入
pop bx
mov cx, es:168[bx] ; 人员数量
pop bx
push dx
mov ax, es:84[bx] ; 总收入
mov dx, es:84[bx][2]
call divdw
call dtoc
pop dx
; 打印字符
mov dl,35
mov cl,31
call show_str
pop cx
pop dx
pop si
pop ds
pop bx
pop es
ret
; 名称: dtoc
; 功能: 将dword型数转变为表示十进制数的字符串,字符串以0为结尾符
; 参数: (ax)=dword型数据的低16位
; (dx)=dword型数据的高16位
; ds:si指向字符串的首地址
; 返回: 无
dtoc:
push dx
push cx
push ax
push bx
mov bx,0
push bx ; push进栈一个0值,用于在pop的时候判断是否已经到字符串尾部
dtoc_div_start:
mov cx,10
call divdw
add cx,30H ; cx是余数,入栈
push cx
mov cx,dx ; 判断商的dx和ax是否都为0,如果是则结束
jcxz judge_ax
loop dtoc_div_start
judge_ax:
mov cx,ax ; 把ax放入cx,用于判断商为0时结束循环
inc cx
loop dtoc_div_start
dtoc_stack_to_data:
pop dx
mov byte ptr ds:[si][bx],dl
inc bx
mov cx,dx ; 把dx放入cx,用于判断dx为0时结束循环
inc cx
loop dtoc_stack_to_data
pop bx
pop ax
pop cx
pop dx
ret
; 名称:divdw
; 功能:进行不会溢出的除法运算,被除数为dword型,除数为word型,结果为dword型
; 参数:(ax)=dword型数据的低16位
; (dx)=dword型数据的高16位
; (cx)=除数
; 返回:(dx)=结果的高16位,(ax)=结果的低16位
; (cx)=余数
; 公式:X/N = int(H/N)*65536 + (rem(H/N)*65536+L)/N
divdw:
push bx
push ax ; 把ax中的被除数低位暂存 L
mov ax,dx ; 把dx放入低ax位计算 H/N
mov dx,0
div cx ; H/N 商在AX,余数在DX
mov bx,ax ; 暂存 H/N 商
; mov dx, dx ; 因为 rem(H/N)*65536 = rem(H/N)*10000H 即左移4位,所以上次余数在DX中不用动
pop ax ; 取出被除数低位 L
div cx ; 商在AX,余数在DX
; mov ax,ax ; 低位的商在ax中不变
mov cx,dx ; dx中的余数传送到cx中
mov dx,bx ; 高位计算的商传送到dx中
pop bx
ret
; divdw
; 名称:show_str
; 功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
; 参数:(dh)=行号(取值范围0~24), (dl)=列号(取值范围0~79),
; (cl)=颜色,ds:si 指向字符串的首地址
; 返回:无
show_str:
push ax
push dx
push cx
push bx
; 计算指定行号的偏移地址
mov al,160
mov ah,0
mul dh
mov bx,ax
; 计算列号偏移地址
mov al,2
mov ah,0
mul dl
; 把列号偏移地址加到行号偏移地址中,保存在bx
add bx,ax
; 打印字符串
push es
push di
push si
print_str:
; 把显存地址B800段地址放入ES段寄存器
mov ax,0B800H
mov es,ax
; di作为显存地址的字符列偏移地址,每个字符占2字节
mov di,0
; 先把cl中的颜色保存到al中,因为后面会用到cx做为跳转判断字符串是否结束
mov al,cl
print_str_put:
mov ch,[si] ; 把字符串放入ch,并把cl置为0
mov cl,0
jcxz ok ; 判断cx中的字符串是否为0,如果是说明字符串已结束,跳转到OK处
mov byte ptr es:[bx][di],ch
mov byte ptr es:[bx][di][1], al
add si,1 ; si作为字符串偏移地址
add di,2 ; di作为显存偏移地址
loop print_str_put
ok:
pop si
pop di
pop es
pop bx
pop cx
pop dx
pop ax
ret
; show_str
clear_screen:
push bx
push ds
mov ax,0b800h
mov ds,ax
mov bx,0h
mov cx,2000
clear_screen_bx:
mov word ptr ds:[bx][si],0h
add bx,2
loop clear_screen_bx
pop ds
pop bx
ret
; clear_screen
code ends
end start