assume cs:code, ds:data, ss:stack
data segment
        db '1975','1976','1977','1978','1979','1980','1981','1982','1983','1984','1985'
        db '1986','1987','1988','1989','1990','1991','1992','1993','1994','1995'
 
        dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980
        dd 590827,803530,1183000,1843000,2758000,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

number segment
        db 1024 dup(0)
number ends

stack segment stack                     ;!!!事实证明,后面这个stack加上可以自动赋值sp,不加默认sp从0开始
        db 1024 dup(0)
stack ends

code segment
        start:  

                mov ax, data
                mov ds, ax

                mov ax, stack
                mov ss, ax
                mov sp, 1024            ;养成习惯,数据段及时初始化

                call clear_screen
                call show_year
                call show_summ
                call show_ne
                call show_av
                
                mov ax, 4c00h
                int 21h


;=================Function=================
        ;==================================
        show_year:
                ;输入:年份数据段
                ;将内容输出到屏幕
                push ax
                push cx
                push dx
                push si
                push di

                mov si, 500             ;指定位置
                mov di, 0

                mov cx, 21
        total_year:
                mov ax, ds:[di]
                mov dx, ds:[di+2]
                call str_store
                call show_str
                add di, 4
                add si, 160
                loop total_year
                
                pop di
                pop si
                pop dx
                pop cx
                pop ax
                ret

        ;==================================
        show_summ:
                ;输入总收入字段
                ;输出数据到屏幕
                push ax
                push cx
                push si
                push di

                mov si, 530 
                mov di, 0
                mov cx, 21
        total_summ:
                
                mov ax, ds:[84+di]
                mov dx, ds:[84+di+2]
                call dtoc_pro
                call show_str

                add di, 4
                ;sub si, 0              ;这里不需要减去偏移量,因为都是从0开始
                add si, 160
                loop total_summ

                pop di
                pop si
                pop cx
                pop ax
                ret
        ;==================================
        show_ne:
                ;输入人数字段
                ;输出数据到屏幕
                push ax
                push cx
                push si
                push di

                mov si, 570 
                mov di, 0

                mov cx, 21
        total_ne:
                
                mov ax, ds:[168+di]
                call dtoc
                call show_str

                add di, 2
                ;sub si, 0      ;这里不需要减去偏移量,因为都是从0开始
                add si, 160
                loop total_ne

                pop di
                pop si
                pop cx
                pop ax
                ret
        ;==================================
        show_av:
                ;输入数据段:总收入和人数
                ;输出平均值(取整)
                push ax
                push bx
                push cx
                push dx
                push di
                push si

                mov si, 610
                mov bx, 0
                mov di, 0
                mov cx, 21
        total_av:
                push cx

                mov ax, ds:[84+bx]
                mov dx, ds:[84+bx+2]
                add bx, 4
                mov cx, ds:[168+di]
                add di, 2
                call div_dw
                
                call dtoc_pro
                call show_str
                add si, 160
                pop cx
                loop total_av

                pop si
                pop di
                pop dx
                pop cx
                pop bx
                pop ax

                ret

        ;==================================
        div_dw: 
                ;(输入):ax低16位,dx高16位,cx为16位除数
                ;(输出):dx结果高16位,ax结果低16位,cx为余数
                push bx

                mov bx, ax      ;暂存ax,低位
                mov ax, dx      ;设置被除数 
                mov dx, 0       ;高位置为0
                div cx          ;高16作除法,余数dx并到低16位,这里无需改动,dx也是除法的高位
                push ax         ;暂存高16位除法结果中的商
        
                mov ax, bx
                div cx          ;低16位除法,结果,ax为商,dx为余数

                mov cx, dx      
                pop dx          ;将暂存的高位ax,置于dx

                pop bx
                ret
                
        ;==================================
        dtoc_pro:
                ;输入ax低16,dx高16
                ;内容输出到number字段
                ;注意,检测商为0才跳出
                push bx
                push cx
                push si
                push ds

                mov si, 0               ;记录次数
                mov bx, number
                mov ds, bx              ;目标地址

        in_num_pro: 
                mov cx, 10              ;除数10
                call div_dw             ;返回余数cx
                
                push cx                 ;保存余数
                inc si
                
                push cx                              
                mov cx, ax              ;判断商为0
                or cx, 0
                or cx, dx 
                jcxz in_num_pro_exit    ;商为0,跳转,开始存入number字段
                pop cx
                
                jmp in_num_pro

        in_num_pro_exit:
                pop bx                  ;!!!!!!!!!!!注意多余的push要及时出栈,影响数据排布!!!!
                mov cx, si
                mov si, 0
                mov bx, 0
        set_num_pro:
                pop bx                  ;写入目标地址操作
                add bx, 30h
                mov ds:[si], bl
                inc si             
                loop set_num_pro

                mov byte ptr ds:[si], 0         ;末尾添0,表示字符串结束
                
                pop ds
                pop si
                pop cx
                pop bx
                ret

        ;==================================
        dtoc:
                ;X输入ax,(16位)
                ;结果保存在number字段
                ;注意,检测商为0才跳出!!
                push bx
                push cx
                push dx
                push ds
                push si

                mov bx, number          
                mov ds, bx              ;目标地址

                mov si, 0               ;偏移指针,个数
                mov bx, 10              ;除数
                mov dx, 0               ;32位除法,但这里只有ax参与,dx得置0
                
        in_num: 
                div bx
                push dx
                inc si
                mov cx, ax              ;这里没有loop循环,cx可放心使用
                jcxz in_num_exit
                mov dx, 0
                jmp in_num

        in_num_exit:
                mov cx, si
                mov si, 0
                mov bx, 0
        set_num:
                pop bx
                add bx, 30h
                mov ds:[si], bl
                inc si
                loop set_num
                mov byte ptr ds:[si], 0         ;末尾添0,表示字符串结束

                pop si
                pop ds
                pop dx
                pop cx
                pop bx
                ret 
        ;==================================
        str_store:
                ;输入;字码,ax低16,dx高16
                ;输出:number字段
                push ds

                mov bx, number
                mov ds, bx

                mov ds:[0], ax
                mov ds:[2], dx
                mov byte ptr ds:[4], 0          ;结束符号

                pop ds
                ret
        ;==================================
        show_str:
                ;X参数cx输入字节
                ;直接输出number字段中的数值
                push ax
                push bx                 ;这里有bl暂存颜色
                push cx                 ;cl暂存字符,这俩都不能删
                push es
                push ds
                push si
                push di

                mov ax, number
                mov ds, ax

                ;mov si, 1500            ;指定位置
                mov di, 0               ;字符串起始位置
                mov bl, 00000010B       ;指定颜色
                mov ax, 0b800h          
                mov es, ax              ;输出位置

                mov ch, 0
        forward:
                mov cl, ds:[di]
                jcxz exit
                mov es:[si], cl
                mov es:[si+1], bl
                add si, 2
                inc di
                jmp forward

        exit:   
                pop di
                pop si
                pop ds
                pop es
                pop cx
                pop bx
                pop ax
                ret
        ;==================================
        clear_screen:
                ;无输入
                ;执行清屏操作
                push bx
                push cx
                push es
                push si

                mov bx, 0b800h
                mov es, bx
                mov cx, 4096
                mov si, 0
        swap:   mov byte ptr es:[si], 0
                inc si
                loop swap

                pop si
                pop es
                pop cx
                pop bx
                ret
        ;==================================
code ends
end start