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. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  2. [BZOJ2794][Poi2012]Cloakroom

    2794: [Poi2012]Cloakroom Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 167  Solved: 119[Submit][St ...

  3. CodeForces 670D1 暴力或二分

    今天,开博客,,,激动,第一次啊 嗯,,先来发水题纪念一下 D1. Magic Powder - 1   This problem is given in two versions that diff ...

  4. 制作本地 odoo deb包安装镜像

    [本来这不是个事,可是在阿里云部署的时候,这个网速真是让我无语,本来10分钟就能解决的事,得俩三个小时,太没效率了!] 原文转自 http://www.cnblogs.com/xwdreamer/p/ ...

  5. hdu Code Lock

    题意是说有N个字母组成的密码锁, 如[wersdfj],   每一位上的字母可以转动, w可转动变成x, z变成a.但是题目规定, 只能同时转动某个区间上的所有字母, 如[1,3], 那么第1到第3个 ...

  6. php发送邮件处理功能页面去除重复的邮箱地址

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. js官网判断是否手机跳转到手机页面

    <script src="http://siteapp.baidu.com/static/webappservice/uaredirect.js" type="te ...

  8. 【iCore3 双核心板】例程二十三:LAN_HTTP实验——网页服务器

    实验指导书及代码包下载: http://pan.baidu.com/s/1getgyKr iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...

  9. itertools 介绍

    在python中itertool为python提供一系列迭代iterator的方法. 第一个:组合 排列 itertools.combinations(sq, r) 该函数的作用是在列表sq中穷举所有 ...

  10. Oracel数据库连接时出现:ORA-12518:监听程序无法分发客户机连

    在连接Oracel数据库时,每隔一段时间就会出现:ORA-12518:监听程序无法分发客户机连接,如图 上网查了资料原因和解决方案如下: 一.[问题描述] 最近,在系统高峰期的时候,会提示如上的错误, ...