30天自制操作系统学习-第13天
1 简化字符串显示
将HariMain中显示字符串的步骤:
1 :设置背景色
2:描绘字符串
3:刷新画面
我们简化这一过程,封装为一个用于字符串显示系列操作的putfont_asc_sht函数。
这时,主函数HariMain里只需调用传参即可:
2 重新调整FIFO缓冲区
在HariMain主函数中我们判断计时器的状态,是否超时,其中的判断部分:
倘若有一百多个计时器同时运行,我们的if语句中的岂不是要写一百多个连接判断,由此,我们将计时器的缓冲区设置为一个即可,在超时的时候,我们往FIFO缓冲区写入不同的数据即可区分哪个计时器超时了。
修改后的计时器超时的判断:
尝试运行我们修改后的程序:
3 测试性能
我们不需要计时器一开始就在画面上不断的刷新count的值,我们等待10秒后再显示出来。需要注意的是count在到达3秒的时候需要重新复位一下,原因是电脑在初始化的时候只要某些条件改变,花费的时间就会大大增加,在计时的时候,我们鼠标键盘的输入的时候发送的中断,也会影响计时器的速度。
修改count的显示:
刚开始运行:
大概10秒后:
4 重新调整缓冲区
我们接收键盘鼠标的输入,以及计时器状态的读取,都频繁与这三个缓冲区交互,我们尝试将缓冲区的个数设置为一个,但是设置为一个缓冲区如何区分是键盘还是鼠标或是计时器的数据呢,我们可以使用汇编中的段这一概念,将一段连续的内存空间划分为独立的三段,一段用于键盘输入,一段用于鼠标输入,一段用于计时器。
计时器的处理我们需要继续改进,为了知道下一个即将超时的计时器,我们需要频繁的移动数组进行检查,我们其实可以在每个计时器结构体体添加一个指向下一个即将超时的计时器指针,链表的优势就体现出来了。
我们修改一下bootpack.c中缓冲区结构体,让它能够传入int类型参数用于设置分段:
/* fifo.c */
struct FIFO32 {
int *buf;
int p, q, size, free, flags;
};
我们修改fifo.c,以后不再使用FIFO8了,而是使用FIFO32:
/* FIFO */
#include "bootpack.h"
#define FLAGS_OVERRUN 0x0001
void fifo32_init(struct FIFO32 *fifo, int size, int *buf)
/* FIFO缓冲区的初始化*/
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /*空*/
fifo->flags = 0;
fifo->p = 0; /*写入位置*/
fifo->q = 0; /*读取位置*/
return;
}
int fifo32_put(struct FIFO32 *fifo, int data)
/*给FIFO发送数据并储存在FIFO中*/
{
if (fifo->free == 0) {
/*没有空余空间,溢出*/
fifo->flags |= FLAGS_OVERRUN;
return -1;
}
fifo->buf[fifo->p] = data;
fifo->p++;
if (fifo->p == fifo->size) {
fifo->p = 0;
}
fifo->free--;
return 0;
}
int fifo32_get(struct FIFO32 *fifo)
/*从FIFO取得一个数据*/
{
int data;
if (fifo->free == fifo->size) {
/*当缓冲区为空的情况下返回-1*/
return -1;
}
data = fifo->buf[fifo->q];
fifo->q++;
if (fifo->q == fifo->size) {
fifo->q = 0;
}
fifo->free++;
return data;
}
int fifo32_status(struct FIFO32 *fifo)
/*报告已经存储了多少数据*/
{
return fifo->size - fifo->free;
}
相应的keyborad.c修改适应FIFO32缓冲区:
/* 键盘控制代码 */
#include "bootpack.h"
struct FIFO32 *keyfifo;
int keydata0;
void inthandler21(int *esp)
{
int data;
io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */
data = io_in8(PORT_KEYDAT);
fifo32_put(keyfifo, data + keydata0);
return;
}
#define PORT_KEYSTA 0x0064
#define KEYSTA_SEND_NOTREADY 0x02
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47
void wait_KBC_sendready(void)
{
/* 等待键盘控制电路准备完毕 */
for (;;) {
if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
break;
}
}
return;
}
void init_keyboard(struct FIFO32 *fifo, int data0)
{
/* 将FIFO缓冲区的信息保存到全局变量里 */
keyfifo = fifo;
keydata0 = data0;
/* 键盘控制器的初始化 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
mouse.c修改:
/* 鼠标控制 */
#include "bootpack.h"
struct FIFO32 *mousefifo;
int mousedata0;
void inthandler2c(int *esp)
/* 来自PS/2鼠标的中断 */
{
int data;
io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */
io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */
data = io_in8(PORT_KEYDAT);
fifo32_put(mousefifo, data + mousedata0);
return;
}
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec)
{
/* 将FIFO缓冲区的信息保存到全局变量里 */
mousefifo = fifo;
mousedata0 = data0;
/* 鼠标有效 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
/* 顺利的话,ACK(0xfa)会被发送*/
mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/
return;
}
int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
if (mdec->phase == 0) {
/* 等待鼠标的0xfa的阶段 */
if (dat == 0xfa) {
mdec->phase = 1;
}
return 0;
}
if (mdec->phase == 1) {
/* 等待鼠标第一字节的阶段 */
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;
mdec->x = mdec->buf[1];
mdec->y = mdec->buf[2];
if ((mdec->buf[0] & 0x10) != 0) {
mdec->x |= 0xffffff00;
}
if ((mdec->buf[0] & 0x20) != 0) {
mdec->y |= 0xffffff00;
}
mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */
return 1;
}
/* 应该不可能到这里来 */
return -1;
}
bootpack.h中对应TIMER结果体修改如下:
/* timer.c */
#define MAX_TIMER 500
struct TIMER {
struct TIMER *next;
unsigned int timeout, flags;
struct FIFO32 *fifo;
int data;
};
timer.c:
/* 定时器 */
#include "bootpack.h"
#define PIT_CTRL 0x0043
#define PIT_CNT0 0x0040
struct TIMERCTL timerctl;
#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */
#define TIMER_FLAGS_USING 2 /* 定时器运行中 */
void init_pit(void)
{
int i;
struct TIMER *t;
io_out8(PIT_CTRL, 0x34);
io_out8(PIT_CNT0, 0x9c);
io_out8(PIT_CNT0, 0x2e);
timerctl.count = 0;
for (i = 0; i < MAX_TIMER; i++) {
timerctl.timers0[i].flags = 0; /* 没有使用 */
}
t = timer_alloc(); /* 取得一个 */
t->timeout = 0xffffffff;
t->flags = TIMER_FLAGS_USING;
t->next = 0; /* 末尾 */
timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/
timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */
return;
}
struct TIMER *timer_alloc(void)
{
int i;
for (i = 0; i < MAX_TIMER; i++) {
if (timerctl.timers0[i].flags == 0) {
timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC;
return &timerctl.timers0[i];
}
}
return 0; /* 没找到 */
}
void timer_free(struct TIMER *timer)
{
timer->flags = 0; /* 未使用 */
return;
}
void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data)
{
timer->fifo = fifo;
timer->data = data;
return;
}
void timer_settime(struct TIMER *timer, unsigned int timeout)
{
int e;
struct TIMER *t, *s;
timer->timeout = timeout + timerctl.count;
timer->flags = TIMER_FLAGS_USING;
e = io_load_eflags();
io_cli();
t = timerctl.t0;
if (timer->timeout <= t->timeout) {
/* 插入最前面的情况 */
timerctl.t0 = timer;
timer->next = t; /* 下面是设定t */
timerctl.next = timer->timeout;
io_store_eflags(e);
return;
}
for (;;) {
s = t;
t = t->next;
if (timer->timeout <= t->timeout) {
/* 插入s和t之间的情况 */
s->next = timer; /* s下一个是timer */
timer->next = t; /* timer的下一个是t */
io_store_eflags(e);
return;
}
}
}
void inthandler20(int *esp)
{
struct TIMER *timer;
io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */
timerctl.count++;
if (timerctl.next > timerctl.count) {
return;
}
timer = timerctl.t0; /* 首先把最前面的地址赋给timer */
for (;;) {
/* 因为timers的定时器都处于运行状态,所以不确认flags */
if (timer->timeout > timerctl.count) {
break;
}
/* 超时 */
timer->flags = TIMER_FLAGS_ALLOC;
fifo32_put(timer->fifo, timer->data);
timer = timer->next; /* 将下一个定时器的地址赋给timer*/
}
timerctl.t0 = timer;
timerctl.next = timer->timeout;
return;
}
修改后的判断:
运行结果: