前言:
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
项目github地址rick521/My-OS (github.com)给我点颗star