《汇编语言》_王爽 第10章 call和ret指令 实验10 编写子程序_课程设计1_作业

assume cs:code,ds:data,ss:stack
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982'
dd 16,22,382,1356,2390,8000,16000,5937000
dw 3,7,9,13,28,38,130,17800
dw 8 dup(0)
data ends

stack segment
db 32 dup(0)
stack ends

code segment
_start:
    mov ax, data
    mov ds, ax
    mov ax,stack
    mov ss,ax
    mov sp,32
    mov ax, 0b800h
    mov es, ax          ; ES指向显示缓冲区
    
    mov bx, 0           ; 数据索引(年份数组)
    mov bp, 0           ; 显示缓冲区位置(屏幕左上角)
    mov dx, 8           ; 循环计数:8个年份

;显示db数据(年份)

year_loop:
    mov cx, 4           ; 每个年份4个字符
    mov si, 0           ; 字符在年份内的偏移

char_loop:
    mov al, ds:[bx+si]          ; 读取年份字符
    mov es:[bp], al             ; 显示字符
    mov byte ptr es:[bp+1], 07H ; 属性:黑底白字
    add bp, 2                   ; 下一个显示位置
    inc si
    loop char_loop
    
    ; 显示8个空格分隔
    mov cx, 8
space_loop:
    mov byte ptr es:[bp], 20H   ; 空格字符
    mov byte ptr es:[bp+1], 07H ; 属性
    add bp, 2
    loop space_loop
    
    ; 准备下一次循环
    add bx, 4           ; 下一个年份(4字节)
    add bp, 136       ; 下一行,计算:160 – (4+8)*2=160-24=136

    dec dx
    jnz year_loop       ; 继续处理下一个年份

;显示dd数据(收入)
mov si,32        ;si指向第一个dd数值的位置
mov bp,24    ;显示位置,年份+空格(4+8)*2=24

dd1:
mov di,0        ;用于计算余数个数
mov ax, ds:[si]    ; 被除数低16位
    mov dx, ds:[si+2]     ; 被除数高16位  
    mov cx, 000ah    ; 除数
dd0:
 call show_numToStr
add bx,'0'        ;把数值转化为ASCII码值
push bx        ;把余数压入栈
inc di        ;统计压入栈的个数
add dx,ax
cmp dx,0
jnz dd0

mov cx,di
show_dd:
pop ax
mov es:[bp],al
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dd
mov cx,10
sub cx,di
show_dd_space:
mov byte ptr es:[bp],20H   ; 空格字符
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dd_space
add si,4        ;si指向下一个dd数值
add bp, 140      ; 下一行,计算:160 -10*2=140
cmp si,64
jnz dd1

;显示dw数据(雇员数)
mov si,64        ;si指向第一个dw数值的位置
mov bp,44    ;年份+空格(4+8)*2+10*2=44
dw1:
mov di,0        ;用于计算余数个数
mov ax, ds:[si]    ; 被除数低16位
    mov dx, ds:[si+2]     ; 被除数高16位  
    mov cx, 000ah    ; 除数
dw0:
 call show_numToStr
add bx,'0'        ;把余数的值转化为ASCII码值
push bx        ;把余数压入栈
inc di        ;统计压入栈的个数
add dx,ax
cmp dx,0
jnz dw0

mov cx,di
show_dw:
pop ax
mov es:[bp],al
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dw
mov cx,10
sub cx,di
show_dw_space:
mov byte ptr es:[bp],20H   ; 空格字符
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dw_space
add si,4        ;si指向下一个dw数值
add bp, 140      ; 下一行,计算:160 -10*2=140
cmp si,64
jnz dw1

;显示平均数
mov si,32        ;si指向第一个dd数值的位置
mov word ptr ds:[80],64    ;指向第一个dw数值的位置
mov bp,64    ;年份+空格(4+8)*2+10*2+10*2=64
avg1:
mov ax,ds:[80]
mov cx, ax        ; 除数
mov ax, ds:[si]    ; 被除数低16位
mov dx, ds:[si+2]     ; 被除数高16位  
call show_numToStr        ;此时dx:ax即为平均数

mov di,0        ;用于计算余数个数

avg0:
mov cx,0ah    ;把除数设为10
 call show_numToStr
add bx,'0'        ;把数值转化为ASCII码值
push bx        ;把余数压入栈
inc di        ;统计压入栈的个数
add dx,ax
cmp dx,0
jnz avg0

mov cx,di
show_avg:
pop ax
mov es:[bp],al
mov byte ptr es:[bp+1],07H
add bp,2
loop show_avg
mov cx,10
sub cx,di
show_avg_space:
mov byte ptr es:[bp],20H   ; 空格字符
mov byte ptr es:[bp+1],07H
add bp,2
loop show_avg_space
add si,4        ;si指向下一个dd数值
mov ax,ds:[80]
add ax,2
mov ds:[80],ax    ;ds:[80]的值+2
add bp, 140      ; 下一行,计算:160 -10*2=140
cmp si,64        ;si=64时,表示数据全部读完
jnz avg1

mov ax, 4c00h  
int 21h

;以下是防溢出的除法运算子程序
show_numToStr:
 push di
      push si
;公式:X/N = int(H/N) × 65536 + [rem(H/N) × 65536 + L] / N
;X = 被除数 (32位: DX:AX)
;N = 除数 (16位: CX),
;H = X的高16位 (DX),
;L = X的低16位 (AX)
;int():描述性运算符,取商,比如,int(38/10)=3
;rem():描述性运算符,取余数,比如,rem(38/10)=8

    ; 第一步:计算 int(H/N),注意不需要显式乘以65536
    mov si, ax       ; 保存低16位
    mov ax, dx       ; AX = H (高16位)
    mov dx, 0        ; DX = 0,形成32位被除数 0:H
    div cx           ; AX = 商,DX = 余数
    
    ; 第二步:保存 int(H/N) × 65536 的高16位
    mov di, ax       ; di = int(H/N),这已经是结果的高16位
    
    ; 第三步:计算 [rem(H/N) × 65536 + L] / N
    mov ax, si       ; 恢复低16位 L
    ; DX 已经是 rem(H/N),与AX形成新的32位被除数 DX:AX
    div cx           ; AX = 商的低16位,DX = 余数

    ; 第四步:组合最终结果
    ; DX = 商的高16位,AX = 商的低16位,bx = 余数
     mov bx,dx
    mov dx,di

    pop si
 pop di
     ret

code ends
end _start



assume cs:code,ds:data,ss:stack
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982'
dd 16,22,382,1356,2390,8000,16000,5937000
dw 3,7,9,13,28,38,130,17800
dw 8 dup(0)
data ends
 
stack segment
db 32 dup(0)
stack ends
 
code segment
_start:
    mov ax, data
    mov ds, ax
    mov ax,stack
    mov ss,ax
    mov sp,32
    mov ax, 0b800h
    mov es, ax          ; ES指向显示缓冲区
    
    mov bx, 0           ; 数据索引(年份数组)
    mov bp, 0           ; 显示缓冲区位置(屏幕左上角)
    mov dx, 8           ; 循环计数:8个年份
 
;显示db数据(年份)
 
year_loop:
    mov cx, 4           ; 每个年份4个字符
    mov si, 0           ; 字符在年份内的偏移
 
char_loop:
    mov al, ds:[bx+si]          ; 读取年份字符
    mov es:[bp], al             ; 显示字符
    mov byte ptr es:[bp+1], 07H ; 属性:黑底白字
    add bp, 2                   ; 下一个显示位置
    inc si
    loop char_loop
    
    ; 显示8个空格分隔
    mov cx, 8
space_loop:
    mov byte ptr es:[bp], 20H   ; 空格字符
    mov byte ptr es:[bp+1], 07H ; 属性
    add bp, 2
    loop space_loop
    
    ; 准备下一次循环
    add bx, 4           ; 下一个年份(4字节)
    add bp, 136       ; 下一行,计算:160 - (4+8)*2=160-24=136
 
    dec dx
    jnz year_loop       ; 继续处理下一个年份
 
;显示dd数据(收入)
mov si,32        ;si指向第一个dd数值的位置
mov bp,24    ;显示位置,年份+空格(4+8)*2=24
 
dd1:
mov di,0        ;用于计算余数个数
mov ax, ds:[si]    ; 被除数低16位
    mov dx, ds:[si+2]     ; 被除数高16位  
    mov cx, 000ah    ; 除数
dd0:
 call show_numToStr
add bx,'0'        ;把数值转化为ASCII码值
push bx        ;把余数压入栈
inc di        ;统计压入栈的个数
add dx,ax
cmp dx,0
jnz dd0
 
mov cx,di
show_dd:
pop ax
mov es:[bp],al
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dd
mov cx,10
sub cx,di
show_dd_space:
mov byte ptr es:[bp],20H   ; 空格字符
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dd_space
add si,4        ;si指向下一个dd数值
add bp, 140      ; 下一行,计算:160 -10*2=140
cmp si,64
jnz dd1
 
 
;显示dw数据(雇员数)
mov si,64        ;si指向第一个dw数值的位置
mov bp,44    ;年份+空格(4+8)*2+10*2=44
dw1:
mov di,0        ;用于计算余数个数
mov ax, ds:[si]    ; 被除数低16位
    mov dx, ds:[si+2]     ; 被除数高16位  
    mov cx, 000ah    ; 除数
dw0:
 call show_numToStr
add bx,'0'        ;把余数的值转化为ASCII码值
push bx        ;把余数压入栈
inc di        ;统计压入栈的个数
add dx,ax
cmp dx,0
jnz dw0
 
mov cx,di
show_dw:
pop ax
mov es:[bp],al
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dw
mov cx,10
sub cx,di
show_dw_space:
mov byte ptr es:[bp],20H   ; 空格字符
mov byte ptr es:[bp+1],07H
add bp,2
loop show_dw_space
add si,4        ;si指向下一个dw数值
add bp, 140      ; 下一行,计算:160 -10*2=140
cmp si,64
jnz dw1
 
 
;显示平均数
mov si,32        ;si指向第一个dd数值的位置
mov word ptr ds:[80],64    ;指向第一个dw数值的位置
mov bp,64    ;年份+空格(4+8)*2+10*2+10*2=64
avg1:
mov ax,ds:[80]
mov cx, ax        ; 除数
mov ax, ds:[si]    ; 被除数低16位
mov dx, ds:[si+2]     ; 被除数高16位  
call show_numToStr        ;此时dx:ax即为平均数
 
mov di,0        ;用于计算余数个数
 
avg0:
mov cx,0ah    ;把除数设为10
 call show_numToStr
add bx,'0'        ;把数值转化为ASCII码值
push bx        ;把余数压入栈
inc di        ;统计压入栈的个数
add dx,ax
cmp dx,0
jnz avg0
 
mov cx,di
show_avg:
pop ax
mov es:[bp],al
mov byte ptr es:[bp+1],07H
add bp,2
loop show_avg
mov cx,10
sub cx,di
show_avg_space:
mov byte ptr es:[bp],20H   ; 空格字符
mov byte ptr es:[bp+1],07H
add bp,2
loop show_avg_space
add si,4        ;si指向下一个dd数值
mov ax,ds:[80]
add ax,2
mov ds:[80],ax    ;ds:[80]的值+2
add bp, 140      ; 下一行,计算:160 -10*2=140
cmp si,64        ;si=64时,表示数据全部读完
jnz avg1
 
mov ax, 4c00h  
int 21h
 
;以下是防溢出的除法运算子程序
show_numToStr:
 push di
      push si
;公式:X/N = int(H/N) × 65536 + [rem(H/N) × 65536 + L] / N
;X = 被除数 (32位: DX:AX)
;N = 除数 (16位: CX),
;H = X的高16位 (DX),
;L = X的低16位 (AX)
;int():描述性运算符,取商,比如,int(38/10)=3
;rem():描述性运算符,取余数,比如,rem(38/10)=8
 
    ; 第一步:计算 int(H/N),注意不需要显式乘以65536
    mov si, ax       ; 保存低16位
    mov ax, dx       ; AX = H (高16位)
    mov dx, 0        ; DX = 0,形成32位被除数 0:H
    div cx           ; AX = 商,DX = 余数
    
    ; 第二步:保存 int(H/N) × 65536 的高16位
    mov di, ax       ; di = int(H/N),这已经是结果的高16位
    
    ; 第三步:计算 [rem(H/N) × 65536 + L] / N
    mov ax, si       ; 恢复低16位 L
    ; DX 已经是 rem(H/N),与AX形成新的32位被除数 DX:AX
    div cx           ; AX = 商的低16位,DX = 余数
 
    ; 第四步:组合最终结果
    ; DX = 商的高16位,AX = 商的低16位,bx = 余数
     mov bx,dx
    mov dx,di
 
    pop si
 pop di
     ret
 
code ends
end _start

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容