DAY 0x0C
PIT (Programmable Interval Timer 可编程的间隔型定时器)
查阅资料知道AT兼容机中PIT时钟频率为1.19318MHz
中断周期设定的值的单位是一个时钟周期,因此要达到频率为100Hz
的中断,中断周期应该设定为1.19318*1000000/100=11931.8≈11932
在qemu上跑的时候,count是按照预想的速度增加的,而在bochs上面时,count的速度明显的降低,猜测是bochs的时钟的问题,google了一番发现很多用bochs的也遇到了类似的问题,但是好像并没有找到解决方案
DAY 0x0D
timerctl
这里由于pit设置了100Hz的定时器,所以理想的情况下能够以0.01ms的整数倍的时间间隔来进行中断,作者在实现完成以后进行了先后三次优化,但是对于最后一次优化,我感觉作者在超时后将定时器指针数组整体移位的优化还不如不优化,所以我只实现了using变量,以确定一个循环检索的上界
fifo重用优化
这一段我没有使用作者的优化方式,因为将fifo重用会增加程序的复杂性,对于排错也不友好,另外,将数据按大小分层的话,如果后面增加了设备或者数据种类一多,又要去更改分层方式。
DAY 0x0E
到这里遇到了一个小插曲,程序能够在qemu模拟器上运行,但是到了bochs,由于定时器的速度太快,而bochs比qemu忙,每轮循环中都有定时器事件发生,导致鼠标和键盘中断被定时器所抢先,键盘和鼠标的相应被“饿死”了,在这种情况下更换循环中if条件判断的先后顺序解决了问题
提高分辨率
做到这一步的时候被作者坑到了,作者给的nas文件里面把[INSTRSET "i486p"]
提前到了第一行但是却没有在书中说明,导致nask一直编译不通过,害我还以为哪里写错了。
使用VBE时,显卡能利用的VBE信息写入到以ES:DI开始的512字节中。 视频缓冲区位置也变成了由VBE信息指定的区域(不再是VGA的0x0x000a0000)
键盘输入
做到这里的时候倒是发现了以前写下的好几个bug,本着自己写自己修的原则只好修复之。
由于我之前将光标封装成了Cursor类,所以字符操作什么的用Cursor::next()
和Cursor::backspace()
还是很爽的。遗憾的是我封装的时候还是直接对varm区域进行操作,没有绑定到画板Canvas
(也就是作者的SHEET)上面这样的话对于窗口边界的判断就很麻烦了,后面考虑改成和Canvas
组合在一起。
改善log的性能
为了改善log的性能,原先是每次来一条日志信息,当场就把数据给写到log拥有的那块画板上面,这样的话,如果一个主循环周期内产生了多条log,那么除了最后一次刷新操作,之前的操作全部都是浪费的,因此,给Canvas里面增加了一个函数指针callback字段,在每一轮主循环周期判别进行屏幕刷新前,首先调用所有canvas的callback函数,这样虽然会带来循环时的浪费,但是相比于多次log时的多次刷新来说,还是划得来的。 后面还可以考虑只对新增的log进行绘制,而对于旧的log绘制时只拷贝对应区域的图像数据
debug屏幕刷新
由于我刷新机制和作者的不太一样,是按分块刷新屏幕的,有时候也容易出bug,为了检验效果同时也使其更加直观,所以我用宏来做了一个显示屏幕刷新区域的debug功能,将每次刷新时进行的的分块用红色线条圈起来,如图所示