荣誉值:1
信誉值:2
注册日期:2009-05-25 18:12 |
经过好几天的痛苦挣扎,总算把课程设计1给完成了,呵呵,自己觉得程序可能有点儿啰嗦,但是,思路还比较清晰,发出来大家看看吧,自己也留下个脚印……
下面啰嗦一下这几天的总结:
1.子程序使用寄存器前一定要保存,避免在主程序中被调用时由于数据覆盖造成错误,其错误发现比较困难;
2.写程序时要养成写注释的好习惯,避免在程序调用的时候方便,同时以后在读程序时,让人快速理解程序的思路和流程;
3.程序的模块儿化优势:各个子程序功能分解,易于优化和扩展,方便调用
4.还有就是debug,虽然麻烦,但是很有效
就这些吧,具体还有好多体会,表达能力欠佳,就说这些吧···
下面是我的源代码(已测试结果无误):
assume cs:code,ds:data,ss:stack
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'
;以上是表示21年的21个字符(共84个字节,0-53H)
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以上是表示21年公司总收入的21个dword型数据(共84个字节,54H-A7H)
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示21年公司雇员人数的21个word型数据(共42个字节,A8H-D1H)
data ends
stack segment
dw 80 dup (0) ;定义栈段来暂存数据
stack ends
table segment
db 672 dup (0) ;定义21X32个字节来存放整个数据段的所有数据
table ends
code segment
;-------------------------------------------------------------------------------------------
; 程序开始,初始化各段和寄存器
;-------------------------------------------------------------------------------------------
start: mov ax,stack
mov ss,ax
mov sp,0a0h
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
mov si,0
mov di,0
mov bx,0
;-------------------------------------------------------------------------------------------
; 将各项数据存入进table段中,以便稍后进行格式化
;-------------------------------------------------------------------------------------------
mov cx,21
loop1: mov ax,0[bx] ;将年份存入table段中,以0结束
mov dx,2[bx]
mov es:0[di],ax
mov es:2[di],dx
mov BYTE ptr es:4[di],0h
mov ax,54h[bx] ;将总收入存入table段中,以0结束
mov dx,56h[bx]
mov es:5[di],ax
mov es:7[di],dx
mov BYTE ptr es:15[di],0h
mov ax,0a8h[si] ;将雇员人数存入table段中,以0结束
mov es:16[di],ax
mov BYTE ptr es:21[di],0h
mov ax,54h[bx] ;计算出人均收入并存入table段中,以0结束
div word ptr ds:0a8h[si]
mov es:22[di],ax
mov BYTE ptr es:32[di],0h
add bx,4 ;定位到下一个data段中的数据项
add di,32 ;定位到下一个table段中的行
add si,2 ;定位到下一个table段中的列
loop loop1
;-------------------------------------------------------------------------------------------
; 格式化table段中的数据,将将之从第行第列开始显示到屏幕上
;-------------------------------------------------------------------------------------------
mov ax,table
mov ds,ax
mov si,0
mov cx,21 ;用循环将年份显示到第5行第1-11列
mov dh,5
mov dl,1
year: push cx
mov cl,2
call show_str
pop cx
inc dh
add si,20h
loop year
;----------------------------------------------------------------------------
;格式化总收入数据,并显示到第5行第12-22列
mov cx,21
mov bx,5
tot_inco_1: mov ax,ds:[bx]
mov dx,ds:2[bx]
call dtoc32
add bx,20h
loop tot_inco_1
mov cx,21
mov si,5
mov dh,5
mov dl,12
tot_inco_2: push cx
mov cl,2
call show_str
pop cx
inc dh
add si,20h
loop tot_inco_2
;----------------------------------------------------------------------------
;格式化雇员人数数据,并显示到第5行第23-33列
mov cx,21
mov bx,16
emp_1: mov ax,ds:[bx]
mov dx,0
call dtoc32
add bx,20h
loop emp_1
mov cx,21
mov si,16
mov dh,5
mov dl,23
emp_2: push cx
mov cl,2
call show_str
pop cx
inc dh
add si,20h
loop emp_2
;----------------------------------------------------------------------------
;格式化人均收入数据,并显示到第5行第34列
mov cx,21
mov bx,22
avg_inco_1: mov ax,ds:[bx]
mov dx,0
call dtoc32
add bx,20h
loop avg_inco_1
mov cx,21
mov si,22
mov dh,5
mov dl,34
avg_inco_2: push cx
mov cl,2
call show_str
pop cx
inc dh
add si,20h
loop avg_inco_2
mov ax,4c00h ;程序结束,返回
int 21h
;-----------------------------------------------------------------------------------
;说明:将dword型数据转变为表示十进制的字符串,字符串以0为结尾符
;参数:(ax)=dword型数据的低16位,(dx)=dword型数据的高16位,ds:si指向字符串的首地址
;返回:无
;-----------------------------------------------------------------------------------
dtoc32: push dx ;将子程序里可能用到的寄存器入栈保存
push ax
push cx
push bx
push si
push di
mov di,0 ;;初始化di做计数器
s1: mov cx,10
call divdw ;调用子程序divdw来做除法运算,求余
push cx ;将余数入栈保存
mov cx,dx
jcxz s2 ;判断商的高16位是不是0,如果高16位是0则跳转到s2处去判断低位,不是0则继续执行
pop cx ;将余数出栈,做修改
add cx,30h
push cx ;再次将余数入栈保存
inc di
jmp short s1 ;跳到s1断续做除法
s2: mov cx,ax ;判断商的低16位是不是0,如果低16位是0则跳转到s3处去,若不是0则继续执行
jcxz s3
pop cx
add cx,30h
push cx
inc di
jmp short s1
s3: pop cx ;由于结果的商即使是0,也要将当前的余数做修改保存的处理,则此处也要再一次做保存
add cx,30h
push cx
inc di
mov cx,di
mov si,0
s4: pop ax
mov ds:[si][bx],al
inc si
loop s4
mov BYTE ptr ds:[bx][si],0 ;在最后一位加入一个0来标识字符处理结束
jmp short ok
ok: pop di
pop si
pop bx
pop cx
pop ax
pop dx
ret
;-------------------------------------------------------------------------------------------
;说明:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
;参数:(ax)=dword型数据的低16位,(dx)=dword型数据的高16位,(cx)=除数
;返回:(dx)=结果的高16位,(ax)=结果的低16位,(cx)=余数
;-------------------------------------------------------------------------------------------
divdw: push bx ;将bx的值入栈保存
push ax ;先将低16位压栈保存
;先计算高位除法
mov ax,dx ;将高16位的数据放到ax中,做为被除数的低16位,来做16位除法运算
mov dx,0 ;将被除数的高16设0处理
div cx
mov bx,ax ;将商保存在bx寄存器中(此商稍后将会做为最后结果的高16位)
;再计算低位除法
pop ax ;将之前压入栈的原数低16位的数据出栈
div cx
mov cx,dx ;除法完成之后,将余数保存到cx中
mov dx,bx ;将之前高位除法算的商放到dx中,做为结果的高16位(默认低16位已存放到了ax当中)
pop bx ;将bx的值还原
ret
;----------------------------------------------------------------------------------------------------
;说明:在指定的位置,用指定的颜色,显示一个用0结束的字符串
;参数:(dh)=行号(0`24),(dl)=列号(0`79),(cl)=颜色,ds:si指向字符串的首地址
;结果:无返回值
;----------------------------------------------------------------------------------------------------
show_str: push ax
push bx
push cx
push dx
push bp
push si
push di
mov ax,0b800h
mov es,ax
mov di,0
;算出指定的位置的偏移地址
mov ax,0
mov al,160 ;每行有160个字节
dec dh ;用行数减1乘以160个字节,算出整行的字节数
mul dh
mov bx,ax ;将结果入栈保存起来
dec dl ;将列减1乘以2得出第几列所占的字节数(显示1个字符需要用2个字节)
mov al,2
mul dl
add bx,ax ;将两数的结果相加,得出所规定的行、列所的偏移地址
mov dl,cl ;因为S标号下将会用到CX值的判断,所以,在运行之前,将提供颜色值的寄存器CL保存下来
s0: mov cl,[si]
mov ch,0
jcxz return
mov al,[si] ;ax低8位用来保存字符的ascii码
mov ah,dl ;ax高8位用来保存字条的颜色信息
mov es:[bx][di],ax ;将保存了ascii码和颜色的字符信息写入显存区
inc si ;定位到下一个字符
add di,2 ;定位到下一个显存位
jmp s0
return: pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start | | |