Day 4 C 語言與畫面顯示的練習
這天很多在介紹 C,尤其是 pointer,作者用組語的角度去看 C,很有趣。這邊只寫些簡單的筆記。
組語跟 C 一起使用時,只有 EAX
、ECX
、EDX
三個 register 可以使用,其他 register 只能 read 不能 write,因為它們存著 C 語言程式的相關資料。
C 語言中,普通數值跟表示 memory address 的數值被當作兩種不同的東西。
根據 C 語言規定,組語執行 RET
指令時, EAX
中的值就被看作是 function return value。
調色盤設定顏色
在 8 bit 彩色模式下,顏色以 8 個 bit 表示,也就是 0~255。
每個數字表示什麼顏色,是由 developer 來決定的,不像 RGB 的 #ffffff
固定代表某個顏色。使用 0~255 表示顏色前,developer 要先幫這些數字指定好對應的顏色,例如 25 對應 #ffffff
等等。這種方式稱為「調色盤」。
設定調色盤的步驟如下:
- 先 block interrupt
- 依據設定調色盤的方式,對 IO device 的某些 port 寫入資料
- 恢復對 interrupt 的處理
向 IO Device read/write
先來看怎麼對 IO device 讀寫。
CPU 與 IO device 相連,CPU 要能控制 IO device 當然有向 device 發送訊號與從 device 接收訊號的指令。
向 device 發送訊號的指令是 OUT
,反之從 device 接收訊號的指令是 IN
。就像 memory 用 memory address 區分不同位置,device 以 device port 區分不同 device。組語實作從 device read 與 write 到 device 的 function 們:
1 | ; read 8 bit |
我們要設定調色板,就是找出對應 device 設定調色板的指令,然後照著做~
CLI 與 STI
CLI
是將 interrupt flag clear 為 0 的指令, STI
則是將 interrupt flag set 為 1 的指令。
interrupt flag 為 0 時,CPU 遇到 interrupt 會忽略它、不處理,flag 為 1 時 CPU 就會處理 interrupt。
EFLAGS register
EFLAGS
是由 FLAGS
16 bit 的 register 擴展而來的 32 bit register。
FLAGS
儲存 carry flag(進位 flag)與 interrupt flag 等 flag,不同 bit 代表不同 flag(有 1 個 bit 表示一個 flag 也有 2 個 bit),如下所示:
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
NT | IOPL | IOPL | OF | DF | IF | TF | SF | ZF | AF | PF | CF |
IOPL
是第 12 跟 13 bit 放在一起處理。
EFLAGS 沒有 MOV
指令,只能使用 PUSHFD
跟 POPFD
來讀寫。
PUSHFD
是 push flags double-word 的縮寫,以 double word 的長度(32 bit)將 flag 的值 push 進 stack,等同 PUSH EFLAGS
。POPFD
是 pop flags double-word,將 double word 長度的值從 stack pop 出來到 flag,等同 POP EFLAGS
。
如果想把 EFLAGS
內的資料放到 EAX
裡,不能用 MOV
,而要先 PUSHFD
再 POP EAX
。反過來想把 EAX
的資料放進 EFLAGS
裡則是 PUSH EAX
再 POPFD
。操作 EFLAGS
的組語 code 如下:
1 | _io_load_eflags: ; int io_load_eflags(void); |
設定調色盤要先執行 CLI
,為了在設定完後恢復 interrupt flag 的值,要先把原本的值記下來。我們可以直接把整個 eflags 記下來、執行 CLI
、設定調色盤,最後直接把整個 eflags 的值再存回去,達到恢復 interrupt flag 的效果。
在螢幕上畫圖
螢幕上每個像素都對應到 VRAM 中的一個 address。向 VRAM 指定值,便能指定螢幕上像素的顏色。