前言:
0x03我們提到:
把12(紅色)用迴圈寫入視訊記憶體,每個畫素點怎麼顯示都要看對應的視訊記憶體地址,比如0xa0000到0xaffff就是每一個畫素點的視訊記憶體
你問為什麼12就是紅色,這些東西在主機板出廠的時候就是規定好的,就是有點呼叫主機板api的味道,這是我的猜測,具體為什麼還要你們來查
你會發現12是紅色,11就是另一種顏色,有沒有辦法可以自定義顏色呢
自定義顏色的原因是:
顏色豐富度不夠,因此使用調色盤功能來增強顏色顯示,使用RGB模式,表示一個RGB顏色需要24位數
修改class01名字為class02,把我給出的程式碼對原來的內容進行替換,當然你也可以找不同,如果你有這個耐心的話
程式碼:
naskfunc.asm
; naskfunc ; TAB=4 [FORMAT "WCOFF"] ; 製作目標檔案的模式 [INSTRSET "i486p"] ; 使用到486為止的指令 [BITS 32] ; 3製作32位模式用的機器語言 [FILE "naskfunc.asm"] ; 檔名 GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt GLOBAL _io_load_eflags,_io_store_eflags [SECTION .text] _io_hlt: ; void io_hlt(void); HLT RET _io_cli: ; void io_cli(void); CLI RET _io_sti: ; void io_sti(void); STI RET _io_get8: ; int io_get8(int port); MOV EDX,[ESP+4] ; port MOV EAX,0 IN AL,DX RET _io_set8: ; void io_set8(int port, int data); MOV EDX,[ESP+4] ; port MOV AL,[ESP+8] ; data OUT DX,AL RET _io_stihlt: ; void io_stihlt(void); STI HLT RET _write_mem8: ; void write_mem8(int addr, int data); MOV ECX,[ESP+4] ; taking content of add MOV AL,[ESP+8] ; taking content of data MOV [ECX],AL ; *ecx=al RET _io_load_eflags: ; int io_load_eflags(void); PUSHFD ; PUSH EFLAGS POP EAX RET _io_store_eflags: ; void io_store_eflags(int eflags); MOV EAX,[ESP+4] PUSH EAX POPFD ; POP EFLAGS RET
這裡增加了一些函式,看不懂沒關係,我等下呼叫他們的時候講一下是幹嘛的
新建一個檔案graphic.c
#include "include/head.h" void init_palette(void) { static unsigned char table_rgb[18 * 3] = { 0x24, 0x86, 0xb9, /* 0:寶石藍(#2486b9) */ 0xff, 0x00, 0x00, /* 1:梁紅 */ 0x00, 0xff, 0x00, /* 2:亮綠 */ 0xff, 0xff, 0x00, /* 3:亮黃 */ 0x00, 0x00, 0xff, /* 4:亮藍 */ 0xff, 0x00, 0xff, /* 5:亮紫 */ 0x00, 0xff, 0xff, /* 6:淺亮藍 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ 0x84, 0x00, 0x00, /* 9:暗紅 */ 0x00, 0x84, 0x00, /* 10:暗綠 */ 0x84, 0x84, 0x00, /* 11:暗黃 */ 0x00, 0x00, 0x84, /* 12:暗青 */ 0x84, 0x00, 0x84, /* 13:暗紫 */ 0x33, 0x33, 0x33, /* 14:淺暗藍 */ 0x84, 0x84, 0x84, /* 15:暗灰 */ 0xD0, 0xD0, 0xD0, 0x20, 0x20, 0x20 }; set_palette(0, 17, 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_set8(0x03c8, start); for (i = start; i <= end; i++) { io_set8(0x03c9, rgb[0] / 4); io_set8(0x03c9, rgb[1] / 4); io_set8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 復原中斷許可標誌 */ return; } 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; }
前兩個函式是用來實現調色盤的,具體原理我解釋不了,Ctrl+CV大佬不需要知道原理,你懂我意思吧,裡面呼叫了很多asm裡的函式
第三個函式是繪製方塊的引數意思分別是:視訊記憶體地址,顯示寬度,顏色代號,從x0到x1,y0到y1進行繪製一個矩形
head.h
/*naskfunc.asm*/ void io_stihlt(); void io_hlt(void); void io_cli(void); void io_sti(void); int io_get8(int port); void io_set8(int port, int data); void write_mem8(int addr, int data); int io_load_eflags(void); void io_store_eflags(int eflags); /* asmhead.nas */ struct BOOTINFO { /* 0x0ff0-0x0fff */ char cyls; /* 啟動區讀磁碟讀到此為止 */ char leds; /* 啟動時鍵盤的LED的狀態 */ char vmode; /* 顯示卡模式為多少位彩色 */ char reserve; short scrnx, scrny; /* 畫面解析度 */ char *vram; }; #define ADR_BOOTINFO 0x00000ff0 /*graphic.c*/ void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
我們主要看第二個asmhead.asm的函式宣告,這個BOOTINFO結構體,是涵蓋了顯示器的資訊,資訊的位置在0x0ff0-0x0ffff
main.c
#include "include/head.h" struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; void Main(void){ int i; init_palette(); boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); for (;;) { io_hlt(); } }
第一句是獲取這個顯示器資訊的結構體,呼叫boxfill8填充整個螢幕,顏色代號是調色盤中的0號寶石藍
最後在make指令碼中增加graphic.obj
執行:
cd class02
..\z_tools\make.exe run
自制作業系統合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html