30天自制操作系统第八天

操作系统实验日志8

第8天:鼠标控制和32位模式切换

一、实验主要内容

1、 内容1: 鼠标解读(1)

在第七天的时候,我们已经能够获得鼠标的数据,但是每次只能显示一个字节,不过每次鼠标传送出来的数据都是3个字节一组,所以我们要在显示屏每次显示一组数据。
在这里插入图片描述

第一个字节和按键有关,第二个字节和左右移动有关,第三个字节和上下移动有关。

在bootpack.c文件的入口函数中,我们还是先检测键盘的缓冲区有没有数据,当键盘中断都处理完了再处理鼠标中断产生的数据

在这里插入图片描述

当一组数据的三个字节数据都存到了mouse_phase数组中,就向屏幕输出

运行结果:

在这里插入图片描述
在这里插入图片描述

运行结果分析: “08”部分的0只会在0-3范围内变化,仅当按下触摸板左键,8变为9,按下触摸板右键,8变为A。向左滑动触摸板,中间部分数字变大,向右滑动触摸板,中间部分数字减小;向下滑动触摸板,右边部分数字变大,向上滑动,右边数字减小。

2、 内容2:整理

将保存数据的数组和用来计数的参数放在一个结构体:

在这里插入图片描述
对鼠标激活函数进行处理:舍去读到的0xfa,鼠标激活进行归零处理

在这里插入图片描述

然后通过一个函数对鼠标数据的处理进行整合:

在这里插入图片描述

最后,通过在这里插入图片描述语句来判断三个数据是否都准备好了。

3、 内容3: 鼠标解读(2)

①结构体增加变量描述鼠标的移动情况

在这里插入图片描述

②增加对第一字节的检查:判断前4位是否在0-3之内,后四位是否在8-F之内
在这里插入图片描述

代码解读: 7-4位与0xc=1100相与,若前4位在0-3之内(0000、0001、0010、0011),则第6、7位都为0,相与的结果就为0000;3-0位于0x8=1000相与,若3-0位表示的值在8-F之内,则其第3位为1,与1000相与结果就为1000,否则相与结果为0000。

检测原因: 鼠标连线偶尔也会有接触不良、即将断线的可能,这时就会产生不该有的数据丢失,这样一来数据会错开-一个字节。数据一旦错位,就不能顺利解读,后面的数据就都“错位”。而如果添加上对第-字节的检查,就算出了问题,鼠标也只是动作上略有失误,很快就能纠正过来,所以加上了这项检查。

③获取鼠标的按键信息
在这里插入图片描述
因为鼠标的按键信息保存在3-0位上,且值在8-F之间,他们的第3位都为1,所以只需要取后三位就可获得鼠标的按键信息。

④在第三阶段对数据进行处理:根据鼠标的移动情况获取鼠标的相对坐标

在这里插入图片描述
代码解读: 第一个字节的前4位的值得变化范围是0-3,即0000、0001、0010、0011,在测试得时候发现,它表示的是鼠标移动的方向。

在这里插入图片描述

同理,前四位代表的值为3(11)和2(10)时,(mdec->buf[0] & 0x20)=1,鼠标向y轴的负方向移动,所以将其第八位以后都设成1,在计算机里面即为负数,这样纵坐标就成了负值。

又,y轴的正方向其实是向下为正,所以最后再将y的值取反。

⑤显示部分:用字母位置把初始的小写l\r\c变成大写L\R\C表示按下鼠标的左\右\中

在这里插入图片描述

4、 内容4:移动鼠标指针

在这里插入图片描述

可以得到鼠标的坐标范围在[(0,0),(304,184)]之间,即320-16,200-16。

从代码中可以看出,关于鼠标坐标的计算不是时刻连续的,而是仅计算的是更新之后的坐标。

5、 内容5:通往32位模式之路

asmhead.nas中部分代码解析:


在这里插入图片描述
意思是主PIC和从PIC的中断的关闭了,里面的新指令有NOP,让CPU休息一个时钟。

(因为CPU运行的速度远远高于IO设备的运行速度,所以先让CPU休息1个时钟的时间,等待IO操作的完成,不然CPU要一直轮询)

如果当CPU进行模式转换时进来了中断信号,就会有麻烦。而且后来还要进行PIC的初始化,初始化时不允许中断。所以最后要把中断全都屏蔽掉。

在这里插入图片描述

这次输出0xdf要完成的功能是让A20GATE信号线变成ON的状态。这条信号线能使内存的1MB以上的部分变成可使用状态。

PS:wait_KBC_sendready是多余的,在此之后虽然不会往键盘送命令,但仍然要等到下一个命令能够送来为止,这是为了等待A20GATE的处理切实完成。

在这里插入图片描述

CR0寄存器:即control register 0,只有操作系统可以使用。

在这里插入图片描述

其中,CR0的第0位PE,即protection enable,第31位PG,即paging。如果PE=0、PG=0,处理器工作在实地址模式下;如果PG=0、PE=1,处理器工作在没有开启分页机制的保护模式下;如果PG=1、PE=0,此时由于不在保护模式下不能启用分页机制,因此处理器会产生一个一般保护异常,即这种标志组合无效;如果PG=1、PE=1,则处理器工作在开启了分页机制的保护模式下。

保护模式的段寄存器解释不是16倍而是能够使用GDT。这种模式下应用程序既不能随便更改段的设定,又不能使用操作系统的专用段,操作系统受到CPU的保护。保护模式分带保护的16位模式和带保护的32位模式两种,我们使用带保护的32位模式。

通过代入CR0而且换到保护模式时,由于机器语言的解释要发生变化,CPU为了加快指令的执行速度而使用了管道这一机制(前一条指令还在执行的时候就开始解释下一条甚至再下一条指令)。因为模式变了,就要重新解释一遍,所以要马上执行JMP指令。

进入保护模式以后,段寄存器的意思也变了(不是×16再加了)除了CS(CS变了会造成混乱)以外所有段寄存器的值都从0x0000变成了0x0008(相当于gdt+1的段)。

④memcpy函数:将一块内存的数据复制到另一块内存中

memcpy(转送源地址,转送目的地址,转送数据大小(以双字为单位所以/4来指定))
在这里插入图片描述
意思是从bootpack的地址开始的512kb内容复制到0x00280000号地址,就是将bootpack.hrb复制到0x00280000号地址。
在这里插入图片描述
从0x7c00复制512个字节到0x00100000(DSKCAC),就是将启动扇区复制到1MB以后的内存。

在这里插入图片描述
将始于0x00008200的磁盘内容,复制到0x00100200。转送数据大小计算:cyls值为10,表示10个柱面;512表示一个扇区容纳的字节数;18表示一个盘面共18个扇区;2表示一个柱面有两个磁头。它需要减去启动扇区的那一部分长度。(为什么是0x8200开始,请看最后我的内存使用整理)

在这里插入图片描述在这里插入图片描述在这里插入图片描述

代码解析:这段代码将执行所必需的数据传送过去。EBX代入的是BOTPAK。JZ是条件跳转指令,根据前-个计算结果是否为0来决定是否跳转。在这里,根据SHR的结果,如果ECX变成了0,就跳转到skjp那里去。在harib05d里, ECX没有变成0,所以不跳转。 最终,memcpy将bootpack.hrb第0x10c8字节开始的0x11a8字节复制到0x00310000号地址去。最后将0x310000代人到ESP里,然后用一个特别的JMP指令,将2*8代人到CS里,同时移动到0x1b号地址。这里的0x1b号地址是指第2个段的0x1b号地址。第2个段的基地址是0x280000,所以实际上是从0x28001b开始执行的。这也就是bootpack.hrb的0x1b号地址。这样就开始执行bootpack.hrb了。

在这里插入图片描述

IN AL,0x64:读端口 0x64 到 AL.

读端口0x64就是读8042的状态寄存器(一个8bit的只读寄存器),bit_1为1时表示输入缓冲器满,为0时表示输入缓冲器空。要向8042写命令(通过0x64端口写入),必须当输入缓冲器为空时才可以。所以当CPU从设备号码读取的倒数第二位是0,键盘控制电路才准备好,如果不为0,就跳到waitbdout不断循坏。

在这里插入图片描述

ALIGNB指令:于对指令或者数据的存放地址进行对齐

ALIGNB 16:要求下面的起始地址是16的倍数

(剩下的书上说的不是很清楚,我也没太搞懂)

最后结合作者给的内存分布以及前7天学习的内容整理一下内存使用过程:

  • 0x7c00-0x7dff:用于存放启动区内容。
  • 0x7E00-0x7FFF:一般bootloader还需要一个栈空间或者读磁盘的交换空间,一般是放到0x7E00-0x7FFF这512字节里,所以有些操作系统的镜像起点是0x8000。
  • 0x8000-0x81FF:启动区会拷贝一份映射到0x8000位置上,所以8000-81FF还是启动区。
  • 0x8200-0x34fff:存放从磁盘读取的启动区之外的数据。
  • 0xa0000-0xaffff:INT 0x10画面模式下VRAM是0xa0000~0xaffff的64KB。
  • 0x100000-0x1001FF:从0x7c00复制过来的512个字节,即启动区内容。
  • 0x100200-0x267fff:存放从磁盘读取的启动区之外的数据,与0x8200-0x34fff内相同。
    在这里插入图片描述

二、遇到的问题及解决方法

1.描述问题1:
在这里插入图片描述
既然是想让x,y变成负数,为什么x,y不直接取反?

解决方法: 和同学讨论了一下,同学说没啥区别,然后我修改了代码尝试了一下,发现现象还真的有!区!别! 如果直接取反的话,及时鼠标移动的很慢但是它的显示也会发生跳变(举个例子,就是鼠标移动到右上角的时候,再动一下就出现在左上角了)至于为什么我还没想通,大概是与数据在内存中的存储方式有关。

2.描述问题2:为什么会出现鼠标指针“吃掉”任务栏的现象

解决方法: 因为每次鼠标移动前都要清除掉目前的鼠标,而作者的做法是让背景色即暗浅蓝覆盖指针,所以在上面背景色为暗浅蓝的时候看起来是移动正常的,但是移动到了下面之后,再加上鼠标本身背景色就会让下面鼠标所在的地方变成暗浅蓝。

3.描述问题3:为什么bootpack的地址就是bootpack.hrb?

在这里插入图片描述

解决方法:

在这里插入图片描述
可以看到bootpack标签在asmhead.nas的最后面

在这里插入图片描述

而bootback.hrb是拼接在asmhead.bin后面的,所以指的就是bootback.hrb的首地址。

4.描述问题4:关于鼠标硬件设计传输的一点猜想

在这里插入图片描述

对于不同的鼠标移动方向而发送的数据为什么是上图那样的,即,而不是按0、1、2、3的顺序?

我的猜想:我们习惯上移动鼠标并不是走直线,举个例子,我们向左移动鼠标时鼠标的实际移动方向更倾向于在左上角和左下角之间,这时候数据不稳定,即在01和11间不停的变动,但是变动只会改变左边的1位,如果原设计将11变为10,两位数据就都会改变,为了避免不必要的时间浪费,所以设计成相近方向的数据只有一位改变。

三、程序设计创新点

1、描述创新点1: 改善鼠标指针“吃掉”任务栏的现象

因为主函数中的for循环每循环一次,就会用一个绿色的方块对上一次鼠标所在的位置进行颜色的恢复,所以我们可以用一个256大小的数组保存上一次鼠标所在的位置的颜色,然后用这个数组去恢复它的值。

在这里插入图片描述
在这里插入图片描述
在计算完鼠标的左上角的坐标后,在显示鼠标之前,保存下来鼠标将要覆盖的位置的值:

在这里插入图片描述
在这里插入图片描述

最后需要看我们用来显示鼠标的函数putblock8_8,鼠标的颜色是存到了mcursor数组中,而鼠标的初始化函数将鼠标的背景设置成了绿色,所以应该在鼠标初始化的时候不设置背景颜色。

在这里插入图片描述
在这里插入图片描述
最后的结果:
在这里插入图片描述
成功!

四、实验心得体会

随着实验的进一步进行,涉及到的内存也越来越多,所以我感觉全局了解一下内存分布还是很必要的,不然在内存拷贝的那个代码的时候就会很懵逼。还有就是要对硬件端口有一定的了解,这样对IN和OUT指令才能理解。
本次实验主要能让鼠标进行移动,好开心!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值