assume cs:code,ds:data
data segment
db '1975','1976','1977','1978','1979','1980','1981'
db '1982','1983','1984','1985','1986','1987','1988'
db '1989','1990','1991','1992','1993','1994','1995',0
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980
dd 590827,803530,1183000,1843000,2759000,3753000,4649000,5937000,0
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793
dw 4037,5635,8826,11542,14430,15257,17800,0
dw 5,3,42,104,85,210,123,111,105,125,140,136,153,211,199,209,224,239,260,304,333,0
data ends
code segment
start:
mov ax,data
mov ds,ax
mov ax,0b800h
mov es,ax
call show_year ;输出年份
call show_output;输出收入
call show_num ;输出雇员数
call show_input ;人均收入
mov ax,4c00h
int 21h
;1111111111111111111111---------------------------------------
show_year:push ax
push bx
push cx
push dx
push es
push si
push di
push bp
mov al,0a0h
mov bl,02h
mul bl
mov bx,ax ;bx存储行偏移量,年份处第3行
mov si,0 ;data段的内容从0开始取数据
show: mov ch,0
mov cl,[si] ;cx内为字符或为字符最后的0
inc si ;si代表data内的字符位置,在打印过程中不应当清零,每次增一字节,第一次存字符,第二次存属性
jcxz ok ;若cx不为0则顺序执行,为0则跳转到ok标记
;这里可以用个4次的循环,目前就算了
mov es:[bx],cl
mov byte ptr es:1[bx],02h ;第1个字
mov cl,[si]
inc si
mov es:2[bx],cl
mov byte ptr es:3[bx],02h ;第2个字
mov cl,[si]
inc si
mov es:4[bx],cl
mov byte ptr es:5[bx],02h ;第3个字
mov cl,[si]
inc si
mov es:6[bx],cl
mov byte ptr es:7[bx],02h ;第4个字
add bx,0a0h
jmp short show ;打下一个年份
ok: pop bp
pop di
pop si
pop es
pop dx
pop cx
pop bx
pop ax
ret ;当cl从[si]取得0时就代表字符串打完了
;1111111111111111111111111111111111111111111111111111111----------------------------------------------------------------------------------------------------------------
;2222222222222222222222222222222222222222222222222222222-----------------------------------------------------------------------------------------
show_output:push ax ;这个子程序只是调用,要保存子程序中用到的相关寄存器的值
push bx
push cx
push si
push bp
push dx
push di
mov ax,00a0h
mov bl,02h ;减一位预设行,用于下边循环递增
mul bl
mov bx,ax ;bx存储行偏移量,收入处第3行
mov bp,0 ;全局只清零一次
;这个si的定位必须的,有可能是上边哪里出问题了
mov si,55h
;此处的bx内容在整个计算/转换过程中都不能修改,否则显示不出来
fetch: mov ax,[si] ;上一个call已经把si指向收入的第一个数据了,但由于是dd型,于是低位在前并放入ax
add si,02h
mov dx,[si] ;高位在后并放入dx
add si,02h
mov cx,ax ;ax低位检测是否为0
jcxz cmbk ;取到数据段中的0即代表收入数据个数够了,跳出该子程序
;此时ax、bx、cx、dx、bp已经被初始化,下方修改cx故cx是什么无所谓,bp应当为0,dx和ax组成被除数,bx为行数
;以下为没取完数据的流程
trsfm: mov cx,10
call divdw
;此时dx内装余数,ax内装商,divdw函数中余数位于cx
add cx,30h
push cx ;余数加30h之后为相应余数的ascii码,入栈用于顺序输出
mov cx,ax
inc bp
jcxz prnt ;ax=cx=0则开始打印该十进制数(实际上是字符串)
;cx不为零即需要继续除10来取得余数,先假设ax内的商没有溢出
jmp short trsfm
prnt: mov cx,bp ;得到pop次数
mov bp,0
mov di,10 ;di存储列偏移量,收入处第6列,其中第五列放空先不管
print: pop ax
mov es:[bx+di],al
inc di
mov byte ptr es:[bx+di],02h
inc di
loop print
add bx,00a0h
jmp short fetch ;重新取数据
cmbk: pop di
pop dx
pop bp
pop si
pop cx
pop bx
pop ax
ret
;双字型数据的除法子函数(防溢出)---------------------------------------------------------------------------------------------
divdw:
;ax装低16位,dx装高16位,cx装除数,bx绝对不能动,结果dx返回高16位,ax返回低16位
;计算(dx)/(cx)
push bx
push ax
;先算高16位
mov ax,dx
mov dx,0
div cx ;(ax)即结果的高16位,余数(dx)就是下一回div时被除数的高16位
mov bx,ax ;bx内为本次除法结果的高16位
;下面计算原本的被除数的低16位
pop ax
div cx ;(ax)即结果的低16位本位,本次被除数的余数在dx中
mov cx,dx
mov dx,bx
;还原bx内容
pop bx
ret
;222222222222222222222222222222222222222222222------------------------------------------------------
;333333333333333333333333333333333333333333333------------------------------------------------------
show_num:push ax ;这个子程序只是调用,要保存子程序中用到的相关寄存器的值
push bx
push cx
push si
push bp
push dx
push di
mov ax,00a0h
mov bl,02h
mul bl
mov bx,ax ;bx存储行偏移量,从第三行开始
mov bp,0 ;全局只清零一次
;这个si的定位必须的,上边的si已经退出了,被pop处新的数了
mov si,0adh
;此处的bx内容在整个计算/转换过程中都不能修改,否则显示不出来
fetch1: mov ax,[si] ;数据取入ax内,此次dw数据大小不超过16位
add si,02h
mov dx,0 ;dx得清零
mov cx,ax ;ax位检测是否为0
jcxz change ;取到数据段中的0即代表收入数据个数够了,跳出该子程序
;此时ax、bx、cx、dx、bp已经被初始化,下方修改cx故cx是什么无所谓,bp应当为0,dx和ax组成被除数,bx为行数
;以下为没取完数据的流程
trsfm1: mov cx,10
div cx
;此时ah内装余数,al内装商
add dx,30h
push dx ;余数加30h之后为相应余数的ascii码,入栈用于顺序输出
;此处有个问题就是dx没有清零的话,就会出现dx为前一次除法的余数+30h,所以可能表现为除法溢出,使得下次div溢出然后add dx,30h变成???
mov dx,0
mov cl,al
inc bp
jcxz prnt1 ;al=cl=0则开始打印该十进制数(实际上是字符串)
jmp short trsfm1
prnt1: mov cx,bp ;得到pop次数
mov bp,0
mov di,1ah ;di存储列偏移量,雇员数处第14列,其中第13列放空先不管
print1: pop ax
mov es:[bx+di],al
inc di
mov byte ptr es:[bx+di],02h
inc di
loop print1
add bx,00a0h
jmp short fetch1 ;重新取数据
change: pop di
pop dx
pop bp
pop si
pop cx
pop bx
pop ax
ret
;33333333333333333333333333333333333333333-------------------------------------------
;44444444444444444444444444444444444444444-------------------------------------------
show_input:push ax ;这个子程序只是调用,要保存子程序中用到的相关寄存器的值
push bx
push cx
push si
push bp
push dx
push di
mov ax,00a0h
mov bl,02h
mul bl
mov bx,ax ;bx存储行偏移量,从第三行开始
mov bp,0 ;全局只清零一次
;这个si的定位必须的,上边的si已经退出了,被pop处新的数了
mov si,0d9h
;此处的bx内容在整个计算/转换过程中都不能修改,否则显示不出来
fetch2: mov ax,[si] ;数据取入ax内,此次dw数据大小不超过16位
add si,02h
mov dx,0 ;dx得清零
mov cx,ax ;ax位检测是否为0
jcxz change1 ;取到数据段中的0即代表收入数据个数够了,跳出该子程序
;此时ax、bx、cx、dx、bp已经被初始化,下方修改cx故cx是什么无所谓,bp应当为0,dx和ax组成被除数,bx为行数
;以下为没取完数据的流程
trsfm2: mov cx,10
div cx
;此时ah内装余数,al内装商
add dx,30h
push dx ;余数加30h之后为相应余数的ascii码,入栈用于顺序输出
;此处有个问题就是dx没有清零的话,就会出现dx为前一次除法的余数+30h,所以可能表现为除法溢出,使得下次div溢出然后add dx,30h变成???
mov dx,0
mov cl,al
inc bp
jcxz prnt2 ;al=cl=0则开始打印该十进制数(实际上是字符串)
jmp short trsfm2
prnt2: mov cx,bp ;得到pop次数
mov bp,0
mov di,26h ;di存储列偏移量,雇员数处第14列,其中第13列放空先不管
print2: pop ax
mov es:[bx+di],al
inc di
mov byte ptr es:[bx+di],02h
inc di
loop print2
add bx,00a0h
jmp short fetch2 ;重新取数据
change1: pop di
pop dx
pop bp
pop si
pop cx
pop bx
pop ax
ret
;------------------------------------------------------------------
code ends
end start
容我吐槽一句,我要设计哭了