《30天自制操作系统》读书笔记Day13
2013-08-31 13:44
183 查看
1.简化字符串显示
查看代码发现在屏幕上显示字符串需要3行代码:
即先涂上背景色、再写字符,最后刷新。因此考虑单独设置一个函数:
然后修改要使用的函数即可。
2.调整FIFO缓冲区
继续看代码发现前面用了3个计时器就使用了3个缓冲区,这样在使用多个计时器时会使用很多缓冲区,浪费空间。考虑使用一个缓冲区代替。在缓冲区中通过不同的数据分辨不同计时器。
然后修改for循环:
即可
注:可以设置自增count,并在10s后打印count数值判断前面的优化性能(3s左右将count设置为0,避免系统启动的干扰)。
既然可以将定时器的缓冲区合并,那也可以将其他的几个缓冲区合并,这里分配他们的数字代码:
但是fifo8_put中的参数是char,不支持767,因此改为int:
添加结构体:
修改fifo.c:
FIFO32
接着修改键盘鼠标的所有使用fifo8的地方。然后是定时器结构体和定时器相关函数。最后在bootpack.c中修改即可。这里只贴出
bootpack.c中的代码:
3.加快中断
前面对中断的处理还有一个问题,就是timer_setting中进行移位还比较浪费时间,可以考虑使用链表的形式解决。
这样就不需要timers[]了,因此修改TIMERCTL:
使用链表首先修改结构体:
然后修改定时器中断:
接着是timer_settime:
分析前面的链表发现timer_settime中存在四种情况:
比较复杂,考虑设置队尾结点的方式(即“哨兵”),从而简化以上情况,只存在2、3。
因此在init_pit中添加“哨兵”:
继续简化timer_settime:
最后就可以简化inthandler20:
make run即可。
查看代码发现在屏幕上显示字符串需要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即可。
相关文章推荐
- 30天自制操作系统第一周(二)
- 《30天自制操作系统》读书笔记Day8
- 《30天自制操作系统》之——第3天
- 30天自制操作系统第九天
- 30天自制操作系统笔记(三)
- <30天自制操作系统>第三天
- <30天自制操作系统>第五天
- 《30天自制操作系统》学习笔记——第三天
- 30天自制操作系统笔记第4天
- 《30天自制操作系统》12_day_学习笔记
- 30天自制操作系统day13
- 30天自制操作系统day14
- 《30天自制操作系统》 day01
- 30天自制操作系统day18&day19
- 30天自制操作系统(一)从计算机结构到汇编程序入门
- 《30天自制操作系统》笔记三
- 读书笔记《30天自制操作系统》day04
- 30天自制操作系统学习笔记
- 读书笔记《30天自制操作系统》day01
- 30天自制操作系统笔记 第1天