30日OS自作入門13日目(Win10)

はじめに

プラサミすごい人がいっぱい…

目次

タイマ-2

文字表示を簡単に(harib10a)

Harimainでの文字表示を行う処理がいつも
1、背景を書く
2、文字を記す
3、シートをリフレッシュ
になっている部分があるので、まとめることで整理しようといった流れのようです。

実行
f:id:No000:20191229150944p:plain

FIFOバッファを見直す(harib10b)

FIFOバッファがタイマの場合に3つもある…無駄な処理というか、100個あったら100個作るのか…?ということでまとめるみたいです。

方法は各タイマーのデータは、同じバッファを通して送るのですが、受け取り先の描画の処理の段階にて条件分岐で古いにかけている感じみたいです。

その条件分岐が

} 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 {
                    /* 0か1 */
                    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);

これで配線が3本だったのが1本になった感じですっきり!

実行すると
f:id:No000:20191229150919p:plain

性能を比較してみる(harib10c~harib10f)

各種タイマーを色々な方法で実装しているので、それを性能比較する下地を作り、性能比較を行うみたいです。

まずは下地としてcount++を復活させ、10秒後にいくつなのかを表示させるようにするみたいです。
そして、起動後3秒間は数えないようにして(誤差がたくさん発生してしまうそうです)

あとは、12日の時のデータで確認すると
harib10c
f:id:No000:20191229162621p:plain

harib10d
f:id:No000:20191229162742p:plain

harib10e f:id:No000:20191229162754p:plain

harib10f
f:id:No000:20191229162817p:plain

といった感じになります。

FIFOバッファを見直す(harib10g)

全てのデータの送信に一つのFIFOバッファで対応しようということみたいです。
そのためにデータを大幅に加算したりすることで値を変え、条件分岐するようですが、Char型なので対応ができないと…
ということでint型で対応するために全体的な修正を行うようです。
基本的にやること同じみたいですが、int型への対応のため結構いじるみたいでした…

このデータ構造のことを線形リストと呼ぶそうです。

実行すると
f:id:No000:20191229200138p:plain

番兵を使ってプログラムを短くしてみる(harib10i)

番兵というプログラミングテクニックを使用しプログラミングの短縮を行ってみるみたいです。

この番兵がいるおかげで
・動作中のタイマはこれ一つになる場合
・先頭に入れる場合
・一番後ろに入れる場合
のうち、1個目(番兵がいるので最低2個になる)と四個目(番兵がいつも後ろ)を消せることで16行もショートカットできるみたいです。

そのおかげで

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) {
    /* 動作中のタイマはこれ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; /* 次は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;  /* sの次はtimer */
      timer->next = t;  /* timerの次はt */
      io_store_eflags(e);
      return;
    }
  }
  /* 1番目後ろに入れる場合 */
  s->next = timer;
  timer->next = 0;
  io_store_eflags(e);
  return;
}

が

/* timersへの登録を追加 */
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 = io_load_eflags();
  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;
    }
  }
}

こうなります。
また、inthandker20も

/* IDT20の処理設定 */
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; /* 次のタイマの番地をtimerに代入 */
  }
  timerctl.using -= i;

  /* 新しいずらし */
  timerctl.t0 = timer;

  /* timerctl.nextの設定 */
  if (timerctl.using > 0) {
    timerctl.next = timerctl.t0->timeout;
  } else {
    timerctl.next = 0xffffffff;
  }
  return;
}

が

/* IDT20の処理設定 */
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 (;;) {
    /* 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 = timerctl.t0->timeout;
  return;
}

びっくりするくらい短くなりました…こんな技法があったとは…

この後make runすると
f:id:No000:20200110191616p:plain
こんな感じですね!

最後に

色々な改造を学べましたが、これがデータ構造なのかな?終わった後に本格的に学びたいですね…