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

前回の課題というか今までの課題として,第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作ってみたい!」とおもっていろいろ勉強してきた成果というか,なんというか,感慨深いなあ.感動だー.

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

とりあえず移植して割り込み処理まわりとか必要な部分を書いて、ブートだけはできるようになった。

(ブートローダーにも何箇所か手を入れた)


で、起動はできたのだけど、起動直後に落ちる。まああらかた書いたので、あとはデバッグかな。


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

連休だ!OS作成日和だ!

今週はいろいろと忙しくてなんだかんだいって移植作業が進んでいなかったので,今日いっきに作業してしまおう.(そして連休は遊ぶのだ)

で,今回なのだけど,とりあえずKOZOS移植の前に準備としてシリアル割り込み処理を実装してみよう.

H8だとシリアル割り込み処理も簡単で,割り込みフラグを立てるだけ.実装したのは以下のような感じ.今回はブートローダーには手は入っていないので,アプリ側の修正のみ.

修正内容は以下のような感じ.まず serial.c の修正.

diff -ruN h8_06/os/serial.c h8_07/os/serial.c
--- h8_06/os/serial.c Tue Sep 15 00:27:07 2009
+++ h8_07/os/serial.c Sat Sep 19 17:24:41 2009
@@ -1,4 +1,5 @@
#include "types.h"
+#include "interrupt.h"
#include "serial.h"

#define H8_3069F_SCI0 ((volatile struct h8_3069f_sci *)0xffffb0)
@@ -42,15 +43,35 @@
#define H8_3069F_SCI_SSR_RDRF (1<<6)
#define H8_3069F_SCI_SSR_TDRE (1<<7)

+void serial_interrupt()
+{
+ volatile struct h8_3069f_sci *sci = H8_3069F_SCI1;
+ int status, c;
+
+ status = sci->ssr;
+
+ c = serial_getc();
+ serial_putc(c);
+
+ sci->ssr = status & ~H8_3069F_SCI_SSR_RDRF;
+
+ return;
+}
+
int serial_init()
{
volatile struct h8_3069f_sci *sci = H8_3069F_SCI1;

+ /* 割り込みハンドラ登録 */
+ interrupt_sethandler(VECTYPE_RXI1, serial_interrupt);
+
sci->scr = 0;
sci->smr = 0;
sci->brr = 64; /* 20MHz 9600bps */
sci->scr = H8_3069F_SCI_SCR_RE | H8_3069F_SCI_SCR_TE;
sci->ssr = 0;
+
+ sci->scr |= H8_3069F_SCI_SCR_RIE; /* 割り込み許可 */

return 0;
}

割り込みハンドラを用意してinterrupt_sethandler()で登録して,あとSCRの割り込みフラグを立てて割り込み有効にしているだけ.ハンドラ内では1文字受信して,そのままエコーバックしている.注意として,1文字読み込みしてから RDRF フラグを落とすこと.(でないと受信できない)

次に main.c の修正.

diff -ruN h8_06/os/main.c h8_07/os/main.c
--- h8_06/os/main.c Tue Sep 15 00:27:07 2009
+++ h8_07/os/main.c Sat Sep 19 17:24:41 2009
@@ -66,6 +66,7 @@
}
#endif

+#if 0
static int gets(char *buf)
{
int i = 0, c = -1;
@@ -78,6 +79,7 @@
}
return i - 1;
}
+#endif

#if 0
static int dump(char *buf, int size)
@@ -105,7 +107,9 @@

int main()
{
+#if 0
char buf[80];
+#endif

init();

@@ -114,10 +118,12 @@
ENABLE_INTR;

while (1) {
+#if 0
puts("os> ");
gets(buf);
puts(buf);
puts("\n");
+#endif
}

return 0;

単に従来のポーリング処理に蓋をしただけ.

では実行してみよう.今回はブートローダーには手は入っていないので,フラッシュROMを書き換える必要は無い.

Hello World!
> load
~CLocal command? lsx hello
Sending hello, 19 blocks: Give your local XMODEM receive command now.
Bytes Sent: 2560 BPS:870

Transfer complete
eceive succeeded.
> run
starting from entry point.boot succeed!
IabIcIABICIIIIIII

問題なくあっさり動いた.H8は楽でいいねー.

これでKOZOS移植の準備はだいたいできた.あとはいよいよOS実装だ!