assume cs:code,ds:data
; 字符串临时区
string segment
db 16 dup(0)
string ends
; 源数据
data segment
db '1975',0,'1976',0,'1977',0,'1978',0,'1979',0,'1980',0,'1981',0,'1982',0,'1983',0
db '1984',0,'1985',0,'1986',0,'1987',0,'1988',0,'1989',0,'1990',0,'1991',0,'1992',0
db '1993',0,'1994',0,'1995',0
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,15257,17800
data ends
; 栈
stack segment stack
dw 32 dup(0)
stack ends
code segment
start: mov bp, sp
sub sp, 16 ; 划分出16字节的变量区
mov word ptr ss:[bp - 2], 0 ; 年份的指针
mov word ptr ss:[bp - 4], 0 ; 总收入的指针
mov word ptr ss:[bp - 6], 0 ; 雇员数的指针
mov word ptr ss:[bp - 8], 100h ; 记录行和列
mov cx, 21
mainloop:
call draw
loop mainloop
mov ax, 4c00h
int 21h
draw: ; 绘制子函数
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
; ---------------------------
; 输出3个字符的空格
mov ax, string
mov ds, ax
mov si, 15
mov cx, 317h ; 设定颜色与宽度
mov dx, ss:[bp - 8]
call show_str
; ---------------------------
; 输出年份
mov ax, data
mov ds, ax
mov es, ax
mov si, ss:[bp - 2]
mov cx, 0a17h ; 设定颜色与宽度
add byte ptr ss:[bp - 8], 3
mov dx, ss:[bp - 8]
call show_str
; 指向下一个年份
add word ptr ss:[bp - 2], 5
; ---------------------------
; 输出总收入
mov ax, string
mov ds, ax
mov bx, ss:[bp - 4]
mov ax, es:[bx + 21 * 5]
mov dx, es:[bx + 21 * 5 + 2]
xor di, di
call dwtoc
push dx; 保存总收入高16位
mov si, di
mov cx, 0a20h
add byte ptr ss:[bp - 8], 10
mov dx, ss:[bp - 8]
call show_str
; 指向下一个总收入
add word ptr ss:[bp - 4], 4
; ---------------------------
; 输出雇员数
push ax ; 保存总收入低16位
mov bx, ss:[bp - 6]
mov ax, es:[bx + 21 * (4 + 5)]
xor dx, dx
xor di, di
call dwtoc
mov si, di
mov cx, 0a30h
add byte ptr ss:[bp - 8], 10
mov dx, ss:[bp - 8]
call show_str
mov cx, ax
pop ax
pop dx
; 指向下一个雇员数
add word ptr ss:[bp - 6], 2
; ---------------------------
; 计算并输出人均收入
call divdw
xor di, di
call dwtoc
mov si, di
mov cx, 0a47h ; 设定颜色与宽度
add byte ptr ss:[bp - 8], 10
mov dx, ss:[bp - 8]
call show_str
; ---------------------------
; 清除后面的字符
mov si, 15
mov cx, 2507h ; 设定颜色与宽度
add byte ptr ss:[bp - 8], 10
mov dx, ss:[bp - 8]
call show_str
; ---------------------------
; 转入下一行
add byte ptr ss:[bp - 7], 1
mov byte ptr ss:[bp - 8], 0
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
; ==============================
; 整型(32位)转为字符型
; 结果:di
; 源数据低16位:ax
; 源数据高16位:dx
; ==============================
dwtoc: push dx
push cx
push bx
push ax
add di, 14
nextnum:
mov cx, 10
call divdw
add cx, 30h
mov [di], cl
; 判断是否已经除尽
or ax, dx
mov cx, ax
jcxz end_dtoc
; 在尚未统计完所有数码时,才前移指针
dec di
jmp short nextnum
end_dtoc:
pop ax
pop bx
pop cx
pop dx
ret
; ==============================
; 在指定位置显示字符串(去掉指定宽度的字符)
; 源字串:si
; 行数:dh(0~24)
; 列数:dl(0~79)
; 颜色:cl
; 每个数据的宽度:ch
; ==============================
show_str:
push bp
mov bp, sp
push cx
push bx
push ax
push dx
push si
push di
push es
mov ax, 0b800h
mov es, ax ; 定位段地址
mov ax, 160
mul dh ; 定位行数
mov di, ax
xor dh, dh
add dx, dx
add di, dx
; 开始复制了
xor ch, ch
; 计算字符串的长度
xor bx, bx
copy_oneword:
mov cl, [si]
jcxz return
mov es:[di], cl
inc di
mov al, [bp - 2]
mov es:[di], al
inc di
inc si
inc bx
jmp short copy_oneword
return: ; 在返回前,判断是否超出了规定的宽度
; 如果超出了,直接返回
; 如果没有超出,那么还得填充空格
mov cl, [bp - 1]
xor ch, ch
cmp cx, bx
jng popstack
sub cx, bx
clear_after:
mov byte ptr es:[di], 0
mov al, [bp - 2]
mov es:[di + 1], al
add di, 2
loop clear_after
popstack:
pop es
pop di
pop si
pop dx
pop ax
pop bx
pop cx
pop bp
ret
; ==============================
; 32位/16位不溢出除法
; ax:被除数低16位(商低16位)
; dx:被除数高16位(商高16位)
; cx:除数(余数)
; ==============================
divdw: push bx
mov bx, ax ; 被除数低16位
; int(H/N)
mov ax, dx
xor dx, dx
div cx ; 结果在ax中,余数在dx中
push ax ; 保存的是H/N的结果
; (rem(H/N) * 65536 + L) / N
mov ax, bx
div cx
mov cx, dx ; 余数得到了
; int(H/N) * 65536
pop dx ; 结果高16位
pop bx
ret
code ends
end start