想要在画面里画点什么东西,就需要往VRAM的内存区里写入点什么东西。
但是如何写入呢?
作者先用了汇编:
_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
SP是指向栈的指针,C语言压入参数又是从右往做压的,而压栈又是高地址压入低地址,而32位一次入栈就是4个字节。所以自然而然,[ESP+4]的内容就是地址,+8那就是数据了。
下面的一些C语言代码我就省略了。
作者的第二个方法是使用指针。我觉得C语言的指针还是应该去好好了解的,建议看一下
《C和指针》这本书。
至于什么调色板,想来也是十分好理解。
因为设定调色板的时候要屏蔽中断,但是设定好了又要回复,所以作者写了2个函数,先屏蔽在回复。
哦,实在不想赘述太多,因为这一章没有啥新概念,单纯的一些C语言罢了。
直接上代码吧。
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); 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); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 void HariMain(void) { char *p; /* pという変数は、BYTE [...]用の番地 */ init_palette(); /* パレットを設定 */ p = (char *) 0xa0000; /* 地址赋值 */ boxfill8(p, 320, COL8_FF0000, 20, 20, 120, 120); boxfill8(p, 320, COL8_00FF00, 70, 50, 170, 150); boxfill8(p, 320, COL8_0000FF, 120, 80, 220, 180); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 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:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 用来保存当前flag寄存器的信息 */ io_cli(); /* 屏蔽中断 */ io_out8(0x03c8, start); //IO_OUT8 作用不详,作者的意思说,以后在进行解释 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); /* 恢复flag寄存器 */ return; } //根据像素坐标(x,y)对应的VRAM地址的换算公式写的函数 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; }
那段汇编不解释了。 其中什么_io_in16,_io_in32作者说留到以后解释,那就留到以后吧。