30天自制操作系统——第四天使用C语言制作操作系统进度条
昨天已经让画面显示黑屏了,但是黑屏太没意思,今天来让画面画点东西吧。
今天的任务还是比较有趣的,主要包括内存写入、画面显示条纹图案、设定色号、绘制矩形,最后制作一个进度条。
每个大标题下的代码,都在文末的资源里,可自行下载实验。
内存写入(harib01a)
想要在画面上画东西,只要往VRAM里写点东西就可以了。
那什么是VRAM呢?
上一篇的最后已经用到了VRAM,不过没有做详细的讲解。
VRAM指的是显卡内存(video RAM),就是可以用来显示画面的内存。这一块内存可以像内存一样存储数据,它的各个地址都对应着画面上的像素。我们可以利用这个机制在画面上绘制各种各样的图案。
VRAM分布在内存分布图好几个不同的地方,不同画面模式的像素不一样,切换不同的画面模式,会使用不同VRAM,即不同画面模式可以使用的内存也不一样,我们预先把要使用的VRAM地址保存在BOOT_INFO里。
我们先来创建一个直接写入指定内存地址的语句,修改一下naskfunc.nas:
_write_mem8: ; void write_mem8(int addr, int data);MOV ECX,[ESP+4] ; [ESP+4]中存放的是地址,将其读入ECXMOV AL,[ESP+8] ; [ESP+8]中存放的是数据,将其读入ALMOV [ECX],ALRET
这个函数类似于C语言中的“write_mem8(0x1234,0x56)”,汇编语言中的“MOV BYTE[0x1234],0x56”。
在naskfunc.nas开头增加了一行INSTRSET指令的语句,它用来告诉nask这个是给486型号的CPU用的。
[INSTRSET "i486p"] ;
汇编部分已经准备好了,下面来修改一下C语言吧,这次导入了变量,bootpack.c内容修改如下:
void io_hlt(void);
void write_mem8(int addr, int data);void HariMain(void)
{int i; /* 变量声明:i是一个32位整数 */for (i = 0xa0000; i <= 0xaffff; i++) {write_mem8(i, 15); /* MOV BYTE [i],15 */}for (;;) {io_hlt();}
}
下一步用make run命令生成 haribote.img,使用该映像文件启动,画面显示了白屏。
这里画面显示为什么是白屏呢?
因为VRAM全部都写入了15,这意味着全部像素颜色都是第15种颜色,而第15种颜色碰巧是纯白,所以画面就显示了白屏。
画面显示条纹图案(harib01b)
不论是黑屏还是白屏,都过于单调了,下面我们就来显示有条纹的图案吧。
稍微改动一下bootpack.c就可以了:
for (i = 0xa0000; i <= 0xaffff; i++) {write_mem8(i, i & 0x0f);}
将写入的值由15改成了i&0x0f,“&”符号是位运算的一种。
这里顺便来复习一下位运算的内容吧——
1.“&”:按位与运算,相同位都为1,则为1;若有一个不为1,则为0。
例:00101&11100 = 00100。
2.“|”:按位或运算, 相同位只要有一个为1,即为1。
例:00101&11100 = 11100。
3.“^”:异或运算,相同位相等为0,不相等为1。
例:00101&11100 = 11001。
4.“~”:取反运算,0变1,1变0。
例:~00101 = 11010。
5.“<<”:左移运算,各二进制位全部左移若干位,高位丢弃,地位补0。
例:1<<3 = 8。
6.“>>”:右移运算,各二进制位全部右移若干位,对于无符号数,高位补0;对于有符号数,有的补符号位 ,有的补0。
例:16>>3 = 2。
运行一下make run,使用生成的映像文件启动,就出现了下面的条纹图案:
显示条纹图案C语言版(harib01e)
C语言中有直接指定内存地址的语句,那就是指针。相信很多同学在大学学习C语言课程的时候,对指针都比较头疼的。
现在我们要用指针替代 write_mem8函数,C语言指针的内容这里就不复习了,忘记的同学可以翻阅课本。
我们再把bootpak.c文件改写一下:
void io_hlt(void);void HariMain(void)
{int i; /* 变量声明,变量i是32位整数 */char *p; /* 变量p,用于BYTE型地址 */p = (char *) 0xa0000; /* 将地址赋值进去 */for (i = 0; i <= 0xffff; i++) {p[i] = i & 0x0f;}for (;;) {io_hlt();}
}
make run一下,依然显示条纹图案。
设定色号(harib01f)
接下来我们要描绘一个操作系统的画面,在这之前我们要先处理颜色问题。我们使用的是320×200的8位颜色模式,色号使用8位的二进制数。
该模式制定0~255的数字,每个数字对应一种颜色,比如25号颜色对应#ffffff,26号颜色对应#123456,这种方式称为调色板(palette)。
事实上绘制一个操作系统,不需要太多种颜色,十几种颜色就够了。这次我们使用16种颜色,并编上号码0-15:
这里需要给bootpack.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 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, /* 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;/* 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;
}
make run 一下,再使用生成的映像文件启动,仔细看哦,这里颜色变了。
绘制矩形(harib01g)
现在我们要着手在画面上画一个矩形,在当前画面模式中,画面上有320×200=64000个像素,假设左上点的坐标是(0,0),右下点的坐标是(319,319),那么像素坐标(x,y)对应的VRAM地址可按下式计算:
0xa0000 + x + y * 320
依据上面计算像素的地址,往该地址的内存里存放某种颜色的号码,那么画面上该像素位置就会出现相应的颜色。
根据这个思路我们制作了函数boxfill8,用它来画三个矩形,下面源程序是bootpack.c(harib01g)节选:
boxfill8函数:
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;
}
HariMain函数:
void HariMain(void)
{char *p; 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();}
}
启动虚拟机,画面上显示三个矩形:
制作一个进度条(harib01h)
使用上面画矩形的方法,来制作一个进度条,只修改HariMain函数:
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();}
}
make run一下,看一下执行结果——
这应该是我见过的最大的进度条了(笑)。
今天是大有进步呢,开始有点操作系统的样子了,明天继续啦~
差点忘了,附上今天的资源:
链接:https://pan.baidu.com/s/1kiHmP5_ZCYa31tAePC2IgA
提取码:wnm1
30天自制操作系统——第四天使用C语言制作操作系统进度条相关推荐
- 操作系统(四)补充---DOS微软磁盘操作系统
dos,是磁盘操作系统的缩写,是个人计算机上的一类操作系统.从1981年直到1995年的15年间,磁盘操作系统在IBM PC 兼容机市场中占有举足轻重的地位.而且,若是把部分以DOS为基础的Micro ...
- 由《30天自制操作系统》引发的漫画创作
大家可还记得<30天自制操作系统>的封面上的那只猫吗?记得当时,在果壳网有人问,为何这只猫长了两只尾巴呢,延着这条线,我把这本书捧上了展示的舞台.事隔四个多月,我又重提此书. 这本经我手宣 ...
- 30天自制操作系统——第五天
第五天 参考<30天自制操作系统>GDT&IDT - 谷月轩 - 博客 梳理一下文件 现在我们拥有这么9个文件: ipl10.nas InitialProgramLoader, 占 ...
- 30天自制操作系统第三天
操作系统实验日志3 学号 201708010402 姓名 徐冰娜 专业年级班级 实验日期 2019.9.28 实验项目 第3天:进入32位模式并导入C语言 智能1701 30天自制操作系统第三天 操作 ...
- 《30天自制操作系统》day1
今天开始正式学习操作系统啦!!!<30天自制操作系统>一本比较老旧的书,希望30天都能坚持看完. 内容1:利用二进制编辑器编写操作系统,输出"hello world": ...
- 30天自制操作系统——第二天
30天自制操作系统--第二天 今天是该系列的第二天,继续昨天的开发,今天的任务主要有以下几项: 1.进一步的加工一下汇编程序(去除昨天的二进制代码) 2.对启动区进行制作 3.利用makefile简化 ...
- 【操作系统】30天自制操作系统--(27)文件操作
本章主要介绍了对 _alloca 函数的兼容,日文的显示,以及着重介绍了文件系统操作. 一 对_alloca的支持 首先作者写了一个小应用程序,功能是找出并打印1000以内的质数: #include ...
- 30天自制操作系统——第2天
操作系统实验日志 实验日期 2018/9/29 实验项目 第2天:汇编语言学习与Makefile入门 一.实验主要内容 (一)汇编 1.关键代码 运行结果: 2.相关汇编指令的解释 指令 格式 含义 ...
- 【操作系统】30天自制操作系统--(14)多任务1
本章开始多任务的设计. 一 多任务的说明 多任务(multitask),指的是操作系统中,多个应用程序同时运行的状态.然而,对于单核CPU来说,同一个瞬间只能处理一个事情,不能做到左右互搏.一心二用的 ...
最新文章
- python线下培训-北京哪里有Python线下培训辅导班
- LOJ bitset+分块 大内存毒瘤题
- gearman mysql编译_gearman初探(一、编译和安装)
- linux多用户运行同一程序_linux系统中CentOS有哪些优势,让它长盛不衰?
- .NET Framework各版本比较
- 1.7 编程基础之字符串 25 最长最短单词 python
- php的转义字符quot;反斜杠quot;是,php如何去除转义字符中的反斜杠
- python拦截数据包_使用Python进行TCP数据包注入(伪造)
- HDOJ2005 ( 第几天? ) 【水题】
- cofax(网络传真机) v3.1.0.0
- 重新思考路易斯维尔足球品牌
- 推荐书籍 《半小时漫画经济学1--生活常识篇》
- 如何用Python画一只机器猫?
- java中五子棋_Java简单五子棋的实现
- 利用百度地图API获取地理编码
- Raspberry Pi 4 树莓派4 支持操作系统
- linux设备模型--sysfs
- 【网络游戏植入营销案例】
- form表单的多种提交方式及提交前验证
- 数据分析方法——判别分析
热门文章
- duilib制作窗体动画效果
- 安装算量软件哪个速度快效率高?
- 两个质数互质是_科学网—理解黎曼猜想(二)两个自然数互质的概率是多少? - 袁岚峰的博文...
- 2022版Maven教程 - 第六章 单一架构案例
- ogg19.1.0.0.4打补丁
- 最全最详细的蓝牙版本介绍包含蓝牙4.0和4.1
- HDU-1253-胜利大逃亡
- 万豪国际成立全球清洁卫生委员会,推行更高标准清洁消毒措施
- 从源码看ANDROID中SQLITE是怎么通过CURSORWINDOW读DB的
- 前端根据后端返回数据导出指定样式的表格(xlsx-js-style)