昨天已经让画面显示黑屏了,但是黑屏太没意思,今天来让画面画点东西吧。

今天的任务还是比较有趣的,主要包括内存写入、画面显示条纹图案、设定色号、绘制矩形,最后制作一个进度条。

每个大标题下的代码,都在文末的资源里,可自行下载实验。


内存写入(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语言制作操作系统进度条相关推荐

  1. 操作系统(四)补充---DOS微软磁盘操作系统

    dos,是磁盘操作系统的缩写,是个人计算机上的一类操作系统.从1981年直到1995年的15年间,磁盘操作系统在IBM PC 兼容机市场中占有举足轻重的地位.而且,若是把部分以DOS为基础的Micro ...

  2. 由《30天自制操作系统》引发的漫画创作

    大家可还记得<30天自制操作系统>的封面上的那只猫吗?记得当时,在果壳网有人问,为何这只猫长了两只尾巴呢,延着这条线,我把这本书捧上了展示的舞台.事隔四个多月,我又重提此书. 这本经我手宣 ...

  3. 30天自制操作系统——第五天

    第五天 参考<30天自制操作系统>GDT&IDT - 谷月轩 - 博客 梳理一下文件 现在我们拥有这么9个文件: ipl10.nas InitialProgramLoader, 占 ...

  4. 30天自制操作系统第三天

    操作系统实验日志3 学号 201708010402 姓名 徐冰娜 专业年级班级 实验日期 2019.9.28 实验项目 第3天:进入32位模式并导入C语言 智能1701 30天自制操作系统第三天 操作 ...

  5. 《30天自制操作系统》day1

    今天开始正式学习操作系统啦!!!<30天自制操作系统>一本比较老旧的书,希望30天都能坚持看完. 内容1:利用二进制编辑器编写操作系统,输出"hello world": ...

  6. 30天自制操作系统——第二天

    30天自制操作系统--第二天 今天是该系列的第二天,继续昨天的开发,今天的任务主要有以下几项: 1.进一步的加工一下汇编程序(去除昨天的二进制代码) 2.对启动区进行制作 3.利用makefile简化 ...

  7. 【操作系统】30天自制操作系统--(27)文件操作

    本章主要介绍了对 _alloca 函数的兼容,日文的显示,以及着重介绍了文件系统操作. 一 对_alloca的支持 首先作者写了一个小应用程序,功能是找出并打印1000以内的质数: #include ...

  8. 30天自制操作系统——第2天

    操作系统实验日志 实验日期 2018/9/29 实验项目 第2天:汇编语言学习与Makefile入门 一.实验主要内容 (一)汇编 1.关键代码 运行结果: 2.相关汇编指令的解释 指令 格式 含义 ...

  9. 【操作系统】30天自制操作系统--(14)多任务1

    本章开始多任务的设计. 一 多任务的说明 多任务(multitask),指的是操作系统中,多个应用程序同时运行的状态.然而,对于单核CPU来说,同一个瞬间只能处理一个事情,不能做到左右互搏.一心二用的 ...

最新文章

  1. python线下培训-北京哪里有Python线下培训辅导班
  2. LOJ bitset+分块 大内存毒瘤题
  3. gearman mysql编译_gearman初探(一、编译和安装)
  4. linux多用户运行同一程序_linux系统中CentOS有哪些优势,让它长盛不衰?
  5. .NET Framework各版本比较
  6. 1.7 编程基础之字符串 25 最长最短单词 python
  7. php的转义字符quot;反斜杠quot;是,php如何去除转义字符中的反斜杠
  8. python拦截数据包_使用Python进行TCP数据包注入(伪造)
  9. HDOJ2005 ( 第几天? ) 【水题】
  10. cofax(网络传真机) v3.1.0.0
  11. 重新思考路易斯维尔足球品牌
  12. 推荐书籍 《半小时漫画经济学1--生活常识篇》
  13. 如何用Python画一只机器猫?
  14. java中五子棋_Java简单五子棋的实现
  15. 利用百度地图API获取地理编码
  16. Raspberry Pi 4 树莓派4 支持操作系统
  17. linux设备模型--sysfs
  18. 【网络游戏植入营销案例】
  19. form表单的多种提交方式及提交前验证
  20. 数据分析方法——判别分析

热门文章

  1. duilib制作窗体动画效果
  2. 安装算量软件哪个速度快效率高?
  3. 两个质数互质是_科学网—理解黎曼猜想(二)两个自然数互质的概率是多少? - 袁岚峰的博文...
  4. 2022版Maven教程 - 第六章 单一架构案例
  5. ogg19.1.0.0.4打补丁
  6. 最全最详细的蓝牙版本介绍包含蓝牙4.0和4.1
  7. HDU-1253-胜利大逃亡
  8. 万豪国际成立全球清洁卫生委员会,推行更高标准清洁消毒措施
  9. 从源码看ANDROID中SQLITE是怎么通过CURSORWINDOW读DB的
  10. 前端根据后端返回数据导出指定样式的表格(xlsx-js-style)