结构体

  • 接收启动区信息:从asmhead.nas中用指针获取VRam的地址(0xa0000),xsize,ysize等值;把前一天的背景显示部分(最后绿色的矩阵图)做成一个函数独立出来(init_screen)。
void init_screen(char *vram, int x, int y)
void HariMain(void)
{char *vram;int xsize, ysize;short *binfo_scrnx, *binfo_scrny;int *binfo_vram;init_palette();binfo_scrnx = (short *) 0x0ff4;  //x=320binfo_scrny = (short *) 0x0ff6;  //y=200binfo_vram = (int *) 0x0ff8;    //varm=0xa0000xsize = *binfo_scrnx;ysize = *binfo_scrny;vram = (char *) *binfo_vram;init_screen(vram, xsize, ysize);for (;;) {io_hlt();}
}
  • 做成结构体
  • 相当于把每个像素点作为一个点来处理,每个点有对应的x,y值、地址、柱面(启动区)、led灯的状态、还有显示模式,结构体命名为BOOTINFO,包含了12字节(4个char+2个short+一个4字节地址):
struct BOOTINFO {char cyls, leds, vmode, reserve;short scrnx, scrny;char *vram;
};
需要用到结构体中的值时,指针都是表示成“(*名字).变量” 的格式:binfo = (struct BOOTINFO *) 0x0ff0;  //表示结构体从这个地址开始xsize = (*binfo).scrnx;ysize = (*binfo).scrny;vram = (*binfo).vram;
箭头
上面的(*binfo).scrnx简化成binfo->scrnx,再省略中间变量xsize,ysize:
struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;init_palette();init_screen(binfo->vram, binfo->scrnx, binfo->scrny);

显示字体

字符用8x16的长方形像素点来表示:8“位”是一个字节,1个字符是16个字节。

  1. 描述A字体的数据(实际是16个八位二进制数的16进制表示):
static char font_A[16] = {0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00};
  • 上面的函数只能显示A字体,结合与运算原理,再用一个for循环循环16行,每次比较八位中的1位是否需要显示(从第一列开始到最后一列),16次之后就可以显示一个字符。0x80换成2进制就是1000000,0x40换成2进制就是01000000,那么00011000与00010000比较时P[3]就会描上颜色。P=varm+(y+i)*xsize+x的理解是把这个首地址存到p中,p[1]就表示首地址的下一个,以此类推,赋的值对应的是颜色,font是对应的上面那个字体的数据。
  • 函数编辑之后要在程序前部声明函数,在主函数中直接调用函数就可以了(颜色可以直接用数字传 COL8_FFFFFF ->7):
    putfont8(binfo->vram, binfo->scrnx, 10, 10,7, font_A);
    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;
    }

    Make run 结果:

显示字符串

  • 用OSASK字体,将hankaku.txt文本(256个字符文本,16x256=4096字节)用makefont.exe工具编译生成hankaku.bin文件,再由bin2obj.exe来转换成目标程序,相当于将源程序转换成汇编,实现:

_hankanku:

DB 各种数据(4096字节)

  • 可以修改hankaku.txt的值来修改显示的字体内容,关于生成hankaku的各种文件在Makefile中都有记录(见下图介绍)。

  • 字库文件的链接:字库文件是一个TXT文件,需要一些工具把他编译链接到我们的程序中,由Makefile文件的依赖关系得出下图:

在C中使用字体数据要加上extern char hankaku[4096];像这种在源程序以外准备的数据,都需要加上externa属性(代码中红色字体)。让编译器知道它是外部数据,并在编译时做出相应调整。

另外OSASK的字体数字是依照ASCII字符编码顺序,同样含256个字符。直接查询每个字符的ASCII码对应的十六进制数就可以得出那个字符,比如‘A’字符的十六进制为0x41。那么这个字体的数据就放在“hankaku+0x41*16”开始的16字节里。也可以直接用A代替

0x41->”hankaku + 'A' * 16”。
void HariMain(void)
{struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;extern char hankaku[4096];init_palette();init_screen(binfo->vram, binfo->scrnx, binfo->scrny);  /*显示字符部分*/putfont8(binfo->vram, binfo->scrnx,  8, 8, COL8_FFFFFF, hankaku + 'A' * 16);putfont8(binfo->vram, binfo->scrnx, 16, 8, COL8_FFFFFF, hankaku + 'B' * 16);putfont8(binfo->vram, binfo->scrnx, 24, 8, COL8_FFFFFF, hankaku + 'C' * 16);putfont8(binfo->vram, binfo->scrnx, 40, 8, COL8_FFFFFF, hankaku + '1' * 16);putfont8(binfo->vram, binfo->scrnx, 48, 8, COL8_FFFFFF, hankaku + '2' * 16);putfont8(binfo->vram, binfo->scrnx, 56, 8, COL8_FFFFFF, hankaku + '3' * 16);for (;;) {io_hlt();}
}

加入显示字符的代码Makerun之后得出ABC 1236个字符:

为了减少代码,作者写了一个显示字符串的函数。For循环中的判断是判断s是否结尾(C语言中,字符串以0x00结尾),所以s是指字符串前头的地址,而使用*s就可以读取字符编码(那个地址):

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{extern char hankaku[4096];for (; *s != 0x00; s++) {putfont8(vram, xsize, x, y, c, hankaku + *s * 16);x += 8;}return;
}

整理一下主函数,显示字符 "Haribote OS."调用了两次函数:

void HariMain(void)
{struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;init_palette();init_screen(binfo->vram, binfo->scrnx, binfo->scrny);putfonts8_asc(binfo->vram, binfo->scrnx,  8,  8, COL8_FFFFFF, "ABC 123");putfonts8_asc(binfo->vram, binfo->scrnx, 31, 31, COL8_000000, "Haribote OS.");putfonts8_asc(binfo->vram, binfo->scrnx, 30, 30, COL8_FFFFFF, "Haribote OS.");for (;;) {io_hlt();}
}

结果:

  • 显示变量值(sprintf函数):

sprintf函数和printf函数的区别在于它不是按指定格式输出,只是将输出内容作为字符串 卸载内存中,另外sprintf函数只对内存进行操作,所以在所有的操作系统都适用。

sprintf函数的格式:sprintf(地址,格式,值,值,值,……)

这里的地址指定所生成字符串的存放地址。格式基本上只是单纯的字符串,如果有%的这 类标记,就置换成后面的值的内容。除了%d(将数值作为十进制数转化为字符串)还 有%s,%x(将数值作为十六进制转化为字符串)等符号。

  • 在C语言中使用sprintf函数需要加上#include<stdio.h>这句话:

sprintf(s, "scrnx = %d", binfo->scrnx);

putfonts8_asc(binfo->vram, binfo->scrnx, 16, 64, COL8_FFFFFF, s);

  • 以上两句是输出scrnx=320的代码,那为什么sprintf....这个函数不能一步直接输出来?因为sprintf函数并没有实现输出功能,实现输出的是下面的putfonts8_asc函数,sprintf函数只是先把binfo->scrnx这个值赋给scrnx,再把scrnx=320这个式子放到地址s里面。下一句用函数putfonts8_asc就是输出s的代码。

显示鼠标指针

  • 鼠标整体大小定为16x16,先准备16*16=256字节的内存,然后往里面写入指针的数据。将这个程序写在函数里面,mouse是像素地址,bc是背景色:
void init_mouse_cursor8(char *mouse, char bc)
/*准备鼠标指针(16x16)*/
{static char cursor[16][16] = {"**************..","*OOOOOOOOOOO*...","*OOOOOOOOOO*....","*OOOOOOOOO*.....","*OOOOOOOO*......","*OOOOOOO*.......","*OOOOOOO*.......","*OOOOOOOO*......","*OOOO**OOO*.....","*OOO*..*OOO*....","*OO*....*OOO*...","*O*......*OOO*..","**........*OOO*.","*..........*OOO*","............*OO*",".............***"};int x, y;   //鼠标的各个颜色for (y = 0; y < 16; y++) {for (x = 0; x < 16; x++) {if (cursor[y][x] == '*') {mouse[y * 16 + x] = COL8_000000;}if (cursor[y][x] == 'O') {mouse[y * 16 + x] = COL8_FFFFFF;}if (cursor[y][x] == '.') {mouse[y * 16 + x] = bc;}}}return;
}
背景色部分(16*16中除鼠标箭头外), pxsize, pysize表示鼠标大小(16X16)  px0, py0表示鼠标头所在的坐标 buf是像素地址(上面那个鼠标的每一个点), bxsize表示每行有16个像素。
void putblock8_8(char *vram, int vxsize, int pxsize,int pysize, int px0, int py0, char *buf, int bxsize)
{int x, y;for (y = 0; y < pysize; y++) {for (x = 0; x < pxsize; x++) {vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];}}return;
}
主函数中调用:
void HariMain(void)
{struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;char s[40], mcursor[256];int mx, my;init_palette();init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);mx = (binfo->scrnx - 16) / 2;        /* 鼠标头所在的位置 */my = (binfo->scrny - 28 - 16) / 2;init_mouse_cursor8(mcursor, COL8_008484);putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);sprintf(s, "(%d, %d)", mx, my);        /*显示鼠标的坐标值*/putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);for (;;) {io_hlt();}
}

GDT与IDT的初始化

  • 让鼠标动起来需要将GDT和IDT初始化,他们都是与CPU有关的设定,是为了让操作系统能够使用32位模式,需要对CPU做各种设定。

GDT: Global(segment) Descriptor Table 全局段号记录表

IDT: Interrput Descriptor Table 中断记录表

  • 为了解决内存范围重叠使用的问题,需要对内存进行分段(即对GDT进行初始化)。
  • IDT记录了0~255的中断号码与调用函数的对应关系。
  • 分段:将合计4GB的内存分成很多块(block),每一块的起始地址都看做0来处理。如前面提到的ORG指令明确声明程序要读入的内存地址。这里的分段使用的是前面讲到过的段寄存器(16位),“MOV AL,[DS:EBX]”指令中的DS表示的是段的起始地址(一般省略,默认DS)。为了表示一个段,需要以下信息:
  1. 段的大小是多少
  2. 段的起始地址在哪里
  3. 段的管理属性(禁止写入,禁止执行,系统专用等)
  • CPU用8个字节的数据来表示这些信息。段寄存器只有16位,远远不足。为了解决这个问题,模仿图像调色板的做法:段寄存器中保存段号,再预先设定好段号与段的对应关系。CPU设计原因,段寄存器低三位不能用,能够处理的就只有位于0~8191的区域。即可以定义8191个段,设定这么多段就需要8192x8=65536字节(64KB)。这64KB的数据就称为GDT,“global(segment) description table”的缩写,意思是全局短号记录表。将这些数据整齐地排列在内存的某个地方,然后将内存的起始地址和有效设定个数放在CPU内被称作GDTR的特殊寄存器中。
  • IDT是“interrupt description tabel”的缩写,表示“中断记录表”,用来执行CPU的中断功能。各个设备有变化是就产生中断,中断发生后,CPU暂时停止正在处理的任务,保存现场,转而执行中断程序,执行完毕之后恢复现场。

总结来就是要使用鼠标就需要中断机制,所以必须设定IDT。IDT记录了0~255的中断号码与调用函数的对应关系,其设定方法与GDT很相似。

《操作系统30天》-合川秀实-学习日志day5相关推荐

  1. c语言学习日志 day5

    输入1~n内9的个数 #include<stdio.h> int main() {  int n;  int i,k,a,m=0;  printf("input n\n" ...

  2. 合川专升本计算机怎么学升学率,2019年重庆市合川太和中学高考喜报

    2019年重庆市合川太和中学高考喜报 重庆合川太和中学运动场 太和中学2019年高考捷报 1.重本上线191人,飞行员1人,再创太中历史新高; 2.600分以上11人,遥居合川同类学校第一; 3.刘国 ...

  3. JavaWeb-综合案例(用户信息)-学习笔记02【登录功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb-综合案例(用户信息)-学习笔记01[列表查询] JavaWeb-综合案例(用户信息)-学习笔记02[登录功能] JavaWeb-综合案 ...

  4. 红旗系统是不是linux,红旗linux操作系统是Linux吗?我想学习Linux,已经按完红旗的了、不知道是不是Linux,有没有被红旗改变过。还能按正常的方式学吗?...

    红旗linux操作系统是Linux吗?我想学习Linux,已经按完红旗的了.不知道是不是Linux,有没有被红旗改变过.还能按正常的方式学吗? 更新时间:2019-10-23 17:07 最满意答案 ...

  5. 招商头条:上海2020年将建成国际金融中心;重庆合川签约22个项目

    大数据招商内参第011期 01.区域洞察 青岛出台新政扶持重点企业最高奖5000万 为贯彻<关于落实支持新旧动能转换重大工程财政政策的实施意见>,有效落实财源建设扶持政策,激励企业加快转型 ...

  6. Deepin深度操作系统小问题合集

    Deepin深度操作系统小问题合集 前言 在19年初的时候时候就尝试安装deepin来玩了,但是那时候的版本好像有点卡. 我在19年上半年的时候折腾了好一会ubuntu,不想再折腾了,自己的小主机cp ...

  7. JavaWeb-综合案例(用户信息)-学习笔记06【复杂条件查询功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb-综合案例(用户信息)-学习笔记01[列表查询] JavaWeb-综合案例(用户信息)-学习笔记02[登录功能] JavaWeb-综合案 ...

  8. JavaWeb-综合案例(用户信息)-学习笔记05【分页查询功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb-综合案例(用户信息)-学习笔记01[列表查询] JavaWeb-综合案例(用户信息)-学习笔记02[登录功能] JavaWeb-综合案 ...

  9. JavaWeb-综合案例(用户信息)-学习笔记04【删除选中功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb-综合案例(用户信息)-学习笔记01[列表查询] JavaWeb-综合案例(用户信息)-学习笔记02[登录功能] JavaWeb-综合案 ...

最新文章

  1. Prime Path(bfs)广度优先搜索
  2. AT24C02的多字节数据读写
  3. 基于Nexys4 DDR的VGA显示图片
  4. 禁止IE页面自动跳转到EDGE浏览器的方法教程
  5. tensorflow windows
  6. CenOs6.3下博通BCM4313无线网卡驱动
  7. Javascript的数组对象
  8. idea 编译内存溢出
  9. 【待续】C数据结构2.3-顺序表之插入算法
  10. 北科大计算机顺德,北京科技大学顺德研究生院2020考研预调剂信息
  11. OC开发实例变量的访问控制详解
  12. ubuntu1604 grep sed 正则表达式
  13. (C++)输入两个正整数m和n,求其最大公约数和最小公倍数(辗转相除法)
  14. 3秒教会你在线制作选项卡图标ico
  15. 打开本地html加载网页慢,电脑检查网速正常但打开网页慢如何解决
  16. 国漫的又一次崛起?形成独树一帜的“中国学派”
  17. 工商银行网上支付开发
  18. 【three.js】3D模型创建 + 模型弹框 + 动画效果
  19. Android app 内存分配
  20. mp4转换成gif怎么转?

热门文章

  1. 牛客小白月赛27部分题解(持续更新)
  2. java计算机毕业设计小学生素质成长记录平台源码+lw文档+系统+数据库
  3. 学PHP培训地址,杭州余杭区php培训班地址(PHP是什么)
  4. LOL种刀妹如何对线盖伦?
  5. wegame每次登陆都要滑动验证_wegame一直在验证账号密码【解决方法】
  6. WAR3 天地劫技能节选003
  7. 黑带的含义与责任--献给每一位成为黑带或者即将成为黑带的一篇文章,其中也包括我
  8. 记一位美术变成开发者的经历
  9. 1342. 将数字变成 0 的操作次数 / 1507. 转变日期格式
  10. 开源资产/漏洞管理平台使用测评