显存文本模式详解 ———《x86汇编语言:从实模式到保护模式》读书笔记补遗02
文章修改記錄
| 2018-2-4 | 修改了一處錯(cuò)別字;增加了表格的使用方法 |
今天我們討論如何編程以在屏幕上顯示出彩色的文字。
為了顯示文字,通常需要兩種硬件——顯示器和顯卡。
顯卡的作用是為顯示器提供要顯示的內(nèi)容,并且控制顯示器的模式和狀態(tài)。
顯示器的作用是把那些內(nèi)容以人們可見的方式呈現(xiàn)在屏幕上。
1.顯存
每個(gè)顯卡都有自己的存儲(chǔ)器,因?yàn)樗挥陲@卡上,所以稱為顯示存儲(chǔ)器,簡稱“顯存”。和其他存儲(chǔ)器一樣,顯存并沒有什么特殊的地方,也是一個(gè)按字節(jié)訪問的存儲(chǔ)器件。
2.顯卡的兩種工作模式
顯卡最基本的兩種工作模式是文字(也稱為文本)模式和圖形模式。在不同的模式下,顯卡對顯存內(nèi)容的解釋是不同的。要想設(shè)置顯卡的顯示模式,可以用指令訪問顯卡,也可以直接調(diào)用BIOSint 10h中斷。
3.BIOS調(diào)用之設(shè)置顯示模式
功能號(hào):AH = 00H
用 途:設(shè)置顯示模式
參 數(shù):AL = 顯示模式號(hào)
調(diào) 用:INT 10H
返 回:無
AL的取值說明:
| 00H | 文字 | 40*25 | 2 |
| 01H | 文字 | 40*25 | 16 |
| 02H | 文字 | 80*25 | 2 |
| 03H | 文字 | 80*25 | 16 |
| 04H | 圖形 | 320*200 | 2 |
| 05H | 圖形 | 320*200 | 4 |
| 06H | 圖形 | 640*200 | 2 |
需要說明的是:計(jì)算機(jī)在加電自檢后會(huì)自動(dòng)初始化到AL=03H的文字模式。在這種模式下,一屏幕可以顯示25行,每行80個(gè)字符,總共是80*25=2000個(gè)字符。
4.文本模式下,顯存到內(nèi)存的映射
0xB8000到0xBFFFF這段物理地址被映射到顯存。也就是說,寫這些物理地址,就可以控制顯示內(nèi)容。
顯存和每個(gè)字符(假入從0開始數(shù),那就是0~1999)的對應(yīng)關(guān)系,如下圖所示。
5.關(guān)于屬性
| 含義 | 1:字閃爍;0:字不閃爍 | 背景色 | 前景色 |
5.1 背景色
因?yàn)閇6:4]決定背景色,所以取值是0~7。根據(jù)我判識(shí)色彩的能力,總結(jié)如下。
| 顏色 | 黑 | 深藍(lán) | 綠 | 青 | 紅 | 粉紅 | 棕 | 灰白 |
5.2 前景色
因?yàn)閇3:0]決定前景色,所以取值是0x0~0xF。根據(jù)我判識(shí)色彩的能力,總結(jié)如下。
| 顏色 | 黑 | 深藍(lán) | 綠 | 青 | 紅 | 粉紅 | 棕 | 灰白 | 灰 | 亮藍(lán) | 亮綠 | 亮青 | 亮紅 | 亮粉紅 | 黃 | 亮白 |
6.編程實(shí)踐——遍歷所有顏色
關(guān)于顏色,眼見為實(shí)。也許我眼中的青色,在你眼中就是藍(lán)色。不妨編程看看,顯示在屏幕上的到底是什么顏色。
思路:在不考慮閃爍的情況下,前景色搭配背景色,共有16*8=128種可能,我們的目的是提供一個(gè)表格,每一行表示前景色的不同取值,每一列表示背景色的不同取值。
關(guān)于要顯示的內(nèi)容,可以選擇一個(gè)字符串(考慮到一行最多顯示80個(gè)字符,80/16=5,所以字符串長度不宜超過5個(gè)),一共顯示128次。
6.1 通過調(diào)用BIOS中斷實(shí)現(xiàn)
jmp near startmessage db 'KARL ' ;字符串任意,但是不要超過5個(gè)字符;取KARL是因?yàn)镵ARL是我徒弟的英文名;int 10h (video service) ;AH=13h, 在teletype模式下顯示字符串 ;入口參數(shù): ; AL[1:0]=顯示方式 ; [0]: 0表示不移動(dòng)光標(biāo),1表示移動(dòng)光標(biāo) ; [1]: 0表示字符串中僅包含字符,不包含屬性,屬性在BL中;1表示字符串中包含屬性 ; BH=頁碼 ; BL=屬性 ; CX=字符串長度 ; DH=行 ; DL=列 ; ES:BP=指向字符串 ; ;出口參數(shù):無start:mov ax,0x7c0 ;設(shè)置ES段的段地址 mov es,ax mov bp,message ;ES:BP指向字符串mov ah,0x13 ;在teletype模式下顯示字符串mov al,1 ;顯示方式,表示字符串中僅包含字符,不包含屬性,屬性在BL中,移動(dòng)光標(biāo)mov bl,0 ;屬性初始值mov bh,0 ;頁碼mov dh,0 ;從0行開始mov cx,8 ;循環(huán)8次,從0行到7行put_0_8: ;------------------------------------外層循環(huán)push cx ;因?yàn)閮?nèi)層循環(huán)也要用CX控制循環(huán)次數(shù),所以壓棧保護(hù)mov dl,0 ;從0列開始mov cx,16 ;循環(huán)16次,從0列到15列put_0_F: ;------------內(nèi)層循環(huán)push cx ;因?yàn)檠h(huán)體中要用到CX,所以壓棧保護(hù)mov cx,5 ;設(shè)置字符串長度int 0x10 ;BIOS中斷調(diào)用inc bl ;改變屬性,屬性值增加1add dl,5 ;改變列,列值增加5 pop cxloop put_0_F ;------------內(nèi)層循環(huán)pop cxinc dh ;改變行,行增加1 loop put_0_8 ;----------------------------外層循環(huán)jmp near $ ;使陷入死循環(huán)times 510-($-$$) db 0db 0x55,0xaa運(yùn)行結(jié)果如下圖
6.2 通過自己寫過程實(shí)現(xiàn)
jmp near startmessage db 'KARL 'db 0 ;本程序的過程規(guī)定以0結(jié)尾start:mov ax,0x7c0 ;設(shè)置數(shù)據(jù)段的段基地址 mov ds,axmov bx,message ;使DS:BX指向字符串mov al,0 ;屬性初始值mov dh,0 ;從0行開始mov cx,8 ;循環(huán)8次,從0行到7行put_0_8: ;----------------------------外層循環(huán)push cxmov dl,0 ;列的初始值mov cx,16 ;循環(huán)16次,從0列到15列put_0_F: ;--------內(nèi)層循環(huán)call put_stringinc al ;改變屬性,屬性值增加1add dl,5 ;改變列,列值增加5 loop put_0_F ;--------內(nèi)層循環(huán)pop cxinc dh ;改變行,行增加1 loop put_0_8 ;----------------------------外層循環(huán)jmp near $ ;------------------------------------- ;功能:在某位置顯示字符串 ;入口參數(shù): ; AL=屬性 ; DH=行 ; DL=列 ; DX:BX=指向字符串,字符串必須以0結(jié)尾 ;出口參數(shù):無 put_string:push axpush bxpush cxpush dxpush dipush espush ax ;AX中是屬性,因?yàn)橄旅嬉肁X,所以先進(jìn)棧保護(hù)起來mov ax,0xb800mov es,ax; x行y列,換算成偏移是:(x*80+y)*2mov al,80mul dh ;ax=al*dh (計(jì)算出x*80,結(jié)果在ax中)xor dh,dh ;dh清零add ax,dx ;計(jì)算出(x*80+y),結(jié)果在ax中shl ax,1 ;計(jì)算出(x*80+y)*2,結(jié)果在ax中mov di,ax ;用di保存偏移pop ax ;得到屬性 put_char:mov cl,[bx] ;取要顯示的字符到cl中cmp cl,0 ;和0比較jz end ;等于0則跳轉(zhuǎn)mov [es:di],cl ;寫字符的ASCII碼到顯存inc dimov [es:di],al ;寫字符的屬性到顯存inc di ;di指向顯存中的下一個(gè)位置inc bx ;bx指向下一個(gè)字符jmp put_charend: pop espop dipop dxpop cxpop bxpop axret ;返回 ;-------------------------------------------times 510-($-$$) db 0db 0x55,0xaa6.3 將實(shí)驗(yàn)結(jié)果制作成表格
可以看到,當(dāng)前景色和背景色取值相同時(shí),就看不到字了。所以,屬性組合不是128種,而是128-8=120種。
查詢表格的時(shí)候,最左邊一列的數(shù)字表示背景色,最上面一行的數(shù)字表示前景色(即字的顏色)。
- 舉例1:0x02——黑底綠字
- 舉例2:0x04——黑底紅字
- 舉例3:0x24——綠底紅字
7.使用LOOP要注意什么
上面的代碼使用了LOOP實(shí)現(xiàn)循環(huán),對于初學(xué)者,用LOOP時(shí)需要注意的是:
- 循環(huán)之前的初始化,比如循環(huán)次數(shù)(CX)、變量的初始值等
- 標(biāo)號(hào)的位置
- 循環(huán)體內(nèi)變量的自增/自減
- 對于嵌套的LOOP,尤其要注意CX的壓棧出棧和其他寄存器(如果需要)的壓棧、出棧
【完】
總結(jié)
以上是生活随笔為你收集整理的显存文本模式详解 ———《x86汇编语言:从实模式到保护模式》读书笔记补遗02的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 表达式求值(最详细分析+代码实现+表达式
- 下一篇: 求矩阵中各列数字的和