汇编语言:课程设计1
本文内容来源于王爽《汇编语言(第3版)》
任务
将实验7(见原书)中Power idea 公司的数据按照如下格式在屏幕上显示出来。
提示
注意:有些数据已经超过16位了,因此要写一个新的子程序dtoc(见我的上一篇博文,或者见原书),我把它命名为ddtoc(详细信息见源代码,如果你看得懂我的中式英语的话)。在实现的过程中,要注意除法溢出的问题,因此还要调用自己之前实现的divdw子程序(见我的上一篇博文,或者见原书)
实现代码如下:
;---------------------------------------------------------------------
;proc_name: ddtoc
;function: translate dword type data into a decimal string which
; ends with 0
;interface: (ax) = the low 16 bit of the dword type data
; (dx) = the high 16 bit of the dword type data
; ds:si points to the first address of the string
;return: void
ddtoc: push ax
push cx
push dx
push si
push bp
mov bp,sp
ddtoc_s: mov cx,10
call divdw
add cx,'0'
push cx
mov cx,dx
add cx,ax
jcxz ddtoc_next
jmp short ddtoc_s
ddtoc_next: pop ax
mov [si],al
mov cx,sp
sub cx,bp
jcxz ddtoc_ok
inc si
jmp short ddtoc_next
ddtoc_ok: mov al,0
mov [si+1],al
pop bp
pop si
pop dx
pop cx
pop ax
ret
;--------------------------------------------------------------------------
;proc_name: divdw
;function: Division operation(avoid overflow)
; the dividend is dword type and the divisor is word type
; the result is dword type, the remainder is word type.
;interface: (ax) = the low 16 bit of the dividend
; (dx) = the high 16 bit of the dividend
; (cx) = divisor(word type)
;return: (dx) = the high 16 bit of the result
; (ax) = the low 16 bit of the result
; (cx) = the remainder
divdw: push dx
push ax
push bp
mov bp,sp
mov dx,0
mov ax,[bp+4]
div cx
push ax
mov ax,[bp+2]
div cx
mov cx,dx
pop dx
pop bp
add sp,4
ret
;-----------------------------------------------------------------------------
代码实现
下面给出这个程序的完整代码:
附:由于汇编程序太过琐碎,就不给详细注释了,因为这段代码本身就是垃圾,各位看官扫一眼就可以,最后的效果之后给出(绝对辣眼睛!!!)
就算是给子程序传递参数,我也遇到了寄存器冲突问题,没办法,只能用堆栈保护。子程序show_str,dtoc都要有一段内存空间存放数据,因此我在table段后面放了20个字节的空间。
总而言之,代码乱的很,根本没法看,调试也极其困难,好歹运气好,满足了课程要求(吗?)
assume cs:code,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'
;offset address range:0-53h. informations of the years
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;offset address range:54h-0a7h. information of the gross income each year
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;offset address range:0a8h-0d1h.information of the number of the emploees each year
data ends
stack segment
db 256 dup(0)
stack ends
table segment
db 21 dup('year',0,'summ',0,'ne',0,'??',0)
;offset address range:0~14fh
db 20 dup(?)
;each line has 16byte space
table ends
code segment
main: mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,256
call load_info
mov ax,table
mov ds,ax
mov dh,0
mov bx,0
mov cx,21
s0: push cx
;print the year
mov si,bx
mov dl,12
mov cl,00000111b
call show_str
mov si,150h
;print the gross income
add dl,12
push dx
add bx,5
mov ax,[bx]
mov dx,[bx+2]
call ddtoc
pop dx
call show_str
;print the number of the emploees each year
add dl,12
push dx
add bx,5
mov dx,0
mov ax,[bx]
call ddtoc
pop dx
call show_str
;print the average income
add dl,12
push dx
add bx,3
mov dx,0
mov ax,[bx]
call ddtoc
pop dx
call show_str
inc dh
add bx,3
pop cx
loop s0
mov ax,4c00h
int 21h
;---------------------------------------------------------------
load_info:
push ax
push bx
push cx
push dx
push si
push ds
push es
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
;load the years
mov si,0
mov bx,0
mov cx,21
load_info_s0:
mov ax,[si] ;load the former 2 bytes
mov es:[bx],ax
mov ax,[si+2]
mov es:[bx+2],ax ;load the latter 2 bytes
add si,4
add bx,10h
loop load_info_s0
;load the gross income
mov si,54h
mov bx,0
mov cx,21
load_infor_s1:
mov ax,[si] ;load the former 2 bytes
mov es:[bx+5],ax
mov ax,[si+2] ;load the latter 2 bytes
mov es:[bx+5+2],ax
add si,4
add bx,10h
loop load_infor_s1
;load the number of the emploees
mov si,0a8h
mov bx,0
mov cx,21
load_infor_s2:
mov ax,[si]
mov es:[bx+0ah],ax
add si,2
add bx,10h
loop load_infor_s2
;calculate and load the average income
mov bx,0
mov cx,21
s3: mov ax,es:[bx+5]
mov dx,es:[bx+5+2]
div word ptr es:[bx+0ah]
mov es:[bx+0dh],ax
add bx,10h
loop s3
pop es
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
ret
;---------------------------------------------------------------------
;proc_name: ddtoc
;function: translate dword type data into a decimal string which
; ends with 0
;interface: (ax) = the low 16 bit of the dword type data
; (dx) = the high 16 bit of the dword type data
; ds:si points to the first address of the string
;return: void
ddtoc: push ax
push cx
push dx
push si
push bp
mov bp,sp
ddtoc_s: mov cx,10
call divdw
add cx,'0'
push cx
mov cx,dx
add cx,ax
jcxz ddtoc_next
jmp short ddtoc_s
ddtoc_next: pop ax
mov [si],al
mov cx,sp
sub cx,bp
jcxz ddtoc_ok
inc si
jmp short ddtoc_next
ddtoc_ok: mov al,0
mov [si+1],al
pop bp
pop si
pop dx
pop cx
pop ax
ret
;--------------------------------------------------------------------------
;proc_name: divdw
;function: Division operation(avoid overflow)
; the dividend is dword type and the divisor is word type
; the result is dword type, the remainder is word type.
;interface: (ax) = the low 16 bit of the dividend
; (dx) = the high 16 bit of the dividend
; (cx) = divisor(word type)
;return: (dx) = the high 16 bit of the result
; (ax) = the low 16 bit of the result
; (cx) = the remainder
divdw: push dx
push ax
push bp
mov bp,sp
mov dx,0
mov ax,[bp+4]
div cx
push ax
mov ax,[bp+2]
div cx
mov cx,dx
pop dx
pop bp
add sp,4
ret
;-----------------------------------------------------------------------------
;proc_name: show_str
;function: output a string with one color in a certain postion
;interface: (dh) = row(0~24),(dl) = column(0~79)
; (cl) = color, ds:si points to the first address of the string
;return: void
show_str: push ax
push bx
push cx
push dx
push es
push si
mov ax,0b800h
mov es,ax
;set row
mov al,160
mul dh
mov bx,ax
;set column
mov dh,0
add dx,dx
mov di,dx
;output the string
mov ah,cl
show_str_s: mov al,[si]
mov ch,0
mov cl,al
jcxz show_str_ok
mov es:[bx+di],ax
inc si
add di,2
jmp short show_str_s
show_str_ok: pop si
pop es
pop dx
pop cx
pop bx
pop ax
ret
;------------------------------------------------------------------------
code ends
end main
输出的结果是这样的
这是什么鬼!怎么还有数据被”press any key to continue”覆盖掉了!
这是目前阶段没有办法避免的(按部就班地按照课本内容学习的话)。子程序show_str的原理就是向显存中直接写数据,如果之后数据被新内容覆盖掉,哥就无能为力了。
总结:
之前没觉得汇编有多麻烦,甚至还天真地认为只要把高级语言简单翻译一下,汇编程序就手到擒来了。我还是太天真了,汇编要注意的细枝末节太多,太琐碎了,我写出的程序也和垃圾没什么区别,反正每人认真看,我也只要能让代码运行就行了(这种思想很危险啊!!!)
其实在编程之前,我脑子中有个大概的框架和思路,用循环结构,每次输出一行的内容,在一行中依次输出需要得信息。但是一落实到代码实现,又不得不考虑底层的机器,各种保护寄存器,各种寻址方式,各种方式传参。最后形成的代码就是一个个零散的“部件”,完全看不出我脑海中原本朴素而简单的思想。总之,这次的程序设计,思路很简单,但是实现起来较为繁琐,这么简单的程序居然写了这么长。我写汇编的能力有了长足的进步(高兴)。
最后,我需要写两天高级语言冷静一下(笑)。