實驗8匯編實驗_第1頁
實驗8匯編實驗_第2頁
實驗8匯編實驗_第3頁
實驗8匯編實驗_第4頁
實驗8匯編實驗_第5頁
已閱讀5頁,還剩4頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、實驗八 編寫子程序(4學時) 在本次實驗中,我們將編寫3個子程序,通過它們來認識幾個常見的問題和掌握解決這些問題的方法。同前面的所有實驗一樣,這個實驗室必須獨立完成的,在后面的課程中,將要用到這個實驗中編寫的3個子程序。1、 顯示字符串 顯示字符串是下現實工作中經常要用到的功能,應該編寫一個通用的字程序來實現這個功能。我們應該提供靈活的調用接口,使調用者可以決定顯示的位置(行、列)、內容和顏色。 該子程序描述如下:名稱:show_str功能:在指定位置用指定顏色顯示一個用0結束的字符串。參數:(dh)=行號(取值范圍024),(dl)=列號(取值范圍079),(cl)=顏色,ds:si指向字符

2、串的首地址。返回:無應用舉例:在屏幕的8行3列,用綠色顯示data段中的字符串。assume cs: codedata segment db Welcome to masm!, 0data endscode 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 21hshow_str: : : :code endsend start提示:(1) 子程序的入口參數是屏幕上的行號和列號,注意在子程序內部要將它們轉化為顯存中的地址,首

3、先要分析一下屏幕上的行列位置和顯存地址的對應關系;(2) 注意保存子程序中用到的相關寄存器;(3) 這個子程序的內部處理和顯存的結構密切相關,但是向外提供了與顯存結構無關的接口。通過調用這個子程序,進行字符串的顯示時可以不必了解顯存的結果,為編程提供了方便。在實驗中,注意體會這種設計思想。data segment db Welcome to masm!data endsstack segment db Welcome to masm!stack endscode segment start: mov dh, 8 mov dl, 3 mov cl, 2 mov ax, data mov ds,

4、ax mov si, 0 mov ax,0B800h mov es,ax mov ax, stack mov ss, ax mov sp,10h call show_str mov ax, 4c00h int 21hshow_str: push dx push cx mov al,160 dec dh mul dh mov bx,ax add dx,si add dl,dl add bl,dl mov cl,si mov ch,0 jcxz ok mov es:bx,cl pop cx mov es:bx+1,cl inc si pop dx jmp short show_strok: pop

5、 cx pop dx retcode endsend start2、 解決除法溢出的問題 前面講過,div指令可以做除法。當進行8位除法的時候,用al存儲商,ah存儲余數;進行16位除法時,用ax存儲商,dx存儲余數。可是,現在有一個問題,如果結果的商大于al或ax所能存儲的最大值,那么將如何?比如,下面的程序段:mov bh, 1mov ax, 1000div bh進行的是8位除法,商為1000,而1000在al中放不下。又比如,下面的程序段:mov ax, 1000Hmov dx, 1mov bx, 1div bx進行的是16位除法,商為11000H,而11000H在ax中放不下。我們在用

6、div指令做除法的時候,和可能發生上面的情況:結果的商過大,超出了寄存器所能存儲的范圍。當CPU執行div等除法指令時,如果發生這樣的情況,將引發CPU的一個內部錯誤,這個錯誤被稱為:除法溢出。我們可以通過特殊的程序來處理這個錯誤,但在這里我們不討論這個錯誤的處理,這是后面課程中要涉及的內容。下面我們僅僅來看一下除法發生時的一些現象,如同8.1所示。圖8.1 除法溢出時發生的現象 圖中展示了在Windows 2000中使用Debug執行相關程序段的結果,div指令引發了CPU的除法溢出,系統對其進行了相關的處理。至此,我們已經清楚了問題所在;用div指令做除法的時候可能產生除法溢出。由于有這樣

7、的問題,在進行除法運算時要注意除數和被除數的值,比如1000000/10就不能用div指令來計算。那么怎么辦呢?我們用下面的子程序divdw解決。該子程序的描述如下:名稱:divdw功能:進行不會產生溢出的除法運算,被除數為dword型,除數為word型,結果為dword型。參數: (ax)=dword型數據的低16位;(dx)=dword型數據的高16位;(cx)=除數返回:(ax)=商的低16位;(dx)=商的高16位;(cx)=余數應用舉例:計算1000000/10(F424H/0AH)mov ax, 4240Hmov dx, 000FHmov cx, 0AHcall divdw結果:(

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

9、推導,有興趣的同學可參見王爽所著匯編語言的附注5.代碼:assume cs: codedata segment db Welcome to masm!,0data endsstack segment db Welcome to masm!stack endscode segmentstart: mov ax, 4240Hmov dx, 000FHmov cx, 0AHcall divdwmov ax, 4c00hint 21hdivdw:push axmov ax,dxmov dx,0div cxmov bx,axpop axdiv cxmov cx,dxmov dx,bxretcode en

10、dsend start3、 數值顯示 編程實現將data段中的數據以十進制的形式顯示出來。data segment dw 123, 12666, 1, 8, 3, 38data ends“12666”。由于顯卡遵循的是ASCII編碼,為了讓我們能在顯示器上看到這串字符,它在機器中應以ASCII碼的形式存儲為:31H, 32H, 36H, 36H, 36H(字符“0”“9”對應的ASCII碼為30H39H).通過上面的分析可以看到,在概念世界中,有一個抽象的數據12666,它表示了一個數值的大小。在現實世界中它可以有多種表示形式,可以在電子機器中以高低電平(二進制)的形式存儲,也可以在紙上、黑板

11、上、屏幕上以人類的語言“12666”來書寫。現在,我們面臨的問題的就是,要將同一抽象的數據從一種表示形式轉化為另一種表示形式。可見,要將數據用十進制形式顯示到屏幕上,要進行兩步工作:(1) 將用二進制信息存儲的數據轉變為十進制形式的字符串;(2) 顯示十進制形式的字符串。第二步我們在本次實驗的第一個子程序中已經實現,在這里只要調用一下show_str即可。我們來討論第一步,因為將二進制信息轉變為十進制形式的字符串也是經常要用到的功能,我們應該為它編寫一個通用的子程序。該子程序的描述如下:名稱: dtoc功能: 將word型數據轉變為表示十進制數的字符串,字符串以0為結尾符。參數: (ax)=w

12、ord型數據,ds:si指向字符串的首地址。返回: 無應用舉例: 編程實現將數據12666以十進制形式在屏幕的8行3列用綠色顯示出來。在顯示時我們調用本次實驗中的第一個子程序show_str。assume cs: codedata segment db 10 dup (0)data endscode 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 : : :code endsend start提示: 下面我們對

13、這個問題進行一下簡單的分析。(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 | 1 2 6 6 6 6 10 | 1 2 6 6 6 10 | 1 2 6 6 10 | 1

14、2 2 10 | 1 1 0可見,用基數10除12666,共除5次,記下每次的余數,就得到了每位的值。(3) 綜合上面的分析,可得到處理過程如下: 用12666除以10,循環5次,記下每次的余數;將每次的余數分別加上30H,便得到了表示十進制數的ASCII碼串。如下: 余數 +30H ASCII碼串 字符串 10 | 1 2 6 6 6 6 36H 6 10 | 1 2 6 6 6 36H 6 10 | 1 2 6 6 36H 6 10 | 1 2 2 32H 2 10 | 1 1 31H 1 0(4) 對(3)的質疑。 在已知數據是12666的情況下,知道進行5次循環。可在實際問題中,數據的

15、值是多少程序員并不知道,也就是說,程序員不能事先確定循環次數。 那么,如何確定數據各位的值已經全部求出來了呢?我們可以看出,只要是除到商為0,各位的值就已經全部求出。可以使用jcxz指令來實現相關的功能。代碼:assume cs: codedata segment db 10 dup (0)data endscode segment start: mov ax, 12666 mov bx, data mov ds, bx mov bx,0B800h mov es,bx mov si, 0 call dtoc mov dh, 8 mov dl, 3 mov cl, 2 call show_str mov ax, 4c00h int 21hdtoc: mov bx,10 mov dx,0 div bx mov cx,ax mov si,dx add byte ptr si,30h inc si jcxz ok1 jmp s

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論