(H8移植編第10回)モトローラSレコードフォーマット対応

2009/09/20

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

前回の課題というか今までの課題として, 第4回でちょろっと書いたのだけど, ブートローダーをモトローラSレコードフォーマットに対応させよう.理由は以下.

で,以下の方針で実装してみた.

で,実装したのが以下. モトローラ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とかにすれば解決できるとは思うが. これはそのうち考えよう.


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