30天自制操作系统:第七天 FIFO与鼠标控制

1 获取按键编码(hiarib04a)

小节的内容实现让程序按下一个键后不结束,而是把所按键的编码在画面上显示出来。
在这里插入图片描述
代码 “io_out8(PIC0_OCW2, 0x61);” 用来通知PIC“已经知道发生了IRQ1中断哦”,如果是IRQ3,则写成0x63。也就是说,将“0x60 + IRQ号码”输出给OCW2就可以。执行这句话之后,PIC继续时刻监视IRQ1中断是否发生。反过来,如果忘记了执行这句话,PIC就不再监视IRQ1中断,不管下次键盘输入什么信息,系统都感知不到了。
在这里插入图片描述
接下来需要注意,从编号为0x0060的设备输入的8位信息是按键编码。至于为什么0x0060就是键盘,作者没有给出解释。

运行:
在这里插入图片描述

2 加快中断处理(hiarib04b)

程序有一个问题:字符显示的内容被放在了中断处理程序中。
在这里插入图片描述

中断处理,基本上就是打断CPU本来的工作,加塞要求进行处理,所以必须完成得干净利索。而且中断处理进行期间,不再接受别的中断。因此如果处理键盘的中断速度太慢,就会出现鼠标的运动不连贯、不能从网上接受数据等情况。这都是我们不行看到的。

另一方面,字符显示是要花大块时间来进行的处理。仅仅画一个字符,就要执行8 x 16 = 128次if语句。
在这里插入图片描述
↑显示一个字符需要128条if语句

当然这还只是是否要往VRAM里描画该像素,如果判定为描画该像素,还要执行内存写入指令。为了确定具体内存地址又有一大堆计算,如果有过写算法的经历,应该能够理解这样做会极大地降低运行速度。
在这里插入图片描述
谁也不知道其他中断会在哪个瞬间到来,事实上,很可能在键盘输入的同时,就有数据正在从网上下载,而PIC正在等待键盘中断处理的结束。

那该如何解决这个问题?结论很简单,先将按键的编码接收下来,保存到变量里,然后由HariMain偶尔去查看这个变量。如果发现有了数据,就把它显示出来。
在这里插入图片描述
考虑到键盘输入时需要缓冲区,定义了一个构造体,命名为 keybuf。其中flag变量用于表示这个缓冲区是否为空,如果flag为0,表示缓冲区为空;反之表示缓冲区存有数据。要是这时再来一个中断,那么根据上边的程序是无法处理的(丢掉了)

回头看看 bootpack.c中的HariMain函数
在这里插入图片描述
开始先用 io_cli(Clear Interrupt)指令屏蔽中断。这样做是为了防止在执行其后的处理时又来了一个中断,那样可能会使程序变得混乱。所以,先将中断屏蔽掉。

接下来是if判断,如果flag为0,表示缓冲区为空(没有键被按下,缓冲区没放数据),没有事情可以做,因此执行io_hlt,但是,由于已经执行io_cli屏蔽了中断,如果就这样去执行HLT指令的话,即使有什么键被按下,程序也不会有任何反应。所以,STI(Set Interrupt,开中断)和HLT两个指令都要执行,而执行这两个指令的函数就是 io_stihlt。执行HLT指令后,如果收到了PIC的通知,CPU就会被唤醒。这样,CPU首先会执行中断处理程序,中断处理程序执行完之后,又回到for语句额开头,再执行io_cli函数。

可能有人认为,不做这个函数,而是用“io_sti(); io_hlt();"不也行吗?但是,实际上这么写有点问题。如果io_sti()之后产生了中断,keybuf里就会存入数据,这时候让CPU进入HLT状态,keybuf里存入的数据就不会被察觉到。根据CPU的规范,机器语言的STI指令之后,如果紧跟着HLT指令,那么就暂不受理这两条指令之间的中断,而要等到HLT指令之后才受理,所以使用io_stihlt函数就能克服这一问题。

在这里插入图片描述
说完了flag等于0的情况,再来看看flag等于1时是如何处理的。
在这里插入图片描述
代码理解起来不难,此时缓冲区是有数据的,先将键码(keybuf.data)值保存到变量 i 里,然后将flag置为0表示缓冲区为空,打开中断,虽然如果在keybuf操作当中有中断进来会造成混乱,但现在keybuf.data的值已经保存完毕,再开放中断也就没有关系了。
接下来调用 boxfill8以及 putfont8_asc显示字符。

回头看看,可以发现在中断期间所做的处理非常少(仅仅包含了开关中断以及对应简单的处理),中断处理程序本身做的也非常少(只是从键盘读入键入信息,然后判断缓冲区是否为空,如果为空,就将刚读到的数据放里面,改变flag标志)。

以下是作者关于键盘按下Ctrl键之后有关的不同之处
在这里插入图片描述
在这里插入图片描述

3 制作FIFO缓冲区(hiarib04c)

上面的Ctrl问题的出现就是由于作者之前所用的存储方式有问题:只能同时保存一个中断处理内容,如果有多个中断,则除第一个外其余的均被抛弃(未保存)。

这里作者引入了队列(FIFO),由于较为基础,就不再一一展示了,直接放上作者改进过的队列吧(下一小节)。

4 改善FIFO缓冲区(hiarib04d)

与第三节内容相似,主要是为了改进上一节中队列设计欠佳问题,这一次通过使用一些变量来循环完成数据的保存,避免了数据拷贝。(如果有一定的算法基础,这部分可以不细看)

这个技巧的思路是,不仅要维护下一个要写入的位置,还要维护下一个要读出数据的位置。这就好像数据读出位置在追着数据写入位置跑一样,这样做就不需要做出局移送操作了。数据读出位置追上数据写入位置的时候,就相当于缓冲区为空。

在这里插入图片描述
在这里插入图片描述
上面的内容在数据结构、算法分析与设计这类课程中应该有所涉及,这里不细说了,较为基础,我们直接来看程序吧。

头文件定义

在这里插入图片描述
非常简单的一个结构体,包含了一个数据缓冲区 unsigned char data[32],32字节的一个数组,下面是三个变量next_r、next_w、len,分别记录下一个读的位置、下一个写的位置、缓冲区当前记录了多少字节的数据

int.c文件

在这里插入图片描述
与之前的程序非常相似,只是在几个判断的地方换成另一个写法了。
在这里插入图片描述
↑bootpack.c文件中对于键盘输入的处理代码

5 整理FIFO缓冲区(hiarib04e)

这里是为了将FIFO缓冲区变得更加具有通用性,比如可以用于鼠标信息的存储,鼠标只要稍微动一动,就会连续发送3个字节的数据。
改造结构体:
在这里插入图片描述
如果将缓冲区大小固定成32字节的话,以后改起来就不方便了,所以用变量size来表示,变量free用于保存缓冲区里”空闲“的位置,就是还可以存放数据的字节数(这个好理解吧,空闲的位置)。p表示下一个数据写入地址(next_w),q代表下一个数据读出地址(next_r)。

下面的几个函数都比较基础,所以直接放上代码,稍微看看就明白了。
在这里插入图片描述
↑用于初始化结构体的fifo8_init函数

在这里插入图片描述
↑用于放置数据的fifo8_put函数

在这里插入图片描述
从FIFO缓冲区取出1字节的fifo8_get函数

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

6 总算讲到鼠标了(harib04f)

这里的内容大多是作者介绍鼠标相关的一些硬件知识,笔者还没有太多可说的,先放上比较重要的部分吧。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7 从鼠标接受数据(harib04g)

鼠标和键盘的原理几乎相同,所以程序也非常相似。
在这里插入图片描述
不同之处只有送给PIC的中断受理通知。IRQ-12是从PIC的第4号(从PIC相当于IRQ-08 ~ IRQ-15),首先要通知IRQ-12受理已完成,然后再通知主PIC。这是因为主/从PIC的协调不能够自动完成,如果程序不教给主PIC该怎么做,它就会忽视从PIC的下一个中断系统。从PIC连接到主PIC的第2号上,这么做OK。

感受

每天都是一些比较新颖的内容,随着内容的推进,难度开始有所上升,外加笔者的时间不是很充足(课程分布不均,有时候需要先应付完学校),所以博客可能有很多不全、解释不准确甚至错误,这些希望小伙伴们前来指正(热烈欢迎~!),当然笔者会定期回顾,不断更新该系列文章中的内容。
今天先这样了,Over

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nepu_bin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值