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