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

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

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

以下,修正したソース.

■ ブートローダーの修正

まず大きな修正として,割り込み発生時にスタックにレジスタを退避する際に,レジスタの退避順番を逆にするように仕様変更した.これは,従来の順番だとアドレスの低位から 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もばっちり動いて,だいたいソースもすっきりした.さて次は何をやろうか.