1 使用定时器(harib09a)
定时器(Timer)对于操作系统非常重要。它在原理上很简单,只是每隔一段时间(比如0.01秒)就发送一个中断信号给CPU。辛亏有了定时器,CPU才不用辛苦的去计量时间。
注:英文的Timer在汉语有“定时器” 或 “时钟” 等多种译法,这里将Timer称作“定时器”,Clock称作“时钟周期” 或 “周期”
如果没有定时器,假如CPU看不到定时器而仍想计量时间的话,就只能牢记每一条指令的执行时间了。比如,往寄存器写入常数的MOV指令是1个时钟周期(Clock);加法计算的ADD原则上是1个时钟周期,但根据条件不同可能是2个时钟周期等等。CPU不仅要牢记这些内容,然后还要据此调查一下调用这些函数所需的时间,比如,调用这个函数需要150个时钟周期,调用那个函数因参数不同需要106到587个时钟周期等。
而这里的“时钟周期”又不是一个固定值。比如CPU主频是100MHz的话,一个时钟周期是10ns,但主频如果是200MHz,1个时钟周期就是5ns。既然CPU有各种主频,那么1个时钟周期的时间也就各不相同了。
这样做可以勉强通过程序对时间进行管理,实现每隔一定时间进行一次某种处理,比如让钟表(程序)的秒钟转起来。如果程序中时间计算出错了,那么做出的钟表不是快就慢,没法使用。
如果没有定时器,还会出现别的麻烦,即不能使用HLT指令。完成这个指令所需的时钟周期,不是个固定值。这样,一旦执行HLT指令,程序就不知道时间了。不能执行HLT指令,就意味着要浪费很多电能。所以只能二选一,要么放弃时间的计量,要么选择浪费电能,左右为难,实在糟糕透顶。
那么有定时器的好处呢:
init_pit函数以及HariMain中的相关设定
程序没什么难度,按照编者对 PIT 的介绍,这里做的是IRQ0的中断周期变更。通过对指定端口写入内容完成中断周期的设定。
通过这些设置,IRQ0会在1s内发生100次中断了。
编写IRQ0发生时调用的中断处理程序
2 计量时间(harib09b)
这里让定时器完成计时功能,不断通过中断处理程序自增计数,并将数字显示出来。
代码总体不难,逐条理解比较容易,这里也做不了过多解释。
3 超时功能(harib09c)
现在,从启动开始经过了多少秒这一问题已经解决。另外,我们还可以计量处理所花费的时间。具体做法是:处理前看一下时间并把它放到一个变量中,处理结束之后再看一下时间,然后只需要减法算出时间差,就能得到答案了。
这里往结构体 struct TIMERCTL里添加了一些代码,以便记录有关超时的信息。
结构体中的内容:
- count,计数器,记录当前完成的自增次数(每中断一次自增1)
- timeout,爆发时间,用来记录离超时还有多长时间,一旦剩余为0,程序就往FIFO缓冲区发送数据
- fifo,缓冲队列,用于接收数据
- data,需要存放到fifo队列中的数据
接下来就是修改相关的 timer 函数:
这些内容不难(与之前的很多函数类似),看程序应该可以明白了。在 inthandler20函数里实现了超时功能。每次发生中断时就把 timeout 减1,减到0时,就向fifo发送数据。
在settimer函数里,如果设定还没有完全结束IRQ0的中断就进来的话,会引起混乱,所以我们先禁止中断,然后完成设定,最后再把中断状态复原。
4 设定多个定时器(harib09d)
修改 struct TIMERCTL:
这样超时定时器最多就可以设定为500个了, flags 则用于记录各个定时器的状态。
其实上述程序解释起来还挺麻烦的,但是如果之前章节的程序可以理解,这里完全没有问题,只是将单个变量变为了一个数组。
make run运行一下:
5 加快中断处理(1)(harib09e)
这三小节都是在提升中断处理速度上下功夫,编者一步一步带着我们转换思路,内容较为简单(有过一定的算法编程实力这里不在话下)
6 加快中断处理(2)(harib09f)
后续章节的内容就不放上面了。
感受
今天是封校的第二天,事态过于紧急,之前可以在实验室欢快学习,现在只能呆宿舍里面尽量自觉。效率比较低,本小节内容笔者没有过多可以叙述的,先这样,等后续沉淀下来再来填补这些空白,到这了,over