课程设计1
任务:将实验7中的数据按照图示格式在屏幕上显示出来。
这个程序需要用到我们以前学到的所有知识,尤其是实验10中的3个实验。
上篇中的divdw子程序由于要被另一个子程序调用,我采用的用内存空间保存返回值的方法,用着不太方便啊,于是参考了一下别人的比较简洁的程序。
子程序描述:
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
所需参数:
(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:
(dx)=结果的高16位,(ax)=结果的低16位
(cx)=余数
以下,为代码:
"""子程序描述
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
所需参数:
(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:
(dx)=结果的高16位,(ax)=结果的低16位
(cx)=余数
"""
divdw:
push ax ;保存低16位(公式中的L)
mov ax,dx ;将H存入ax中
mov dx,0 ;将16位除法运算高位置0(以作(H/N))
div cx ;进行(H/N)除法运算
mov bx,ax ;将(H/N)的商作为结果的商的高16位,暂由bx保存
pop ax ;将之前保存的L弹出到ax作为下步除法运算的低16位
div cx ;dx中保存的是(H/N)的余数,作为此除法运算的高16位
mov cx,dx ;将此除法运算的余数作为结果的余数,由cx保存并返回
mov dx,bx ;将暂存的结果的商的高16位由dx保存返回
;ax中保存的是此除法运算的商,即结果的商的低16位
ret
"""
此程序精简干练,但是没有对相关寄存器的保护,调用时应特别注意bx的使用。))))
"""
经过运行,结果完全正确,此处不再展示结果。
还要重写实验10中的dtoc子程序,以让其完成dword型数据到字符串的转换
以下,为课程设计的代码。
assuem cs:code
#此段用来保存10进制数据的ascii字符串
data segment
db 100 dup (0)
data ends
code segment
start:
mov ax,data
mov ds,ax
mov si ;使ds:si指向10进制ascii字符串的入口
#用到的数据5937000d=5a9768h
#4649000d=46f028h
mov ax,9768h
mov dx,005ah ;设置dtoc所需参数(dword型数据)
call dtoc
mov dh,8
mov dl,3
mov cl,2 ;设置show_str所需参数(颜色,显示位置)
call show_str
mov ax,4c00h
int 21h
#子程序dtoc
"""
子程序描述:
名称:dtoc
功能:将dword型数据转变为表示10进制数的字符串,字符串以0为结尾符。
所需参数:
(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
ds:si指向字符串的首地址
返回:无
(注:需要调用divdw子程序)
"""
dtoc:
push ax
push bx
push cx
push dx
push si
push ds
push bp
mov bp,0 ;用bp来保存入栈次数
change:
mov cx,10 ;设置divdw所需参数(dword型数据的高16位,低16位,除数)
call divdw
add cx,30h ;divdw的返回值中,余数在cx中
push cx ;将表示10进制数据的ascii字符入栈保存
inc bp ;记录入栈次数
add ax,dx
mov cx,ax ;将divdw的返回值商的高,低位相加送进cx中,作为结束依据
jcxz rev
sub ax,dx ;未除尽时恢复ax中的值
jmp short change
rev:
mov cx,bp ;将入栈次数作为循环次数
save:
pop ax
mov ds:[si],al ;进行转存
inc si
loop save
inc si
mov byte ptr ds:[si],0 ;将表示10进制字符串的后边补0作为其结束符
pop bp
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
ret
"""子程序描述
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
所需参数:
(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:
(dx)=结果的高16位,(ax)=结果的低16位
(cx)=余数
"""
divdw:
push ax ;保存低16位(公式中的L)
mov ax,dx ;将H存入ax中
mov dx,0 ;将16位除法运算高位置0(以作(H/N))
div cx ;进行(H/N)除法运算
mov bx,ax ;将(H/N)的商作为结果的商的高16位,暂由bx保存
pop ax ;将之前保存的L弹出到ax作为下步除法运算的低16位
div cx ;dx中保存的是(H/N)的余数,作为此除法运算的高16位
mov cx,dx ;将此除法运算的余数作为结果的余数,由cx保存并返回
mov dx,bx ;将暂存的结果的商的高16位由dx保存返回
;ax中保存的是此除法运算的商,即结果的商的低16位
ret
"""
名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
所需参数:(dh )=行号(范围:0~24),(dl)=列号(范围:0-79),
(cl)=颜色,ds:si指向字符串的首地址;
返回:无
"""
show_str:
push ax
push bx
push cx
push dx
push si
push di
push ds
push es ;将子程序所有用到的寄存器入栈保存,方便调用。
#将参数转化为显存上的地址。其对应关系为:行起始=0a0h*行号;列起始=02h*列号;
mov al,0a0h
mul dh
mov bx,ax ;对应显存的行
mov al,2
mul dl
mov di,ax ;对应显存的列
mov ax,0b800h
mov es,ax ;用es:[bx].[di]来寻址显存
mov ah,cl ;先将颜色用ah保存,因为一开始就要用cx进行判断
#完成字符串到显存的传送
trans:
mov cx,ds:[si]
jcxz back ;判断要传送的字符是否为‘0’,为0则直接返回。
mov al,ds:[si]
mov es:[bx].[di],al
;传送字符到奇数列,对应显存上的ASCII码
mov es:[bx].1[di],ah
;传送颜色到偶数列,对应显存上的颜色
inc si
add di,2 ;控制字符串及显存地址指向下一个单元
jmp short trans
back:
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
以下为运行结果:
经过测试,子程序具有一般性。
接下来,
接下来,
接下来,
我们开始课程设计。
--------------------------
思路说明:借助实验10的第3题的框架;
1,把所有数据按dword型数据处理;
2,用es:[bx].idata[di]来对要处理的数据寻址;
3,用二重循环,并在内层循环内调用子程序来完成数据向字符串的转换和在显存上的显示;(每次内层循环完成一个数据的显存上的显示,每次外层循环完成一行数据在显存上的显示)
4,程序中,注意对相关寄存器的保护处理;特别是向show_str子程序传参时的dh,dl。
--------------------------
assume cs:code
data segment
"""
年份的21条数据
"""
dd 1975,1976,1977,1978,1979,1980,1981,1982,1983
dd 1984,1985,1986,1987,1988,1989,1990,1991,1992
dd 1993,1994,1995
"""
总收入的21条数据
"""
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
"""
总雇员数的21条数据
"""
dd 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dd 11542,14430,15257,17800
"""
人均的21条数据
"""
dw 5,3,42,104,85,210,123,111,105,125,140,136,153,211,199,209,224,239
dw 260,304,333
data ends
"""
此段用来作为10进制数据字符串表示保存区
"""
asc segment
db 1000 dup (0)
asc ends
code segment
start:
mov ax,data
mov es,ax
mov di,0 ;用es:di指向data段
mov ax,asc
mov ds,ax
mov si,0 ;用ds:si指向asc段
mov cx,21 ;控制外层循环次数
mov ah,3 ;将show_str的参数dh用ah保存(dh随行而改变,在外层)
co0:
push cx ;外层循环次数入栈保存
mov bx,0 ;data段中每种数据段的寻址用bx来控制
mov cx,4 ;内层循环次数
mov al,2 ;将show_str的参数dl用al保存(dl随列而改变,在内层)
co:
push cx
push ax ;将内层循环及dh,dl的保存寄存器入栈保存
mov ax,es:[bx].[di]
mov dx,es:[bx].2[di] ;使ax指向dword型数据低16位,dx指向dword型数据高16位;也即dtoc所需参数。
call dtoc
pop ax ;将保存的dh,dl值出栈,做传参准备
mov dh,ah
mov dl,al
mov cl,4 ;向show_str传参
call show_str
add al,20 ;控制列号,每列相距20
add bx,84 ;用bx寻址时,指向data段中的各个数据区
pop cx ;内层循环次数出栈做循环判断
loop co
inc ah ;控制行号,使行号递增
add di,4 ;用di寻址时,指向data段中的每个数据区的下一个数据
pop cx ;外层循环次数出栈做循环判断
loop co0
mov ax,4c00h
int 21h
#子程序dtoc
"""
子程序描述:
名称:dtoc
功能:将dword型数据转变为表示10进制数的字符串,字符串以0为结尾符。
所需参数:
(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
ds:si指向字符串的首地址
返回:无
(注:需要调用divdw子程序)
"""
dtoc:
push ax
push bx
push cx
push dx
push si
push ds
push bp
mov bp,0 ;用bp来保存入栈次数
change:
mov cx,10 ;设置divdw所需参数(dword型数据的高16位,低16位,除数)
call divdw
add cx,30h ;divdw的返回值中,余数在cx中
push cx ;将表示10进制数据的ascii字符入栈保存
inc bp ;记录入栈次数
add ax,dx
mov cx,ax ;将divdw的返回值商的高,低位相加送进cx中,作为结束依据
jcxz rev
sub ax,dx ;未除尽时恢复ax中的值
jmp short change
rev:
mov cx,bp ;将入栈次数作为循环次数
save:
pop ax
mov ds:[si],al ;进行转存
inc si
loop save
inc si
mov byte ptr ds:[si],0 ;将表示10进制字符串的后边补0作为其结束符
pop bp
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
ret
"""子程序描述
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
所需参数:
(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:
(dx)=结果的高16位,(ax)=结果的低16位
(cx)=余数
"""
divdw:
push ax ;保存低16位(公式中的L)
mov ax,dx ;将H存入ax中
mov dx,0 ;将16位除法运算高位置0(以作(H/N))
div cx ;进行(H/N)除法运算
mov bx,ax ;将(H/N)的商作为结果的商的高16位,暂由bx保存
pop ax ;将之前保存的L弹出到ax作为下步除法运算的低16位
div cx ;dx中保存的是(H/N)的余数,作为此除法运算的高16位
mov cx,dx ;将此除法运算的余数作为结果的余数,由cx保存并返回
mov dx,bx ;将暂存的结果的商的高16位由dx保存返回
;ax中保存的是此除法运算的商,即结果的商的低16位
ret
"""
名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
所需参数:(dh )=行号(范围:0~24),(dl)=列号(范围:0-79),
(cl)=颜色,ds:si指向字符串的首地址;
返回:无
"""
show_str:
push ax
push bx
push cx
push dx
#push si ;见下注
push di
push ds
push es ;将子程序所有用到的寄存器入栈保存,方便调用。
#将参数转化为显存上的地址。其对应关系为:行起始=0a0h*行号;列起始=02h*列号;
mov al,0a0h
mul dh
mov bx,ax ;对应显存的行
mov al,2
mul dl
mov di,ax ;对应显存的列
mov ax,0b800h
mov es,ax ;用es:[bx].[di]来寻址显存
mov ah,cl ;先将颜色用ah保存,因为一开始就要用cx进行判断
#完成字符串到显存的传送
trans:
mov cx,ds:[si]
jcxz back ;判断要传送的字符是否为‘0’,为0则直接返回。
mov al,ds:[si]
mov es:[bx].[di],al
;传送字符到奇数列,对应显存上的ASCII码
mov es:[bx].1[di],ah
;传送颜色到偶数列,对应显存上的颜色
inc si
add di,2 ;控制字符串及显存地址指向下一个单元
jmp short trans
back:
pop es
pop ds
pop di
#pop si ;此处的si没有让它受到保护,为的是需要调用此子程序时使字符串和显存地址指向下一个单元;
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
下面是运行结果:
可算是搞完了,开始搞js,。。??
今天是程序员日,我摸了摸我的头发,还好,还在?。?