《操作系统30天》-合川秀实-学习日志day4

用C语言实现内存写入(harib01a)

在naskfunc.nas添加部分:

_write_mem8:	; 
void write_mem8(int addr, int data);
	MOV		ECX,[ESP+4]		; [ESP+4]中存放的是地址,将其读入ECX
	MOV		AL,[ESP+8]		; [ESP+8]中存放的是数据,将其读入AL	
	MOV		[ECX],AL	
	RET

比如说:write_mem8( 0x1234,0x56)相当于MOV BYTE[0x1234],0x56如果C语言中用到了write_mem8函数,就会跳转到_write_mem8,此时参数指定的数字就存放在内存里,分别是:
第一个数字的存放地址:[ESP + 4]
第二个数字的存放地址:[ESP + 8]
第三个数字的存放地址:[ESP + 12]
第四个数字的存放地址:[ESP + 16]

与C语言联合使用,能自由使用的只有EAX,ECX,EDX。增加了[INSTRSET “i486p”],意思是这个程序给486用,古老的CPU会把EAX寄存器名会误认为是标签而不是寄存器。

CPU家谱中到286为止CPU是16位,386以后CPU是32位。8086->80186->286->386->486->Pentium->PentiumPro->PentiumII->PentiumIII->Pentium4->…本次的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();
	}
}

For循环中间条件可以省略,这样就是无限循环,命令窗口输入make run:
在这里插入图片描述

条纹图案

修改一下bootpack.c就可以了

 for (i = 0xa0000; i <= 0xaffff; i++) {  
 write_mem8(i, i & 0x0f); 
 } 

写入的值变成了i&0x0f,运用了与运算:
计算A OR B 时,每一位分别计算,AB对应的位只要有一位是1,结果就是1同理, A AND B运算只要有一位是0结果就是0,全1则1。异或计算时(A XOR B)同样每一位分别计算,AB对应位数值相同则为0,不同为1,异或运算实现数据的翻转。本次用的是“与”运算,将地址值与0x0f相与,第四位原封保留,高四位全部变成0,所以每16个像素翻转一次,出现了图案。
图案

挑战指针

Write_mem3( i , i & 0x0f); 代替=> *i =i & 0x0f;
在这里插入图片描述代替之后运行发现出错
相当于 MOV [ 0x1234], 0x56
出现类型错误,因为指定内存时,不知道是BYTE还是WORD,还是DWORD,只有在另一方也是寄存器的时候才能省略,其他情况下不能省略。
要告诉计算机我们用的是BYTE需要定义成
Char *p; //变量p是用于内存地址的专用变量声明这样的变量p,p内放入与i相同的值,然后执行
*p= i & 0x0f;这样编译器就可以成功识别p是地址专用变量,用来存放字符

  • Char *p; short *p; int *p;

分别用于存放BYTE \WORD\DWORD类型的地址但是变量p都是四个字节的,因为p是记录地址的变量。这样修改之后再运行,会出现条纹图案但是有一行警告
在这里插入图片描述
在这里插入图片描述

“赋值语句没有经过类型转换,由整数生成指针”这里的p是char类,而i是int型的所以两个在赋值的时候需要转换一下:
P=(char *) i;
改成这样C编译器不会弹出警告
在这里插入图片描述
在这里插入图片描述

色号设定

我们使用的是320×200的8位彩色模式,也就是用6位十六进制数来指定颜色(0-255色号这里是0-15色号 )。调色板:由程序员随意指定0-255的数字所对应的颜色,若不做任何设定,那么0号颜色->#000000,15号颜色->#ffffff。作者给出这次实验使用16种颜色(编号0-15)就可以绘制一个操作系统模样的画面:

#000000:黑 		
#00ffff:	  浅亮蓝		
#000084:暗蓝
#ff0000:	  亮红		
#ffffff:    白			
#840084:暗紫
#00ff00:  亮绿		
#c6c6c6:  亮灰			
#008484:浅暗蓝
#ffff00:   亮黄		
#840000:暗红			
#848484:暗灰
#0000ff:  亮蓝		
#008400:暗绿
#ff00ff:   亮紫		
#848400:暗黄

本次的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] = {/*  static *//*  unsigned */		
	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;
}

关于0x03c7、0x03c8、0x03c9设备号码的理解:
作者给出的网页中“video DA converter”记述调色板的访问顺序:

  • 首先在一连串的访问中屏蔽中断(CLI)
  • 将想要设定的调色板号码写入0x03c8,再按照R,G,B的顺序写入0x03c9,如果继续设定下一个调色板,则省略调色板号码,再按照RGB的顺序写入0x03c9即可
  • 若想读取当前调色板状态,要将调色板的号码写入0x03c7,再从0x03c9读取3次,R G
  • B的顺序读出,若继续读出下一个调色板,同样省略调色板号码的设定,按顺序读出
  • 如果最初执行了CLI,那么最后要执行STI(还原中断标志位)CLI:将中断标志置为0,STI:将中断指令置为1Set_palette中要在设定调色板之前首先执行CLI,处理之后要恢复中断标志,所以上面的函数中要先记录初始的中断标志,设定之后再还原中断标志位。
    EFLAGS寄存器(书本):
    在这里插入图片描述
    进位标志可以通过JC或者JNC等跳转指令来判断0还是1;但是对于中断标志,没有类似的指令,只能读入EFLAGS来检查第九位是0还是1。书本上只给了16位寄存器的内容,可以百度一下32位寄存器保存的值:
    在这里插入图片描述
    CF:(进位标志)=1算术操作最高位产生了进位或借位 =0 最高位无进位或借位
    PF:(奇偶标志位)=1数据最低8位中1的个数为偶数 =0 数据最低8位中1的个数为奇数
    AF:(辅助进位标志) =1 D3→D4位产生了进位或借位 =0 D3→D4位无进位或借位
    ZF:(零标志) =1 操作结果为0 =0 结果不为05
    SF:(符号标志) =1 结果最高位为1 =0 结果最高位为0
    OF:(溢出标志) =1 此次运算发生了溢出 =0 无溢出

绘制矩阵

本次加入两个部分一个是矩阵函数,一个是调用矩阵函数显示三个矩阵:
主函数部分:加入三行显示矩阵的代码,boxfill8函数传的参数分别是(地址,x坐标的最大值,颜色,x坐标的起始值,y坐标的起始值,x坐标的结束值,y坐标的结束值),比如说下面的boxfill8(p, 320, COL8_FF0000, 20, 20, 120, 120);就可以表示为在p中的像素点x坐标取值范围(0-320),选定的是COL8_FF0000(对应上面的颜色表表示亮红色)亮红色,从点(20,20)开始到(120,120)成一个矩阵填充,如下测试所示。

void HariMain(void){	char *p; /* 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();
	}
}

下面是这个函数部分,我们要实现的是二维的一个坐标点,但实际上存储每个像素的地址是一个一维的地址空间,我们要利用下面的公式进行转换(具体在遇到的问题2中有详细理解),先循环用点画出行,再循环用行画出一个矩阵,这就是下面函数的意思。

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;
}

最后的结果图,可以自己改变颜色
在这里插入图片描述

1、 最后成果图最后显示的东西添加了很多显示部分,都是显示矩阵,但是有叠加和组合,这样就可以显示想要的东西,用编号来一一对应起来在图中标出:
① 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);
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值