H8の移植がだいたいいいかんじで動いたので次なのだけど、まあほんとはH8版のソースコードをきれいにしていくべきなのだけど、こないだSH2のマニュアルをちょっとみたらペリフェラル周りとか割り込みまわりがH8にかなり似ていて、もしかしたらH8をベースに移植すれば、SH2でもあっさり動くのでは。。。と思って現在SH2に移植中。


ターゲットはまた秋月のボード。今度はSH7125Fってやつ。


SH2なのだけど、アセンブラまわりとかI/Oまわりも、さすがにH8よりは格段に32ビットCPUっぽいかんじで、H8ほど単純ではなく、あっさり簡単にはいかないようだ。ちょっと甘く見ていたか。。。


とりあえずブートローダーは動くようになった。で、OSが起動するとこまでは動いたのだけど、そのあとコマンド応答が無い。うーん、ブートメッセージは出ていてスレッドに切り替わるあたりで固まっているように思えるので、スレッドのディスパッチ周りか割り込み周りに問題がありそうだ。


SHもおもしろいね。さすがに32ビットCPUってかんじで、いろいろできそうだ。

ただ、内蔵RAMが少なすぎ!せめて16KBはほしかった。。。8KBしかないので、H8用のKOZOSだとあふれてしまうので、Interface誌に掲載したときの極限までサイズを削ったやつをベースにして移植を進めている。。。

(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.

昨日からアホみたいに更新しているが,久々に時間がとれて一気に書き進めるいい機会なので,いっきにやってしまおう.

ということでちょっと見直しして,細かいところというかイマイチな部分を直してみた.

以下,修正したソース.

■ ブートローダーの修正

まず大きな修正として,割り込み発生時にスタックにレジスタを退避する際に,レジスタの退避順番を逆にするように仕様変更した.これは,従来の順番だとアドレスの低位から ER6, ER5, ER4, ... のように格納されてしまっていて,なんか順番が逆になっていたので,逆にするようにした.これによりOSのthread.c のレジスタ値保存部分で,memcpy() で一撃でレジスタ値を退避できるようになるメリットがある.

実際に修正したのは intr.S で,以下のように手を入れている.

diff -ruN h8_10/kzload/intr.S h8_11/kzload/intr.S
--- h8_10/kzload/intr.S Sun Sep 20 13:39:14 2009
+++ h8_11/kzload/intr.S Sun Sep 20 18:42:36 2009
@@ -8,20 +8,20 @@
mov.l er7,er0
mov.l #_stack,sp
mov.l er0,@-er7
- mov.l er1,@-er7
- mov.l er2,@-er7
- mov.l er3,@-er7
- mov.l er4,@-er7
- mov.l er5,@-er7
mov.l er6,@-er7
+ mov.l er5,@-er7
+ mov.l er4,@-er7
+ mov.l er3,@-er7
+ mov.l er2,@-er7
+ mov.l er1,@-er7
mov.w #1,r0
jsr @_interrupt
- mov.l @er7+,er6
- mov.l @er7+,er5
- mov.l @er7+,er4
- mov.l @er7+,er3
- mov.l @er7+,er2
mov.l @er7+,er1
+ mov.l @er7+,er2
+ mov.l @er7+,er3
+ mov.l @er7+,er4
+ mov.l @er7+,er5
+ mov.l @er7+,er6
mov.l @er7+,er0
mov.l er0,er7
mov.l @er7+,er0
...



次に,シリアルの速度を上げる修正.モトローラSフォーマットにしたためにOSのダウンロードにやたら時間がかかるようになってしまったので,とりあえずシリアルの転送レートを上げる.いろいろ試した結果,19200bpsよりも上げると通信がうまくいかないので,19200bpsとする.

diff -ruN h8_10/kzload/serial.c h8_11/kzload/serial.c
--- h8_10/kzload/serial.c Sun Sep 20 13:39:14 2009
+++ h8_11/kzload/serial.c Sun Sep 20 18:42:36 2009
@@ -15,8 +15,10 @@
volatile uint8 scmr;
};

-#define H8_3069F_SCI_SMR_CKS0 (1<<0)
-#define H8_3069F_SCI_SMR_CKS1 (1<<1)
+#define H8_3069F_SCI_SMR_CKS_PER1 (0<<0)
+#define H8_3069F_SCI_SMR_CKS_PER4 (1<<0)
+#define H8_3069F_SCI_SMR_CKS_PER16 (2<<0)
+#define H8_3069F_SCI_SMR_CKS_PER64 (3<<0)
#define H8_3069F_SCI_SMR_MP (1<<2)
#define H8_3069F_SCI_SMR_STOP (1<<3)
#define H8_3069F_SCI_SMR_OE (1<<4)
@@ -48,7 +50,17 @@

sci->scr = 0;
sci->smr = 0;
+#if 0
sci->brr = 64; /* 20MHz 9600bps */
+#elif 1
+ sci->brr = 32; /* 20MHz 19200bps */
+#elif 0
+ sci->brr = 15; /* 20MHz 38400bps */
+#elif 0
+ sci->brr = 9; /* 20MHz 57600bps */
+#else
+ sci->brr = 4; /* 20MHz 115200bps */
+#endif
sci->scr = H8_3069F_SCI_SCR_RE | H8_3069F_SCI_SCR_TE;
sci->ssr = 0;

同様の修正はOS側にも入れる.このため,今後はシリアル接続の際には9600bpsでなく19200bpsを選択する必要あり.これは cu で接続する場合には

# cu -s 19200 -l /dev/cuad0

のようにして,-sオプションで転送レートを指定できる.

次に,XMODEMでのモトローラSフォーマット転送時の処理をちょろっと修正.エラー発生時にエラー検出できていなかったので,戻り値を int としてエラーを返せるように修正した.

diff -ruN h8_10/kzload/xmodem.c h8_11/kzload/xmodem.c
--- h8_10/kzload/xmodem.c Sun Sep 20 13:39:14 2009
+++ h8_11/kzload/xmodem.c Sun Sep 20 18:42:36 2009
@@ -33,7 +33,7 @@
return 0;
}

-static char *xmodem_read_block(char *buf)
+static int xmodem_read_block(char **buf)
{
unsigned char c, block_num, check_sum;
int i;
@@ -42,19 +42,20 @@
block_num ^= serial_getb();

if (block_num != 0xff)
- return NULL;
+ return -1;

check_sum = 0;
for (i = 0; i < XMODEM_BLOCK_SIZE; i++) {
c = serial_getb();
- if (!buf) {
+ if (*buf == NULL) {
if (srec_decode(c) < 0)
- return NULL;
+ return -1;
} else {
#ifdef USE_UUENCODE
- buf = uu_decode(buf, c);
+ *buf = uu_decode(*buf, c);
#else
- *(buf++) = c;
+ **buf = c;
+ (*buf)++;
#endif
}
check_sum += c;
@@ -62,16 +63,15 @@

check_sum ^= serial_getb();
if (check_sum)
- return NULL;
+ return -1;

- return buf;
+ return 0;
}

int xmodem_recv(char *buf)
{
int receiving = 0, size = 0;
unsigned char c;
- unsigned char *p;

srec_init();

@@ -86,12 +86,9 @@
break;
} else if (c == XMODEM_SOH) {
receiving++;
- p = xmodem_read_block(buf);
- if (buf && !p) {
+ if (xmodem_read_block(&buf) < 0) {
serial_putc(XMODEM_NAK);
} else {
- if (p)
- buf = p;
size += XMODEM_BLOCK_SIZE;
serial_putc(XMODEM_ACK);
}

ブートローダーの修正はこんだけ.次はOSの修正点.

■ OSの修正

まず,シリアルの転送レートを19200bpsにする修正.これはブートローダーの修正と同じもの.

diff -ruN h8_10/os/serial.c h8_11/os/serial.c
--- h8_10/os/serial.c Sun Sep 20 13:39:30 2009
+++ h8_11/os/serial.c Sun Sep 20 18:43:09 2009
@@ -18,8 +18,10 @@
volatile uint8 scmr;
};

-#define H8_3069F_SCI_SMR_CKS0 (1<<0)
-#define H8_3069F_SCI_SMR_CKS1 (1<<1)
+#define H8_3069F_SCI_SMR_CKS_PER1 (0<<0)
+#define H8_3069F_SCI_SMR_CKS_PER4 (1<<0)
+#define H8_3069F_SCI_SMR_CKS_PER16 (2<<0)
+#define H8_3069F_SCI_SMR_CKS_PER64 (3<<0)
#define H8_3069F_SCI_SMR_MP (1<<2)
#define H8_3069F_SCI_SMR_STOP (1<<3)
#define H8_3069F_SCI_SMR_OE (1<<4)
@@ -64,7 +66,17 @@

sci->scr = 0;
sci->smr = 0;
+#if 0
sci->brr = 64; /* 20MHz 9600bps */
+#elif 1
+ sci->brr = 32; /* 20MHz 19200bps */
+#elif 0
+ sci->brr = 15; /* 20MHz 38400bps */
+#elif 0
+ sci->brr = 9; /* 20MHz 57600bps */
+#else
+ sci->brr = 4; /* 20MHz 115200bps */
+#endif
sci->scr = H8_3069F_SCI_SCR_RE | H8_3069F_SCI_SCR_TE;
sci->ssr = 0;

次に,消費電力低減のためにアイドル時にスリープモードに入るようにする修正.

diff -ruN h8_10/os/idle.c h8_11/os/idle.c
--- h8_10/os/idle.c Sun Sep 20 13:39:30 2009
+++ h8_11/os/idle.c Sun Sep 20 18:43:09 2009
@@ -5,6 +5,6 @@
int idle_main(int argc, char *argv[])
{
while (1) {
- /* none */
+ asm volatile ("sleep");
}
}

スリープ命令を実行すればいいだけのようなので,そのように修正した.idleスレッド中にシリアル出力するような処理を入れて実際に試してみたところ,sleep実行するとシリアル出力されなくなるので,たしかにスリープしているようだ.

次に,スタックサイズ指定の修正.これにより,idleスレッドのようなたいしてスタックを利用しないスレッドはスタックサイズを少なく指定して起動できるので,メモリの節約になる.

具体的には,kz_start()とkz_run()に stacksize というパラメータを追加して,スレッド単位でスタックサイズを指定できるように修正している.ちょっとソースコード全体に渡って修正が入っているのだけど,まあパラメータ追加とか引数追加のちょろっとした修正なので,全部ここで説明するのはやめておく.興味のある人はdiffをとって見てみて.とりあえず kozos.h と syscall.[ch] の修正内容を以下に添付しておく.

diff -ruN h8_10/os/kozos.h h8_11/os/kozos.h
--- h8_10/os/kozos.h Sun Sep 20 13:39:30 2009
+++ h8_11/os/kozos.h Sun Sep 20 18:43:09 2009
@@ -11,7 +11,7 @@
typedef int (*kz_dbgfunc)(struct _kz_thread *thp, int signo);

/* syscall */
-uint32 kz_run(kz_func func, char *name, int pri, int argc, char *argv[]);
+uint32 kz_run(kz_func func, char *name, int pri, int stacksize, int argc, char *argv[]);
void kz_exit();
int kz_wait();
int kz_sleep();
@@ -35,7 +35,7 @@
int kx_kmfree(void *p);

/* library */
-void kz_start(kz_func func, char *name, int pri, int argc, char *argv[]);
+void kz_start(kz_func func, char *name, int pri, int stacksize, int argc, char *argv[]);
void kz_sysdown();
void kz_trap();
void kz_break();


diff -ruN h8_10/os/syscall.c h8_11/os/syscall.c
--- h8_10/os/syscall.c Sun Sep 20 13:39:30 2009
+++ h8_11/os/syscall.c Sun Sep 20 18:43:09 2009
@@ -12,12 +12,13 @@

/* System Call */

-uint32 kz_run(kz_func func, char *name, int pri, int argc, char *argv[])
+uint32 kz_run(kz_func func, char *name, int pri, int stacksize, int argc, char *argv[])
{
kz_syscall_param_t param;
param.un.run.func = func;
param.un.run.name = name;
param.un.run.pri = pri;
+ param.un.run.stacksize = stacksize;
param.un.run.argc = argc;
param.un.run.argv = argv;
kz_syscall(KZ_SYSCALL_TYPE_RUN, &param);


diff -ruN h8_10/os/syscall.h h8_11/os/syscall.h
--- h8_10/os/syscall.h Sun Sep 20 13:39:30 2009
+++ h8_11/os/syscall.h Sun Sep 20 18:43:09 2009
@@ -28,6 +28,7 @@
kz_func func;
char *name;
int pri;
+ int stacksize;
int argc;
char **argv;
int ret;

次に,extintr でメッセージ使用するための修正.

diff -ruN h8_10/os/extintr.c h8_11/os/extintr.c
--- h8_10/os/extintr.c Sun Sep 20 13:39:30 2009
+++ h8_11/os/extintr.c Sun Sep 20 18:43:09 2009
@@ -5,7 +5,7 @@

#include "lib.h"

-/* #define USE_MESSAGE */
+#define USE_MESSAGE

#define BUFFER_SIZE 16

これを有効にする場合には,extintr が優先度ゼロで起動して,さらに優先度ゼロのスレッドは割り込み禁止で動作するという対処を入れる必要がある(でないと割り込みフラグが落ちないままにスレッドのディスパッチが行われ,割り込み有効になって再度割り込みが入って無限ループになってしまう).割り込み禁止にする処理はすでに thread.c の thread_run() に入っているので,extintr の起動時に優先度ゼロで起動するように kozos.c に対処を入れる.

diff -ruN h8_10/os/kozos.c h8_11/os/kozos.c
--- h8_10/os/kozos.c Sun Sep 20 13:39:30 2009
+++ h8_11/os/kozos.c Sun Sep 20 18:43:09 2009
@@ -10,18 +10,18 @@
kz_debug(stub_proc);
#endif

- extintr_id = kz_run(extintr_main, "extintr", 1, 0, NULL);
- idle_id = kz_run(idle_main, "idle", 31, 0, NULL);
+ extintr_id = kz_run(extintr_main, "extintr", 0, 0x200, 0, NULL);
+ idle_id = kz_run(idle_main, "idle", 31, 0x100, 0, NULL);
#if 0
- command0_id = kz_run(command_main, "command0", 11, 0, NULL);
+ command0_id = kz_run(command_main, "command0", 11, 0x200, 0, NULL);
#endif
- command1_id = kz_run(command_main, "command1", 11, 1, NULL);
+ command1_id = kz_run(command_main, "command1", 11, 0x200, 1, NULL);

return 0;
}

int kozos_start(int argc, char *argv[])
{
- kz_start(mainfunc, "main", 0, argc, argv);
+ kz_start(mainfunc, "main", 0, 0x100, argc, argv);
return 0;
}

上の差分だとスレッドのスタック指定の差分がいっしょになっていてちょっとわかりづらいのだけど,extintr の優先度が1→0に変更されている点に注意.

次に thread.c の修正.以下の点を修正してある.
  • thread_run()にstacksizeの引数を追加し,スタックをスレッドごとに指定されたサイズで獲得するように処理を変更.
  • schedule()の処理をデバッグ用にベタ書きで書いてそのまま忘れていたので,もとに戻す.
  • 割り込み発生時のレジスタ退避順序が変更されたので,それに合わせて退避処理を修正.ついでにmemcpy()で簡略化する.

diff -ruN h8_10/os/thread.c h8_11/os/thread.c
--- h8_10/os/thread.c Sun Sep 20 13:39:30 2009
+++ h8_11/os/thread.c Sun Sep 20 18:43:09 2009
@@ -80,7 +80,7 @@
thread_end();
}

-static uint32 thread_run(kz_func func, char *name, int pri,
+static uint32 thread_run(kz_func func, char *name, int pri, int stacksize,
int argc, char *argv[])
{
int i;
@@ -100,9 +100,9 @@
thp->func = func;
thp->pri = pri;

- memset(thread_stack, 0, SIGSTKSZ);
+ memset(thread_stack, 0, stacksize);

- thread_stack += THREAD_STACK_SIZE;
+ thread_stack += stacksize;
thp->stack = thread_stack;

thp->context.pc = (uint32)thread_init | ((uint32)(pri ? 0 : 0xc0) << 24);
@@ -306,7 +306,8 @@
/* システムコールの実行中にcurrentが書き換わるので注意 */
switch (type) {
case KZ_SYSCALL_TYPE_RUN:
- p->un.run.ret = thread_run(p->un.run.func, p->un.run.name, p->un.run.pri,
+ p->un.run.ret = thread_run(p->un.run.func, p->un.run.name,
+ p->un.run.pri, p->un.run.stacksize,
p->un.run.argc, p->un.run.argv);
break;
case KZ_SYSCALL_TYPE_EXIT:
@@ -384,7 +385,6 @@

static void schedule()
{
-#if 0
#if PRI_NUM > 32
#error ビットマップを配列化する必要あり
#endif
@@ -412,14 +412,6 @@
while (1)
;
}
-#else
- int n;
- for (n = 0; n < PRI_NUM; n++)
- if (readyque[n].head) break;
- if (n == PRI_NUM)
- while (1)
- ;
-#endif

current = readyque[n].head;
}
@@ -505,14 +497,8 @@
break;
}

- p = (uint32 *)INTR_STACK_START;
- current->context.er[7] = *(--p);
- current->context.er[1] = *(--p);
- current->context.er[2] = *(--p);
- current->context.er[3] = *(--p);
- current->context.er[4] = *(--p);
- current->context.er[5] = *(--p);
- current->context.er[6] = *(--p);
+ p = (uint32 *)INTR_STACK_START - 7;
+ memcpy(&current->context.er[1], p, sizeof(*p) * 7);
current->context.er[0] = *(uint32 *)(current->context.er[7]);

current->context.pc = *(uint32 *)(current->context.er[7] + 4);
@@ -521,7 +507,7 @@
current = thp;
}

-static void thread_start(kz_func func, char *name, int pri, int argc, char *argv[])
+static void thread_start(kz_func func, char *name, int pri, int stacksize, int argc, char *argv[])
{
memset(threads, 0, sizeof(threads));
memset(readyque, 0, sizeof(readyque));
@@ -535,16 +521,16 @@
* 直接関数を呼び出してスレッド作成する.
*/
current = NULL;
- current = (kz_thread *)thread_run(func, name, pri, argc, argv);
+ current = (kz_thread *)thread_run(func, name, pri, stacksize, argc, argv);

dispatch(&current->context);
}

-void kz_start(kz_func func, char *name, int pri, int argc, char *argv[])
+void kz_start(kz_func func, char *name, int pri, int stacksize, int argc, char *argv[])
{
kzmem_init();

- thread_start(func, name, pri, argc, argv);
+ thread_start(func, name, pri, stacksize, argc, argv);

/* ここには返ってこない */
while (1)

修正は以上.いちおう,これできちんと動作することは確認できた.

これでOSもばっちり動いて,だいたいソースもすっきりした.さて次は何をやろうか.
(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.

前回の課題というか今までの課題として,第4回でちょろっと書いたのだけど,ブートローダーをモトローラSレコードフォーマットに対応させよう.理由は以下.
  • 現状で loadbuf[] というバッファにいったんロードしてから実メモリ上に展開しているので,RAM16KBの半分の8KBまでのサイズしか原理的にロードできない.
  • ELFフォーマットのプログラムヘッダを読みながら解析して実メモリ上に直接展開,ということはできなくはないが,なんかめんどい.
  • モトローラSレコードフォーマットだと,読み込みながら実メモリ上に直接展開が非常にやりやすい.
  • 現状でKOZOSのバイナリサイズとロード用のバッファとかがギリギリの感じで,これ以上機能拡張するのはちょっと難しい.ロード用バッファが不要な構成にしたい.
  • 他にもテキストのみのフォーマットなのでなにかと便利だし,安全安心.(バイナリコードだと7bit回線は通らないとか,そーいうことも気にしなくて済む)
  • いろんなところで使われていて,組み込み分野ではかなり普及度が高いフォーマットである.


で,以下の方針で実装してみた.
  • ELFとモトローラSフォーマットの両方に対応.
  • ELFの場合は loadelf, runelf コマンドでロードと起動.動作的には従来と同様で,loadelf でバッファにいったん読み込んで,runelf で実メモリに展開して実行する.
  • モトローラSフォーマットの場合は,load,run コマンドでロードと起動.
  • つまり従来の load, run コマンドは,ELFでなくモトローラSフォーマットを解釈するように仕様変更し,ELF用には loadelf, runelf を新設するということだ.
で,実装したのが以下.モトローラSフォーマットの解釈のために,ブートローダーに srec.c というファイルが追加されている.モトローラSフォーマットについてはネットで検索するといっぱい出てくるのでここではいちいち説明しないけど,まあ解析はたいしてたいへんではない.

修正内容について,以下に説明しよう.まずはブートローダーの修正箇所.

diff -ruN h8_08/kzload/ld.scr h8_10/kzload/ld.scr
--- h8_08/kzload/ld.scr Sun Sep 20 00:33:51 2009
+++ h8_10/kzload/ld.scr Sun Sep 20 13:39:14 2009
@@ -8,6 +8,7 @@
rom(rx) : o = 0x000100, l = 0x07ff00 /* 512kb */
ram(rwx) : o = 0xffbf20, l = 0x004000 /* 16kb */
buffer(rwx) : o = 0xffdf20, l = 0x002000 /* 8kb */
+ data(rwx) : o = 0xffdf20+7400, l = 0x002000-7400 /* -BUFSIZE */
stack(rw) : o = 0xffff00, l = 0x000010 /* end of RAM */
}

@@ -30,18 +31,22 @@
_erodata = . ;
} > rom

+ .buffer : {
+ _buffer_start = . ;
+ } > buffer
+
.data : AT(_erodata) {
_data_start = . ;
*(.data)
_edata = . ;
- } > buffer
+ } > data

.bss : {
_bss_start = . ;
*(.bss)
*(COMMON)
_ebss = . ;
- } > buffer
+ } > data

_end = . ;

まずリンカスクリプトなのだけど,従来はグローバル変数も loadbuf[] も両方ともバッファ領域に配置されていて,BSSの展開時にグローバル変数も破壊される恐れがあった(ていうか,破壊されていた).

対策として,ロード用のバッファ領域とデータ領域を別セクションとして,データ領域はバッファ領域の後ろのほうに配置してグローバル変数などのデータはそっちに持っていくように修正した.

同様に,main.c の修正が以下.

diff -ruN h8_08/kzload/main.c h8_10/kzload/main.c
--- h8_08/kzload/main.c Sun Sep 20 00:33:51 2009
+++ h8_10/kzload/main.c Sun Sep 20 13:39:14 2009
@@ -1,12 +1,10 @@
#include "lib.h"
#include "serial.h"
#include "xmodem.h"
+#include "srec.h"
#include "elf.h"
#include "interrupt.h"

-#define BUFSIZE 7400
-static unsigned char loadbuf[BUFSIZE];
-
static int init()
{
extern int erodata, data_start, edata, bss_start, ebss;
@@ -33,7 +31,8 @@
return 0;
}

-static int putval(unsigned int value, int column)
+#if 0
+static int putval(unsigned long value, int column)
{
char buf[12];
char *p;
@@ -54,8 +53,9 @@

return 0;
}
+#endif

-static int putxval(unsigned int value, int column)
+static int putxval(unsigned long value, int column)
{
char buf[9];
char *p;
@@ -118,6 +118,8 @@
int size = -1;
char *entry_point;
void (*f)();
+ unsigned char *loadbuf;
+ extern int buffer_start;

init();

@@ -127,7 +129,11 @@
puts("kzboot> ");
gets(buf);

- if (!strcmp(buf, "load")) {
+ if (!strcmp(buf, "load") || !strcmp(buf, "loadelf")) {
+ if (!strcmp(buf, "load"))
+ loadbuf = NULL;
+ else
+ loadbuf = (char *)(&buffer_start);
size = xmodem_recv(loadbuf);
if (size < 0) {
puts("XMODEM receive error!\n");
@@ -136,15 +142,20 @@
}
} else if (!strcmp(buf, "dump")) {
puts("size: ");
- putval(size, 0);
+ putxval(size, 0);
puts("\n");
dump(loadbuf, size);
- } else if (!strcmp(buf, "run")) {
- entry_point = elf_load(loadbuf);
+ } else if (!strcmp(buf, "run") || !strcmp(buf, "runelf")) {
+ if (!strcmp(buf, "run"))
+ entry_point = srec_startaddr();
+ else
+ entry_point = elf_load(loadbuf);
if (!entry_point) {
puts("run error!\n");
} else {
- puts("starting from entry point.\n");
+ puts("starting from entry point: ");
+ putxval((unsigned long)entry_point, 0);
+ puts("\n");
f = (void (*)())entry_point;
f();
}

従来はロード用のバッファ領域を loadbuf[] として静的に獲得していたが,リンカスクリプト内で定義されている &buffer_start を見て,バッファ領域を利用するように修正.

あと loadelf とか runelf とかのコマンド対応がされている.load が実行されたときにはバッファ領域は必要無いのでバッファ未指定でxmodem_recv()が呼ばれ,この場合にはモトローラSフォーマットを受信して直接展開する,という動作になる.

次に xmodem.c の修正.

diff -ruN h8_08/kzload/xmodem.c h8_10/kzload/xmodem.c
--- h8_08/kzload/xmodem.c Sun Sep 20 00:33:51 2009
+++ h8_10/kzload/xmodem.c Sun Sep 20 13:39:14 2009
@@ -1,5 +1,6 @@
#include "lib.h"
#include "serial.h"
+#include "srec.h"
#include "uudecode.h"
#include "xmodem.h"

@@ -46,11 +47,16 @@
check_sum = 0;
for (i = 0; i < XMODEM_BLOCK_SIZE; i++) {
c = serial_getb();
+ if (!buf) {
+ if (srec_decode(c) < 0)
+ return NULL;
+ } else {
#ifdef USE_UUENCODE
- buf = uu_decode(buf, c);
+ buf = uu_decode(buf, c);
#else
- *(buf++) = c;
+ *(buf++) = c;
#endif
+ }
check_sum += c;
}

@@ -67,6 +73,8 @@
unsigned char c;
unsigned char *p;

+ srec_init();
+
while (1) {
if (!receiving)
xmodem_wait();
@@ -79,10 +87,11 @@
} else if (c == XMODEM_SOH) {
receiving++;
p = xmodem_read_block(buf);
- if (!p) {
+ if (buf && !p) {
serial_putc(XMODEM_NAK);
} else {
- buf = p;
+ if (p)
+ buf = p;
size += XMODEM_BLOCK_SIZE;
serial_putc(XMODEM_ACK);
}

バッファ未指定の場合の対処が追加されている.

ブートローダーの修正のおおまかな内容は以上.次にOS側の修正点.

まず make image でモトローラSフォーマットのファイル「kozos.mot」を作成するように Makefile にターゲットを追加.

diff -ruN h8_08/os/Makefile h8_10/os/Makefile
--- h8_08/os/Makefile Sun Sep 20 00:34:04 2009
+++ h8_10/os/Makefile Sun Sep 20 13:39:30 2009
@@ -42,11 +42,14 @@
#$(LIB) : $(LIBOBJS)
# $(AR) ruc $(LIB) $(LIBOBJS)

-$(TARGET).uu : $(TARGET)
+$(TARGET).mot : $(TARGET)
+ $(OBJCOPY) -O srec $(TARGET) $(TARGET).mot
+
+$(TARGET).uu : $(TARGET)
uuencode -o $(TARGET).uu $(TARGET) $(TARGET)

-image : $(TARGET).uu
+image : $(TARGET).mot $(TARGET).uu

clean :
rm -f $(OBJS) $(LIBOBJS) $(LIB) \
- $(TARGET) $(TARGET).elf $(TARGET).uu
+ $(TARGET) $(TARGET).elf $(TARGET).mot $(TARGET).uu

次に,BSSの初期化処理を追加する.モトローラSフォーマットだとBSSの情報が来ないみたいなので,OS側でゼロクリアする必要がある.これをやらないとなんかうまく動かなかった.

diff -ruN h8_08/os/main.c h8_10/os/main.c
--- h8_08/os/main.c Sun Sep 20 00:34:04 2009
+++ h8_10/os/main.c Sun Sep 20 13:39:30 2009
@@ -9,6 +9,12 @@

static int init()
{
+ extern int bss_start;
+ extern int ebss;
+
+ /* clear BSS */
+ memset(&bss_start, 0, (uint32)&ebss - (uint32)bss_start);
+
serial_initialize(0, 0);
return 0;
}

OS側の修正はこれだけ.

では実際に試してみよう.ブートローダーをビルドしてフラッシュROMに書き込んで起動し,従来通りの動作として,loadelf; runelf でELFフォーマットをダウンロードさせてOS起動してみる.

kzboot> loadelf
~CLocal command? lsx kozos
Sending kozos, 56 blocks: Give your local XMODEM receive command now.
Bytes Sent: 7296 BPS:777

Transfer complete
eceive succeeded.
kzboot> runelf
starting from entry point: ffc120
kozos boot succeed!
command> echo aaa
aaa
OK
command> threads
extintr
idle
command1
OK
command>

とりあえず問題なさそう.

次に,リセットボタンを押してブートローダーを起動しなおして,load; run でモトローラSフォーマットでダウンロードしてOS起動してみる.

kzboot> load
~CLocal command? lsx kozos.mot
Sending kozos.mot, 153 blocks: Give your local XMODEM receive command now.
Bytes Sent: 19712 BPS:827

Transfer complete
eceive succeeded.
kzboot> run
starting from entry point: ffc120
kozos boot succeed!
command> echo aaaa
aaaa
OK
command> threads
extintr
idle
command1
OK
command>

おー問題無さそうだ.ちゃんと動いている.

ただ,当り前だけどモトローラSフォーマットはテキスト形式なので,ダウンロード時間がやたら長くなる.修正しては試してまた修正してをガンガン繰り返すような感じでやりたいときにはちょっとうっとうしいかも.まあシリアルの速度が9600bpsなので,115200bpsとかにすれば解決できるとは思うが.これはそのうち考えよう.
(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.

前回よーやくH8への移植ができたが,移植の作業内容について説明しよう.

作業した内容として,だいたい以下のようなものがあった.

■ ブートローダー側の対応
  • ELFファイルのサイズが一気に増えたことに対する対応.
  • 割り込み時に割り込み用スタックを利用するように修正.


■ OS側の対応
  • メモリ調整.
  • 割り込みまわりをH8に合わせて修正.
  • intが16ビットなので,必要に応じて uint32 にする対応.


まあこんなとこかな.

まずブートローダーの修正だけど,ロードするELFファイルのサイズが格段に増えたので,そのままだとうまくロードできなかったので何箇所か手を入れた.

まずはそもそもバッファのサイズが足りなかったので拡張する修正.

diff -ruN h8_06/kzload/main.c h8_08/kzload/main.c
--- h8_06/kzload/main.c Tue Sep 15 00:26:55 2009
+++ h8_08/kzload/main.c Sun Sep 20 00:33:51 2009
@@ -4,7 +4,7 @@
#include "elf.h"
#include "interrupt.h"

-#define BUFSIZE 4096
+#define BUFSIZE 7400
static unsigned char loadbuf[BUFSIZE];

static int init()

さらに,BSSの展開時に(BSSのサイズがこれがまたでかいため)上記 loadbuf の内容を上書きしてしまうことが判明した.このためloadbuf上にあるELFヘッダを上書きしてしまい誤動作していることが判明.本当はなんかきちんと考える必要があるのだが,とりあえずBSSを展開したらそのまま終了するように修正.

diff -ruN h8_06/kzload/elf.c h8_08/kzload/elf.c
--- h8_06/kzload/elf.c Tue Sep 15 00:26:55 2009
+++ h8_08/kzload/elf.c Sun Sep 20 00:33:51 2009
@@ -72,6 +72,11 @@
phdr->file_size);
} else {
memset((char *)phdr->physical_addr, 0, phdr->memory_size); /* for BSS */
+ /*
+ * BSSがバッファ領域にまたがっている場合,BSSをクリアすることで
+ * バッファが破壊されてしまうので,BSSが見つかったらそのまま終了する.
+ */
+ break;
}
}

@@ -81,12 +86,16 @@
char *elf_load(char *buf)
{
struct elf_header *header = (struct elf_header *)buf;
+ char *entry_point;

if (elf_check(header) < 0)
return NULL;

+ /* BSSの展開でバッファが書きつぶされる場合があるので,保存しておく */
+ entry_point = (char *)header->entry_point;
+
if (elf_load_program(header) < 0)
return NULL;

- return (char *)header->entry_point;
+ return entry_point;
}

上述のようにBSSの展開でELFヘッダが破壊されてしまうので,エントリポイントを保存しておくように修正している.

次に,割り込みまわり.

まず割り込みハンドラを呼ぶ際に,引数として割り込み番号を渡すように修正.これはOS側で割り込みハンドラを共通化して内部で割り込み番号を見て処理を分けるために利用する.

diff -ruN h8_06/kzload/interrupt.c h8_08/kzload/interrupt.c
--- h8_06/kzload/interrupt.c Tue Sep 15 00:26:55 2009
+++ h8_08/kzload/interrupt.c Sun Sep 20 00:33:51 2009
@@ -19,6 +19,6 @@
{
interrupt_handler_t handler = VECTORS[vec];
if (handler)
- handler();
+ handler(vec);
return;
}
diff -ruN h8_06/kzload/interrupt.h h8_08/kzload/interrupt.h
--- h8_06/kzload/interrupt.h Tue Sep 15 00:26:55 2009
+++ h8_08/kzload/interrupt.h Sun Sep 20 00:33:51 2009
@@ -3,7 +3,7 @@

#define VECTOR_NUM 64
#define VECTOR_ADDR ((void *)0xffbf20)
-typedef void (*interrupt_handler_t)(void);
+typedef void (*interrupt_handler_t)(int vec);

#define VECTORS ((interrupt_handler_t *)VECTOR_ADDR)

さらに,従来は割り込み発生時にはそのときのスタックをそのまま利用していたのだけど,スレッドベースでの動作になったときに,スレッドのスタックをそのまま割り込み処理に使うのはなんかイヤ.スレッドから見ると,なんか突然スタックの未使用領域が汚されることになるからね.ということで,割り込み処理用のスタックを用意してそっちに切替えて動作するように修正.

diff -ruN h8_06/kzload/intr.S h8_08/kzload/intr.S
--- h8_06/kzload/intr.S Tue Sep 15 00:26:55 2009
+++ h8_08/kzload/intr.S Sun Sep 20 00:33:51 2009
@@ -5,6 +5,9 @@
.type _intr01,@function
_intr01:
mov.l er0,@-er7
+ mov.l er7,er0
+ mov.l #_stack,sp
+ mov.l er0,@-er7
mov.l er1,@-er7
mov.l er2,@-er7
mov.l er3,@-er7
@@ -20,12 +23,17 @@
mov.l @er7+,er2
mov.l @er7+,er1
mov.l @er7+,er0
+ mov.l er0,er7
+ mov.l @er7+,er0
rte

スタックポインタ(ER7)の保存のためにER0を使っている.なのでER0の値は現在使用中のスタックに退避するようになっている.なので厳密にアプリのスタックをまったく使わないということではないのだけど,まあそもそも割り込み発生時にスタックにPCとかCCRとかが退避されてしまうので,アプリのスタックをまったく汚さないというのは不可能なので,まあそのまま引続きアプリのスタック上で動作しなければまあいいかなということで,これでいいとする.

ちなみに上記修正のために,前々回のサンプルプログラムはそのままでは動作しなくなってしまう.これは,前々回まではスレッドベースの動作ではなくアプリは 0xffff00 をスタックとして利用していたが,割り込み処理でも0xffff00 をスタックとして利用するようになったため,スタックポインタが前に戻ってアプリのスタックを上書きしてしまうから.

なのでもしも前々回のアプリを動かすならば,アプリに以下の修正を入れて,アプリ用のスタックと割り込み処理用のスタックを別々にする必要あり.

diff -ruN serial/ld.scr serial2/ld.scr
--- serial/ld.scr Sat Sep 19 16:58:54 2009
+++ serial2/ld.scr Sat Sep 19 19:56:47 2009
@@ -9,7 +9,8 @@
* and 256bytes space for ELF header.
*/
ram(rwx) : o = 0xffbf20 + 0x200, l = 0x004000 - 0x200 /* 16kb */
- stack(rw) : o = 0xffff00, l = 0x000010 /* end of RAM */
+ bootstack(rw) : o = 0xfffd00, l = 0x000010 /* end of RAM */
+ intrstack(rw) : o = 0xffff00, l = 0x000010 /* end of RAM */
}

SECTIONS
@@ -42,7 +43,11 @@

_end = . ;

- .stack : {
- _stack = .;
- } > stack
+ .bootstack : {
+ _bootstack = .;
+ } > bootstack
+
+ .intrstack : {
+ _intrstack = .;
+ } > intrstack
}
diff -ruN serial/startup.s serial2/startup.s
--- serial/startup.s Sat Sep 19 16:58:54 2009
+++ serial2/startup.s Sat Sep 19 19:57:14 2009
@@ -3,7 +3,7 @@
.global _start
.type _start,@function
_start:
- mov.l #_stack,sp
+ mov.l #_bootstack,sp
jsr @_main

_loop:

あとついでにブートローダーのメッセージをなんかそれっぽいものに変える修正.

@@ -121,10 +121,10 @@

init();

- puts("Hello World!\n");
+ puts("kzboot (kozos boot loader) started.\n");

while (1) {
- puts("> ");
+ puts("kzboot> ");
gets(buf);

if (!strcmp(buf, "load")) {

ブートローダー側の修正は以上.

次にOS側の対応.

まずは Makefile の修正.

--- h8_07/os/Makefile Sat Sep 19 17:24:41 2009
+++ h8_08/os/Makefile Sun Sep 20 00:34:04 2009
@@ -1,15 +1,24 @@
OBJS += startup.o main.o interrupt.o
-OBJS += lib.o serial.o timer.o
+OBJS += lib.o serial.o
+#OBJS += timer.o
+
+# sources of kozos
+OBJS += thread.o syscall.o memory.o idle.o
+OBJS += extintr.o
+OBJS += kozos.o command.o
+
#LIBOBJS +=
#LIB = libxxx.a
-TARGET ?= hello
+TARGET ?= kozos
#CC ?= gcc
CFLAGS =
CFLAGS += -Wall -mh -nostdinc -nostdlib -fno-builtin
#CFLAGS += -mint32 # intを32ビットにすると掛算/割算ができなくなる
CFLAGS += -I.
-CFLAGS += -g
+#CFLAGS += -g
#CFLAGS += -O
+CFLAGS += -Os
+CFLAGS += -DKOZOS

LFLAGS += -static -T ld.scr -L.

KOZOS移植で追加されるソースをコンパイル対象に追加して,あとターゲット名をhelloからkozosに変更.さらに -g がついてるとデバッグ情報が付加されてリンカスクリプトで指定したメモリ上に入りきれなくてリンクエラーになってしまうので,まあどうせ strip でデバッグ情報は捨ててしまうので-gを削除.あとサイズを極力小さくするために,コンパイルオプションに -Os を追加(これがけっこう威力がでかくて,これのおかげでなんとかメモリ上に収まった).

次にKOZOSのソースコードで大きな変更を行った部分やハマッた部分について説明しよう.

まずはthread.cなどで,32ビットが必要な部分(ポインタの値を保存しているとか)でintを使っている部分を uint32 に変更.まあ本来なら -mint32 オプションでコンパイルすることで int を32ビットにできるのだけど,そもそも16ビットCPUなのだからネイティブな状態で動作させたいし,KOZOSの16ビット対応をするいい機会なので,ごっそり書き換えることにした.

ここで1箇所ハマッた部分があって,レディーキューのビットマップを立てる以下の箇所

readyque_bitmap |= (1 << current->pri);

上記はシフト演算が16ビットで行われてしまうので,優先度が16以上のスレッドが動作できないという問題が発覚(このためidleスレッドが動作できず,動作可能なスレッドの検索に失敗して schedule() 内で停止してしまっていた).以下のように修正した.

readyque_bitmap |= ((uint32)1 << current->pri);

スレッドのコンテキストは,レジスタの内容をH8に合わせて thread.h の定義を変更.

typedef struct _kz_context {
uint32 er[8];
uint32 pc;
} kz_context;

あとは割り込み発生時に割り込み処理スタックの先頭にレジスタ情報が退避されるので,そっから情報を吸い上げてスレッドのコンテキストに保存する対応.

void thread_intr(int vec)
{
...
p = (uint32 *)INTR_STACK_START;
current->context.er[7] = *(--p);
current->context.er[1] = *(--p);
current->context.er[2] = *(--p);
current->context.er[3] = *(--p);
current->context.er[4] = *(--p);
current->context.er[5] = *(--p);
current->context.er[6] = *(--p);
current->context.er[0] = *(uint32 *)(current->context.er[7]);

current->context.pc = *(uint32 *)(current->context.er[7] + 4);
...

あとちなみに INTR_STACK_START の定義だが,configure.h で

extern uint32 intrstack;
#define INTR_STACK_START (&intrstack)

のようにしているけど,これも最初は

extern uint32 intrstack;
#define INTR_STACK_START intrstack

のように書いてしまっていて,割り込みスタックからレジスタ情報をうまく保存できなくてその後のスレッドのディスパッチに失敗するというバグでハマッた.ああまぬけ.configure.h では,スレッドのスタックの位置やサイズも調整してある.

startup.s にはディスパッチ用の処理を追加.

.global _dispatch
.type _dispatch,@function
_dispatch:
mov.l er0,er7
mov.l @er7+,er0
mov.l @er7+,er1
mov.l @er7+,er2
mov.l @er7+,er3
mov.l @er7+,er4
mov.l @er7+,er5
mov.l @er7+,er6
mov.l @er7+,er0
mov.l er0,er7
mov.l @er7+,er0
rte

上述したようにER0の値はスレッドのスタック上に退避されているので,そっちを利用するようにしてある.これも,最初はER0の値を読み出すのを忘れていたためにスタックポインタがER0を指している状態で rte してしまって,おかしなアドレスにジャンプしていたというバグがあった.

あと,serial.c は3本のSCIを選択できるように引数に index を渡せるように修正(これは,流用したPowerPCのKOZOSがそのようになっていたのでそれに合わせた).あと memory.c はもともとは湯水のようにメモリを使っていたのだけど,あんまし無駄にメモリ獲得しないように修正.extintr.c もバッファに無駄に1024バイトとか使っていた部分があったので,修正.

extintr.c はとりあえずSCI1を利用するようにして,あと USE_MESSAGE を未指定にするようにした.これは USE_MESSAGE 有効だと,割り込み発生時にはメッセージ送信だけ行って割り込みフラグを落とさずにスレッドのディスパッチに入ってしまい,ディスパッチ直後にまた割り込みが入ってしまって無限ループになって,そのうちメッセージ用のメモリの枯渇で固まる,というバグがあったから.これもハマッた.(PowerPCはスレッドレベルがゼロのスレッドは割り込み禁止で動作する対応が入っていて,H8にも同じ対応を入れたのだけど,extintr のスレッドレベルをゼロにするのを忘れていて現状では USE_MESSAGE 有効だとうまく動作しない)

kozos.c はSCI1が利用されるように command1 スレッドを起動するように修正.これも,当初はメッセージが出なくてちょっと悩んだところだ.

あと puts() とか putxval() とかのライブラリが main.c にあったのだけど,lib.c に移動した.

あと thread.c の thread_run() で,従来はスタックをてきとうに確保していたのだけど,下方伸長なので thread_stack を増加させてからスタックポインタを設定するように修正.これでスタックひとつぶんのメモリが節約できる.thread_run()は他にもレジスタ周りの設定をH8に合わせて修正.

あとはまあこまごまと,メモリ節約のためにいろんなところを修正してある.

説明のためにソースを見返すと,なんというかちょっとなんだかなあな箇所がいっぱい.ちょっと細かいところをきれいにして,すっきりしたソースコードにしたいところだ.
  • モトローラSフォーマットにして,メモリ上に直接ロードするようにしてロード用のバッファを不要にする.
  • schedule()の処理をすっきりさせる.
  • スタックサイズをスレッドごとに指定可能にする.
  • extintr.c のUSE_MESSAGE対応.
  • 全体的に見直して,不要な部分を削除してすっきりさせる.
あとは気が向けば,puts() や putxval() などのライブラリはブートローダー側でROM上にサービスルーチンとして用意して,そっちを呼び出すようにすることでOSのサイズを削減できる(BIOSっぽいものを作る).まあでもなるべくならBIOSに依存せずにOS側ですべて行いたいので,これはほんとに気が向けば.

まあでもサービスルーチンをBIOS側で用意するっつーのは,それはそれで面白いかも.BIOSがどんなことをやっているのかの学習用にはいいかもしれん.

こー考えると,H8って内蔵フラッシュROMが512KBで内蔵RAMが16KBなのでROMのほうがずっとサイズがでかいのだけど,これって基本的にはプログラムはROM上で動かして,RAMはスタックとデータ領域とBSSだけに使うっていう使いかたを想定しているんだろうね.今回のKOZOSのように,ROMはブートローダーだけにして,すべてRAM上で動作させるっつー使いかたをするときは,RAMを増設して使うべきなのかもしれん.
(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.

KOZOS移植のためにブートローダー作ったりH8の割り込み周りを試したりといろいろ準備していたが,いよいよKOZOSを移植しよう.

まず移植にあたってだが,とりあえずPowerPCへの移植ソースの最新版をベースにしてみた.

で,移植したのがこれ.とりあえずコマンドプロンプトを出して,コマンド受け付けて動作するようになっている.まあ移植にあたってはいろいろそれなりに苦労したのだけど,詳しい説明は次回に回して,とりあえず公開しよう.ブートローダーにちょこっと手を入れているので,ブートローダーも修正版を公開.移植なのだけど,まずH8が16ビットマイコンなので,intの16ビット対応がいろんなとこに手が入っている.あと割り込み周りをH8に合わせて書き直してある.

まず,OSをビルドしてみよう.ビルド方法は今までと同じ.

hiroaki@teapot:~/h8/os/kozos>% ./make.sh
+ LOCAL=/usr/local
+ TARGET=h8300-elf
+ TARGETDIR=/usr/local/h8300-elf
+ PATH=/usr/local/h8300-elf/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/usr/pkg/sbin:/usr/pkg/bin:/usr/X11R6/sbin:/usr/X11R6/bin:/home/hiroaki/bin: export PATH
+ GCC_EXEC_PREFIX=/usr/local/h8300-elf/bin export GCC_EXEC_PREFIX
+ AR=/usr/local/h8300-elf/bin/ar export AR
+ AS=/usr/local/h8300-elf/bin/as export AS
+ CC=/usr/local/h8300-elf/bin/gcc export CC
+ /usr/local/h8300-elf/bin/gcc -print-prog-name=cpp
+ CPP=cpp export CPP
+ CXX=/usr/local/h8300-elf/bin/gcc export CXX
+ FC=/usr/local/h8300-elf/bin/f77 export FC
+ LD=/usr/local/h8300-elf/bin/ld export LD
+ NM=/usr/local/h8300-elf/bin/nm export NM
+ RANLIB=/usr/local/h8300-elf/bin/ranlib export RANLIB
+ SIZE=/usr/local/h8300-elf/bin/size export SIZE
+ ADDR2LINE=/usr/local/h8300-elf/bin/addr2line export ADDR2LINE
+ GASP=/usr/local/h8300-elf/bin/gasp export GASP
+ OBJCOPY=/usr/local/h8300-elf/bin/objcopy export OBJCOPY
+ OBJDUMP=/usr/local/h8300-elf/bin/objdump export OBJDUMP
+ STRINGS=/usr/local/h8300-elf/bin/strings export STRINGS
+ STRIP=/usr/local/h8300-elf/bin/strip export STRIP
+ HOSTED_CC=/usr/bin/cc export HOSTED_CC
+ NOGCCERROR=yes export NOGCCERROR
+ OBJECT_FMT=ELF export OBJECT_FMT
+ MAKE=gmake -f Makefile
+ export MAKE
+ set -x
+ exec gmake -f Makefile
/usr/local/h8300-elf/bin/gcc -c startup.s -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c main.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c interrupt.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c lib.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c serial.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c thread.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c syscall.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c memory.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c idle.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c extintr.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c kozos.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc -c command.c -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS
/usr/local/h8300-elf/bin/gcc startup.o main.o interrupt.o lib.o serial.o thread.o syscall.o memory.o idle.o extintr.o kozos.o command.o -o kozos -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS -static -T ld.scr -L.
cp kozos kozos.elf
/usr/local/h8300-elf/bin/strip kozos
hiroaki@teapot:~/h8/os/kozos>%

では実行してみよう.ブートローダーも修正してあるので,ブートローダーをフラッシュROMに書き込んで起動する.

teapot# cu -l /dev/cuad0
Connected
kzboot (kozos boot loader) started.
kzboot>

ブートローダーの起動メッセージだけど,まあいままでは開発中の名残でHello World とか出していてそのままでちょっとアレだったので,ついでにちょっと変えてみた.プロンプトもついでに修正.

で,OSをダウンロード.

kzboot> load
~CLocal command? lsx kozos
Sending kozos, 56 blocks: Give your local XMODEM receive command now.
Bytes Sent: 7296 BPS:767

Transfer complete
eceive succeeded.
kzboot>

けっこうサイズがギリギリになってしまっている.

で,OSを起動してみる.

kzboot> run
starting from entry point.
kozos boot succeed!
command>

とりあえず問題なく起動できている.

てきとうにコマンド入力してみよう.

command> echo aaa
aaa
OK
command> threads
extintr
idle
command1
OK
command>

おー,ちゃんと動作している.すげえ.感動.

うーむ,これでひとまずブートローダーから起動して自作OSをダウンロード,起動するとこまでひととおりできたわけだ.まあ実作業はたいした時間はかかってないのだけど,昔むかしに「OS作ってみたい!」とおもっていろいろ勉強してきた成果というか,なんというか,感慨深いなあ.感動だー.

ソースの詳しい説明はとりあえず次回.いやー,動いた動いた.