第4天:C语言与画面显示的练习

**一、实验主要内容
1、内容1:**用C语言实现内存写入
如果想要在画面上显示东西的话,那么只需要向内存中写入东西即可。但是C语言没有直接写入指定内存地址的语句,便需要采用汇编语言创建一个有这种功能的函数。
修改naskfunc.nas,向其添加部分代码:
30天自制操作系统(day4)
这个函数类似于C语言中的write_mem8(0x1234,0x56),其中addr是内存地址,data是数据,在这里指的是颜色的色号。
在C语言中如果用到了write_mem8函数,就会跳转到_ write_mem8。此时参数指定的数字就存放在内存里,分别是;
第一个数字的存放地址 [ESP+4]
第二个数字的存放地址 [ESP+8]
第三个数字的存放地址 [ESP+12]
第四个数字的存放地址 [ESP+16]
在指定内存地址的地方,需要使用32位寄存器。除此以外,还需要给naskfunc.nas增加一行,也就是INSTRSET指令,其是告知nask“这个程序是给486使用的”,如果见到EAX,会解释成寄存器名。如果不指定的话,会将其解释成标签,因为在老的CPU中,会用EAX来做标签。
修改C语言,添加循环函数,使其填充0xa0000-0xaffff的内存。
30天自制操作系统(day4)
这样的话,内存中能够全部写入了15,也就是全部像素的颜色都是第15种颜色,而第15种颜色是纯白,因此画面变成了白色。
实验结果:
30天自制操作系统(day4)

**2、内容2:**条纹图案
修改C语言中能够for循环的内容:
30天自制操作系统(day4)
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个像素,色号就会反复一次,便使得显示的结果为条纹图案。
实验结果:
30天自制操作系统(day4)

**3、内容3:**挑战指针
使用指针函数来替换write_mem8函数。
修改内容:
30天自制操作系统(day4)
其声明了变量P,并将地址编号赋给P,再将色号填入到内存地址中。
C编译器会认为P是地址专用变量,而且是用于存放字符(char)的,所以就是BYTE。
Char p;用于BYTE类地址
Short p;用于WORD类地址
Int p;用于DWORD类地址
在这里,因为P是记录地址的变量,因此其都是4字节的。在汇编语言中,地址向ECX一样,用4字节的寄存器来指定,因此其也是4字节的。
深入理解指针:
在整个写入内存的函数中,最关键的是 MOV BYTE [i],(i &0x0f),因此最关键的也是如下两条指令:
p=(char *)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的结果写入内存的某个不可知的地址中。

**4、内容4:*指针的应用(1)与(2)
除了内容3中指针函数的写法之外,还有两种常见的写法:
30天自制操作系统(day4)
30天自制操作系统(day4)
需要注意的是,这里的P[i]并不是数组,其相当于
(p+i)。

5、内容5:色号设定
如果想描绘一个操作系统模样的画面,首先就是要处理颜色问题。这次使用的是320x200的8位色号模式,色号使用8位(二进制)数,也就是只能使用0-255的数。但一般指定颜色,都是采用#0xffffff一类的数,也就是RGB(红绿蓝)方式,用6位16进制数,也就是24位二进制数来指定颜色。
但该怎么指定#ffffff方式的颜色呢?
所谓的8位彩色模式,是由程序员随意指定0-255的数字所对应的颜色的,比如25 号颜色对应#ffffff,26号颜色对应#123456等,这种方式便是调色板。
要描绘一个操作系统模样的画面,只要有下述的16种颜色就够了。
30天自制操作系统(day4)
要实现调用16种色号,首先需要有16种色号的编号函数。
30天自制操作系统(day4)
该函数的结果就是声明了一个常数的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进制写成这样的形式呢?
因为前面所提到的,红绿蓝方式除了可以用6位16进制表示,还可以用24位二进制,在这里将其切割为3个2位16进制来表示,方便之后的调色板调用。
除此以外所添加的函数如下:
30天自制操作系统(day4)
该函数就是由调色板访问步骤所产生的函数,其主要所做的事情是多次调用io_out8函数。那么io_out8函数是用来做什么的呢?其是向指定装置里传送数据的函数。
什么是OUT指令与IN指令?
因为CPU不仅与内存相连,还与设备相连,那么就必须要有向这些设备发送电信号或者从这些设备中取得信息的指令。向设备发送电信号的是OUT指令,从设备取得电信号的是IN指令。
在这两个指令中,为了区别不同的设备,那么就需要使用设备号。当然,在C语言中能够没有与IN或者OUT指令相当的语句,因此只能通过汇编语言来实现。
什么是调色板的访问步骤?
30天自制操作系统(day4)
那什么是CLI和STI?
CLI是将中断标志置为0的指令,而STI是将这个中断标志置为1的指令,其与CPU的中断处理有关系。当CPU遇到中断请求时,是立即处理中断请求(中断标志为1),还是忽略中断请求(中断标志为0),就由中断标志位决定。
什么是EFLAGS寄存器?
其是有FLAGS的16位寄存器扩展而来的32位寄存器。FLAGS是存储进位标志和中断标志的寄存器。对于中断标志,没有类似的JI或者JNI指令,只能读入EFLAGS,再检查第9位是0还是1。
30天自制操作系统(day4)
在set_palette函数中想要做的事情实在设定调色板之前首先执行CLI,但处理结束以后一定要恢复中断标志,因此需要记住最开始的中断标志是什么。
能用来读写EAFLAGS的指令只有PUSHFD和POPFD指令。
PUSHFD指令是将标志位的值按双字长压入栈,POPFD是按双字将标志位从栈弹出。即PUSHFD POP EAX 是指先将EAFLAGS压入栈,再将弹出的值代入EAX。另一方面,PUSH EAX POPFD正好相反。
再次make run,条纹图案没有变化,但是颜色变了。
实验结果:
30天自制操作系统(day4)

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

**二、遇到的问题及解决方法
1、问题1:**为什么在该式中要除以4?
30天自制操作系统(day4)
解决方法: 这可能是一种颜色调整,如果不除以4,显示的画面会变灰。大体意思就是说RGB只能是0到63位,所以前两位置0,不使用。当读取时,将前2位视为0,所以6位即可,除以4表示右移两位。就不进行除法操作那个来说,就是调色板的原色,而进行了除法操作的都是相应色调降低了的。如下:依次是除以2,除以4,除以6
30天自制操作系统(day4)
30天自制操作系统(day4)
30天自制操作系统(day4)

三、程序设计创新点
做个定格动画怎么样?
30天自制操作系统(day4)

相关文章: