(H8移植編その2第3回)DRAM上で動かそう

2010/04/05

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

前回の最後に書いたけど,TCP/IPの実装を進める準備としてDRAM上で動くように しよう.

DRAM対応に関しては「移植編その2:KOZOSをH8に移植する」の (H8移植編第12回)DRAMを使えるようにする(H8移植編第14回)DRAM上で動かそうですでに動いて いるので,それを持ってくるだけ.

DRAMの使いかたについて詳しくは上記ですでに説明済みなので,知りたいひとは そっちを見て.DRAMに関しては,メモリコントローラの初期化を行ってしまえば あとは0x400000〜0x600000の2MBの領域が自由に使えるようになる.

まず上記の第14回のソースコードから dram.h, dram.c をそのまま持ってくる. 持ってくる先なのだけど,OSをDRAM上で動作させたいので,ブートローダー側で DRAMの初期化を行って,あとはOSのリンカスクリプトを修正してDRAM上にロード されるようにする.

というわけで,適当に修正して動かしてみた.以下,修正したソース.

以下に修正点を説明しよう.

まずブートローダー側の修正.以下はブートローダーのリンカスクリプトの修正.

diff -ruN h8_02/bootload/ld.scr h8_03/bootload/ld.scr
--- h8_02/bootload/ld.scr	Sun Apr  4 20:21:25 2010
+++ h8_03/bootload/ld.scr	Mon Apr  5 22:35:25 2010
@@ -4,14 +4,19 @@
 
 MEMORY
 {
+	/* internal ROM (512KB) */
 	romall(rx)	: o = 0x000000, l = 0x080000 /* 512KB */
 	vectors(r)	: o = 0x000000, l = 0x000100 /* top of ROM */
 	rom(rx)		: o = 0x000100, l = 0x07ff00
 
+	/* DRAM (2MB) */
+	dramall(rwx)	: o = 0x400000, l = 0x200000 /* 2MB */
+	buffer(rwx)	: o = 0x500000, l = 0x100000 /* 1MB */
+
+	/* internal RAM (16KB) */
 	ramall(rwx)	: o = 0xffbf20, l = 0x004000 /* 16KB */
 	softvec(rw)	: o = 0xffbf20, l = 0x000040 /* top of RAM */
-	buffer(rwx)	: o = 0xffdf20, l = 0x001d00 /* 8KB */
-	data(rwx)	: o = 0xfffc20, l = 0x000300
+	data(rwx)	: o = 0xffc000, l = 0x003f00
 	bootstack(rw)	: o = 0xffff00, l = 0x000000
 	intrstack(rw)	: o = 0xffff00, l = 0x000000 /* end of RAM */
 }
DRAMが使えるようになるので,ELF形式のロード用のバッファを内蔵RAMから DRAMに移した.これにより,1MBちかいサイズのファームウェアまでロード可能になる.

ついでにバッファをDRAMに移すことでデータ領域に余裕ができたので, データ領域を内蔵RAMの先頭付近まで拡張しておいた.これはブートローダーに 機能追加して静的変数などのサイズが増えたときの考慮.サイズが不足すると いきなり固まったりして,機能追加したその機能が原因なのかよくわからなくなって 原因追求しにくくなるので,あらかじめサイズ拡張しておく.

次にブートローダーの main.c の修正.

diff -ruN h8_02/bootload/main.c h8_03/bootload/main.c
--- h8_02/bootload/main.c	Sun Apr  4 20:21:25 2010
+++ h8_03/bootload/main.c	Mon Apr  5 22:23:32 2010
@@ -3,6 +3,7 @@
 #include "serial.h"
 #include "xmodem.h"
 #include "elf.h"
+#include "dram.h"
 #include "lib.h"
 
 static int init(void)
@@ -23,6 +24,9 @@
   /* シリアルの初期化 */
   serial_init(SERIAL_DEFAULT_DEVICE);
 
+  /* DRAMの初期化 */
+  dram_init();
+
   return 0;
 }
 
@@ -101,6 +105,12 @@
 	f(); /* ここで,ロードしたプログラムに処理を渡す */
 	/* ここには返ってこない */
       }
+    } else if (!strcmp(buf, "ramchk")) {
+      dram_check();
+    } else if (!strcmp(buf, "ramchk2")) {
+      dram_check2();
+    } else if (!strcmp(buf, "ramclr")) {
+      dram_clear();
     } else {
       puts("unknown.\n");
     }
初期化用関数から dram_init() を呼び出してDRAMの初期化を行うようにする. さらにコマンドとして ramchk, ramchk2, ramclr を追加して,DRAMのチェックを 行えるようにする.

さらにMakefileの修正.

diff -ruN h8_02/bootload/Makefile h8_03/bootload/Makefile
--- h8_02/bootload/Makefile	Sun Apr  4 20:21:25 2010
+++ h8_03/bootload/Makefile	Mon Apr  5 22:23:32 2010
@@ -20,7 +20,7 @@
 H8WRITE_SERDEV = /dev/cuad0
 
 OBJS  = vector.o startup.o intr.o main.o interrupt.o
-OBJS += lib.o serial.o xmodem.o elf.o
+OBJS += lib.o serial.o xmodem.o elf.o dram.o
 
 TARGET = kzload
 
dram.cをコンパイル対象に加えるようにMakefileを修正した.

ブートローダーの修正はこれだけ.次にOS側の修正.

diff -ruN h8_02/os/ld.scr h8_03/os/ld.scr
--- h8_02/os/ld.scr	Sun Apr  4 20:21:25 2010
+++ h8_03/os/ld.scr	Mon Apr  5 22:23:32 2010
@@ -4,10 +4,14 @@
 
 MEMORY
 {
+	/* DRAM (2MB) */
+	dramall(rwx)	: o = 0x400000, l = 0x200000 /* 2MB */
+	ram(rwx)	: o = 0x400000 + 0x100, l = 0x200000 - 0x100
+
+	/* internal RAM (16KB) */
 	ramall(rwx)	: o = 0xffbf20, l = 0x004000 /* 16KB */
 	softvec(rw)	: o = 0xffbf20, l = 0x000040 /* top of RAM */
-	ram(rwx)	: o = 0xffc020, l = 0x003f00
-	userstack(rw)	: o = 0xfff400, l = 0x000000
+	userstack(rw)	: o = 0xffc000, l = 0x003f00
 	bootstack(rw)	: o = 0xffff00, l = 0x000000
 	intrstack(rw)	: o = 0xffff00, l = 0x000000 /* end of RAM */
 }
OSのリンカスクリプトを修正して,ram領域を内蔵RAMからDRAMに移動した. これにより,テキスト領域などがDRAMに配置されるようになる. 具体的には,DRAM上のアドレスでセグメント情報が生成されるので, 後はローダがプログラムヘッダのセグメント情報を見て,それに応じて DRAM上にOSを展開する,というわけだ.

ついでにOS本体をDRAM上に移したことで内蔵RAMがだいぶ空いたので, スレッド用のスタック領域(userstack)のサイズを大幅に拡張しておいた. これは将来的にスレッド数が増加したときに備えた修正だ.

では動作させてみよう.今回はブートローダーにも手が入っているので, ブートローダーをフラッシュROMに書き込んで,で,OSをロードして起動する.

kzload> run
starting from entry point: 400100
kozos boot succeed!
command> ready.
echo sample
 sample
command> ready.
timer
timer start.
command> expired.
command> ready.
ready.

動作は前回と変わらず問題無いのだが,最初に出力されている 「starting from entry point:」が0x400100という値になっている. つまり,DRAM上で起動できている.

readelfでメモリ配置を確認してみよう. 以下,ブートローダーの実行形式「kzload.elf」をreadelfで解析した結果.

hiroaki@teapot:~/h8_osbook/src/dram/bootload>% readelf -a kzload.elf 
...(中略)...
   148: 00500000     0 NOTYPE  GLOBAL DEFAULT    4 _buffer_start
...(後略)...
バッファ領域のアドレスが0x500000になっており,DRAM上に配置されていることが わかる.

次に,OSの実行形式「kozos.elf」をreadelfで解析した結果.

hiroaki@teapot:~/h8_osbook/src/dram/os>% readelf -a kozos.elf
...(中略)...
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00400100 000074 0019c8 00  AX  0   0  2
  [ 2] .rodata           PROGBITS        00401ac8 001a3c 0000d8 00   A  0   0  4
  [ 3] .data             PROGBITS        00401ba0 001b14 000034 00  WA  0   0  4
  [ 4] .bss              NOBITS          00401bd4 001b48 00024c 00  WA  0   0  4
  [ 5] .shstrtab         STRTAB          00000000 001b48 000034 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 001cbc 001040 10      7  b8  4
  [ 7] .strtab           STRTAB          00000000 002cfc 0006dc 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x0040008c 0x0040008c 0x01b14 0x01b14 R E 0x1
  LOAD           0x001b14 0x00401ba0 0x00401ba0 0x00034 0x00280 RW  0x1
...(後略)...
.text, .rodata, .data, .bss セクションのアドレスが0x40XXXXになっていて, DRAM上に配置されていることがわかる.セグメントもアドレスが0x40XXXXに なっていて,やはりDRAM上に配置されている.問題無いようだ.
メールは kozos(アットマーク)kozos.jp まで