彙編語言:課程設計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的原理就是向顯存中直接寫數據,如果之後數據被新內容覆蓋掉,哥就無能爲力了。
總結:
之前沒覺得彙編有多麻煩,甚至還天真地認爲只要把高級語言簡單翻譯一下,彙編程序就手到擒來了。我還是太天真了,彙編要注意的細枝末節太多,太瑣碎了,我寫出的程序也和垃圾沒什麼區別,反正每人認真看,我也只要能讓代碼運行就行了(這種思想很危險啊!!!)
其實在編程之前,我腦子中有個大概的框架和思路,用循環結構,每次輸出一行的內容,在一行中依次輸出需要得信息。但是一落實到代碼實現,又不得不考慮底層的機器,各種保護寄存器,各種尋址方式,各種方式傳參。最後形成的代碼就是一個個零散的“部件”,完全看不出我腦海中原本樸素而簡單的思想。總之,這次的程序設計,思路很簡單,但是實現起來較爲繁瑣,這麼簡單的程序居然寫了這麼長。我寫彙編的能力有了長足的進步(高興)。
最後,我需要寫兩天高級語言冷靜一下(笑)。