汇编语言王爽第三版实验10.1解析 (汇编教程王爽)

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,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,45257,17800

data ends

agency segment

db 8 dup(0)

agency ends

stack segment

dw 32 dup(0)

stack ends

code segment

;————————————————————————————主程序开始———————————————————————————————

start:

call clr_scr ;清屏

mov ax,agency

mov ds,ax ;设置agency为数据段

mov ax,data

mov es,ax ;设置data为扩展段

mov si,0 ;用于数据段寻址

mov di,0 ;用于扩展段寻址

mov bx,0 ;雇员数每个数据占2个字节,与其他数据不同步,故单独用bx寻址

mov dh,4 ;记录行号,从显示屏的第4行开始显示

mov cx,21 ;显示的行数为21行

x1:

push cx

;--------------------------年份------------------------------

mov ax,es:[di]

mov ds:[si],ax

mov ax,es:[di+2]

mov ds:[si+2],ax ;将年份存入数据段

mov byte ptr ds:[si+4],0

mov dl,0

mov cl,2 ;设置显示参数

call show_str ;显示年份

;--------------------------收入------------------------------

mov ax,es:[84+di]

push dx ;由于dh存储行数,下面的dtoc函数又要使用dx,故先将dx入栈

mov dx,es:[84+di+2]

call dtoc_dword ;将dx和ax联合存储的dword型数据转成以ds:si为首地址,以0结尾的字符串

pop dx

mov dl,20

mov cl,2 ;设置显示参数

call show_str ;显示收入

;-------------------------雇员数-----------------------------

mov ax,es:[84+84+bx]

call dtoc_word ;将ax存储的word型数据转成以ds:si为首地址,以0结尾的字符串

mov dl,40

mov cl,2 ;设置显示参数

call show_str;显示雇员数

;------------------------人均收入----------------------------

mov ax,es:[84+di]

push dx

mov dx,es:[84+di+2]

div word ptr es:[84+84+bx] ;人均收入=收入÷雇员数,结果存储在ax中

call dtoc_word ;将ax存储的word型数据转成以ds:si为首地址,以0结尾的字符串

pop dx

mov dl,60

mov cl,2 ;设置显示参数

call show_str;显示人均收入

add di,4

add bx,2

add dh,1 ;设置下次循环参数变化

pop cx

loop x1

mov ax,4c00h

int 21h

;————————————————————————————主程序结束———————————————————————————————

;++++++++++++++++++++++++++++子函数开始+++++++++++++++++++++++++++++++

show_str:

;—————————————————————以0结尾的字符串显示————————————————————————

;参数:| (dh)=行号 | (dl)=列号 | ds:si指向字符串的首地址 |

;——————————————————————————————————————————————————————————————

push ax

push cx

push dx

push es

push si

push di ;数据保存

mov ax,0b800h

mov es,ax ;设置es为显存段地址

mov al,160

mul dh ;每行占160字节,故用dh*160

add dl,dl ;每列占2个字节,故dl*2

mov dh,0

add ax,dx

mov di,ax ;设置di为显存偏移地址

mov ah,cl ;用ah存放颜色属性

show_str_x:

mov cl,ds:[si]

mov ch,0

jcxz show_str_f ;判断字符串是否结束(以0结尾)

mov al,cl ;用al存放要显示的字符

mov es:[di],ax ;向显存中写入内容

inc si ;si指示字符串,每次移动一个字符

add di,2 ;di指示显存位置,每次移动两个字符

jmp show_str_x

show_str_f:

pop di

pop si

pop es

pop dx

pop cx

pop ax

ret ;数据恢复,返回主程序

dtoc_word:

;———————————————word型数据转十进制字符串—————————————————

;参数:| (ax)=word型数据 | ds:si指向字符串的首地址 |

;——————————————————————————————————————————————————————

push ax

push bx

push cx

push dx

push si ;数据保存

mov bx,0 ;用bx来记录要生成的字符串长度

dtoc_word_x:

mov dx,0

mov cx,10

div cx ;对ax进行除10操作,得到其每一位数字的大小

mov cx,ax ;用cx记录每次除10得到的商

add dx,'0' ;将得到的每位数字转为其对应的ASCII码

push dx ;将得到的每个ASCII码依次入栈

inc bx ;每除一次,就有一个ASCII码对应的字符,故bx+1

jcxz dtoc_word_f ;通过判断商是否为零来确定ax是否还能被10除

jmp dtoc_word_x

dtoc_word_f:

mov cx,bx ;将字符串长度赋给cx确定循环次数

dtoc_word_x1:

pop ds:[si] ;入栈时低位先入栈,故出栈时高位先出栈,无需改变顺序

inc si

loop dtoc_word_x1

pop si

pop dx

pop cx

pop bx

pop ax

ret ;数据恢复,返回主程序

dtoc_dword:

;—————————————————————————dword型数据转十进制字符串——————————————————————————————————————

;参数:| (ax)=dword型数据低16位 | (dx)=dword型数据高16位 | ds:si指向字符串的首地址 |

;——————————————————————————————————————————————————————————————————————————————————————

push ax

push bx

push cx

push dx

push si ;数据保存

mov bx,0 ;用bx来记录字符串长度

dtoc_dword_x:

s:

mov cx,10

call divdw ;由于存在除法溢出,故调用子函数来进行除法操作

push cx

inc bx

mov cx,ax

jcxz ok

jmp short s

ok:

mov cx,bx

dtoc_dword_x1:

pop ds:[si]

add byte ptr ds:[si],'0'

inc si

loop dtoc_dword_x1 ;

pop si

pop dx

pop cx

pop bx

pop ax

ret ;数据恢复,返回主程序

divdw:

;—————————————————————————————解决除法溢出问题———————————————————————————————————————————

;参数:| (ax)=dword型数据低16位 | (dx)=dword型数据高16位 | ds:si指向字符串的首地址 |

;返回:| (ax)=结果的低16位 | (dx)=结果的高16位 | (cx)=余数 |

;———————————————————————————————————————————————————————————————————————————————————————

push bx ;数据保存

push ax ;ax入栈(先进行高16位除法)

mov ax,dx

mov dx,0

div cx ;高16位除法

mov bx,ax ;ax要出栈(进行低16位除法),故用bx来暂存ax现在的数据(结果的高16位)

pop ax

div cx ;低16位除法,此时ax存放的是结果的低16位

mov cx,dx ;此时cx存放的是余数

mov dx,bx ;此时dx存放的是结果的高16位

pop bx

ret ;数据恢复,返回主程序

clr_scr:

;————————清屏操作————————

; 无参数和返回值

;———————————————————————

push cx

push si

push ax

mov cx,4000

mov si,0

mov ax,0B800h

mov es,ax

s1:

mov es:[si],0

inc si

loop s1

pop ax

pop si

pop cx

ret

;++++++++++++++++++++++++++++子函数结束+++++++++++++++++++++++++++++++

code ends

end start