操作系统第八天:鼠标控制与32位模式切换

一、实验主要内容
内容1:鼠标解读
对Harimain函数进行一些修改

在这里插入图片描述
在读到0xfa之后,每次当读到的字节积累到3个字节,就将之显现在屏幕上。
mouse_phase用来记录接受鼠标数据的工作进展到了什么阶段。存在mouse_dbuf中。
运行之后
在这里插入图片描述

第一个数字依旧是显示键盘上的数值,后面的三个数值的第一个“08”部分,0这一位只会在0-3内变化,8那一位是在点击的时候会有变化,范围是(8-F)
作者让观察一下数值变化关系。总结如下:
第一位:左上左下右下左下分别对应了0123四个位置。
第二位:左键:9 右键A 左右键B 滑轮C 左+滑轮:D 右+滑轮:E 左右+滑轮:F
内容2:稍事整理
作者在这里只是简单整理了一下Harimain文件,因为太乱了。
在这里插入图片描述

添加了如上图的结构体,是想把解读鼠标所需要的变量归到一起。
在这里插入图片描述

作者将phase归零。之所以要舍去读到的0xfa,其实因为只是表示鼠标激活了而已,没必要表示出来。
内容3:鼠标解读(2)
作者对Harimain函数进行了小小的修改,修改如下:
在这里插入图片描述

在这个第一部分,作者将对第一个字节的判断中加了一个if语句。
0xc8=(11001000)2, 也就是分别判断这个字节的第一位和第二位分别与3和8的关系,是不是分别在0-3和8-f之间,如果是的话,相与操作之后应该是0x08。之后再进行和之前一样的操作。
另一个部分是在第三个字节的部分。如下:
在这里插入图片描述

这是解读处理的核心。鼠标键的状态,放在buf[0]的低3位,我们只取出这3位。十六进制的0x07相当于二进制的00000111,因此通过与运算可以很顺利地取出低3位的值。
x和y,基本上是直接使用buf[1]和buf[2],但是需要使用第一字节中对鼠标移动有反应的几位信息,将x和y的第8位及第8位以后全部都设成1,或全部都保留为0。这样就能正确地解读x和y。
这部分的最后,对y的符号进行了取反的操作。这是因为,鼠标与屏幕的y方向正好相反,为了配合画面方向,就对y符号进行了取反操作。
以上对鼠标数据的解读就结束了。下面修改显示的部分。
在这里插入图片描述

通过这样的方法,对于我们鼠标点击的显示就变成了,左边按下就l变成大写L,右边按下就变成大写R,更容易辨认。
内容4:移动鼠标指针
鼠标解读完成之后,就可以考虑修改图形显示的问题。可以让鼠标在屏幕上移动。
在这里插入图片描述

修改的部分为/鼠标指针的移动/之后的部分。
至于其以后的部分,则是先隐藏掉鼠标指针,然后在鼠标指针的坐标上,加上解读得到的位移量。"mx += mdec.x;"是"mx=mx+mdec.x;"的省略形式。因为不能让鼠标指针跑到屏幕外面去,所以进行了调整,调整后重新显示鼠标坐标,鼠标指针也会重新描画。
至于为什么要先隐藏鼠标再重新显示鼠标,是为了防止产生鼠标移动时跟随产生一条白色的情况。如下:
在这里插入图片描述

这是现在的程序的一些bug,只会在下面产生这种情况,但如果不先用背景色隐藏鼠标,再画的画,就是全屏白色的各种一片。
在这里插入图片描述

内容5:通往32位模式之路
在这部分中,作者介绍了之前的asmhead.nas中大约100行的东西。这一直是令人迷惑的一个地方。
这段程序中,最开始做的事情为:
在这里插入图片描述

这相当于如下的C程序:
在这里插入图片描述

这是为了防止在CPU进行模式转换时进来中断信号。并且在之后还要进行PIC的初始化,这个时候也是不可以发生中断的。所以要把中断全部屏蔽掉。
在这里插入图片描述

这里的waitkbdaout指令,就仅仅是往键盘控制电路发送指令,令键盘控制电路的附属端口输出0xdf。这个附属端口连接着很多地方,不同的指令也就可以实现不同的控制功能。
0xdf对应的功能是什么呢?是让一个叫A20GATE的信号线变成ON。这是为了兼容在大内存机器上运行的旧版操作系统。这样就可以限制电路只能使用1MB内存。
在这里插入图片描述

LGDT指令,把随意准备的GDT读进来,然后将CR0这个特殊的32位寄存器带入EAX。并将最高位置设为0,最低位置为1,再将这个值返回给CR0寄存器,这样子就完成了模式转换,进入到保护模式。
我们需要使用的是带保护的32位模式。
在保护模式中,CPU为了加快指令的执行速度而使用了管道这个机制。就是说在前一条指令还在执行的时候,就开始解释下一条甚至是再下一条指令。
而且在程序中,进入保护模式以后,段寄存器的意思也变了(不再是乘以16后再加算的意思了),除了CS以外所有段寄存器的值都从0x0000变成了0x0008。CS保持原状是因为如果CS也变了,会造成混乱,所以只有CS要放到后面再处理。0x0008,相当于"gdt+1"的段。
在这里插入图片描述

对应C语言代码如下:
在这里插入图片描述

memcpy函数用来复制内存,memcpy(转送源地址,转送目的地址,转送数据的大小);
比如memcpy(0x7c00,DSKCAC,512/4),DSKCAC是0x0010000,所以这句话的意思就是从0x7c00复制512字节到0x001000。这正好是将启动扇区复制到1MB以后的内存去的意思。
memcpy(DSKCACO+512,DSKCAC+512,cyls51218*2/4-512/4);
它的意思就是将始于0x00008200的磁盘内容,复制到0x00100200那里。
上文中"转送数据大小"的计算有点复杂,因为它是以柱面数来计算的,所以需要减去启动区的那一部分长度。这样始于0x00100000的内存部分,就与磁盘的内容相吻合了。
内存分布图:
在这里插入图片描述
在这里插入图片描述

后面涉及到了ALIGNB指令:一直添加DBO,直到地址能被ALIGNB后面跟的数据整除的时候。如果最开始就可以,则不做任何处理
GDT0是一种特定的GDT。0号是空区域,不能在哪里定义段。1号和2号由下式设定:
在这里插入图片描述

GDTR0是LGDT指令,意思是通知GDT0有了GDT。在GDT0里,写入了16位的段上限,和32位的段起始地址。

二、遇到的问题及解决方法
问题1:关于下面这一部分代码是在执行一个什么操作,以及为何要这么执行。
在这里插入图片描述

后来仔细分析了一下,应该是每次鼠标在四个区域转换时,左右地转换就把x轴取反,上下地转换就把y轴取反,这也就是为什么四个区域并不是按我想的顺时针的0123,而是奇奇怪怪的。那么这里为什么不直接取负值呢?尝试过后,发现运行会发生跳变,不管运动的多慢都会,具体原因还没搞清楚,可能没有这样按位异或慢,不符合节奏?

问题2:
关于任务栏被吃掉的问题应该怎么更好的优化?
除了按下面的创新点的做法,我想的是能不能事先存储用一个256大小的数组保存上一次鼠标所在的位置的颜色,然后用这个数组去恢复它的值。在下面也确实进行了实现。

三、创新点
创新点1:思考如何在鼠标移动的时候优化鼠标在下部分运行时的抹除下桌面的问题:
第一个想法是,每次隐藏鼠标的时候,多进行一个初始化下工具栏桌面的函数,其实也就是之前的init_screen8函数除去第一行。然后添加在隐藏鼠标功能的下一行即可。
相关函数如下:
在这里插入图片描述

运行结果虽然不是很完美,但是也算是解决了一部分问题。运行结果如下:
在这里插入图片描述

这是因为隐藏鼠标是用上半部分的背景色隐藏的。
创新点二:为什么会有绿色底呢?是因为在绘制鼠标的时候设置的背景色就是绿色,那么如果我们在绘制鼠标的时候,不对除了鼠标图案的点设置颜色,是不是就可以优化了?依据这个思路,在创新点1的基础上对以下两个函数进行了修改。
在这里插入图片描述

也就是将之对应部分设置为一个字符,然后在绘制的时候,对’x’的区域不进行绘制即可。运行结果如下(可以看到已经优化成功):
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值