assume cs:code
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,97478,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1422,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends
buff_mem segment
db 1280 dup(0) ;48个字节储存一行数据,共使用1008个字节为了内存对齐申请1280字节内存空间
buff_mem ends
;es:[3f0] 21年循环变量 3f0h 3f0h
;es:[3202] 年数据最低位 3f2h 3f2h
;es:[3203] 年数据次低位 3f3h 3f3h
;es:[3204] 年数据次高位 3f4h 3f4h
;es:[3205] 年数据最高位 3f5h 3f5h
;es:[3206] 除数 3f6h 3f6h
;es:[3208] 四位十六进制数除法的低位商 3f8h 3f8h
;es:[3210] 四位十六进制除法的 余数 3fah 3fah
;es:[3212] ds:[bx]中bx的值 3fch 3fch
;es:[3214] 保存bp的值 3f8h 3feh
;es:[3216] 保存di的值 0400h
;ds:[0402] 保存字符处理循环中的临时cx变量
;ds:[0404] 保存显示函数中的di
code segment
start: call get_data
call process_data ;0014
call display_data
mov ax,4c00h
int 21h
get_data: mov ax,data
mov ds,ax
ret
process_data: ;ip=0014
;初始化
mov ax,buff_mem ;es指向buff_mem es=0b5e
mov es,ax
mov bx,0
mov si,84 ;数据偏移到收入地址
mov bp,0
mov di,48 ;行递增数据,初始化为距左边4字节
mov cx,21
_loop_21_: push cx ;保存21年的循环
mov es:[0400h],di ;保存21年循环中di的当前值
mov es:[3feh],bp
call covent_year ;年份 ip=0086
call covent_summ ;资产 ip=00a3
call covent_ne ;人数 ip=00e0
call covent_pcdi ;人均收入
pop cx
dec cx
jcxz _l_21_out
add bp,4
add di,2ch
add word ptr es:[3fch],4 ;bx镜像递增
mov bx,es:[3fch]
jmp _loop_21_
_l_21_out: ret
display_data:
mov ax,0b80ah
mov es,ax
mov ax,buff_mem
mov ds,ax
mov bx,0
mov si,0
mov bp,0
mov di,20h
mov cx,21
b:push cx
push di ;用来定位要显示字符的位置
push bx ;用来定位要载入字符的位置
mov ds:[404h],di ;定位年列的位置
mov cx,4
get_year: push cx ;年份字符串的循环处理
mov cx,ds:[bx] ;取得年份字符的
mov es:[di],cx
pop cx
add bx,2
add di,2
loop get_year
add di,16
mov cx,8
mov ax,0
add word ptr ds:[404h],16 ;定位资产列的位置
mov di,ds:[404h]
_get_summ: push cx ;资产字符串的循环处理
mov cx,ds:[bx]
jcxz _summ_eq0 ;判断字符是否为空,在48字节的段中去掉空格存入显存
mov es:[di],cx
add di,2
_summ_eq0: add ax,2
add bx,2
pop cx
loop _get_summ
add di,16
mov cx,8
sub di,ax
add di,16
add word ptr ds:[404h],20 ;定位人员列的位置
mov di,ds:[404h]
get_ne: push cx
mov cx,ds:[bx] ;取得人员的字符
jcxz _cx_ne_eq_0 ;判断字符是否为空,在48字节的段中去掉空格存入显存
mov es:[di],cx
add di,2
_cx_ne_eq_0: add ax,2
add bx,2
pop cx
loop get_ne
add di,16
mov cx,4
sub di,ax
add di,32
add word ptr ds:[404h],16 ;定位人均收入列的位置
mov di,ds:[404h]
get_sr: push cx
mov cx,ds:[bx] ;取得人均收入位置的字符
jcxz _cx_sr_eq_0 ;判断字符是否为空,在48字节的段中去掉空格存入显存
mov es:[di],cx
add di,2
_cx_sr_eq_0: add ax,2
add bx,2
pop cx
loop get_sr
add di,16
pop bx
pop di
add di,0a0h
add bx,48
pop cx
dec cx
jcxz dp_out
jmp b ;此处原本用loop循环,但循环溢出,只能使用jmp段内转移
dp_out: ret
covent_year: push bx ;ip=0086 年份字符串处理
push si
push bp
push di
mov cx,4
_loop_str: mov al,byte ptr ds:[bx];年的单位字节数据
mov byte ptr es:[bp+di-48],al
mov byte ptr es:[bp+di-47],07h
inc bx
add bp,2
loop _loop_str
pop di
pop bp
pop si
pop bx
ret
covent_summ: push bx ;ip=00a3 资产字符串处理
push si
push bp
push di
mov ax,word ptr ds:[bx+si]
mov dx,word ptr ds:[bx+si+2]
mov word ptr es:[3f6h],10
_div_loop: call divdw ;cx为余数,ax为商
mov word ptr es:[3fah],cx ;余数用来做显示位
add word ptr es:[3fah],30h ;转换成字符
mov ax,word ptr es:[3fah] ;字符放入ax
mov ah,07h ;把ah变成颜色位
mov word ptr es:[bp+di-26],ax ;保存入显示缓冲中
mov ax,word ptr es:[3f8h] ;低位商
mov cx,ax
jcxz _div_out ;只要低位商为零就跳出
sub bp,2 ;从后往前放资产值
jmp _div_loop
_div_out: pop di
pop bp
pop si
pop bx
ret
covent_ne: push bx ;ip=00e0 人员字符串处理
push si
push bp
push di
push word ptr es:[3fch]
mov cx,es:[3fch] ;被保存的bx的值??????
mov ax,cx
jcxz _init_data ;检测第一次循环bx是否为零,若为零则跳过-2步骤
mov dx,0
mov cx,2
div cx ;4/2,8/2,12/2,16/2....
mov bx,ax ;2,4,6,8....
_init_data: mov ax,ds:[bx+si+84] ;ax的值是ne部分
mov dx,0 ;因为都是求余数,并且人数不会超过32位
_divw_loop: call divdw
mov word ptr es:[3fah],cx ;余数用来做显示位
add word ptr es:[3fah],30h ;转换成字符
mov ax,word ptr es:[3fah] ;放入ax
mov ah,07h ;把ah变成颜色位
mov word ptr es:[bp+di-14],ax ;保存入显示缓冲中32-8-20
mov ax,word ptr es:[3f8h] ;低位商
mov dx,0
mov cx,ax
jcxz _divw_out ;只要低位商为零就跳出
sub bp,2 ;从右到左(从小到大)写数据
jmp _divw_loop
_divw_out: pop word ptr es:[3fch]
pop di
pop bp
pop si
pop bx
ret
covent_pcdi: ;ip=013b 人均收入字符串处理
push bx ;ip=00e0 人员字符串处理
push si
push bp
push di
push word ptr es:[3fch]
mov ax,word ptr ds:[bx+si] ;把资产低位当作被除数
mov dx,word ptr ds:[bx+si+2] ;把资产高位当作被除数
push ax ;此处注意保存ax和dx的值
push dx
mov cx,es:[3fch] ;被保存的bx的值??????
mov ax,cx
jcxz _init_ne_data ;检测第一次循环bx是否为零,若为零则跳过-2步骤
mov dx,0
mov cx,2
div cx ;4/2,8/2,12/2,16/2....
mov bx,ax ;2,4,6,8....
_init_ne_data: pop dx ;还原dx和ax的值
pop ax
mov cx,ds:[bx+si+84]
mov word ptr es:[3f6h],cx ;把人数当作除数
call divdw
mov word ptr es:[3fah],ax ;商用来做人均收入的被除数
mov word ptr es:[3f6h],10 ;循环中的除数,意思是缩小十倍
mov dx,0
pcdi_: call divdw
mov word ptr es:[3fah],cx ;余数用来做显示位
add word ptr es:[3fah],30h ;转换成字符
mov ax,word ptr es:[3fah] ;字符放入ax
mov ah,07h ;把ah变成颜色位
mov word ptr es:[bp+di-2],ax ;保存入显示缓冲中
mov ax,word ptr es:[3f8h] ;低位商
mov cx,ax
jcxz pcdi_out ;只要低位商为零就跳出
sub bp,2 ;从后往前放资产值
jmp pcdi_
pcdi_out: pop word ptr es:[3fch]
pop di
pop bp
pop si
pop bx
ret
divdw:
push ax ip= 0175h
mov ax,dx
mov dx,0
div word ptr es:[3f6h] ;ax=ax/【x】 高位商 dx=ax/cx高位余 如果高位为零,则全为零
mov bx,ax ;bx=ax 如果高位被除为零则取ES:[510]的值为商
pop ax ;ax=低位被除数 dx=在进行高位除法时作为高位被除数,低位时为余数(隐含高位被除数)
div word ptr es:[3f6h] ;dx:ax= 14240 / cx= 0f
mov es:[3f8h],ax ;保存低位除法的商
mov cx,dx ;将余数保存在cx
mov dx,bx ;将商保存在dx(高位商)
ret
code ends
end start