harib10a:

  简化字符串的显示:我们发现字符串显示三条语句总是重复出现,并且总是一起出现的。接下来我们把它归纳到一个函数中,这样便于使用。

  • x,y--位置的坐标
  •    c--字符颜色  (color)
  •    b--背景颜色  (back color)
  •    s--字符串     (string)
  •    l--字符串长度(length)
void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l)
{
boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * - , y + );//涂背景颜色
putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s);     //在背景上写字符串
sheet_refresh(sht, x, y, x + l * , y + );            //完成刷新
return;
}

harib10b:
  重新调整FIFO缓冲区(01):前面我们设置了3个定时器,就需要3个FIFO缓冲区;如果我们需要100个定时器,难道需要malloc()100个缓冲区吗?下面我们通过把定时器用的多个FIFO缓冲区集中在1个上面来对此进行优化,我们通过往FIFO中写入不同的数据来分辨出是哪个定时器超时了。

    //HariMain节选
fifo8_init(&timerfifo, , timerbuf);//只初始化一个FIFO缓冲区
timer = timer_alloc();  //第一个定时器,向缓冲区中写入数据10
timer_init(timer, &timerfifo, );
timer_settime(timer, );
timer2 = timer_alloc(); //第二个定时器,向缓冲区中写入数据3
timer_init(timer2, &timerfifo, );
timer_settime(timer2, );
timer3 = timer_alloc(); //第三个定时器,向缓冲区中写入数据1
timer_init(timer3, &timerfifo, );
timer_settime(timer3, );
//接下来:...................
//1、判断fifo8_status(&timerfifo)!=0;定时器缓冲区开辟成功
//2、判断i = fifo8_get(&timeerfifo);根据i的值判断是哪个定时器超时

harib10c--harib10f:
  前面我们在对定时器不断进行改进,下面来看看改进的效果,测试一下性能。

  测试方法:先修改HariMain恢复变量count,然后完全不现实计数,执行count++;在启动3秒后,把count复位为0一次。当到了10s后超时的时候,再显示这个count的值。(为什么要在系统启动3s后,把count复位为0。因为系统在刚启动进行初始化时,所花费的时间会因为某些条件发生很大的变化,3s后复位可以消除因为系统启动的不确定性给测试带来的影响。)

  结果说明:下面的结果可以看出,每改良一次速度就会提高;这些测试数据都是笔者在真机上运行的结果。在模拟器上,会受到Windows的影响,导致结果的波动性较大;

    • harib10d:  0074619985(利用harib09d时的timer.c和bootpack.c;最初的定时器)
    • harib10e:  0074629087(利用harib09e时的timer.c和bootpack.c;timeout改进为记忆超时时刻)
    • harib10f:   0074633350(利用harib09f时的timer.c和bootpack.c;导入了next表示下一个定时器时刻)
    • harib10c:  0074643595(导入timers [ ] )
    //修改后的HariMain
    if (fifo8_status(&timerfifo) != ) {      //定时器缓冲区开辟成功
    i = fifo8_get(&timerfifo);            /* 获得FIFO中定时器的DATA,看哪个定时器超时 */
    io_sti();
    if (i == ) {                  //获取的数据为10,第一个定时器,10s
      putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, "10[sec]", );
      sprintf(s, "%010d", count);
      putfonts8_asc_sht(sht_win, , , COL8_000000, COL8_C6C6C6, s, );
    } else if (i == ) {              //获取的数据为3,第二个定时器,3s
putfonts8_asc_sht(sht_back, , , COL8_FFFFFF, COL8_008484, "3[sec]", );
count = ;             /* 應掕奐巒 */
    } else {                     //第三个定时器,闪烁定时器
      if (i != ) {                //i=1;将定时器数据设定为0;之后显示背景
        timer_init(timer3, &timerfifo, );
        boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, , , , );
      } else {                   //i=0;将定时器数据设定为1;之后显示背景
        timer_init(timer3, &timerfifo, );
        boxfill8(buf_back, binfo->scrnx, COL8_008484, , , , );
      }
      timer_settime(timer3, );        //设定第三个定时器时间,50个中断时间
      sheet_refresh(sht_back, , , , );//刷新背景图层
    }

harib10g:
  重新调整FIFO缓冲区(02):在上一次调整FIFO缓冲区时,我们把三个定时器归纳到一个FIFO缓冲区中。这里,我们再将鼠标壳键盘的缓冲区也归纳起来,用1个FIFO缓冲区来管理。我们将FIFO缓冲区的大小从8位扩展到32位(将char型变为int型)来进行改进。先来设置往FIFO中写入数值的中断类型。

    •          0-1:光标闪烁用定时器
    •             3:3秒定时器
    •           10:10秒定时器
    • 256-511:键盘输入(从键盘控制器读入的值+256)
    • 512-767:鼠标输入(从鼠标控制器读入的值+512)

    1、重写FIFO结构体、初始化、写数据、取数据、存储状态函数(FIFO.C有点长,我们折起来吧!)

struct FIFO32 { //扩展结构体为32位
int *buf;
int p, q, size, free, flags;
};
/* 以下是:FIFO.C */ #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表示有空余;FLAGS_OVERRUN表示溢出了
fifo->p = ;             /* 写入位置指向头部 */
fifo->q = ;             /* 读取位置指向头部 */
return;
}
int fifo32_put(struct FIFO32 *fifo, int data)
/* 向FIFO缓冲区发送数据 */
{
if (fifo->free == ) {
/* 空闲=0;表示缓冲区已满 */
fifo->flags |= FLAGS_OVERRUN;//标志位置0x0001溢出
return -;           //返回-1,发送数据失败
}                   //否则下面表示缓冲区未满
fifo->buf[fifo->p] = data;    //把数据写到下一个位置
fifo->p++;             //写入位置指针向后移动一个单位
if (fifo->p == fifo->size) {   //如果写到了buf尾
fifo->p = ;         //将写入位置p置0;
}
fifo->free--;          //写入了一个数据,空闲大小减1
return ;             //写入成功
} int fifo32_get(struct FIFO32 *fifo)
/* 从FIFO缓冲区的q位置读取一个单位的数据 */
{
int data;             //临时变量用来保存读取的数据
if (fifo->free == fifo->size) {
/* 此时全空,没有数据可读,返回-1;读取失败 */
return -;
}                 //有数据可读
data = fifo->buf[fifo->q];  //在q出读取一个数据
fifo->q++;           //读取位置向后面移动一个
if (fifo->q == fifo->size) { //读到了buf尾
fifo->q = ;         //读入位置置0
}
fifo->free++;         //读取了一个,空闲+1
return data;         //返回读取的数据
}
int fifo32_status(struct FIFO32 *fifo)
   /* 报告已经存储了多少数据 */
{ //缓冲区的大小减去空闲大小=占用大小
return fifo->size - fifo->free;
}

FIFO结构体+FIFO.C

    2、使用FIFO32修改键盘相关程序

void init_keyboard(struct FIFO32 *fifo, int data0)//键盘初始化
{
/* 保存传入的两个参数到全局变量 */
keyfifo = fifo;
keydata0 = data0;
/* 键盘控制器初始化 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
void inthandler21(int *esp)          //键盘中断程序
{
int data;
io_out8(PIC0_OCW2, 0x61);       /* 设置PIC芯片信息,IRQ01使能 */
data = io_in8(PORT_KEYDAT);      //获取键盘读取的数据
fifo32_put(keyfifo, data + keydata0); //读取数据+256送到缓冲区中
return;
}

    3、用FIFO32修改鼠标相关程序

void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec)
{
/* 保存传入的参数到全局变量中 */
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 = ;              /* 等待0xfa返回的阶段 */
return;
}
void inthandler2c(int *esp)         //鼠标的中断程序
{
int data;
io_out8(PIC1_OCW2, 0x64);       /* PIC-01的IRQ12 */
io_out8(PIC0_OCW2, 0x62);       /* PIC-00的IRQ02 */
data = io_in8(PORT_KEYDAT);     //获取鼠标数据
fifo32_put(mousefifo, data + mousedata0);//将数据+512写到FIFO中
return;
}

    4、用FIFO32修改定时器结构体

struct TIMER {
unsigned int timeout, flags;
struct FIFO32 *fifo;//加入了FIFO32缓冲区
int data;
};
void inthandler20(int *esp)
{ //...调用写入函数,将数据写到FIFO缓冲区中。修改相应的传入参数即可
fifo32_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data);
/...
}

    5、性能再次测试

                   在模拟器上比较   在真机上进行比较

    •   harib10c:   0002638668       0074643595
    •   harib10g:   0004587870      0099969263

    (从上面的测试数据可以看到,精简了程序之后,速度获得了一定的提升)

harib10h:
  加快中断处理(04):timer_settime()是在中断禁止期间进行的,当面对多任务时,它会托掉很多时间。而且FIFO中用来存储定时器排序后地址的timers[]的排序和跟新也会浪费很多时间;为了解决这两个问题,我们使用链表来重新组织TIMER结构体,在结构体中加入NEXT指向下一个TIMER结构体,这样不用原来的timers[]一直进行排序等工作。
  注---------------意:timer->next指的是下一个定时器的地址;timerctl.next指的是下一个定时器的超时时刻(下图是插入到定时器s和t中间的情况)

    

    1、在TIMER结构体中加入next指向下一个TIMER结构体

struct TIMER {
struct TIMER *next;//指向下一个TIMER结构体
unsigned int timeout, flags;
struct FIFO32 *fifo;
int data;
};

    2、修改定时器的中断处理程序

void inthandler20(int *esp) {
int i;
struct TIMER *timer;
io_out8(PIC0_OCW2, 0x60); /* PIC芯片的设置,使能IRQ-00*/
timerctl.count++;    //count++计数器
if (timerctl.next > timerctl.count) {
return;          //count还没有计数到下一个时刻
}
timer = timerctl.t0;     /* 获取第一个TIMER结构体地址 */
for (i = ; i < timerctl.using; i++) {
/* 对于每一个运行中的定时器 */
if (timer->timeout > timerctl.count) {
//此时退出获得第一个未超时的定时器
break;
}
/* 这个时候超时 了。根据next向后再找,直到找到第一个未超时的 */
timer->flags = TIMER_FLAGS_ALLOC;
fifo32_put(timer->fifo, timer->data);
timer = timer->next;   /* 下一个TIMER的地址 */
}
timerctl.using -= i;     //已经有i个超时了
timerctl.t0 = timer;     //重新设定第一个结构体的地址    /* timerctl.next的设定 */
if (timerctl.using > ) {  //有未超时(活动)的定时器
//获得下一个
timerctl.next = timerctl.t0->timeout;
} else {
//没有活动的定时器,回到初始化状态
timerctl.next = 0xffffffff;
}
return;
}

    3、修改timer_settime()函数

void timer_settime(struct TIMER *timer, unsigned int timeout)
{   //...................
if (timerctl.using == ) {
/*情况一:只有这一个定时器;链表长度为1 */
timerctl.t0 = timer;       //第一个定时器地址就是这个
timer->next = ;          /* 没有下一个定时器了 */
timerctl.next = timer->timeout;//下一个超时的时刻
io_store_eflags(e);       //允许中断
return;
}
t = timerctl.t0;           //第一块定时器地址
if (timer->timeout <= t->timeout) {
/* 情况二:加入的TIMER超时时刻比第一个TIMER小,加入到链表最前面 */
timerctl.t0 = timer;      //第一块定时器地址改为新加入的地址
timer->next = t;         /* 下一个定时器是原来的第一块T */
timerctl.next = timer->timeout;//跟新下一个超时的时刻
io_store_eflags(e);       //允许中断
return;
}
   /* 情况三:插入到中间位置 */
for (;;) {
s = t;
t = t->next;
if (t == ) {
break;            /* 这是已经没有下一个了 */
}
if (timer->timeout <= t->timeout) {
               /* timer超时时刻在t的前面 */
s->next = timer;      /* 跟新s的下一个定时器为timer */
timer->next = t;      /* timer的下一个定时器为t */
io_store_eflags(e);   //允许中断
return;
}
}
   /* 情况四:插入到最后面 */
s->next = timer;          //timer直接放到s的后面
timer->next = ;          //timer没有下一个
io_store_eflags(e);        //允许中断
return;
}

harib10i:
  使用“哨兵”简化程序:上一步中,在链表中插入一个TIMER一共有四种情况,下面我们初始化时,在末尾加上一个超时时刻为0xffff_ffff的定时器。让程序简化到两种情况:timer插入到链表头部和timer插入到中间位置。

    1、在init_pit()中加入“哨兵”

void init_pit(void)
{ //......
t = timer_alloc();        /* 分配“哨兵”的内存空间 */
t->timeout = 0xffffffff;    //“哨兵”超时时刻最大
t->flags = TIMER_FLAGS_USING; //哨兵FLAG,活动定时器
t->next = ;            /* 没有最后一个,“哨兵”就是最后一个 */
timerctl.t0 = t;         /* 链表的第一个地址 */
timerctl.next = 0xffffffff; /* 下一个超时时刻最大 */
return;
}

    2、timer_settime()修改

void timer_settime(struct TIMER *timer, unsigned int timeout)
{ //...这里只剩下两种情况 了
if (timer->timeout <= t->timeout) {
/* 情况二:插入到最前面 */
timerctl.t0 = timer;
timer->next = t;
timerctl.next = timer->timeout;
io_store_eflags(e);
return;
}
   /* 情况三:插入到S和T之间 */
for (;;) {
s = t;
t = t->next;
if (timer->timeout <= t->timeout) {
s->next = timer;
timer->next = t;
io_store_eflags(e);
return;
}
}
}

    3、修改中断程序

void inthandler20(int *esp)
{
struct TIMER *timer;
io_out8(PIC0_OCW2, 0x60);         /* IRQ-00为PIC的中断口 */
timerctl.count++;            //计数器count++
if (timerctl.next > timerctl.count) {
return;                 //下一个还没有超时,退出,不进行中断处理
}
timer = timerctl.t0;             /* 获得timer的首地址 */
for (;;) {
/* timers的flag都为USING */
if (timer->timeout > timerctl.count) {
break;                //超时时刻大于当前时刻,没有超时
}
/* 超时了 */
timer->flags = TIMER_FLAGS_ALLOC;  //flag置已分配,调用timer_settime()才是USING
fifo32_put(timer->fifo, timer->data);//把数据写到缓冲区
timer = timer->next;          /* 下一个的地址 */
}
timerctl.t0 = timer;            //跟新链表首地址
timerctl.next = timer->timeout;      //跟新下一个的超时时刻
return;
}

《30天自制操作系统》13_day_学习笔记的更多相关文章

  1. 《30天自制操作系统》学习笔记--Mac下工具的使用

    现在来介绍官网上下的工具怎么用首先是官网地址,书上有个注释上有:hrb.osask.jp 翻译成中文大概是这个样子滴. 上面有两个文件可以下载,一个是工具,一个是工具的源代码,很好的学习资料 下面把工 ...

  2. 《30天自制操作系统》学习笔记--Mac环境搭建

    弄了三天了,终于弄好了,先说结果,就是作者在网站上放了os x的工具(hrb.osask.jp,也有linux下的工具,可以自己去下载),也就是说我白忙活了三天... 再说一下这几天都干啥了,主要是想 ...

  3. 《30天自制操作系统》学习笔记--番外篇之Mac环境下的工具介绍

    这几天又有点不务正业了,书也没看,一直在搞这个破环境,尝试各种做法,网上各种垃圾信息,浪费了很多时间,说的基本都是废话,不过还是找到了一些,赶紧写下来,不然这个过几天又忘了 首先是环境,我用的是Max ...

  4. 《30天自制操作系统》读书笔记(5) GDT&IDT

    梳理项目结构 项目做到现在, 前头的好多东西都忘了, 还是通过Makefile重新理解一下整个项目是如何编译的: 现在我们拥有这么9个文件: ipl10.nas    InitialProgramLo ...

  5. 《30天自制操作系统》读书笔记(3) 引入C语言

    这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是 ...

  6. 《30天自制操作系统》读书笔记(2)hello, world

    让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实 ...

  7. 30天自制操作系统第九天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第九天的课程已学完,确实有点不想写 ...

  8. 从你的u盘启动:30天自制操作系统第四天u盘启动学习笔记

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 developing environment:ubuntu 关于u盘启动自己做的操 ...

  9. 30天自制操作系统第八天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第八天的学习思考: 关于鼠标是怎么 ...

  10. 《30天自制操作系统》笔记(03)——使用Vmware

    <30天自制操作系统>笔记(03)——使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测 ...

随机推荐

  1. HTML5与移动端web学习笔记

    HTML5 提供了很多新的功能,主要有: 新的 HTML 元素,例如 section, nav, header, footer, article 等 用于绘画的 Canvas 元素 用于多媒体播放的 ...

  2. URAL 1635. Mnemonics and Palindromes(DP)

    题目链接 本来用区间DP,3次方的复杂度,T了,看了看题解,降维,直接二次方的复杂度可以解.然后折腾一下输出路径..终于过了. #include <cstring> #include &l ...

  3. thinkphp上传至服务器后模板无法解析原因

    前几日做好的响应式静态页面上传至虚拟空间,打开网址地址出现: 模板不存在:./app/Home/View/Index/index.html 错误位置 FILE: /home/u333385714/pu ...

  4. jquery中对动态生成的标签响应click事件(二)…与ajax交互使用

    <%@ page language="java" contentType="text/html; charset=GB18030" pageEncodin ...

  5. vector容器的用法

    转自一篇博客^-^: 1 基本操作 (1)头文件#include<vector>. (2)创建vector对象,vector<int> vec; (3)尾部插入数字:vec.p ...

  6. 安装redis,执行make test时遇到You need tcl 8.5 or newer in order to run the Redis test

    安装他yum install tcl

  7. 怎么启动或停止mysql服务

    在linux下,  启动mysql用 service mysql start   停止用 service mysql stop 在windows下, 启动用 net start mysql    停止 ...

  8. win2003远程桌面端口修改

    win2003远程桌面端口修改   1.改端口:简单操作步骤:打开"开始→运行",输入"regedit",打开注册表,进入以下路径:[HKEY_LOCAL_MA ...

  9. 大量查询SQL语句 实例

    1.查看表结构语句:DESC   表名   2.查询所有列:select  *  from  表名   3.查询指定列:select  字段名  form  表名   4.查询指定行:SELECT * ...

  10. sax解析原理与案例

    package itcast.sax; import java.io.IOException; import javax.xml.parsers.ParserConfigurationExceptio ...