每天日志就是为了监督自己坚持下去的说,我又没人工置顶什么的,没办法在日志动态被显示了,没有别的任何的意图- -,想吐槽的就省省您珍贵的口水吧,我不敢浪费您时间。
在之前显示什么图像的时候都是直接的去在程序里标出 0xa0000啊什么的,(意图也就是将表示颜色啊,尺寸啊什么的数据写进显卡内存而已)。但是画面模式改变的时候会发生系统不能正常运行这样的问题。
“
因为C在设计的时候是认为的普通数值和指针数值是2种不同的数值,于是如果在C中要是不先转换类型就使用的话就会出现警告。那么如何解决这个问题呢:
p = (char *) i;就是实现了数据类型的转换,之前char *很眼熟。将数值变成了表示内存地址的整数。”
这是昨天的内容,放在这里也可以解释为什么写的是binfo = (struct bootinfo *)0xff0。
程序里面的(*binfo).scrnx本来应该写成 *binfo.scrnx,但是这么写的话编译的时候编译器会认为是*(binfo.scrnx)所以这里改成(*binfo).scrnx。
但是我们发现还有一种写法就是: binfo→scrnx,这种就叫做箭头标记方式。
OK,以上讲的都是指针写法的变幻,下面继续学习外部显示:
之前我们想实现显示的时候都是调用的BIOS函数,这次因为进入了32位的模式,所以我们不这么做。
显示字形状的数据叫做字体数据,font。有一种临时方案将这个字体数据写进程序里。
直接建立一个:
static char font_A[16] = {
0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
};
这是将显示的2进制的数据写成16进制的而已,C语言无法使用二进制记录数据,只能写成八进制或者十六进制。
下面制作显示函数:
void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
int i;
char *p, d /* data */;
for (i = 0; i < 16; i++) {
p = vram + (y + i) * xsize + x;
d = font[i];
if ((d & 0x80) != 0) { p[0] = c; }
if ((d & 0x40) != 0) { p[1] = c; }
if ((d & 0x20) != 0) { p[2] = c; }
if ((d & 0x10) != 0) { p[3] = c; }
if ((d & 0x08) != 0) { p[4] = c; }
if ((d & 0x04) != 0) { p[5] = c; }
if ((d & 0x02) != 0) { p[6] = c; }
if ((d & 0x01) != 0) { p[7] = c; }
}
return;
}
这段的理解就是,因为是8X16 的像素点,那么要执行16次,没次是要过8个像素点的。这里的0x80,0x40等等是要事先勾画好字母,然后对应像素点的位置的。就和单片机里点亮晶体管显示数字是一个道理。
下面就是显示多字体了。因为字体对应之后字母实在是太多了,于是就开始使用之前有人做好的。
使用方法没啥含量,书上步骤很清楚。
只是在使用的时候是要链接的,在C中使用的话只要extern char hankaku[4096]这样的说明就可以了,extern告诉编译器使用的外部的数据。
下面要是想显示字符串的话要一个字母一个字母显示实在是很麻烦,于是就可以搞一个函数显示字符串。
首先,字符串是按照顺序排列在内存里面然后结尾是0x00的字符编码,于是*S就是字符串前面的地址,然后使用*S就可以读取字符编码。
下面是如何显示变量值呢?可以使用sprintf函数,sprintf不是按照固定的格式输出,而是将输出的内容做为字符串写在内存里面。
下面直接就是写指针的显示了。(这么快就到这个了。。)OK,写出来的是不可移动的。
下面进入GDT和IDT的初始化了,之前提到的那个鼠标的光标是不可以移动的。那么怎么才可以移动呢?作者说了,首先要GDT和IDT初始化。
补充知识1:分段,segmentation.不就是段segment的再次n形式么。首先提到的是ORG,指引走向程序锁在的内存的地址。有个知识就是程序在执行的时候要是在内存里是重叠的话会发生内存地址冲突无法执行的问题,那么如何解决呢,就用了分段的做法,分页什么的先不说。分段就是将其分成很多个区域。每一个块就是block的首地址都可以作为0,那么就没啥问题了。
那么这个分段使用的是什么寄存器呢?段寄存器,segment register。16位的时候直接将地址X16 就可以了,但是这里是32位的所以我们使用的是 MOV AL,[DS:EBX],这里的DS是Data segment,这也就是为什么汇编语言一书讲到DS时是这么说的,用于存放程序设计的源数据或结果。CPU会在EBX上加上DS所表示的段的起始地址。即使省略了段寄存器的地址的话,也会自动认为是DS的地址。16,32位都适用。
但是为了表示一个段需要表示出段的大小,起始地址,管理属性。
CPU用8个字节表示这些信息。短号适用0~8191,因为CPU无法使用16位段寄存器的低3位,所以可以处理的也就是0~8191.
可以使用这么多段的话就定义8192个段好了,就需要8192X8个字节,就是64K,536个字节。但是CPU没有那么大的存储能力,于是这些信息都要存储在内存里。
GDT就是这个64K的数据。段的标号。然后将这部分东西在内存的地址和起始地址放在CPU内称作GDTR的特殊存储器中。global descriptor table register.OVER了~~~
当然这上面做的目的就是为了给程序在内存的工作腾出空间所做的分类标号工作。
哈哈哈哈哈~~这下GDT的含义我更清晰了~~还学到了什么是分段~~~~收获很大啊~哈哈哈哈~
下面就是IDT的内容了,IDT就是interrupt descriptor table的缩写。中断记录表。中断在单片机的时候就看到不少,这里不难理解。
鼠标啊这些设备可以给CPU中断信息,所以这里要用到这个。
IDT的作者留到下一天去看~好吧~那么今天就完成了~
还是有很多收获的~目前还在整理一些东西~总之加油继续学好了~