(H8移植編第11回)いろいろ見直してソースコード整理しよう

2009/09/20

あなたは 人目のお客様です.

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

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

以下,修正したソース.

■ ブートローダーの修正

まず大きな修正として,割り込み発生時にスタックにレジスタを退避する際に, レジスタの退避順番を逆にするように仕様変更した.これは,従来の順番だと アドレスの低位から 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, ¶m);
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 の修正.以下の点を修正してある.

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(¤t->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(¤t->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もばっちり動いて,だいたいソースもすっきりした.さて次は何をやろうか.


メールは kozos(アットマーク)kozos.jp まで