操作系统实验--30天自制操作系统第4天实验日志

一、实验主要内容

1、内容1:用C语言实现内存写入
如果想要在画面上显示东西的话,那么只需要向显存中写入适当的值(代表每个像素的颜色)即可。但是C语言没有直接写入指定内存地址的语句,便需要采用汇编语言创建一个有这种功能的函数。
修改naskfunc.nas,向其添加以下部分代码:
在这里插入图片描述

这个函数类似于C语言中的write_mem8(0x1234,0x56),其中addr是内存地址,data是数据,在这里指的是颜色的色号。
在C语言中如果用到了write_mem8函数,就会跳转到_ write_mem8。此时参数指定的数字就存放在内存里,分别是;
第一个数字的存放地址 [ESP+4]
第二个数字的存放地址 [ESP+8]
第三个数字的存放地址 [ESP+12]

在指定内存地址的地方,需要使用32位寄存器。除此以外,还需要给naskfunc.nas增加一行INSTRSET指令,作用是告知nask“这个程序是给486使用的”,这样如果使用EAX,会解释成寄存器名。如果不指定的话,就会将其解释成标签。
修改C语言,添加循环函数,使其填充0xa0000-0xaffff的内存(显存地址为0xa0000-0xaffff)。
在这里插入图片描述

在这里插入图片描述

这样的话,内存中能够全部写入了15,也就是全部像素的颜色都是第15种色号的颜色,而第15种颜色是白色,因此画面变成了白色。
实验结果如上图

2、内容2:显示条纹图案
修改C语言中能够for循环的内容:
在这里插入图片描述

I&0x0f是实现条纹图案的关键内容,其将0xa0000-0xaffff与上0x0f,使得高位全部为0,低位保留。因此,写入的值为:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 …
这样使得每隔16个像素,色号就会反复一次,同时加上显示屏幕的像素为320*200,所以这就会使得显示的结果为条纹图案。
实验结果如下图
在这里插入图片描述

3、内容3:使用指针代替汇编函数
使用指针函数来替换write_mem8函数。
修改内容为:
在这里插入图片描述

其用char声明了一个变量P,并将地址编号赋给P,再将色号填入到内存地址中。
此时C编译器会认为P是地址专用变量,而且是用于存放字符(char)的,所以就是BYTE。
Char p;用于BYTE类地址
Short p;用于WORD类地址
Int p;用于DWORD类地址
在这里,因为P是记录地址的变量,因此其都是4字节的。在汇编语言中,地址向ECX一样,用4字节的寄存器来指定,因此其也是4字节的。
4、内容4:深入理解指针:
在整个写入内存的函数(write_mem8)中,最关键的是 MOV BYTE [i],(i &0x0f),因此最关键的也是如下两条指令:
char
p;
p=i;
*p=i&0x0f;
如果将p假设为ECX寄存器的话,那么其相当于:
MOV ECX , I;
MOV BYTE [ECX],(i&0x0f);
先向ECX寄存器赋值,再向ECX号内存地址赋值。如果将两者的顺序调换的话:
MOV BYTE [ECX],(i&0x0f);
MOV ECX , I;
第一个MOV的时候,ECX的值不确定,是个随机数,这回导致i&0x0f的结果写入内存的某个不可知的地址中。
5、内容5:指针的应用
除了内容3中指针函数的写法之外,还有两种常见的写法:
在这里插入图片描述
在这里插入图片描述

需要注意的是,这里的P[i]并不是数组,其相当于(p+i),所以以下写法也是可以的。
在这里插入图片描述

6、内容6:色号设定
如果想描绘一个操作系统模样的画面,首先就是要处理颜色问题。这次使用的是320x200的8位色号模式,色号使用8位(二进制)数,也就是只能使用0-255的数。但一般指定颜色,都是采用#0xffffff一类的数,也就是RGB(红绿蓝)方式,用6位16进制数,也就是24位二进制数来指定颜色。
但该怎么指定#ffffff方式的颜色呢?
所谓的8位彩色模式,是由程序员随意指定0-255的数字所对应的颜色的,比如25 号颜色对应#ffffff,26号颜色对应#123456等,这种方式便是调色板。
要描绘一个操作系统模样的画面,只要有下述的16种颜色就够了。
在这里插入图片描述

要实现调用这16种色号,首先需要有
在这里插入图片描述

扫描二维码关注公众号,回复: 13188276 查看本文章

16种色号的编号函数即init+palette()。
该函数的结果就是声明了一个常数的table_rgb数组,拿char a[3]举例,其就相当于
a:
RESB 3
char a[3]={1,2,3}等价于
a[0]=1;
a[1]=2;
a[3]=3;
因此这里带入的char …[16*3]也就是相当于进行了上述的赋值。
因为前面所提到的,红绿蓝方式除了可以用6位16进制表示,还可以用24位二进制,在这里将其切割为3个2位16进制来表示,可以方便之后的调色板调用。
除此以外所添加的函数如下:
在这里插入图片描述

该函数就是由调色板访问步骤所产生的函数,其主要所做的事情是多次调用io_out8函数。那么io_out8函数是用来做什么的呢?其是向指定装置里传送数据的函数。
OUT指令与IN指令:
因为CPU不仅与内存相连,还与设备相连,那么就必须要有向这些设备发送电信号或者从这些设备中取得信息的指令。向设备发送电信号的是OUT指令,从设备取得电信号的是IN指令。
在这两个指令中,为了区别不同的设备,那么就需要使用设备号。当然,在C语言中能够没有与IN或者OUT指令相当的语句,因此只能通过汇编语言来实现。
而调色板的访问步骤为
在这里插入图片描述

其中CLI是将中断标志置为0的指令,而STI是将这个中断标志置为1的指令,其与CPU的中断处理有关系。当CPU遇到中断请求时,是立即处理中断请求(中断标志为1),还是忽略中断请求(中断标志为0),就由中断标志位决定。
而EFLAGS寄存器是由FLAGS的16位寄存器扩展而来的32位寄存器。FLAGS是存储进位标志和中断标志的寄存器。对于中断标志,没有类似的JI或者JNI指令,只能读入EFLAGS,再检查第9位是0还是1。
在这里插入图片描述

在set_palette函数中想要做的事情实在设定调色板之前首先执行CLI,但处理结束以后一定要恢复中断标志,因此需要记住最开始的中断标志是什么。
能用来读写EAFLAGS的指令只有PUSHFD和POPFD指令。
PUSHFD指令是将标志位的值按双字长压入栈,POPFD是按双字将标志位从栈弹出。即PUSHFD POP EAX 是指先将EAFLAGS压入栈,再将弹出的值代入EAX。另一方面,PUSH EAX POPFD正好相反。
再次make run,条纹图案没有变化,但是颜色变了。
实验结果:
在这里插入图片描述

7、内容7:绘制矩形
在画面模式中,画面上有320x200=64 000个像素。假设左上角点的坐标为(0,0),那么右下角的点的坐标为(319,199)那么像素坐标(x,y)对应的VRAM地址计算公式如下:
0xa0000+x+y*320
在根据上式计算像素地址,往该地址的内存里存放某种颜色的号码,那么画面上该像素的位置就出现相应的颜色,这样就画出了一个点。通过循环,便可以画出线与面。
在这里插入图片描述

实验结果:
在这里插入图片描述

二、遇到的问题及解决方法
1、问题1:为什么在该式中要除以4?
在这里插入图片描述

解决方法: 这是一种颜色调整,如果不除以4,显示的画面会变灰还有一些颜色无法显示。
除4和不除4的情况如下(上边是不除4的):
在这里插入图片描述
在这里插入图片描述

这里再测试一下其他颜色除4的区别
在网上随便找一种颜色比如这个(喜洋洋脖子上的蓝色)通过截图方式查看这个颜色的RGB值如图是15,118,170,然后添加到调色板在除4和不除4的情况下显示如图所示(上面是除4):
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

由此可以说明想要正确的得到想要的颜色RGB只能是0到63位,所以前两位置0,不使用。当读取时,将前2位视为0,所以6位即可,除以4表示右移两位。就不进行除法操作那个来说,就是调色板的原色,而进行了除法操作的都是相应色调降低了的。
三、程序设计创新点
1、描述创新点1,写一个画圆形的函数
现在教材上已经有了可以画出一个矩形的函数,但我们画图肯定不止要矩形,所以我们这里写一个可以画圆形的函数,函数代码如下:
color表示要画出圆的颜色(调色板上的色号)R表示圆的半径,x,y则表示圆心的坐标

在这里插入图片描述

现在画一个白色的圆试一下

在这里插入图片描述

看来还是比较成功的,如果想要画一个圆环的话只要在同一个圆心处再画一个半径较小的圆就行了,因为我们的操作系统现在还不能计算三角函数所以还不能随意画出扇形来。
2、描述创新点2,提取图片像素信息
现在显示的图片得我们一个像素一个像素的写进去,虽然有一些画图形的函数,但如果我们想将一张图片显示在我们的操作系统上,工作量实在是太大,那能不能通过把图片的每个像素的颜色信息读取出来(RGB)存到一个数组中然后在我们的操作系统上显示出来呢,不过我们现在的系统最多只有256中颜色而图片颜色的种类有256^3种是,远远不够的,所以我考虑显示一张黑白的图片,结果发生报错工作空间超了,因为我们的数组有(3202003)太大了
在这里插入图片描述

不过万幸,图片像素的提取还是成功的,代码如下:
在这里插入图片描述

在可执行文件的同一目录下放入名为1格式为jpg的图片,运行后可以生成存有像素信息的txt文件,运行结果如下:
在这里插入图片描述

3、描述创新点3,制作一个动画(进度条)
我们的操作系统肯定不能只有图片,我们可以想办法做出一个简单的动画出来
1,想要做出动画来,那肯定需要画与画之间的显示有间隔,那么我们就需要一个延时函数,延时函数很简单我们不需要精确的时间延时,那么我们跑一个比较长的循环即可
在这里插入图片描述

如图会循环n^2次

2,进行绘图,绘图的代码如下:
在这里插入图片描述

最终结果如下
在这里插入图片描述

四、实验心得体会
这次实验的前面部分是关于指针的操作,有以前的基础理解起来还是很快的,这次实验我最大的收获还是学会了图形的显示,也就是显示图片的原理,其他方面基本上都是基于像素点的描绘了,不过这次虽然由于我们系统空间限制,没有办法将图片直接显示出来(这个真亏,搞了半天结果颜色种类和空间大小限制了),不过也学会了如何将图片每一个像素的颜色信息导出来的方法,还算是很不亏吧。

猜你喜欢

转载自blog.csdn.net/qq_49327751/article/details/120873149