71歳の挑戦... ゼロからのOS自作入門を囓ってみた。osbook_day03cを改造。いくつかわかったこと。

　無謀にも「ゼロからのOS自作入門」を購入し挑戦というか、少し囓ってみました。

 https://book.mynavi.jp/ec/products/detail/id=121220

    【追記】USBメモリからの起動はできたのですが問題もありました。
    失敗...電源オフ状態でUSBメモリを挿して電源オン、画像がうまく表示されない。
    成功...UBUNTUが立ち上がっているときにUSBメモリを挿しておき、再起動をする
    コンピュータ本体とディスプレーの信号やタイミングの関係と思われます。

　ここに至るまでの経緯と環境について触れておきます。

    １．windows11(core i5,SSD 500GB)パソコンに、WSL2とUBUNTU20.04を導入。day03あたりまでできることを確認。
    ２．WSL2での作業が面倒に感じ、他の環境移行を考える。
    ３．Dockerを使う事例を参考にしてやってみたが私にはよくわからず。
    ４．無料になったという「VMWare Workstation Pro」を導入し、始めてみた。環境構築もコンパイルもできたが、最後のqemuでの表示ができず、断念。
    ５．ジャンク品レベルのスモールサイズパソコン(core i3,SSD 120GB)を入手できたので、UBUNTU20.04をインストールし環境構築。現在に至る。
    （いやいや何度もインストールやら環境構築やらしました。）

　このようにして順調に行くかと思いましたが、day09bまで進んだところで、もうC++の構文について行けず。単にコンパイル、続くQEMU表示、で喜んでいてもなあ、どうしたものかと悩む。何かちょっとでも自分独自のモノを作りたい。そこで思いついたのが、マンデルブロ集合の描画。以前の投稿です。

 https://qiita.com/Mobu_Kyoto/items/a0672624e21711a06a25

これを移植しようと考え、day03c の main.cpp に書き加えてみました。有り難い事に、けっこう簡単に動きました（コードは後ほど示します）。
　他に一つ分かった事があるので触れておきます。QEMUで実行させてみたところ速さが今ひとつ。USBメモリから起動させればもっと速いかもと、やってみました。書籍のp.30、p.34、p.35を参考にUSBメモリ起動を何度も試みるのですが、「kernel.elf」が無いと表示され起動が停止します。最後の手段。WindowsパソコンでLinuxインストール用USBメモリとして作成。その中の、EFI/BOOT/BOOTX64.EFI を置き換えることまでしてみましたが、だめでした。まあいいかと諦めかけ、いつものようにQEMU表示をしておりました。そのときターミナル上を流れる文字をぼんやり見ていて気付きました。/mnt/ つまり /dev/sdb/ の kernel.elf を読みにいってると。早速、コンパイルで作られた

    ~/workspace/mikanos/kernel/kernel.elf
    
をUSBメモリのルートにコピーして起動をかけました。表示できました、それも速いです、感動です。
　ついでですが、linux起動時の「GRUB」って良いですね。USBから起動したいとき、今までスイッチオンからのF2キー連打でBIOS画面を出してましたが、GRUBのメニューから入れることを知りました。 今回もいろいろ勉強になりました。でも、私にはやっぱり「C++」は難しいです。マンデルブロ集合を描くように改造した main.cpp を示します。

```~/workspace/mikanos/kernel/main.cpp
/**
 * @file main.cpp
 *
 * カーネル本体のプログラムを書いたファイル．
 */

#include <cstdint>
#include <cstddef>

#include "frame_buffer_config.hpp"

//#include <math.h>

// #@@range_begin(write_pixel)
struct PixelColor {
  uint8_t r, g, b;
};

/** WritePixelは1つの点を描画します．
 * @retval 0   成功
 * @retval 非0 失敗
 */
int WritePixel(const FrameBufferConfig& config,
               int x, int y, const PixelColor& c) {
  const int pixel_position = config.pixels_per_scan_line * y + x;
  if (config.pixel_format == kPixelRGBResv8BitPerColor) {
    uint8_t* p = &config.frame_buffer[4 * pixel_position];
    p[0] = c.r;
    p[1] = c.g;
    p[2] = c.b;
  } else if (config.pixel_format == kPixelBGRResv8BitPerColor) {
    uint8_t* p = &config.frame_buffer[4 * pixel_position];
    p[0] = c.b;
    p[1] = c.g;
    p[2] = c.r;
  } else {
    return -1;
  }
  return 0;
}
// #@@range_end(write_pixel)

#define W 480// tft.width()
#define H 320// tft.heght()
#define X0 240//tft.width()/2
#define Y0 160//tft.height()/2

const float absZ = 4.0;       // 発散判定
const uint16_t page = 20;
const uint16_t dp = 2;

// default Mandelbrot Set -----------------------------------------
// viewpW=2.4; CtoX = 0.0; CtoY = 0.0;
// repeat=200; page=1; dp=0;
// ----------------------------------------------------------------

// viewpW = 0.00024; // 10000倍に拡大
// Viewport width; Viewport Center CtoX;CtoY;

// 風景の良い場所例
// example 1
// viewpW = 0.00024; CtoX = -1.24997; CtoY = -0.00877;
// repeat=190; page=28; dp=2;

// example 2
// viewpW = 0.00024; CtoX=-1.401;CtoY=-0.000178;
// repeat=300; page=19; dp=2;

const float viewpW = 0.0012;    // viewport width(window width)
const float di = viewpW / 480.0;// real/imaginary calculation step
                                // 1 pixel in Real and Imaginary number
const float CtoX = -1.19998;    // 現在の表示（viewpW）の中心
const float CtoY = -0.15507;

uint16_t repeat = 120;  // 反復上限、page進行に応じ増加させる
uint16_t k;             // 反復回

float x, y, zr, zi, R, I;//複素計算変数
uint16_t C[800];        // 色配列

uint32_t now, starttime;

uint16_t pi;
int16_t j,i;
uint16_t Xi,Yj;
bool cels[W][H];  // 各セルの発散状況記憶


// #@@range_begin(call_write_pixel)
extern "C"
void KernelMain(const FrameBufferConfig& frame_buffer_config) {
  for (int x = 0; x < frame_buffer_config.horizontal_resolution; ++x) {
    for (int y = 0; y < frame_buffer_config.vertical_resolution; ++y) {
      WritePixel(frame_buffer_config, x, y, {255, 255, 255});
    }
  }
 
  for (int x = 0; x < W; ++x) {
    for (int y = 0; y < H; ++y) {
      WritePixel(frame_buffer_config, x, y, {0, 0, 0});
    }
  }
  
  for (pi = 1; pi <= page; pi++) {// 反復数上限を増やしていく
    for ( j = - Y0; j < Y0; j++) {
      Yj = Y0-j-1;
      y = j * di + CtoY;
      for ( i = - X0; i < X0; i++) {
	Xi = X0 + i;

	if(cels[Xi][Yj]==false){ // 未発散のピクセル(黒)のみ計算
	  x = i * di + CtoX;
	  zr = 0.0;
	  zi = 0.0;
	  k = 0;//-1;
	  do {
	    k++;
	    R = zr * zr - zi * zi + x;
	    I = 2 * zr * zi + y;
	    zr = R;
	    zi = I;
	    if ( k == repeat ) break;
	  } while ( (zr * zr + zi * zi) < absZ );

	  if (k < repeat) {// 新たに発散したピクセルのみ描画

	    WritePixel( frame_buffer_config, Xi, Yj,
			{static_cast<uint8_t>(255 -( k % 255)), // コンパイラが教えてくれた
			 static_cast<uint8_t>(255 - (k % 128)),
			 static_cast<uint8_t>(255 - (k % 64))} );
	    cels[Xi][Yj]=true;
	  }
	}
      }
    }
    repeat += dp * pi;
  }

  for (int x = 0; x < W; ++x) {
    for (int y = H-5; y < H; ++y) {
      WritePixel(frame_buffer_config, x, y, {0, 255, 255});
    }
  }

  while (1) __asm__("hlt");
}
// #@@range_end(call_write_pixel)
```
　最後までお付き合い頂き有難うございました。