實驗9
??????編程,在屏幕中間分別顯示綠色,綠底紅色,白底藍色的字符串‘welcome to masm!’。 ??????80x25彩色字符模式下的顯示緩沖區,每頁可以顯示25行,每行80個字符,其中每個字符占兩個字節的存儲空間,低位字節存儲字符的ASCII值,高位字節存儲字符的屬性。所以一行總共有160個字節。其中屬性字節的格式如下:
??????其中BL為閃爍,R為紅色,G為綠色,B為藍色,I為高亮,在高位的RGB表示背景顏色,低位的表示前景顏色。 ??????以綠底紅色為例,它的顏色屬性為00100100B。顯示緩沖區的段地址為0b800h,默認在第0頁的屏幕中間的偏移地址為12x160+(40-16/2)x2。其中16為本程序中字符串的字節數。搞清楚了目的地址和顏色屬性之后,我們開始編寫程序:
assume cs:code
data segmentdb
'welcome to masm!' data endscode segment
start :mov ax
, 0b800hmov es
, axmov di
, 12
* 160
+ 32
* 2 目的地址存儲在es:di中mov ax
, data mov ds
, axmov bx
, 0mov cx
, 10hs: mov al
, [bx] mov es:
[di] , almov byte ptr es:
[di+1] , 00100100Binc bxadd di
, 2loop smov ax
, 4c00hint 21hcode ends
end start
實驗10
問題1 顯示字符串
??????編寫一個通用的子程序來讓調用者可以決定顯示的位置(行、列、內容和顏色) ??????子程序描述如下: ????????????名稱:show_str ????????????功能:在指定的位置、用特定的顏色,顯示一個用0結束的字符串 ????????????參數:(dh)=行號(取值范圍為0-24),(dl)=列號(取值范圍為0-79),(cl)=顏色,ds:si指向字符串的首地址 ????????????返回:無 ??????在屏幕的8行3列,用綠色顯示data段中的字符串,完整的程序如下:
assume cs:code
data segmentdb
'Welcome to masm!' , 0
data endscode segment
start : mov dh
, 8mov dl
, 3mov cl
, 2mov ax
, data mov ds
, axmov
si , 0call show_strmov ax
, 4c00hint 21hshow_str: push cxpush dxpush axpush
si push dspush dipush esmov ax
, 0b800hmov es
, axmov di
, dh
* 160
+ dl
* 2 es:di為目的地址s: mov al
, [si] cmp al
, 0je donemov es:
[di] , almov es:
[di+1] , cladd di
, 2inc
si jmp short sdone: pop espop dipop dspop
si pop axpop dxpop csretcode ends
end start
問題2 解決除法溢出
??????問題:除法溢出指的是商過大,超出了寄存器的存儲范圍。比如:16位的被除數和8位的除數在做除法的時候,用al存儲結果的商,ah存儲結果的余數。如果當除數為1時,那么商也是一個16位數據,這超過了al這個8位寄存器所能表示數據的范圍了。 ??????子程序描述如下: ????????????名稱:divdw ????????????功能:進行不會溢出的除法運算,被除數為dword型,除數為word型,結果為dword型。 ????????????參數:(ax)=dword型數據的低16位,(dx)=dword型數據的高16位,(cx)=除數 ????????????返回:(dx)=結果的高16位,(ax)=結果的低16位,(cx)=余數 ??????提示:參考公式如下: ????????????X:被除數,范圍:[0,FFFFFFFF] ????????????N:除數,范圍:[0,FFFF] ????????????H:X高16位,范圍:[0,FFFF] ????????????L:X低16位,范圍:[0,FFFF] ????????????int():描述性運算符,取商,比如,int(38/10)=3 ????????????rem():描述性運算符,取余數,比如,rem(38/10)=8
????????????公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N ????????????注意:乘以65536相當于左移16位。 ??????計算1000000/10(F4240H/0AH)完整程序如下:
assume cs:code
data segmentdw 4 dup
( 0
) data endscode segment
start : mov ax
, data mov ds
, axmov
si , 0mov ax
, 4240hmov dx
, 0fhmov cx
, 0ahcall divdwmov ax
, 4c00hint 21hdivdw: push dspush
si push cxpush axpush dxmov
[si] , ax 保存被除數的低16位Lmov
[si+2] , dx 保存被除數的高16位Hmov ax
, dxmov dx
, 0div cx 用高16位H除以除數Nmov
[si+4] , ax 保存商mov ax
, [si] div cx rem
( H
/ N
) 作為高16位,L作為低16位,除以Nmov
[si+2] , axmov
[si] , dx
/ / 將商的高16位存儲在
[si+4] 處,低16位存儲在
[si+2] 處,余數存儲在
[si] 處。done: pop dxpop axpop cxmov cx
, [si] 保存返回值到相應的寄存器中mov ax
, [si+2] mov dx
, [si+4] pop
si pop dsretcode ends
end start
問題3 數值(int)到字符串形式的轉換
??????問題:把數據用十進制的形式顯示到屏幕上,需進行兩步的操作:(1),將用二進制信息存儲的數據轉變為十進制形式的字符串(2),顯示十進制形式的字符串(只需調用問題1的show_str即可) ??????子程序描述如下: ????????????名稱:dtoc ????????????功能:將word型數據轉變為十進制數的字符串,字符串以0為結尾符。 ????????????參數:(ax)=word型數據、ds:si指向字符串的首地址 ????????????返回:無 ??????編程,將數據12666以十進制形式在屏幕的8行3列,用綠色顯示出來。在顯示時調用本次實驗中的第一個子程序show_str。 ??????思路:想要得到十進制數12666的每一位數值,需將12666除以10,它的余數6為個位上的數值,它的商1266作為新的被除數再除以10,余數6為原數據十位上的數值,它的商再次除以10,以此類推,進行5次除以10操作就可以得到每一位的值了。 ??????在已知數據為12666的情況下,循環次數為5,但對于數據未知的情況下,就需要判定每次得到的商是否為0了,當除到商為0時,所有位上的值就被全部求出。在此采用jcxz指令來實現此功能。 ??????除法功能在此采用32位除以16位的方式來實現,因為這樣不會導致溢出。因為如果采用16位除以8位的方式的話,那么它的商也是用8位來保存的,而12666/10=1266,這已經大于8位數據的最大值255了。
assume cs:code
data segmentdb 10 dup
( 0
) data endscode segment
start : mov ax
, 12666mov bx
, data mov ds
, bxmov
si , 0call dtocmov dh
, 8mov dl
, 3mov cl
, 2call show_str mov ax
, 4c00hint 21hdtoc: push bxpush cxpush axpush dxmov bx
, 10 整數10作為16位的除數放在bx中mov
si , 9mov byte ptr
[si] , 0 字符串末尾置0sub
si , 1s: mov dx
, 0div bxadd dl
, '0' 容易看出dh中全為0,計算出數據的實際ASCII值mov
[si] , dl 字節單元數據的傳送,將余數保存到內存中mov cx
, axjcxz donesub
si , 1jmp short sdone: pop dxpop axpop cxpop bxretcode ends
end start
課程設計1
??????將實驗七中的公司21年的數據在屏幕上顯示出來,一共占據屏幕21行,每一行中顯示出每一年的數據,依次為年份、收入、雇員數和平均收入。 ??????思路: ????????????先計算出每一字段的行號和列號,可得,行號范圍為[2,22];每一行第一個字段起始地址為6,第二個字段起始地址為28,第三個字段起始地址為50,最后一個字段起始地址為72。這樣就可以將所有數據內容顯示在屏幕中央。 ????????????說明一點,前面已經實現了的子程序在此將被直接調用。
????????????但還需要編寫一個將dword型數據轉換為字符串的子程序。說明如下: ??????????????????名稱:ddtoc (為了和word型數據轉換子程序dtoc區分開來) ??????????????????功能:將dword型數據轉變為表示十進制數的字符串,字符串以0為結尾符 ??????????????????參數:(ax)=dword型數據的低16位,(dx)=dword型數據的高16位,ds:si指向字符串的首地址 ??????????????????返回:無 ??????????????????仍需要注意除法溢出 的問題。 ??????完整程序如下:
assume cs:code
data segamentdb
'1975' , '1976' , '1977' , '1978' , '1979' , '1980' , '1981' , '1982' , '1983' db
'1984' , '1985' , '1986' , '1987' , '1988' , '1989' , '1990' , '1991' , '1992' db
'1993' , '1994' , '1995' / / 用21個字符串來表示年份dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514dd 245980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
/ / 用21個雙字型數據來表示公司每年的總收入dw 3,7,9,13,28,38,130,220,476,778,100,1442,2258,2793,4037,5635,8226dw 11542,14430,15257,17800
/ / 用21個字型數據來表示公司每年的員工數量
data endsbuf segmentdb 16 dup
( 0
) 這塊內存是用來進行雙字型到字符串轉換的buf endscode segment
start :mov ax
, data mov ds
, axmov bx
, 0 ds:bx表示數據段起始的偏移地址mov ax
, 0b800hmov es
, ax mov di
, 160
* 2 es:di指向顯示緩沖區第二行第0列mov al
, 21mov dl
, 8mul dlmov
si , ax 計算21
* 8,保存到
si 中
, 這是雇員數在數據段的起始偏移地址mov cx
, 21 外層循環次數21次body: mov ax
, [bx] mov es:
[di+6] , axmov ax
, [bx+2] mov es:
[di+8] , ax 年份push
si push dsmov ax
, [bx+84] mov dx
, [bx+86] call ddtocmov bp
, 0subb: mov al
, [si] cmp al
, 0je nextmov es:
[di+bp+28] , alinc bpinc
si jmp short subb 總收入next: pop dspop
si mov ax
, [si] push dspush
si mov ax
, bufmov ds
, axcall dtocmov bp
, 0subbo: mov al
, [si] cmp al
, 0je nnextmov es:
[di+bp+50] , alinc bpinc
si jmp short subbo 雇員數 nnext: pop
si pop dsmov dx
, [bx+86] mov ax
, [bx+84] div word ptr
[si] 計算人均收入push dspush
si mov ax
, bufmov ds
, axcall dtoc 字型數據轉換為字符串mov bp
, 0
subbody:mov al
, [si] cmp al
, 0je nnnextmov es:
[di+bp+72] , alinc bpinc
si jmp short subbody nnnext: pop
si pop dsadd di
, 160add
si , 2add bx
, 4loop bodymov ax
, 4c00hint 21hddtoc: push cxpush axpush dxmov ax
, bufmov ds
, axmov
si , 15mov byte ptr
[si] , 0dec
si s: mov cx
, 10 除數10保存在cx中push
si mov
si , 0 將ds:
si 開始后的6個字節作為divdw中的臨時緩存call divdw divdw采用本文中實現的子程序pop
si add cl
, '0' mov
[si] , cldec
si cmp dx
, 0jne scmp ax
, 0je donejmp short sdone: inc
si 注意,最后退出時
si 并不是剛好指向字符串首地址pop dxpop axpop cxretcode ends
end start
總結
以上是生活随笔 為你收集整理的汇编语言随笔(8)-实验9(显示字符串)、实验10(子程序:除法溢出,数值到字符串的转换)和课程设计1 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。