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 指定值,便能指定螢幕上像素的顏色。