前回の最後に書いたけど,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 = kzloaddram.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上に配置されている.問題無いようだ.