自制操作系统日志——第八天
今天,就让我们把鼠标动起来,以及解释一下之前遗留的代码理解。
一、鼠标数据的解读
首先,为了能够更好的了解我们移动鼠标时候,产生的数据有什么作用,这里我们将把 鼠标收到的数据显现出来,然后,移动鼠标看看:
主函数部分:
unsigned char mouse_dbuf[3], mouse_phase;
enable_mouse();
mouse_phase = 0;
for (;;) {
io_cli();
if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
io_stihlt();
} else {
if (fifo8_status(&keyfifo) != 0) {
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
} else if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
if (mouse_phase == 0) {
if (i == 0xfa) {
mouse_phase = 1;
}
} else if (mouse_phase == 1) {
mouse_dbuf[0] = i;
mouse_phase = 2;
} else if (mouse_phase == 2) {
mouse_dbuf[1] = i;
mouse_phase = 3;
} else if (mouse_phase == 3) {
mouse_dbuf[2] = i;
mouse_phase = 1;
sprintf(s, "%02X %02X %02X", mouse_dbuf[0], mouse_dbuf[1], mouse_dbuf[2]);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 8 * 8 - 1, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
}
}
}
}
}
这里,我们利用phase这个标志,来将鼠标最初读到的数据,即0xfa进行丢弃,然后利用下面的3个if语句进行将鼠标的三个数据显示出来。
你的屏幕上可能会出现类似08 00 00这三个数据:
08 中的 0 会在0~3范围内变动;
08 中的 8 是与鼠标点击有关;
第一个00 是与 鼠标的左右移动有关
第二个00 是与 鼠标的上下移动有关。
好了,再解读完这些数据后,我们进行一下修改,优化一下我们之前所写的代码,方便后续进行鼠标的移动处理:
bootpack.c:
struct MOUSE_DEC
{
unsigned char buf[3],phase;
int x, y, btn;//x,y移动信息,btn是按键状态
};
for(;;)
{.....
else if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
if (mouse_decode(&mdec, i) != 0) {
/* ƒf[ƒ^‚ª3ƒoƒCƒg‘µ‚Á‚½‚Ì‚Å•\Ž¦ */
sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
if ((mdec.btn & 0x01) != 0) {
s[1] = 'L';
}
if ((mdec.btn & 0x02) != 0) {
s[3] = 'R';
}
if ((mdec.btn & 0x04) != 0) {
s[2] = 'C';
}
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
}
}
}
int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
if (mdec->phase == 0) {
/*等待鼠标的0xfa阶段,舍弃激活后的答复0xfa */
if (dat == 0xfa) {
mdec->phase = 1;
}
return 0;
}
if (mdec->phase == 1) {
/* 等待鼠标第一字节 */
if((dat & 0xc8) == 0x08)
{//如果第一字节正确的话
mdec->buf[0] = dat;
mdec->phase = 2;
}
return 0;
}
if (mdec->phase == 2) {
/* 等待鼠标第二字节 */
mdec->buf[1] = dat;
mdec->phase = 3;
return 0;
}
if (mdec->phase == 3) {
/* 等待鼠标第三字节*/
mdec->buf[2] = dat;
mdec->phase = 1;
mdec->btn = mdec->buf[0] & 0x07; //鼠标按键状态是在buf[0]的低三位,因此只取出这一部分即可
mdec->x = mdec->buf[1];
mdec->y = mdec->buf[2];
if((mdec->buf[0] & 0x10) != 0)
{
mdec->x |= 0xffffff00;//xy的左右移动信息就只有8位,因此用这个方法取出即可
}
if((mdec->buf[0] & 0x20) != 0)
{
mdec->y |= 0xffffff00;
}
mdec->y = - mdec->y;//鼠标的y方向与屏幕的y方向相反
return 1;
}
return -1; /* 应该不会来这的,鼠标激活了就会传送数据的 */
}
代码中,鼠标在接收第一个字符的那里,进行判断的原因是: 鼠标数据的第一字节的数据变化范围应该是 [0~3] [8~f] 因此,只要这这个数据范围内的与0xc8相与后结果必是0x08 。
lcr 就是鼠标点击时出现的相应变化。
二、移动鼠标
由于有了鼠标解读后的数据,因此直接上代码:
else if(fifo8_status(&mousefifo) != 0)
{
i = fifo8_get(&mousefifo);
io_sti();
if(mouse_decode(&mdec,i) != 0)
{
//凑齐三字节了进行输出!!
sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
if((mdec.btn & 0x01) != 0)
{
s[1] = 'L';
}
if((mdec.btn & 0x02) != 0)
{
s[3] = 'R';
}
if((mdec.btn & 0x04) != 0)
{
s[3] = 'C';
}
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32+15*8 - 1, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
//让鼠标动起来
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, mx, my, mx+15, my+15);//隐藏鼠标
mx += mdec.x;
my += mdec.y;
if(mx < 0)
{
mx =0;
}
if(my < 0)
{
my = 0;
}
if(mx > binfo->scrnx - 16)
{
mx = binfo->scrnx - 16;
}
if(my > binfo->scrny - 16)
{
my = binfo->scrny - 16;
}
sprintf(s,"(%3d,%3d)", mx, my);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 0, 79, 15);//隐藏坐标
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);//显示坐标
putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);//描绘图像
}
}
在后面的if那里,是为了防止鼠标跑到屏幕外的!!
三、解读通往32位的那部分代码
这里,首先参考一下别人对操作系统启动的解释:https://max.book118.com/html/2018/0401/159613305.shtm
⇒ ipl10.nas 在一开始时位于软盘的第一个扇区之中,然后我们启动机器:
⇒ 会先读软盘第一个扇区的末尾,检测到 55 aa 然后就开始装载和读取我们第一个扇区的内容,此时该区内容(ipl) 就会加载到0x7c00处的内存区域。 (由于此时处于实模式下,可用的内存区域为1MB ,需进入到保护模式的32位模式下)
⇒ 然后ip10.nas会读取软盘的内容到内存中去,然后再跳转到sys这个系统程序当中:
⇒ 首先指向asmhead.nas 该文件保存一些bios相关数据,然后启动32位的保护模式,并将原先的数据全部转移至对应的32位下的物理内存当中,:
⇒ 紧接着就开始处理bootpack.hrb的内容了。。
至于代码的解释,我已经写了详细的说明再代码之中,结合最近的中断内容一起进行理解即可。。
总结
今天任务大致就是这些了,先好好消化一下,然后继续开发吧!!