えー、12月に出る単行本が校正の最終段階になってるのと、さらにInterfaceの記事執筆でぜんぜん暇が無い。今日はなんか風邪気味で会社休んだのだけど、家でふつうに(暖かくして)仕事してます。。。熱は無いので、インフルでは無いと思うのだが。


まあ来週にはひととおりカタがついて楽になる。。。はず、です。そしたらよーやくKOZOSの開発を再開できる。。。はずだ。OSCやKOFでKOZOSの説明してきたのはいいのだけどそれからぜんぜん開発が進められていないので非常に心苦しいのだが、はやく開発作業に戻りたいなあ。


ちなみにKOZOSの今後だが、やはり入門者にはドキュメントというか説明が充実していないとダメなので、OSの機能開発とかよりも、きちんとしたドキュメントを作るという方向で進もうと思っている。まあ具体的なことはまだちょっと内緒です。


で、突然ですが日本電子専門学校の電設部 の学外勉強会で、組込みOSについてちょっと説明する機会をもらえたので、12月5日に行ってしゃべってきます。


http://kokucheese.com/event/index/757


時間が30分近くあるのと、聞くのは10人くらいの少人数なのと、聞くのは学生が多いので、今回は発表っていうより説明って感じで、ちょっといままでとはちがう感じでいこうかなと思っています。実際にその場で動かしたりして見せたりとかしたいなあ。


10月末のOSCと11月頭のKOFと、ここんところイベントに立て続けに参加してKOZOSの展示をしてきたのだが、ようやく終わってひと段落。とはいっても別件の校正作業が残っていてそっちに時間をとられていたのだが、昨日ようやくそっちも終わってほんとにひと段落。(まあでもすぐにまた別件の執筆作業を始めなければならないのだが)


なのでもっとKOZOSの開発を進めたいのだけど、残念ながら手が回らない。。。


年内には開発を再開したいなあ。


OSCもKOFも非常に楽しかった。とくに発表が楽しかった。最初はどうなることやらとちょっと不安だったのだが、実際にしゃべり始めてみると楽しいもんだね。ということで今後も発表とかをもっとこなして経験を積んでいきたいので、発表させてくれるところをいろいろ探し中です。しゃべらせてくれる場所がもしもあれば、ぜひ教えてください。


OSC、KOFと、スタッフの方はお疲れさまでした。またKOZOSのブースに寄って私の話を聞いていただいたかたはどうもありがとうございました。ようやく説明にも慣れてきて、KOFではまあまあマシな説明ができたのではと思います。(まだまだな部分も多いですが)


とりあえず、OSCとKOFに参加しての感想として、やはりKOZOSを実ハードに移植して展示したのはそれなりにインパクトがでかくて、以前のシミュレーション動作よりもはるかに興味を持ってもらえた。ということで、今後は実ハードでの動作をもっと発展させていきたい。とはいっても機能をどんどん追加してOSとして充実させていくということではなく(それだと他のいっぱいある組込みOSを追いかけるだけになってしまうので)、いろんなCPUやボードに移植していきたいなあと。いろんなひとが手持ちのボードでパッと試せるようにできれば、もっと組込みOS学習の敷居を下げられるかなあと思うのでそういう方向でいこうかなあ、と思う。



今週末はOSC、来週末には関西オープンソースだ。発表もあるし、KOZOSの改良とか準備を進めたい。。。進めたいのだけど、現在Interface誌の連載記事の作業にかかっていて、なかなか時間がとれない。OSCは今のところ毎回「来てよかった」と思えているし、今回も非常に楽しみではあるのだが、このへんが悩みどころだ。


まあInterface誌のほうはなんとか目途は立ってきたのだけど、それとは別の校正作業(詳細はまだ秘密)も入ってしまったし、別件の執筆作業(こっちもまだ秘密)もあるし、OSCや関西オープンソースの準備もあるし。。。ということで、最近は週末はいろんな作業に時間をとられてどこにも行っとらん。平日は会社だし、帰宅後も作業だし、マジで1週間ぜんぶ仕事です。


実は先週くらいに新型インフルにかかってしまって、会社命令で1週間出社禁止になってしまい、外出もできず自動的にカンヅメ状態ということで、ずっと家にこもって作業していた(他にやることも無いしね)。ということで(不謹慎かもしれないが)まあある意味ラッキーというかかなり作業を進められて、ついでに言うならその前のシルバーウイークもずっと作業していたというのに、それでもまだまだ追いつかん。


とか言ってたら、もうキャンプのシーズンを過ぎてしまった。。。

う~ん、遊びに行きてえ。。。

えー、10月末のOSC東京と11月初旬の関西オープンソースで展示&発表をします。

OSCではライトニングトーク、関西オープンソースではステージ発表です。

とはいっても関西オープンソースのほうは初参加でよく勝手がわからないので、どんなかんじになるのか本人もわかっていません。


もともとは展示だけのつもりだったのだけど、まあたまには社外で不特定多数の知らない人を相手にしてしゃべるのも必要かなーとおもってエントリーしてみました。


内容は、組込みOSを自作しようってことでふだん思っているようなことをしゃべってきます。興味のある人は参加してみてください。


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

今まで内蔵RAM上で動いていたのだけど,LANコントローラ対応でいよいよ内蔵RAMではサイズ的にきつくなってきて,これ以上の機能追加は厳しいので,OSをDRAM上で動かすように修正しよう.

で,DRAMへの以降なのだけど,OSで行っているDRAMコントローラの初期化をブートローダーで行うようにして,あとOSのリンカスクリプト書き換えてDRAM上に持っていくだけで超簡単にできると思っていたのだけど,バグがあってちょっとひと苦労.

まずDRAMの初期化なのだけど,OSのデバッグ中に気がついたことなのだけど,従来のままだとしばらく値を保持させるとビット化けしてしまうアドレスが存在することが判明.というのは,ブートローダー対応してからOSをDRAMに移したのだけど,DRAM上で動かすようにすると固まってしまう(内蔵RAM上だとなぜか正常に動作する)という問題が出て,まあ実際の原因は後述するint型の問題だったのだけど,どうもDRAMがちゃんと動いていないように思えたのでチェックプログラムを作って試してみたらやはりビット化けするアドレスが存在する.

従来のメモリチェックは値を書き込んだ直後に読む,ということをやっていたので値をしばらくのあいだ保持できているかということはチェックできていなかった.なので最初に全領域に値を書き込んで,その後で全領域を読んでチェック,さらに特定のビットが0に化けても1に化けても検出できるように,ビットを立てたパターンとビットを落としたパターンの両方でチェックする,というようなチェックをしたらビット化けが検出された.

ということでdram_init()での設定パラメータがあやしく思い,ウエイトとリフレッシュレートをいろいろ変えてみたのだけど,リフレッシュレートを上げたらビット化けしないようになった.どうもリフレッシュレートが低すぎたらしい.まあほんとはデータシート見たりして適切な値を調べるべきなのだけど,とりあえず全メモリ全パターンチェックでエラーにならなくなったのでよしとする.(なんかDRAM搭載のボートで買うと,DRAMコントローラの設定例が載ったドキュメントがついてくるみたいね.今回利用しているボードだとDRAMはおまけ扱いなのでドキュメントがついてないってことかもしれん)

ただそれだけ直しただけではまだダメ(っていうか,ビット化けするのは使っていないアドレスだったので,これが固まる原因ではなかった)で,OSのテキストとデータ領域はDRAMに移しても正常動作したのだけど,BSS領域を移すとやはりうまく動かず固まってしまう.

いろいろ見直したのだけど原因がよくわからなくて,しかたがないのでいろんなところに puts() を入れてシリアル出力させてどこまで処理が進んだか見るという原始的ないわゆる printf デバッグで追いかけたら,kz_free()でのメモリ解放でおかしな領域を解放しようとして kz_sysdown() が呼ばれて while(1) の無限ループに入っていることが判明.この時点ではうわーメモリ破壊かなーめんどくさそーと思ったのだけど,もっと追いかけたらkz_send()でのメッセージ送信でなんか送信先のスレッドIDがおかしくなっていて,そのせいでおかしなポインタの先を参照して kz_free() におかしなアドレスを渡していることが判明.

ということで原因はおかしなスレッドIDでkz_send()が呼ばれていることなのだけど,printfデバッグで調べたら,送信元は command スレッドになっている.ということは送り先は extintr なのだけど,extintr_id は uint32 としてきちんと定義されている.

で,extintr_id はどこで得られているかというと,kozos.c のスレッド起動部分でkz_run()の戻り値を与えている.このへんでようやく気がついたのだけど,実は kz_run() の戻り値が int 型として定義されていたので,16ビット整数になってしまい,スレッドIDの上位ビットが削られた状態で extintr_id に格納されていたのだ.このため kz_send()でのメッセージ送信時に,おかしなスレッドID宛に送信していたというのが結局の原因.

この原因を考えると,うーんいままでよく動いていたなーと思うのだけど,実は従来は内蔵RAM上にBSSがあったのだけど,内蔵RAMのアドレスが0xffbf20 ~ 0xffff00 なので,上位ビットが削られて16ビット値となっても,その後に extintr_id に格納されるときに32ビットに拡張される際に,上位ビットが符号拡張されて,0xffffXXXX のようなアドレスになって格納されると思うのだな.で,実際にメモリアクセスされる際には上位8ビットが無視されて0x00ffXXXX のアドレスがアクセスされることで,正常動作していたようだ.なのでBSSをDRAMに移したことでアドレスが 0x400000 ~ 0x5fffff になってしまい,正常動作しなくなったということのようだ.

いやー,実は今までもBSSを動かすとなんか固まるときがあるなーとは思っていたのだけど,これが原因だったわけだ.ちょっと調べるのたいへんだったけど,まあ原因判明してよかったよかった.なおしたらあっさりと動いた.

で,今回の修正なのだけど,いい機会なのでリンカスクリプトを修正して,メモリ上のアドレスは基本的にリンカスクリプトで指定して,そこを見るように変更した.というのは,たとえばスレッドのスタックのアドレスを指定するのに今まではconfigure.h で

#define THREAD_STACK_START 0xffe820

のようなことをやっていたわけなのだけど,こーいうアドレス情報は基本的にはリンカスクリプトで指定して,その値を見るようにすべきだと思うのだな.というのは,これだとまずいろんなアドレス設定がいろんなヘッダファイルに点在してしまい,メモリ調整が面倒になったり調整し忘れでバグの原因になったりする可能性が高い.さらに,たとえばある領域の直後の領域を使いたい場合などに,#define でのベタ書きではなく,リンカスクリプトのリンク情報に応じて自動調整されるようにしたほうが効率的,といった理由がある.

ということで,今回の大きな修正は以下.
  • ブートローダーにDRAMコントローラを持っていって,ブートローダーでDRAMの初期化を行う.
  • DRAM初期化時の設定値で,リフレッシュレートを高くする.
  • DRAMチェック用関数を追加.(データ保持をチェックできるように,全領域ライトの後で全領域リードしてチェックをいくつかのメモリパターンで行う)
  • kz_run()の戻り値を32ビットに変更.
  • リンカスクリプトを修正して,メモリアドレスは基本としてリンカスクリプトですべて指定(or調整)されるようにする.
  • intが16ビットで問題ありそうな箇所を部分的に修正.
以下,修正したソース.まずブートローダーの修正点について.

main.cなのだけど,DRAMコントローラの初期化用に dram_init() の呼び出しを追加した.実際の DRAM 初期化処理は dram.c をOS側から持ってきて,リフレッシュレートの対応とメモリチェックの追加を行った.具体的には dram.c に以下のような対応が入っている.

--- os/ether/dram.c Sat Oct 3 13:22:25 2009
+++ bootload/dram/dram.c Sun Oct 4 23:35:28 2009
@@ -27,10 +27,29 @@

int dram_init()
{
+ /*
+ * dram_check2()でチェックしたら,値をうまく保持できないビットが存在した
+ * ので,リフレッシュレートを上げたら解消された.(ウエイトを多めにしても
+ * 効果は無かった)
+ * とりあえず,リフレッシュレート高めの設定にしておく.
+ */
+
*H8_3069F_ABWCR = 0xff;
+#if 0
*H8_3069F_RTCOR = 0x07;
+#else
+ *H8_3069F_RTCOR = 0x03; /* リフレッシュ周期を短めに設定 */
+#endif
+#if 1
*H8_3069F_RTMCSR = 0x37;
+#else
+ *H8_3069F_RTMCSR = 0x2f; /* リフレッシュ周波数UP */
+#endif
+#if 1
*H8_3069F_DRCRB = 0x98;
+#else
+ *H8_3069F_DRCRB = 0x9f; /* ウエイト挿入 */
+#endif
*H8_3069F_DRCRA = 0x30;

*H8_3069F_P1DDR = 0xff;
@@ -39,9 +58,17 @@
/* *H8_3069F_PBDDR = ...; */

/* H8_3069F_WCRH = ...; */
+#if 1
*H8_3069F_WCRL = 0xcf;
-
- *H8_3069F_ASTCR = 0xfb;
+#else
+ *H8_3069F_WCRL = 0xff; /* ウエイト挿入 */
+#endif
+
+#if 1
+ *H8_3069F_ASTCR = 0xfb; /* 2ステートアクセス */
+#else
+ *H8_3069F_ASTCR = 0xff; /* 3ステートアクセス */
+#endif

return 0;
}

dram.c には他にもメモリチェックとメモリクリアの関数が追加されている.これは以下.

@@ -107,4 +134,82 @@
putxval((unsigned long)*p, 8);
puts("\n");
return -1;
+}
+
+static uint32 dram_check2_val0(uint32 *addr) { return 0x55555555UL; }
+static uint32 dram_check2_val1(uint32 *addr) { return 0xaaaaaaaaUL; }
+static uint32 dram_check2_val2(uint32 *addr) { return 0x00000000UL; }
+static uint32 dram_check2_val3(uint32 *addr) { return 0xffffffffUL; }
+static uint32 dram_check2_val4(uint32 *addr) { return (uint32)addr; }
+static uint32 dram_check2_val5(uint32 *addr) { return ~(uint32)addr; }
+
+int dram_check2()
+{
+ uint32 *p;
+ int ret = 0, i;
+ uint32 (*getval[])(uint32 *) = {
+ dram_check2_val0,
+ dram_check2_val1,
+ dram_check2_val2,
+ dram_check2_val3,
+ dram_check2_val4,
+ dram_check2_val5,
+ NULL
+ };
+
+ for (i = 0; getval[i]; i++) {
+
+ puts("DRAM check pattern: ");
+ putxval(i, 0);
+
+ puts("\nDRAM setting...\n");
+
+ for (p = (uint32 *)DRAM_START; p < (uint32 *)DRAM_END; p++) {
+ *p = getval[i](p);
+ if (!((uint32)p & 0xfff)) {
+ putxval((unsigned long)p, 8);
+ puts("\x08\x08\x08\x08\x08\x08\x08\x08");
+ }
+ }
+
+ puts("\nDRAM checking...\n");
+
+ for (p = (uint32 *)DRAM_START; p < (uint32 *)DRAM_END; p++) {
+ if (*p != getval[i](p)) {
+ puts("\nERROR! :");
+ putxval((unsigned long)p, 8);
+ puts(" ");
+ putxval((unsigned long)*p, 8);
+ puts("\n");
+ ret = -1;
+ }
+ if (!((uint32)p & 0xfff)) {
+ putxval((unsigned long)p, 8);
+ puts("\x08\x08\x08\x08\x08\x08\x08\x08");
+ }
+ }
+
+ puts("\n");
+
+ }
+
+ if (ret == 0) {
+ puts("\nall check OK.\n");
+ }
+
+ return ret;
+}
+
+int dram_clear()
+{
+ uint32 *p;
+
+ puts("DRAM clearing...\n");
+
+ for (p = (uint32 *)DRAM_START; p < (uint32 *)DRAM_END; p++)
+ *p = 0;
+
+ puts("DRAM cleared.\n");
+
+ return 0;
}

あとmemset()とかのライブラリ関数を集めた lib.c と,あとシリアルドライバのserial.c が,OS側のやつとちょっとなんか食い違っていたので,OSのものに実装を合わせた.

さらに main.c の init() に dram_init() の呼び出しを加えて,コマンド解釈部分には メモリチェック用に ramchk, ramchk2 と,あとメモリクリア用に ramclr を追加した.以下のような感じ.

@@ -159,6 +76,12 @@
f = (void (*)())entry_point;
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 command.\n");
}

あと serial.c をOS側に合わせて修正したことでSCIの番号指定が必要になったので,シリアルを使っている部分全般(main.cとlib.cとxmodem.c)にインデックス指定の対応が各所に入っている.

次に,OS側の修正.

まず,kz_run()の戻り値がint型になっていて,スレッドIDの上位ビットを渡せていないという大問題の修正.

diff -u os/ether/syscall.h os/ondram/syscall.h
--- os/ether/syscall.h Sat Oct 3 11:01:06 2009
+++ os/ondram/syscall.h Mon Oct 5 01:02:01 2009
@@ -31,7 +31,7 @@
int stacksize;
int argc;
char **argv;
- int ret;
+ uint32 ret;
} run;
struct {
int dummy;

修正はこれだけ.kz_run()の処理の本体である thread.c:thread_run() では戻り値はきちんとuint32になっているので,ホントに修正忘れ.これでずいぶんハマッてしまった.

次に,リンカスクリプトの修正.

diff -u os/ether/ld.scr os/ondram/ld.scr
--- os/ether/ld.scr Sat Oct 3 21:11:47 2009
+++ os/ondram/ld.scr Sun Oct 4 23:38:45 2009
@@ -5,11 +5,19 @@
MEMORY
{
/*
- * reserve 256bytes space for software interrupt vector
- * and 256bytes space for ELF header.
+ * DRAM (2MB)
+ * reserve 256bytes space for ELF header.
*/
+ dram(rwx) : o = 0x400000 + 0x100, l = 0x200000 - 0x100
+
+ /*
+ * internal RAM (16KB)
+ * reserve 256bytes space for software interrupt vector.
+ */
+ uservec(rw) : o = 0xffbf20, l = 0x000100 /* start of RAM */
ram(rwx) : o = 0xffbf20 + 0x200, l = 0x004000 - 0x200 /* 16kb */
- bootstack(rw) : o = 0xffff00, l = 0x000010 /* end of RAM */
+ userstack(rw) : o = 0xffc120, l = 0x000010
+ bootstack(rw) : o = 0xffff00, l = 0x000010
intrstack(rw) : o = 0xffff00, l = 0x000010 /* end of RAM */
}

@@ -19,29 +27,43 @@
_text_start = . ;
*(.text)
_etext = . ;
- } > ram
+ } > dram

.rodata : {
_rodata_start = . ;
*(.strings)
*(.rodata)
+ *(.rodata.*)
_erodata = . ;
- } > ram
+ } > dram

.data : {
_data_start = . ;
*(.data)
_edata = . ;
- } > ram
+ } > dram

.bss : {
_bss_start = . ;
*(.bss)
*(COMMON)
_ebss = . ;
- } > ram
+ } > dram /* DRAMにするとなぜか固まる.要調査 */

+ . = ALIGN(4);
_end = . ;
+
+ .freearea : {
+ _freearea = .;
+ } > dram
+
+ .uservec : {
+ _uservec = .;
+ } > uservec
+
+ .userstack : {
+ _userstack = .;
+ } > userstack

.bootstack : {
_bootstack = .;

dram空間を定義して,テキスト,データ,BSSをdram空間に持っていく.dram空間を+256バイトして定義しているのは,以前にELF形式をロードできるようにしたときと同じ理由で,ELFヘッダがうまく入る領域を空けているため(ELFヘッダがはみ出してしまうので).

さらにソフトウエア割り込みベクタの登録域として uservec 領域,スレッドのスタック領域として userstack 領域というのを新設した.これらは従来は configure.h で THREAD_STACK_START とか,interrupt.h で VECTOR_ADDR とかで直の値で定義してあったのだけど,リンカスクリプトで集中定義することでメモリ調整時の修正ミスや修正洩れを無くすため.

さらにさらに,従来は kz_alloc() で獲得できる動的メモリ領域の2048バイトの領域をDRAMの先頭からとしてこれも直接指定していたのだけど,DRAM先頭付近はOSの本体がロードされるので,それに合わせて後ろの空いた部分を使えるように,freeareaという領域をBSSの直後に作成している.(実際にはその先頭アドレスがわかればいいだけなので,空領域として定義している)

で,リンカスクリプトの修正に合わせて,configure.h と interrupt.h の修正.

diff -u os/ether/configure.h os/ondram/configure.h
--- os/ether/configure.h Sat Oct 3 16:11:48 2009
+++ os/ondram/configure.h Mon Oct 5 01:11:41 2009
@@ -4,13 +4,10 @@
#include "types.h"
#include "lib.h"

-extern uint32 intrstack;
+extern char intrstack;
+extern char userstack;
#define INTR_STACK_START (&intrstack)
-#if 0
-#define THREAD_STACK_START 0xffe820
-#else
-#define THREAD_STACK_START 0x5f0000
-#endif
+#define THREAD_STACK_START (&userstack)

#define SIGHUP 1
#define SIGILL 4

アドレス直指定でなく,リンカスクリプトで定義した userstack シンボルの位置を見るようにしている.userstack はリンカスクリプト内で作成したシンボルなので変数としての実体は無いが,C言語から参照するために extern 宣言して参照している.

次に,interrupt.h の修正.

diff -u os/ether/interrupt.h os/ondram/interrupt.h
--- os/ether/interrupt.h Sat Oct 3 11:01:06 2009
+++ os/ondram/interrupt.h Sun Oct 4 17:32:21 2009
@@ -2,7 +2,10 @@
#define _INTERRUPT_H_INCLUDED_

#define VECTOR_NUM 64
-#define VECTOR_ADDR ((void *)0xffbf20)
+
+extern char uservec;
+#define VECTOR_ADDR (&uservec)
+
typedef void (*interrupt_handler_t)(int vec);

#define VECTORS ((interrupt_handler_t *)VECTOR_ADDR)

これも configure.h の修正と同じで,アドレス直指定でなくリンカスクリプトで定義した uservec シンボルの位置を見ることで,ソフトウエア割り込みベクタの位置を求めるようにしている.どう?スマートになったでしょ?

次に,main.c の修正.

diff -u os/ether/main.c os/ondram/main.c
--- os/ether/main.c Sat Oct 3 19:45:04 2009
+++ os/ondram/main.c Mon Oct 5 01:08:59 2009
@@ -14,11 +14,25 @@
extern int ebss;

/* clear BSS */
+#if 0
memset(&bss_start, 0, (uint32)&ebss - (uint32)&bss_start);
+#else
+ /*
+ * memset()はサイズをintで渡すので,BSSが32KBを越えたときに
+ * 正常にクリアできないので,memset()を利用せずに自前でクリアする.
+ */
+ {
+ char *p;
+ for (p = (char *)&bss_start; p < (char *)&ebss; p++)
+ *p = 0;
+ }
+#endif

serial_initialize(0, 0);

+#if 0 /* ブートローダーで初期化しているので,初期化不要 */
dram_init();
+#endif

return 0;
}

まあコメントの通りなのだけど,BSSのクリアに従来は memset() を呼んでいたが,memset() のサイズは16ビットint型として渡しているので,BSSが大きくなったときにクリアしきれないことが考えられる.これについてはmemset()側を直すべきかとも思ったのだけど,BSSの初期化みたいな基本的な部分がライブラリ関数に左右されるのもよくないかと思ったので,自前で(そしてサイズに依存しないように)クリアするように修正した.

dram_init()によるDRAMの初期化はブートローダー側で行うので呼ばないように修正.ていうかこの段階ではすでにOSがDRAM上で動いているので,下手に設定値をいじったらいきなりDRAMの内容が消えたりしてOSが動かなくなる可能性があるので,dram_init()を呼んではいけない.

次に memory.c での動的メモリ管理の修正.

diff -u os/ether/memory.c os/ondram/memory.c
--- os/ether/memory.c Sat Oct 3 21:10:10 2009
+++ os/ondram/memory.c Mon Oct 5 01:15:24 2009
@@ -4,11 +4,11 @@

#include "lib.h"

-#define MEMORY_AREA1_SIZE 32
+#define MEMORY_AREA1_SIZE (uint32)32
#define MEMORY_AREA1_NUM 16
-#define MEMORY_AREA2_SIZE 64
-#define MEMORY_AREA2_NUM 8
-#define MEMORY_AREA3_SIZE 2048
+#define MEMORY_AREA2_SIZE (uint32)256
+#define MEMORY_AREA2_NUM 16
+#define MEMORY_AREA3_SIZE (uint32)2048
#define MEMORY_AREA3_NUM 64

#if 0
@@ -16,7 +16,8 @@
static char memory_area_2[MEMORY_AREA2_SIZE * MEMORY_AREA2_NUM];
static char memory_area_3[MEMORY_AREA3_SIZE * MEMORY_AREA3_NUM];
#else
-#define memory_area_1 ((char *)DRAM_START)
+extern char freearea;
+#define memory_area_1 (&freearea)
#define memory_area_2 (memory_area_1 + MEMORY_AREA1_SIZE * MEMORY_AREA1_NUM)
#define memory_area_3 (memory_area_2 + MEMORY_AREA2_SIZE * MEMORY_AREA2_NUM)
#endif

まずメモリサイズを uint32 として定義するように修正.というのは,サイズ×領域数の掛け算を行う際に,(int)×(int)になるとintの上限あふれしたときにまたおかしなことになってしまうかな~と思ったので.実際にどうなるかは未確認なのだけど.

あと,DRAM_STARTでなくリンカスクリプトで定義した freearea を見ることで,OSのBSSの直後から無駄無くメモリを利用するように修正.こーいうのができるのが,リンカスクリプトにメモリ定義をすべて移した利点ではある.(自動調整してくれる)

最後に,これはおまけだけど,extintr の修正.

diff -u os/ether/extintr.c os/ondram/extintr.c
--- os/ether/extintr.c Sat Oct 3 16:13:04 2009
+++ os/ondram/extintr.c Sun Oct 4 23:55:35 2009
@@ -8,7 +8,8 @@

#define USE_MESSAGE

-#define BUFFER_SIZE 1800
+#define CONS_BUFFER_SIZE 16
+#define ETH_BUFFER_SIZE 1800

uint32 extintr_id;

@@ -125,9 +126,9 @@
char *buffer;

#ifdef USE_MESSAGE
- buffer = kz_kmalloc(BUFFER_SIZE);
+ buffer = kz_kmalloc(CONS_BUFFER_SIZE);
#else
- buffer = kx_kmalloc(BUFFER_SIZE);
+ buffer = kx_kmalloc(CONS_BUFFER_SIZE);
#endif
size = 1;

@@ -220,9 +221,9 @@
char *buffer;

#ifdef USE_MESSAGE
- buffer = kz_kmalloc(BUFFER_SIZE);
+ buffer = kz_kmalloc(ETH_BUFFER_SIZE);
#else
- buffer = kx_kmalloc(BUFFER_SIZE);
+ buffer = kx_kmalloc(ETH_BUFFER_SIZE);
#endif

size = ether_recv(intp - interrupts, buffer);

従来はシリアル入力もLANからのパケットも1800バイトの領域を獲得することでmemory.c の2048バイト領域を利用していたのだけど,シリアル入力は1文字入力であり,さすがにこれは無駄なので,シリアル入力では少ない領域が利用されるように修正.

あと dram.c は dram_init() を呼ばなくなったのでOS側では必要は無くなったのだけど,いちおうブートローダー側の修正に合わせた修正をしておいた.

修正は以上.で,これでようやくDRAM上で実際に動作するようになった.面倒なので今回はお試し結果は省略.各自で試してみてね.シリアルの速度はちょっと前に 19200bps に変更されているので,接続時には注意してちょうだい.