30天自制操作系统第4天(共17页).docx
《30天自制操作系统第4天(共17页).docx》由会员分享,可在线阅读,更多相关《30天自制操作系统第4天(共17页).docx(17页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、精选优质文档-倾情为你奉上操作系统实验日志学号姓名甘昆禄专业年级班级智能1601实验日期2018.10.17实验项目第4天:C语言与画面显示练习一、实验主要内容1、让C语言读写内存上次实验隐约知道画面显示与vram有关,但具体的对应关系未知。这次我们用C语言来改写vram看看。作者首先用了汇编语言辅助函数,用了简单的方法,便于我们理解。Naskfunc.nas中增加了一个函数可供C语言调用的函数_write_mem8,用于实现直接写入指定内存地址的语句。如果C语言中write_mem8(0x1234,0x56);语句, 则动作上相当于汇编的MOV BYTE0x1234,0x56。第一个数字在内
2、存里的存放地址ESP+4 ,下一个数字的存放就依次累加4。这里两个参数,一个地址,一个数据。汇编与C语言结合时能自由使用的寄存区只有EAX,ECX,EDX3个,其他寄存区用于记忆非常重要的值,只能读不能写。这段代码中还增加了INSTRSET指令,是用来告诉nask这个程序是给486使用的,不然会被默认解释成8086机器使用(偶尔使用)的标签(label)或者常数。C语言代码:void io_hlt(void);void write_mem8(int addr, int data);void HariMain(void) int i; for (int i = 0xa0000; i = 0xaf
3、fff; i+) write_mem8(i, 15); /*将数据15写入地址i*/ for(;) io_hlt(); 2、绘制条纹只需要在bootpack.c中修改写入值”15”为”i&0x0f”:write_mem8(i, i & 0x0f);对图形来说,0和1并不是作为数字来使用,重点是0和1 的排列方式。对于0和1的互相变化,有位运算”或”(OR)运算、”与”(AND)运算和”异或”(XOR)运算。这些我们在数字逻辑和离散数学里都学过。这样,写入的值就高四位变为0,其余不变。就这样,每隔16个像素,色号就反复一次。3、直接用C语言写内存用指针写。指针符号是”*”,*p中的p是地址,而*
4、p是p指向地址的内容。 使用*i = i * 0x0f可直接将i*0x0f写入i指向的内存地址中。 *i = i * 0x0f对应汇编的MOV i, ( i * 0x0f),但如果直接这样写就不清楚i到底是BYTE还是WORD还是DWORD。 由于MOV指令的两个对象必须是相同字节长度,即同类型(BYTE/WORD/DWORD),除非另一方是寄存器才可以省略。同理,在使用指针时需要事先声明它的类型,即指针所指向内容的类型。 char i是类似AL的1字节变量,short i是类似于AX的2字节变量,int i是类似于EAX的4字节变量。char p ; / 用于BYTE类地址 * / shor
5、t p; / 用于 WORD 类 地 址* / int p ; / 用于DWORD 类 地 址 * /以上指针中的p都是4字节,因为p是用于记录地址的变量。在汇编语言中,地址也像ECX一样,用4字节的寄存器来指定,所以也是4字节。p = i; /带入地址/ p = i & 0x0f; /这可以替代write_mem8(i, i&0x0f)*/在执行make run之后出现了“warning: assignment makes pointer from integer without a cast”这句话。在C语言中,普通数值和表示内存地址的数值被认为是两种不同的东西。如果将普通整数值赋给内存地
6、址变量就会有警告,可以在赋值的时候使用强制类型转换: p = (char * ) i; /*注意i的类型要和p类型一样*/指针应用p = (char *) 0xa0000; /*给地址变量赋值*/for (int i = 0; i = 0xffff; +i) *(p + i) = i & 0x0f;在声明p的时候给它赋值为写入内存的起始地址,之后i作为地址增量,由p+i来指定写入内存的地址。C语言中,*(p+i)还可以改写成pi这种形式:p = (char *) 0xa0000; /*给地址变量赋值*/for (int i = 0; i = 0xffff; +i) pi = i & 0x0f;
7、pi与*(p + i)意思相同 ,这两者的差距只有前者4个字符,后者6个字符。但是pi并不能说是数组,只是一个看起来像是数列的使用了地址变量的省略写法而已。加法运算可以交换顺序,于是(p+i)和(i+p),pi和ip,a2和2a都是一个意思,这更能说明它们与数组没有关系。4、调色板这次我们使用的是320*200的8位颜色模式,只有256种颜色,而计算机表示表示颜色时,都是用#ffffff一类的数,就是RGB表示法,可以表示256*256*256种颜色。那么我们现在8位数怎么表示颜色呢,其实我们这次只用到了16种。给每种颜色编上号码,像这样就可以使用了。再根据作者讲解修改完bootpack.c中
8、的代码后,作者以汇编的角度解说table_rgb的声明部分。RESB指令是“reserve byte”的略写预约字节,如果想要从当前位置向后空出3个字节来,并且填0,就可以用RESB 3在RESB 3前面加上地址就变成了:a: RESB 3与C语言中的char a3一个意思。但是汇编中RESB的内容能够保证是0,但是C语言不能保证,因此需要在这个声明后加上“=”,还可以写上数据的初始值。 如char a3 = 1, 2, 3; 即Char a3;a0 = 1;a1 = 2;a2 = 3;a是表示最初地址的数字,也就是说它被认为是指针。像上面两种声明方式,汇编时都是要用到赋值语句的,作者说这样很
9、浪费字节。而在声明前加上static就可以将汇编的RESB指令代替成DB指令,这样它在内存中的存储位置就变了,并且未初始化的全局静态变量会被程序自动初始化为0。而且在程序运行之前,static变量就会被初始化或者赋值。Io_out8函数,CPU如果只与内存相连,则只能完成计算和存储的功能。但CPU还要对键盘输入有响应,要通过网卡从网络取得信息,等等。这些设备会和CPU胡同电信号,为了区别这些设备,要使用设备号码(port)。向设备发送电信号的是OUT指令;从设备取得电信号的是IN指令。但在C语言中没有与IN和OUT相当的语句,所以需要用汇编语言来做。而代码中的0x03c8、0x03c9就是设备
10、号。最后代码如下:void set_palette(int static, 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, rgb0 / 4); io_out8(0x03c9, rgb1 / 4); io_out8(0x03c9, rgb2 / 4); rgb += 3; io
11、_store_eflags(eflags); /*复原中断许可标志*/ return;在调色板的访问步骤中的CLI指将中断标志置为0的指令,STI是将这个终端标志置为1的指令。本来上一次日志就想写这个EFLAGS的,这次又遇到了,就记下笔记吧。8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW),简称flag。flag和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义,而flag寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息。中断处理结束之后需要恢复中断现场,所以需要记住最开始的中断标志,所以io_load_efla
12、gs读取最初的eflags值,io_store_eflags恢复原来的值。这些都需要用汇编语言来实现。而CPU中并没有MOV EAX, EFLAGS之类的指令,能够用来读写EFLAGS的只有PUSHFD(push flags double-word,将标志位的值按双字压入栈)和POPFD(pop flags double-word,按双字长将标志位从栈弹出)指令_io_load_eflags: ; int io_load_eflags(void); PUSHFD ; 指PUSH EFLAGS POP EAX RET_io_store_eflags: ; void io_store_eflags
13、(int eflags); MOV EAX, ESP+4 PUSH EAX POPFD ; 指POP EFLAGS RET5、绘制矩形调色板弄好以后就可以画画了。在当前画面模式中有320x200(=64000)个像素。假设左上点的坐标是(0,0),右下点的坐标是(319,199),那么像素坐标(x, y)对应的VRAM地址应该这样计算:0xa0000 + x + y*320最终bootpack.c如下:/*在下面使用函数前需要先声明函数,相当于告诉C编译器,有一個函数在別的文件里*/ void write_mem8(int addr, int data);void io_hlt(void);v
14、oid 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);/*是函数声明卻不用 ,而用;,这表示的意思是:函数在別的文件中,你自己找一下吧!*/#define COL8_ 0#define COL8_FF00
15、00 1#define COL8_00FF00 2#define COL8_FFFF00 3#define COL8_0000FF 4#define COL8_FF00FF 5#define COL8_00FFFF 6#define COL8_FFFFFF 7#define COL8_C6C6C6 8#define COL8_ 9#define COL8_ 10#define COL8_ 11#define COL8_ 12#define COL8_ 13#define COL8_ 14#define COL8_ 15void HariMain(void) char *vram; int xs
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 30 自制 操作系统 17
限制150内