harib11a--harib11c:
  继续测试性能:我们在harib10h中进行了定时链表结构的改进“消除了移位处理”。下面我们设定490个定时器(它们都被设定启动50天才超时)来测试一下改进的效果。我们首先编写函数set490()来初始化490个定时器,接着测定他们在真机上的运行结果。分别运行5次,取平均值归纳如下:

(1)追加490个定时器的值set490(&fifo,1);
  harib11a:0096521077......harib10g里加入set490(有移位)
  harib11b:0096522038......harib10h里加入set490(没有移位(链表),没有哨兵)
  harib11c:0096522097.......harib10i里加入set490(没有移位(链表),有哨兵)
(2)不追加490个定时器的值set490(&fifo,0);
  harib11a:0096522095......harib10g里加入set490(有移位)
  harib11b:0096522038......harib10h里加入set490(没有移位(链表),没有哨兵)
  harib11c:0096522101.......harib10i里加入set490(没有移位(链表),有哨兵)
(3)参考:不加入set490()语句的时候
  harib10g:0099969263(有移位)
  harib10h:0099969184(没有移位(链表),没有哨兵)
   harib10i:0099969264(没有移位(链表),有哨兵)

  测试结果分析:从上面的结果,我们可以看出,把定时器组织成链表的结构、在链表中加入“哨兵”都有利于系统的改进。对于(2)和(3),在HariMain中,循环执行“count++”的for语句虽然都最终被编译成JMP指令,但是如果前面加上了“set490(&fifo,0)”那么以后各个指令的地址都会相应的错开几个字节,造成JMP指令的地址有很小的变化。因此时间也稍稍延迟,执行结果大约差了3%。

void set490(struct FIFO32 *fifo, int mode)
{  //定时器设置函数SET490()
int i;
struct TIMER *timer;    //一个TIMER结构体临时变量
if (mode != ) {      //mode不为0;创建490个定时器
for (i = ; i < ; i++) {
timer = timer_alloc();      //分配一个定时器的空间,并获得地址
timer_init(timer, fifo, + i);//第i个定时器的数据为1024+i写入FIFO缓冲区
timer_settime(timer, * * * * + i * );//设置时间(笔者所说的50天)
}
}
return;
}

harib11d:
  VBE介绍:由于市面上显卡公司繁多,各个显卡公司在显卡上对画面模式的设定和使用方法各不相同(就是乱七八糟的显卡没有一个统一的标准)。鉴于此,成立了一个VESA协会(Video Electronic Standards Association 视频电子标准协会)这个协会制定了几乎可以通用的画面模式设定方法,制作了专门的BIOS。这个追加的BIOS被称作“VESA BIOS extension”(VESA-BIOS的扩展,简称VBE)利用它,可以提高显卡的分辨率。
  VBE模式号码:(注:QEMU模拟器中不能指定VBE的0x107号)
    0x101......640  *480  *8bit彩色
    0x103......800  *600  *8bit彩色
    0x105......1024*768  *8bit彩色
    0x107......1280*1024*8bit彩色

//例子:设定VBE的640**8bit真彩色模式
MOV BX,0x4101     ; BX = 0x4000 + VBE模式号码
MOV AX,0x4f02     ; AX = 0x4f02(这个是固定值)
INT 0x10      ; 调用0x10(2号)中断
MOV BYTE [VMODE], ; 记录画面模式的信息(关于画面模式信息,请看下一部分)
MOV WORD [SCRNX],   ; x分辨率
MOV WORD [SCRNY],   ; y分辨率
MOV DWORD [VRAM],0xe0000000; VRAM地址

harib11e:
  上一步,我们已经成功在QEMU模拟器上改变了系统的分辨率。接下来,我们想看看在真机上是否也能运行。因为我们不确定真机上是什么显卡(如果机器上显卡公司没有参与VESA,那么就不能使用VBE了)。笔者在这里主要是想让我们明白VBE的原理,虽然没什么卵用,它只是显卡公司通用的一个规则而已。但认真看理解了还是会有收获的!下面我们一步一步确认。

  1、确定VBE是否存在
   方法介绍:如果显卡能利用VBE,那么VBE的信息都写在从ES:DI开始的连续512字节中的(这是规定!)。令ES = 0x9000; DI = 0;AX = 4f00; 在调用0x10中断,如果有VBE,AX就会变成0x004f(不要问为什么,这是检查规则!)

;确认VBE是否存在
MOV AX,0x9000;
MOV ES,AX   ;ES = 0x9000
MOV DI,0    ;DI = 0
MOV AX,0x4f00 ;AX = 4f00
INT 0x10   ;调用0x10中断
CMP AX,0x004f;比较
JNE scrn320 ;不相等跳转AX!=0x004f

  2、检查VBE的版本

;如果VBE版本不是2.0以上,一样不能用高分辨率。
MOV AX,[ES:DI+]
CMP AX,0x0200
JB scrn320 ; if (AX < 0x0200) goto scrn320

  3、获得某个画面模式的信息
    调用0x10中断后,会将画面模式信息保存在ES:DI开始的256字节中。在画面模式信息中,重要的信息由以下6个:
    WORD     [ES : DI+0x00]:模式属性....第7位不为1(+0x4000)
    WORD     [ES : DI+0x12]:x的分辨率
    WORD     [ES : DI+0x14]:y的分辨率
    BYTE       [ES : DI+0x19]:颜色数....必须为8
    BYTE       [ES : DI+0x1B]:颜色的指定方法....必须为4(4是标色板模式)
    DWORD   [ES : DI+0x28]:VRAM的地址

;这里获得VBE号为0x105的画面模式信息  : VBEMODE EQU 0X105
MOV CX,VBEMODE
MOV AX,0x4f01
INT 0x10
CMP AX,0x004f
JNE scrn320

  4、画面模式信息的确认

;下面确认三个信息:颜色数、调色板模式、模式属性BIT7
CMP BYTE [ES:DI+0x19],8 ;确认颜色数是否为8
JNE scrn320
CMP BYTE [ES:DI+0x1b],4 ;确认调色板模式是否为4
JNE scrn320
MOV AX,[ES:DI+0x00]   ;确认模式属性bit7为1
AND AX,0x0080
JZ scrn320

  5、画面模式切换

;上面都确认无误,可以进行模式切换(其实上面的确认是多次一举,主要是笔者想让我们理解VBE)
MOV BX,VBEMODE+0x4000 ;BX = 0x4000 + VBE模式号码
MOV AX,0x4f02      ;AX = 0x4f02(固定值)
INT 0x10       ;调用0x10中断
MOV BYTE [VMODE], ; 记下画面模式
MOV AX,[ES:DI+0x12] ; X分辨率
MOV [SCRNX],AX
MOV AX,[ES:DI+0x14] ; Y分辨率
MOV [SCRNY],AX
MOV EAX,[ES:DI+0x28] ; VRAM地址
MOV [VRAM],EAX
JMP keystatus     ; 跳到键盘的BIOS

  6、最后一步320*200的默认画面

scrn320:
MOV AL,0x13 ; VGA图像,320*200
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE], ; 记录画面模式信息
MOV WORD [SCRNX],
MOV WORD [SCRNY],
MOV DWORD [VRAM],0x000a0000

harib11f:
  键盘上的键按下和弹起都会有一个8位的键值。弹起的键值为松开的键值+0x80;至于键盘按下键的键值表,可以看书本的P273,也可以自行上网搜索。下面我们实现按下A键时,显示字母A。“保留?”指的是还未分配的键值,为以后键盘做准备。

void HariMain(void)
{ //.......
i = fifo32_get(&fifo);//从缓冲区获取中断信息
io_sti();
if ( <= i && i <= ) {    /* 如果是键盘中断 */
sprintf(s, "%02X", i - ); //显示按下的键的键值
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, s, );
if (i == 0x1e + ) {    //如果按下的键值是0xle(A键)在窗口图层显示“A”
putfonts8_asc_sht(sht_win, , , COL8_000000, COL8_C6C6C6, "A", );
}
}
//......
}

harib11g:
  这里我们进一步改进,在键盘上按下键时,在窗口上显示相应的字符。方法:首先建立一个键盘字符表,将常用的字符放在里面,接着每按下一个键,根据键值相对字符‘0’的偏移,在表中寻找字符,然后输出到窗口即可。

static char keytable[0x54] = {//字符表
, , '', '', '', '', '', '', '', '', '', '', '-', '^', , ,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', , , 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', , , ']', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', ',', '.', '/', , '*', , ' ', , , , , , ,
, , , , , , , '', '', '', '-', '', '', '', '+', '',
'', '', '', '.'
};
if ( <= i && i <= ) {      /* FIFO中取出的额是键盘中断的数据 */
sprintf(s, "%02X", i - );   //在背景图层显示键值
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, s, );
if (i < + 0x54) {
if (keytable[i - ] != ) {//在字符表中索引,输出相应的字符
s[] = keytable[i - ];
s[] = ;
putfonts8_asc_sht(sht_win, , , COL8_000000, COL8_C6C6C6, s, );
}
}
}

harib11h:
  这里我们来做一个好玩的东西。在键盘上敲字符,然后输入到窗口中。像一个小的记事本一样的。直接上代码,我们修改bootpack.c中的内容。

//HariMain节选
for (;;) {
io_cli();
if (fifo32_status(&fifo) == ) {//缓冲区没有内容,
io_stihlt();         //CPU等着中断
} else {
i = fifo32_get(&fifo);   //获取缓冲区中断的内容
io_sti();
if ( <= i && i <= ) {                  /* 得到的是键盘的数据 */
sprintf(s, "%02X", i - );              //把键盘的键值输出到背景图层
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, s, );
if (i < 0x54 + ) {                  //获得的键值是一般的字符
if (keytable[i - ] != && cursor_x < ) { /* 字符键值没有超出字母表的范围,而且当前窗口已输入字符少于16个(144/8) */
s[] = keytable[i - ];           //HASH字符表keytable
s[] = ;                    //把字符输出到窗口图层中
putfonts8_asc_sht(sht_win, cursor_x, , COL8_000000, COL8_FFFFFF, s, );
cursor_x += ;                 //光标的位置向后移动8个像素(一个字符宽8个像素)
}
}
if (i == + 0x0e && cursor_x > ) { /* 按下的是Backspace,并且光标没有到行首 */
                    /* 在光标后面的一个字符用‘ ’覆盖 */
putfonts8_asc_sht(sht_win, cursor_x, , COL8_000000, COL8_FFFFFF, " ", );
cursor_x -= ;            //光标的位置迁移8个像素
}
/* 再次显示和刷新光标 */
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, , cursor_x + , );
sheet_refresh(sht_win, cursor_x, , cursor_x + , );
} else if ( <= i && i <= ) {           /* 获取的是鼠标动作的数据 */
if (mouse_decode(&mdec, i - ) != ) {     //获得鼠标数据放在MEDC中
sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);//把鼠标数据的X,Y坐标输出来
if ((mdec.btn & 0x01) != ) {//点击左键,
s[] = 'L';
}
if ((mdec.btn & 0x02) != ) {//点击右键
s[] = 'R';
}
if ((mdec.btn & 0x04) != ) {//按下滚轮
s[] = 'C';
}
//显示字符串S
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, s, );
mx += mdec.x;//鼠标移动到新的位置,不断跟新鼠标的坐标
my += mdec.y;
if (mx < ) {//这几个是判断鼠标坐标的范围,不能超出窗口图层的范围
mx = ;
}
if (my < ) {
my = ;
}
if (mx > binfo->scrnx - ) {
mx = binfo->scrnx - ;
}
if (my > binfo->scrny - ) {
my = binfo->scrny - ;
}
sprintf(s, "(%3d, %3d)", mx, my);//把新的鼠标坐标的位置输出
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, s, );
sheet_slide(sht_mouse, mx, my); //接着调用图层移动函数,把窗口移动到鼠标点击的位置
}
} else if (i == ) {            /* 10秒定时器超时,在背景图层显示"10[sec]" */
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, "10[sec]", );
} else if (i == ) {            /* 3秒定时器超时,在背景图层显示"3[sec]" */
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, "3[sec]", );
} else if (i <= ) {            /* 光标定时器超时 */
if (i != ) {
timer_init(timer3, &fifo, ); /* 初始化光标定时器,设置光标颜色白色 */
cursor_c = COL8_000000;
} else {
timer_init(timer3, &fifo, ); /* 初始化光标定时器,设置光标颜色黑色 */
cursor_c = COL8_FFFFFF;
}
timer_settime(timer3, );     //接着设定光标定时器的时间50次计数
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, , cursor_x + , );
sheet_refresh(sht_win, cursor_x, , cursor_x + , );//刷新。count每计数50光标闪烁一次。
}
}
}

harib11i:
  这里我们使用鼠标来完成窗口的移动吧!还记得我们前面创建的图层移动函数sheet_slide()吗?我们获取鼠标点击位置的坐标,然后把坐标作为参数给函数sheet_slide()来实现窗口图层的移动。好了,我们来看看代码吧!

//HariMain节选
if (mouse_decode(&mdec, i - ) != ) {//把鼠标动作的三个字节的数据写到变量mdec中
//..............
if ((mdec.btn & 0x01) != ) {    //如果按下了鼠标的左键
/* 调用图层移动函数,把窗口图层移动到鼠标的位置 */
sheet_slide(sht_win, mx - , my - );
}
}

《30天自制操作系统》14_day_学习笔记的更多相关文章

  1. 《30天自制操作系统》学习笔记--Mac下工具的使用

    现在来介绍官网上下的工具怎么用首先是官网地址,书上有个注释上有:hrb.osask.jp 翻译成中文大概是这个样子滴. 上面有两个文件可以下载,一个是工具,一个是工具的源代码,很好的学习资料 下面把工 ...

  2. 《30天自制操作系统》学习笔记--Mac环境搭建

    弄了三天了,终于弄好了,先说结果,就是作者在网站上放了os x的工具(hrb.osask.jp,也有linux下的工具,可以自己去下载),也就是说我白忙活了三天... 再说一下这几天都干啥了,主要是想 ...

  3. 《30天自制操作系统》学习笔记--番外篇之Mac环境下的工具介绍

    这几天又有点不务正业了,书也没看,一直在搞这个破环境,尝试各种做法,网上各种垃圾信息,浪费了很多时间,说的基本都是废话,不过还是找到了一些,赶紧写下来,不然这个过几天又忘了 首先是环境,我用的是Max ...

  4. 《30天自制操作系统》读书笔记(5) GDT&IDT

    梳理项目结构 项目做到现在, 前头的好多东西都忘了, 还是通过Makefile重新理解一下整个项目是如何编译的: 现在我们拥有这么9个文件: ipl10.nas    InitialProgramLo ...

  5. 《30天自制操作系统》读书笔记(3) 引入C语言

    这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是 ...

  6. 《30天自制操作系统》读书笔记(2)hello, world

    让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实 ...

  7. 30天自制操作系统第九天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第九天的课程已学完,确实有点不想写 ...

  8. 从你的u盘启动:30天自制操作系统第四天u盘启动学习笔记

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 developing environment:ubuntu 关于u盘启动自己做的操 ...

  9. 30天自制操作系统第八天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第八天的学习思考: 关于鼠标是怎么 ...

  10. 《30天自制操作系统》笔记(03)——使用Vmware

    <30天自制操作系统>笔记(03)——使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测 ...

随机推荐

  1. 转:js-sdk探索之微信网页分享

    原文地址 微信是一个很不错的传播平台,最近公司需要做一个新年贺卡,使用html5制作一个很小的动画,然后发送给客户,不需要和后台有任何的联系,一个很简单的功能,需要利用微信的分享功能,毕竟微信分享的带 ...

  2. 【BZOJ1677】[Usaco2005 Jan]Sumsets 求和 递推

    ... #include <iostream> using namespace std; ]; int n,i; int main() { cin>>n; f[]=; ;i&l ...

  3. jQuery取得select选中的值

    $("#sxselect").change(function(){ alert($("#sxselect option:selected").val()); } ...

  4. Maya 脚本控制物体自转

    在Maya中,我们可以用脚本来控制物体的自转方向,速度等等,步骤如下: 选择需要操作的物体object,打开通道盒Channel Box,点击编辑Edit,打开表达式Expressions面板 选择需 ...

  5. mysql连接查询语句示例

    eg: 内连接:     select student.*,grade.* from student join grade where student.sid=grade.sid;     selec ...

  6. Javascript 编程小技巧总结(部分内容借鉴他人)

    1 – 使用===,而不是== ==(或!=)操作符在需要的时候会自动执行类型转换.===(或!==)操作不会执行任何转换.它将比较值和类型,而且在速度上也被认为优于==. 2 – 使用闭包实现私有变 ...

  7. 使用UEditor 的时候,ajax注意使用同步的方法

    使用UEditor 的时候,ajax注意使用同步的方法去读取后台数据,然后填写到前端的文本域当中.

  8. bzoj4518: [Sdoi2016]征途--斜率DP

    题目大意:把一个数列分成m段,计算每段的和sum,求所有的sum的方差,使其最小. 由方差*m可以化简得ans=m*sigma(ki^2)-sum[n]^2 很容易得出f[i][j]=min{f[i- ...

  9. 【HDU4585 Shaolin】map的经典运用

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4585 题意大意:很多人想进少林寺,少林寺最开始只有一个和尚,每个人有有一个武力值,若这个人想进少林,必 ...

  10. window常用命令(持续更新)

    1.netstat -ano 查看端口占用情况  可以根据PID到任务管理器中找到对应的进程 2.tasklist|findstr 进程号(pid) 查看pid是哪个程序启用的 3.taskkill ...