您的位置:首页 > 其它

《30天自制操作系统》读书笔记Day13

2013-08-31 13:44 183 查看
1.简化字符串显示

查看代码发现在屏幕上显示字符串需要3行代码:

boxfill8(buf_back, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
putfonts8_asc(buf_back, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
sheet_refresh(sht_back, 32, 16, 32 + 15 * 8, 32);

即先涂上背景色、再写字符,最后刷新。因此考虑单独设置一个函数:

void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l)
/* 显示字符串。x,y,c,b,s,l分别代表:显示横纵坐标、字符颜色、背景颜色、字符串、字符串长度 */
{
boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15);
putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s);
sheet_refresh(sht, x, y, x + l * 8, y + 16);
return;
}

然后修改要使用的函数即可。

2.调整FIFO缓冲区

继续看代码发现前面用了3个计时器就使用了3个缓冲区,这样在使用多个计时器时会使用很多缓冲区,浪费空间。考虑使用一个缓冲区代替。在缓冲区中通过不同的数据分辨不同计时器。

fifo8_init(&timerfifo, 8, timerbuf);
timer = timer_alloc();
timer_init(timer, &timerfifo, 10);
timer_settime(timer, 1000);
timer2 = timer_alloc();
timer_init(timer2, &timerfifo, 3);
timer_settime(timer2, 300);
timer3 = timer_alloc();
timer_init(timer3, &timerfifo, 1);
timer_settime(timer3, 50);


然后修改for循环:
}else if (fifo8_status(&timerfifo) != 0){
i = fifo8_get(&timerfifo);
io_sti();
if (i == 10)
{
putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
}
else if (i == 3)
{
putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6);
}
else
{
if (i != 0)
{
timer_init(timer3, &timerfifo, 0);	//然后设置0
boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, 8, 96, 15, 111);
}else{
timer_init(timer3, &timerfifo, 1);	//然后设置1
boxfill8(buf_back, binfo->scrnx, COL8_008484, 8, 96, 15, 111);
}
timer_settime(timer3,50);
sheet_refresh(sht_back, 8, 96, 16, 112);
}

}

即可

注:可以设置自增count,并在10s后打印count数值判断前面的优化性能(3s左右将count设置为0,避免系统启动的干扰)。

既然可以将定时器的缓冲区合并,那也可以将其他的几个缓冲区合并,这里分配他们的数字代码:

0~1			光标闪烁用定时器
3			3秒定时器
10			10秒定时器
256~511			键盘输入
512~767			鼠标输入


但是fifo8_put中的参数是char,不支持767,因此改为int:

添加结构体:
struct FIFO32
{
int *buf;
int p, q, size, free, flags;//p,q为队列前后指针,size为队列空间总大小,free为空闲空间大小,flags用于标志溢出
};

修改fifo.c:

FIFO32

接着修改键盘鼠标的所有使用fifo8的地方。然后是定时器结构体和定时器相关函数。最后在bootpack.c中修改即可。这里只贴出

bootpack.c中的代码:

void HariMain(void)
{

struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
struct FIFO32 fifo;
//struct FIFO32 timerfifo/*, timerfifo2, timerfifo3*/;	//用于计时器队列
//char timerbuf[8]/*, timerbuf2[8], timerbuf3[8]*/;
char s[40]/*, mcursor[256], keybuf[32], mousebuf[128]*/;
int fifobuf[128];
struct TIMER *timer, *timer2, *timer3;
int mx, my, i;
unsigned int memtotal;
int count;	//计数
struct MOUSE_DEC mdec;
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
struct SHTCTL *shtctl;
struct SHEET *sht_back, *sht_mouse;
unsigned char *buf_back, buf_mouse[256];
struct SHEET *sht_win;	//添加窗口图层
unsigned char *buf_win;		//窗口图层的缓冲区

init_gdtidt();
init_pic();
io_sti(); //结束IDT/PIC初始化,解除CPU中断禁用
fifo32_init(&fifo, 128 , fifobuf);
init_pit();
init_keyboard(&fifo, 256);
enable_mouse(&fifo, 512, &mdec);
io_out8(PIC0_IMR, 0xf8); /* PIT和PIC1以外全部禁止(11111000) */
io_out8(PIC1_IMR, 0xef); //鼠标设置为许可

timer = timer_alloc();
timer_init(timer, &fifo, 10);
timer_settime(timer, 1000);
timer2 = timer_alloc();
timer_init(timer2, &fifo, 3);
timer_settime(timer2, 300);
timer3 = timer_alloc();
timer_init(timer3, &fifo, 1);
timer_settime(timer3, 50);

memtotal = memtest(0x00400000, 0xbfffffff);
memman_init(memman);
memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */
memman_free(memman, 0x00400000, memtotal - 0x00400000);

init_palette();
shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);
sht_back  = sheet_alloc(shtctl);
sht_mouse = sheet_alloc(shtctl);
sht_win = sheet_alloc(shtctl);		//将窗口图层添加到窗口管理中
buf_back  = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);
buf_win = (unsigned char *) memman_alloc_4k(memman, 160*52);		//分配窗口内存
sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 没有透明色 */
sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99);	//透明色号99
sheet_setbuf(sht_win, buf_win, 160, 52, -1);	//没有透明色
init_screen8(buf_back, binfo->scrnx, binfo->scrny);
init_mouse_cursor8(buf_mouse, 99);	//背景色号99
make_window8(buf_win, 160, 68, "Window");	//显示窗口函数调用
sheet_slide(sht_back, 0, 0);
sheet_slide(sht_win, 80, 72);
mx = (binfo->scrnx - 16) / 2; /* 按显示在画面中央来计算最终坐标 */
my = (binfo->scrny - 28 - 16) / 2;
sheet_slide(sht_mouse, mx, my);
sheet_updown(sht_back,  0);
sheet_updown(sht_win,   1);
sheet_updown(sht_mouse, 2);
sprintf(s, "(%3d, %3d)", mx, my);
putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
sprintf(s, "memory %dMB   free : %dKB",
memtotal / (1024 * 1024), memman_total(memman) / 1024);
putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40);

for (;;) {
count++;
//sprintf(s, "%010d",count);
//sprintf(s,"%010d",timerctl.count);
//putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 10);

io_cli();
if (fifo32_status(&fifo) == 0) {
io_sti();
} else {
i = fifo32_get(&fifo);
io_sti();
if (i <= 511 && i >=256) {
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
} else if (i <= 767 && i >=512) {
if (mouse_decode(&mdec, i - 512) != 0) {

sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
if ((mdec.btn & 0x01) != 0) {
s[1] = 'L';
}
if ((mdec.btn & 0x02) != 0) {
s[3] = 'R';
}
if ((mdec.btn & 0x04) != 0) {
s[2] = 'C';
}
putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);
/* 移动光标 */
mx += mdec.x;
my += mdec.y;
if (mx < 0) {
mx = 0;
}
if (my < 0) {
my = 0;
}
if(mx > binfo->scrnx - 1)
mx = binfo->scrnx - 1;
if(my > binfo->scrny - 1)
my = binfo->scrny - 1;
sprintf(s, "(%3d, %3d)", mx, my);
putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
sheet_slide(sht_mouse, mx, my); /* 包含sheet_refresh */
}
}else if (i == 10){
putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
sprintf(s, "%010d",count);
putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 10);
}else if (i == 3)
{
putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6);
count = 0;
}else if (i == 1)
{
timer_init(timer3, &fifo, 0);	//然后设置0
boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, 8, 96, 15, 111);
timer_settime(timer3,50);
sheet_refresh(sht_back, 8, 96, 16, 112);
}else if (i == 0)
{
timer_init(timer3, &fifo, 1);	//然后设置1
boxfill8(buf_back, binfo->scrnx, COL8_008484, 8, 96, 15, 111);
timer_settime(timer3,50);
sheet_refresh(sht_back, 8, 96, 16, 112);
}
}
}
}


3.加快中断

前面对中断的处理还有一个问题,就是timer_setting中进行移位还比较浪费时间,可以考虑使用链表的形式解决。

这样就不需要timers[]了,因此修改TIMERCTL:

struct TIMERCTL {
unsigned int count,next,using;
struct TIMER *t0;
struct TIMER timers0[MAX_TIMER];
};


使用链表首先修改结构体:

struct TIMER
{
struct TIMER *next;
unsigned int timeout, flags;
struct FIFO32 *fifo;
unsigned char data;
};


然后修改定时器中断:

void inthandler20(int *esp)
{
int i;
struct TIMER *timer;
io_out8(PIC0_OCW2, 0x60);	//把IRQ-00信号接收完毕的消息通知给PIC
timerctl.count++;	//每次中断计时器自加
if (timerctl.next > timerctl.count)
{
return;	//未到下一时刻,结束
}
timer = timerctl.t0;	//将第一个地址赋值给timer
for (i = 0; i < timerctl.using; i++)	//timers中的定时器都处于动作中,所以不确认flags
{
if (timer->timeout > timerctl.count)
{
break;	//一旦遇到未超时的定时器就跳出循环
}
//超时
timer->flags = TIMER_FLAGS_ALLOC;
fifo32_put(timer->fifo, timer->data);
timer = timer->next;
}
timerctl.using -=i;	//正好有i个定时器超时, 其余的进行移位
//移位
timerctl.t0 = timer;

//timerctl.next设定
if (timerctl.using > 0)
{
timerctl.next = timerctl.t0->timeout;	//还有活动的定时器
}
else
{
timerctl.next = 0xffffffff;
}
return;
}


接着是timer_settime:

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();
timerctl.using++;
if (timerctl.using == 1)
//只有一个定时器
{
timerctl.t0 = timer;
timer->next = 0;
timerctl.next = timer->timeout;
io_store_eflags(e);
return;
}
t = timerctl.t0;
if (timer->timeout <= t->timeout)
//插在最前面的情况
{
timerctl.t0 = timer;
timer->next = t;
timerctl.next = timer->timeout;
io_store_eflags(e);
return;
}
//搜索查询位置
for (;;)
{
s = t;
t = t->next;
if (t == 0)
{
break;
}
if (timer->timeout <= t->timeout)
//插入到s和t之间
{
s->next = timer;
timer->next = t;
io_store_eflags(e);
return;
}
}
//插入到最后面的情况
s->next = timer;
timer->next = 0;
io_store_eflags(e);
return;
}


分析前面的链表发现timer_settime中存在四种情况:

1.运行中的定时器只有一个
2.插入到最前面
3.插入到中间
4.插入到最后。

比较复杂,考虑设置队尾结点的方式(即“哨兵”),从而简化以上情况,只存在2、3。

因此在init_pit中添加“哨兵”:

void init_pit(void)
/* 初始化PIT */
{
int i;
struct TIMER *t;
io_out8(PIT_CTRL, 0x34);
io_out8(PIT_CNT0, 0x9c);
io_out8(PIT_CNT0, 0x2e);
timerctl.count = 0;	//初始化计时器
timerctl.next = 0xffffffff;
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;
timerctl.using = 1;
return;
}


继续简化timer_settime:

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();
timerctl.using++;
t = timerctl.t0;
if (timer->timeout <= t->timeout)
//插在最前面的情况
{
timerctl.t0 = timer;
timer->next = 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;
timer->next = t;
io_store_eflags(e);
return;
}
}
}


最后就可以简化inthandler20:

void inthandler20(int *esp)
{
int i;
struct TIMER *timer;
io_out8(PIC0_OCW2, 0x60);	//把IRQ-00信号接收完毕的消息通知给PIC
timerctl.count++;	//每次中断计时器自加
if (timerctl.next > timerctl.count)
{
return;	//未到下一时刻,结束
}
timer = timerctl.t0;	//将第一个地址赋值给timer
for (i = 0; i < timerctl.using; i++)	//timers中的定时器都处于动作中,所以不确认flags
{
if (timer->timeout > timerctl.count)
{
break;	//一旦遇到未超时的定时器就跳出循环
}
//超时
timer->flags = TIMER_FLAGS_ALLOC;
fifo32_put(timer->fifo, timer->data);
timer = timer->next;
}
//移位
timerctl.t0 = timer;

//timerctl.next设定
timerctl.next = timerctl.t0->timeout;	//还有活动的定时器
return;
}


make run即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: