匯編語言(王爽)實驗十 編寫子程序


標 題:  匯編實驗10—— 編寫子程序
作 者: XHS_12302
時 間: 2016_7_28 16:56



實驗10編寫子程序

  在這次實驗中,我們將要編寫3個子程序,通過它們來認識幾個常見的問題和掌握解決這些問題的方法。同前面的所有實驗一樣,這個實驗是必須要獨立完成的,在后面的課程中,將要用到這個實驗中編寫的3個子程序。
1.  顯示字符串
問題
顯示字符串是現實工作中經常要用到的功能,應該編寫一個通用的子程序來實現這個功能。我們應該提供靈活的調用接口,使調用者可以決定顯示的位置(行、列)、內容和顏色。

提示
(1)  子程序的入口參數是屏幕上的行號和列號,注意在子程序內部要將它們轉化為顯存中的地址,首先要分析一下屏幕上的行列位置和顯存地址的對應關系:
(2)  注意保存子程序中用到的相關寄存器:
(3)  這個子程序的內部處理和顯存的結構密切相關,但是向外提供了與顯存結構無關的接口。通過調用這個子程序,進行字符串的顯示時可以不必了解顯存的結構,為編程提供了方便。在實驗中,注意體會這種設計思想。

子程序描述
名稱:show_str
功能:在指定的位置,用指定的顏色,顯示一個用0結束的字符串。
參數:(dh)=行號(取值范圍0~24),(dl)=列號(取值范圍0~79),
    (cl)=顏色,ds:si指向字符串的首地址
返回:無
就用舉例:在屏幕的8行3列,用綠色顯示data段中的字符串。


代碼:

assume cs:code
data segment
db 'Welcome to masm!',0
data ends

code segment
start: mov dh,8
mov dl,3
mov cl,2
mov ax,data
mov ds,ax
mov si,0
call show_str
mov ax,4c00h
int 21h
show_str: push dx
push cx
push ds
push si

mov ax,0b800h
mov es,ax

mov al,160
mul dh
mov bx,ax
mov al,2
mul dl
add bx,ax
mov al,cl

s: mov cl,[si]
jcxz ok
mov dx,[si]
mov es:[bx],dx
mov es:[bx+1],al
inc si
add bx,2
loop s

ok:
pop si
pop ds
pop cx
pop dx
ret
code ends
end start 
 

實驗截圖





2.  解決除法溢出的問題
問題
前面講過,div指令可以做除法。當進行8位除法的時候,用al存儲結果的商,ah存儲結果的余數:進行16位除法的時候,用ax存儲結果的商,dx存儲結果的余數。可是,現在有一個問題,如果結果的商大於ah或ax所能存儲的最大值,那么將如何?
比如,下面的程序段:
 mov bh,1
 mov ax,1000
 div bh
進行的是8位除法,結果的商為1000,而1000在ah中放不下,
又比如,下面的程序段:
mov ax,1000h
mov dx,1
mov bx,1
div bx
進行的是16位除法,結果的商為11000H,而11000H在ax中存放不下。
我們在用div指令做除法的時候,很可能發生上面的情況:結果的商過大,超出了寄存器所能存儲的范圍。當CPU執行div等除法指令的時候。如果發生這樣的情況,將引發CPU的一個內部錯誤。這個錯誤被稱為:除法溢出。我們可以通過特殊的程序來處理這個錯誤, 這里我們不討論這個錯誤的處理,這是后面的課程中要涉及的內容。

好了,我們已經清楚了問題的所在:用div指令做除法的時候可能產生除法溢出。由於有這樣的問題,在進行除法運算的時候要注意除數和被除數的值,比如1000000/10就不能用div指令來計算。那么怎么辦呢?我們用下面的子程序divdw解決。


子程序描述
名稱:divdw
功能:進行不會產生溢出的除法運算,被除數為dword型,除數為word型,結果為dword型。
參數:(ax)=dword型數據的低16位
    (dx)=dword型數據的高16位
    (cx)=除數
返回:(dx)=結果的高16位,(ax)=結果的低16位
    (cx)=余數
應用舉例:計算1000000/10(F4240H/0AH)

  mov ax,4240h
  mov v dx,000fh
  mov cx,0ah
  call divdw


提示
給出一個公式:
X:被除數,范圍:[0,FFFF FFFF]
N:除數,范圍:[0,FFFF]
H:X高16位,范圍:[0,FFFF]
L:X低16位,范圍:[0,FFFF]
int():描述性運算符,取商,比如:rem(38/10)=8
rem():描述性運算符,取答數,比如:rem(38/10)=8
公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
這個公式將可能產生溢出的除法運算:X/N,轉變為多個不會產生溢出的除法運算。
公式中,等號右邊的所有除法運算都可以用div指令來做,肯定不會導致除法溢出。

代碼:

assume cs:code
code segment
start:mov ax,4240h
mov dx,000fh
mov cx,0Ah
call divdw
mov ax,4c00H
int 21h
divdw:
push ax
mov ax,dx
mov dx,0
div cx
mov bx,ax
pop ax
div cx
mov cx,dx
mov dx,bx
ret
code ends
end start

程序截圖:






3.數值顯示
問題
編程,將data段中的數據以十進制的形式顯示出來。
data segment
dw 123,12666,1,8,3,38
data ends
  這些數據在內存中都是二進制信息,標記了數值的大小。要把它們顯示到屏幕上,成為我們能夠讀懂的信息,需要進行信息的轉化。比如,數值12666,在機器中存儲為二進制信息:0011000101111010B(317AH),計算機可以理解它。而我們要在顯示器上讀到可以理解的數值12666,我們看到的應該是一串字符:“12666”。由於 顯卡遵循的是ASCII編碼,為了讓我們能在顯示器上看到這串字符,它在機器中應以ASCII碼的形式存儲為:31H、32H、36H、36H、36H(字符“0”~“9”對應的ASCII碼為30H~39H)。
  通過上面的分析可以看到,在概念世界中,有一個抽象的數據12666,它表示了一個數值的大小。在現實世界中它可以有多種表示形式,可以在電子機器中以高低電平(二進制)的形式存儲,也可以在紙上、黑板上、屏幕上以人類的語言“12666”來書寫。現在,我們面臨的問題就是,要將同一抽象的數據,從一種表示形式轉化為另一種表示形式。
  可見,要將數據用十進制形式顯示到屏幕上,要進行兩步工作:
(1)  將用二進制信息存儲的數據轉變為十進制形式的字符串:
(2)  顯示十進制形式的字符串。
第二步我們在本次實驗的第一個子程序中已經實現,在這里只要調用一下show_str即可。我們來討論第一步,因為將二進制信息轉變為十進制形式的字符串也是經常要用到的功能,我們應該為它編寫一個通用的子程序。


子程序描述
名稱:dtoc
功能:將word型數據轉變為表示十進制數的字符串,字符串以0為結尾符。
參數:(ax)=word型數據
    ds:si指向字符串的首地址
返回:無
應用舉例:編程,將數據12666以十進制的形式在屏幕的8行3列,用綠色顯示出來。
在顯示時我們調用本次實驗中的第一個子程序show-str。


提示
  下面我們對這個問題進行一下簡單地分析。
(1)  要得到字符串“12666”,就是要得到一列表示該字符的ASCII碼:31H、32H、36H、36H、36H。
十進制數碼字符對應的ASCII碼=十進制數碼值+30H
要得到表示十進制數的字符串,先求十進制數每位的值。
例:對於12666,先求得每位的值:1、2、6、6、6。再將這些數分別加上30H,便得到了表示12666的ASCII碼串:31H、32H、36H、36H、36H。
(2)  那么,怎樣得到每位的值呢?采用如圖10.2所示的方法。

名稱:  10.2.jpg查看次數: 685文件大小:  7.3 KB

圖10.2除10取余法示意

  可見,用10除12666,共除5次,記下每次的余數,就得到了每位的值。
(3)  綜合以上分析,可得出處理過程如下:
用12666除以10,循環5次,記下每次的余數;將每次的余數分別加30H,便得到了表示十進制數的ASCII碼串,如圖10.3所示。

  名稱:  10.3.jpg查看次數: 684文件大小:  9.7 KB

圖10.3得到十進制每位數字字符的方法示意


(4)  對(3)的質疑:
在已知數據是12666的情況下,知道進行5次循環。可在實際問題中,數據的值是多少
程序員並不知道,也就是說,程序員不能事先確定循環次數。
  那么,如何確定數據各位的值已經全部求出了呢?我們可以看出,只要是除到商為0,各位的值就已經全部求出。可以使用jcxz指令來實現相關的功能。

代碼:

assume cs:code
data segment
db 16 dup(0)
data ends


code segment
start:mov ax,12666
mov bx,data
mov ds,bx
mov si,0
call dtoc
mov dh,8
mov dl,3
mov cl,2
call show_str
mov ax,4c00h
int 21h
dtoc:
mov cx,ax ;17
jcxz bk
push ax
mov al,ah
mov ah,0
mov bl,10
div bl
mov cl,al
mov ch,ah
pop ax
mov ah,ch
div bl
mov dl,ah
mov dh,0
push dx
mov ah,cl
jmp short dtoc ;29
bk:pop ax
add ax,30h
mov [si],al

pop ax
add ax,30h
mov [si+1],al

pop ax
add ax,30h
mov [si+2],al

pop ax
add ax,30h
mov [si+3],al ;44

pop ax
add ax,30h
mov [si+4],al
mov byte ptr [si+5],0
ret


show_str:
mov si,0

mov ax,0b800h
mov es,ax

mov al,160
mul dh
mov bx,ax
mov al,2
mul dl
add bx,ax
mov al,cl

s: mov cl,[si]
jcxz ok
mov dx,[si]
mov es:[bx],dx
mov es:[bx+1],al
inc si
add bx,2
loop s

ok: ret
code ends
end start

程序運行截圖



至此    實驗完成    

                           題中有不足之處  希望不吝賜教

                                         文中有的 文字是借鑒別人的    除了代碼和截圖

                                             完成實驗參考過別的資料,在第二個實驗中受過小甲魚視頻(328/2)的啟發

                                                                                               視頻資料上雲盤找:鏈接: http://pan.baidu.com/s/1nvpQiLz 密碼: et5r

                                                                                                                                                                                                                                 日期:2016_7_28


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: