首先啊,今天的內容比較多,但你們能夠直接看書最後面,一想到作完後就能看到這個界面上有咱們畫上去的東西就開心納,朝着這個盡頭,開始吧。數組
首先就是用C語言寫內存,若是用匯編寫的話,就是用[]這種來進行內存讀寫,其實咱們就是要在彙編裏封裝一些函數讓C去調用。這裏忽然想起了,作手遊,爲了熱更新,也是這個套路。函數
_write_mem8: ; void write_mem8(int addr, int data); MOV ECX,[ESP+4] ; [ESP+4]‚中存放的是地址,將其讀入ECX MOV AL,[ESP+8] ; [ESP+8]‚中存放的是數據,將其讀入AL MOV [ECX],AL RET
首先,寫了個函數叫write_mem8,其意是向內存地址中寫入8個字節,因此用的是AL。
函數自己也很簡單,做者在這裏作了說明,只能用EAX,ECX,EDX,由於用於記憶C語言編譯後的機器語言中。
[INSTRSET "i486p"] ; 486‚指定用於486,固然也不是說其餘的就不能用。操作系統
int i; for (i = 0xa0000; i <= 0xaffff; i++) { write_mem8(i, i & 0x0f); } for (;;) { io_hlt(); }
註釋也省略了,由於我以爲到了C語言,應該沒有什麼語法看不懂的了,主要是思惟。昨天已經介紹過0xa00000-0xaffff是使用這個模式,對這部份內存操做就是對最終屏幕繪製出來的內容密切相關。線程
條紋圖案指針
這裏巧妙的運用了AND運算符,因爲每次遍歷出來一個字節,8位,與0x0f與運算,也就是0x0f有低四位可是高四位是0。因爲i、每隔16進一次位,因此每隔16次反覆進行此運算,而這16此每一次的計算,保留低4位,由於f的存在,高四位變成0由於0x0f中0的存在。code
指針
理所固然C語言的指針就是拿來玩兒內存的,多是讀者爲了讓咱們更瞭解原理,而後寫了以前的read_mem8這個函數。若是直接對i進行取地址,那他固然不知道這個地址是個什麼類型,固然也就不知道賦值多少位過去,因此寫了個char *p
指針在專欄裏做者講了一大堆,若是能看懂,哦,做者講的確實對。但我以爲對於初學者,去學一些C語言的書,多看些打印的值,更直觀些。說個我也會忘的知識吧 a[1] 1[a]是同樣的意思。遊戲
void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);ip
// 就算寫在同一個源文件裏,在使用以前必須聲明一下,若是函數在前面則不用內存
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);it
void HariMain(void)
{
int i; // 聲明變量,這裏的變量i是32位整型 char *p; // 變量p是Byte[...]用的地址 init_palette(); // 設定調色板 p = (char *) 0xa0000; // 指定地址 for (i = 0; i <= 0xffff; i++) { p[i] = i & 0x0f; } for (;;) { io_hlt(); }
}
void init_palette(void)
{
static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0xc6, 0xc6, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x84, 0x84, 0x00, 0x00, 0x00, 0x84, 0x84, 0x00, 0x84, 0x00, 0x84, 0x84, 0x84, 0x84, 0x84 }; set_palette(0, 15, table_rgb); return; // C語言中的static char語句只能用於數據,至關於彙編中的DB指令
}
void set_palette(int start, int end, unsigned char *rgb)
{
int i, eflags; eflags = io_load_eflags(); // 記錄中斷許可標誌的值 io_cli(); // 將中斷許可標誌置爲0,禁止中斷 io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); // 復原中斷許可標誌 return;
}
代碼有點長,不過聲明就佔了好些行數。記得無論之前是學C仍是其餘高級語言對於靜態變量的說法都是,靜態存儲區,特有的存儲區。具備全局性等,但如今若是從彙編的角度來看,好像會對他產生全新的認識。記住static就至關於在彙編使用DB同樣。做者說這個方式a[0] = 1;佔三個字節的緣由多是賦值語句轉換位彙編是mov ....多是這樣致使的,因此改爲static就能避免不少這樣的操做。
咱們初始咱們想要的顏色後,如今要設定到調色板裏去。雖然做者說讓咱們先不理解io_out這個函數,但我以爲有點奇怪,一直往一個地址裏面寫值,不久把以前的覆蓋了嗎?仍是我寫一個,就會有相應的東西把值取走,而後保存下來?
有兩個函數CLI與STL這兩個配合起來意思是我在作這段代碼的過程當中不準任何人打攪,感受有點像高級語言的線程鎖。
前面幾個函數相對簡單,我直接來搞後兩個新函數。若是以前知道push和pop的來理解也就不難,PUSHFD先把eflags的值存在棧裏面,而後又放到EAX裏面去(不知道爲何做者沒講,要想返回函數的值,放到EAX裏面就行了,因此在C語言咱們能夠接收到一個返回值)。因爲這個值到C那邊跑了一圈,又傳回來了,因此咱們再入棧,在POPFD又回到了EFLAGS裏邊兒。
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return;
}
看到這裏更帶勁兒了,由於畫出了個正方形,來看看這個函數,思想也比較簡答, 就是塊數組,指定區域用指定值,而後對應的就是指定屏幕變成指定顏色。像這種常值的值,定義成define就好。
void HariMain(void)
{
char *vram; int xsize, ysize; init_palette(); vram = (char *) 0xa0000; xsize = 320; ysize = 200; boxfill8(vram, xsize, COL8_008484, 0, 0, xsize - 1, ysize - 29); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 28, xsize - 1, ysize - 28); boxfill8(vram, xsize, COL8_FFFFFF, 0, ysize - 27, xsize - 1, ysize - 27); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 26, xsize - 1, ysize - 1); boxfill8(vram, xsize, COL8_FFFFFF, 3, ysize - 24, 59, ysize - 24); boxfill8(vram, xsize, COL8_FFFFFF, 2, ysize - 24, 2, ysize - 4); boxfill8(vram, xsize, COL8_848484, 3, ysize - 4, 59, ysize - 4); boxfill8(vram, xsize, COL8_848484, 59, ysize - 23, 59, ysize - 5); boxfill8(vram, xsize, COL8_000000, 2, ysize - 3, 59, ysize - 3); boxfill8(vram, xsize, COL8_000000, 60, ysize - 24, 60, ysize - 3); boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize - 4, ysize - 24); boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize - 4); boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize - 3, xsize - 4, ysize - 3); boxfill8(vram, xsize, COL8_FFFFFF, xsize - 3, ysize - 24, xsize - 3, ysize - 3); for (;;) { io_hlt(); }
}
這段代碼運行後,簡直是太棒啦,感受有點想咱們的桌面了,但其實仍是前面的知識,只是巧妙的利用了boxfill8這個函數。
大概解釋一下吧,第一個boxfill8是繪製桌面的感受,一張藍綠色的低,從左上角到離右下角y29,x1的位置,至於爲何做者在x方向少了一個1不太理解,多是留出邊緣吧。第二個是繪製一個桌面與狀態欄的灰色分割線。而後是藍色分割線,以此。。。還有一個辦法看每一行到底作了哪些東西,能夠一句代碼一句代碼的註釋,而後看效果。實話說這個操做系統是真的小,像我作exe,apk,ipa什麼的隨便弄個空項目出來就好幾百K,甚至用遊戲引擎的話,隨隨便便就是幾MB,簡直不敢想象,那個在咱們看來是個空項目,內部到底有多少代碼。
寫在最後我記得我在編譯這一天代碼的時候出現過一個問題, 不過最後也找到了,就是路徑問題,請你們注意一下,tolsetz_toolsharibote這個路徑下的haribote.rul文件內容的路徑必定也要修改,否則make run會報錯。