Arduinoでの開発をするためにボードとか書籍を通販で頼んだのだけど, まだ到着しないので,H8でのKOZOSの開発を進めています.
で,前回にDRAM上で動くようになったのでこれからはあまりサイズを気にせずに 開発することができる.ということで,いよいよネットワーク機能を実装して いこうと思う.
ネットワーク接続に関しては「移植編その2:KOZOSをH8に移植する」の (H8移植編第13回)LANにつないでみようで LANコントローラ(RTL8019)がすでに動作しているので,そのときのコードを まずはこちらに移植してみる.
まず上記の第13回のソースコードから ether.h, ether.c をOSにそのまま持ってくる. さらに consdrv.h, consdrv.c をベースにして,イーサネット・ドライバ・スレッド として etherdrv.h, etherdrv.c を作成する. さらにさらに,上記第13回のソースコードから network.c を, IP解釈のコードとして ip.c にリネームしてOS側に持ってくる.
ether.h, ether.c にはほぼ変更無し.ip.c は etherdrv.c に合わせて多少修正, etherdrv.c は ether.c に合わせてごっそり修正した.
以下,修正したソース.
以下にその他の修正点について説明しよう.
まずブートローダーに,割り込みとしてIRQ5を受け付ける対応を入れる. (H8移植編第13回)LANにつないでみようで説明したように, H8/3069FマイコンボードのLANコントローラの割り込みピンは,CPUのIRQ5に 接続されている.よって受信割り込みなどはIRQ5として受けることができる.
まずはブートローダーのintr.Sに,LANコントローラ用の割り込みハンドラを追加. これは他のハンドラをコピーして適当に修正しただけ.
diff -ruN h8_03/bootload/intr.S h8_04/bootload/intr.S --- h8_03/bootload/intr.S Mon Apr 5 22:23:32 2010 +++ h8_04/bootload/intr.S Wed Apr 7 12:51:33 2010 @@ -105,3 +105,29 @@ mov.l @er7+,er5 mov.l @er7+,er6 rte + + .global _intr_ethintr +# .type _intr_ethintr,@function +_intr_ethintr: + 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.l er0,@-er7 + mov.l er7,er1 + mov.l #_intrstack,sp + mov.l er1,@-er7 + mov.w #SOFTVEC_TYPE_ETHINTR,r0 + jsr @_interrupt + mov.l @er7+,er1 + mov.l er1,er7 + mov.l @er7+,er0 + mov.l @er7+,er1 + mov.l @er7+,er2 + mov.l @er7+,er3 + mov.l @er7+,er4 + mov.l @er7+,er5 + mov.l @er7+,er6 + rte次に割り込み種別として,「SOFTVEC_TYPE_ETHINTR」を追加.
diff -ruN h8_03/bootload/intr.h h8_04/bootload/intr.h --- h8_03/bootload/intr.h Mon Apr 5 22:23:32 2010 +++ h8_04/bootload/intr.h Wed Apr 7 12:51:33 2010 @@ -3,11 +3,12 @@ /* ソフトウエア・割込みベクタの定義 */ -#define SOFTVEC_TYPE_NUM 4 +#define SOFTVEC_TYPE_NUM 5 #define SOFTVEC_TYPE_SOFTERR 0 #define SOFTVEC_TYPE_SYSCALL 1 #define SOFTVEC_TYPE_SERINTR 2 #define SOFTVEC_TYPE_TIMINTR 3 +#define SOFTVEC_TYPE_ETHINTR 4 #endifさらに vector.c で定義されている割り込みベクタのIRQ5のエントリに, intr_ethintr()をハンドラとして登録する.
diff -ruN h8_03/bootload/vector.c h8_04/bootload/vector.c --- h8_03/bootload/vector.c Mon Apr 5 22:23:32 2010 +++ h8_04/bootload/vector.c Wed Apr 7 12:51:33 2010 @@ -5,6 +5,7 @@ extern void intr_syscall(void); /* システム・コール */ extern void intr_serintr(void); /* シリアル割込み */ extern void intr_timintr(void); /* タイマ割込み */ +extern void intr_ethintr(void); /* イーサネット・コントローラ割込み */ /* * 割込みベクタの設定. @@ -13,7 +14,7 @@ void (*vectors[])(void) = { start, NULL, NULL, NULL, NULL, NULL, NULL, NULL, intr_syscall, intr_softerr, intr_softerr, intr_softerr, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, intr_ethintr /* IRQ5 */, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, intr_timintr, intr_timintr, intr_timintr, intr_timintr,ブートローダーの修正はここまで.次にOS側の修正.
intr.hはブートローダーと同様に修正.さらにethernetのフレーム受信用に, memory.c で2KBの領域を作成する(イーサネットのフレームは最大で1.5KB程度になる). ついでにDRAM動作に移行してメモリサイズに余裕ができたので,他の領域も拡張して おく.
diff -ruN h8_03/os/memory.c h8_04/os/memory.c --- h8_03/os/memory.c Mon Apr 5 22:23:32 2010 +++ h8_04/os/memory.c Wed Apr 7 12:51:33 2010 @@ -21,7 +21,7 @@ /* メモリ・プールの定義(個々のサイズと個数) */ static kzmem_pool pool[] = { - { 16, 8, NULL }, { 32, 8, NULL }, { 64, 4, NULL }, + { 16, 32, NULL }, { 32, 32, NULL }, { 64, 32, NULL }, { 2048, 16, NULL }, }; #define MEMORY_AREA_NUM (sizeof(pool) / sizeof(*pool))defines.hは etherdrv との通信用に,新たにメッセージボックスを定義する.
diff -ruN h8_03/os/defines.h h8_04/os/defines.h --- h8_03/os/defines.h Mon Apr 5 22:23:32 2010 +++ h8_04/os/defines.h Wed Apr 7 12:51:33 2010 @@ -18,6 +18,8 @@ MSGBOX_ID_CONSOUTPUT, MSGBOX_ID_TIMDRIVE, MSGBOX_ID_TIMEXPIRE, + MSGBOX_ID_ETHINPUT, + MSGBOX_ID_ETHOUTPUT, MSGBOX_ID_NUM } kz_msgbox_id_t;kozos.hには新しいスレッドとして イーサネット・ドライバ・スレッド「etherdrvスレッド」と IPの解析用の「ipスレッド」のメイン関数の定義を追加する.
diff -ruN h8_03/os/kozos.h h8_04/os/kozos.h --- h8_03/os/kozos.h Mon Apr 5 22:23:32 2010 +++ h8_04/os/kozos.h Wed Apr 7 12:51:33 2010 @@ -36,9 +36,11 @@ /* システム・タスク */ int consdrv_main(int argc, char *argv[]); int timerdrv_main(int argc, char *argv[]); +int etherdrv_main(int argc, char *argv[]); /* ユーザ・タスク */ int command_main(int argc, char *argv[]); int clock_main(int argc, char *argv[]); +int ip_main(int argc, char *argv[]); #endifさらにmain.cの初期スレッドに etherdrvスレッドとipスレッドの起動を追加. clockスレッドは3秒ごとにメッセージを出してきてうっとうしいので削った.
diff -ruN h8_03/os/main.c h8_04/os/main.c --- h8_03/os/main.c Mon Apr 5 22:23:32 2010 +++ h8_04/os/main.c Wed Apr 7 12:51:33 2010 @@ -9,7 +9,11 @@ kz_run(consdrv_main, "consdrv", 1, 0x200, 0, NULL); kz_run(command_main, "command", 8, 0x200, 0, NULL); kz_run(timerdrv_main, "timerdrv", 2, 0x100, 0, NULL); + kz_run(etherdrv_main, "etherdrv", 3, 0x200, 0, NULL); +#if 0 kz_run(clock_main, "clock", 9, 0x100, 0, NULL); +#endif + kz_run(ip_main, "ip", 10, 0x200, 0, NULL); kz_chpri(15); /* 優先順位を下げて,アイドルスレッドに移行する */ INTR_ENABLE; /* 割込み有効にする */最後に Makefile を修正.ether.c, ip.c, etherdrv.c をコンパイル対象に追加する.
diff -ruN h8_03/os/Makefile h8_04/os/Makefile --- h8_03/os/Makefile Mon Apr 5 22:23:32 2010 +++ h8_04/os/Makefile Wed Apr 7 12:51:33 2010 @@ -14,10 +14,11 @@ STRIP = $(BINDIR)/$(ADDNAME)strip OBJS = startup.o main.o interrupt.o -OBJS += lib.o serial.o timer.o +OBJS += lib.o serial.o timer.o ether.o # sources of kozos -OBJS += kozos.o syscall.o memory.o consdrv.o timerdrv.o command.o clock.o +OBJS += kozos.o syscall.o memory.o command.o clock.o ip.o +OBJS += consdrv.o timerdrv.o etherdrv.o TARGET = kozos修正はここまで.では実行してみよう.
今回はブートローダーにも修正が入っているので,まずはブートローダーを 書き込む必要がある.ブートローダーをフラッシュROMに書き込んで, で,OSをロードして起動する.
OSを起動したら,てきとうなPCでIPアドレスを192.168.0.Xに設定する. マイコンボードのほうはとりあえず 192.168.0.16 に決めうちで書いてあるので, それとは違うアドレスにする.まあ 192.168.0.2 あたりが無難でしょう.
で,HUBを介してLANケーブルで接続すると,マイコンボードのLANポート付近の 青色LEDが光る.リンクアップで光るみたい.
PCからpingを実行すると,応答が返ってくる.ARP解決もされて,無事に疎通が とれている.
(PC側の出力)
hiroaki@teapot:~>% ping 192.168.0.16 PING 192.168.0.16 (192.168.0.16): 56 data bytes 64 bytes from 192.168.0.16: icmp_seq=0 ttl=64 time=24.596 ms 64 bytes from 192.168.0.16: icmp_seq=1 ttl=64 time=23.826 ms 64 bytes from 192.168.0.16: icmp_seq=2 ttl=64 time=24.381 ms 64 bytes from 192.168.0.16: icmp_seq=3 ttl=64 time=23.948 ms 64 bytes from 192.168.0.16: icmp_seq=4 ttl=64 time=23.953 ms ^C --- 192.168.0.16 ping statistics --- 5 packets transmitted, 5 packets received, 0% packet loss round-trip min/avg/max/stddev = 23.826/24.141/24.596/0.295 ms hiroaki@teapot:~>%
(マイコンボード側の出力)
kzload> run starting from entry point: 400100 kozos boot succeed! command> MAC: 0002cb0325f5 network ready. received: 0x0bytes no reply. received: 0x62bytes replyed. received: 0x62bytes replyed. received: 0x62bytes replyed. received: 0x62bytes replyed. received: 0x62bytes replyed.もともとお試しでLAN接続が動作していたこともあり,あっさりと動いた. ちなみにパケットの送受信時には,LANポート近くの白色LEDが光るようだ.
まあちょっとソースコードが整理されていないのと,送信割り込みがまだ サポートされていないのだが,とりあえずは動作した.
さて,これでIP接続はできた.次はいよいよTCPでの接続だ.
TCP接続をサポートしてさらにwebサーバを動作させるには,どのサービスをどの スレッドにやらせるのかをうまいこと設計して,処理を分割する必要がある. 今回作成した「ipスレッド」はIPパケットの処理だけに閉じて,TCPは別にスレッドを 作成したほうがいいだろう.なぜかというと,TCPの動作には状態遷移とタイマが 必須なので,専用のスレッドで管理したほうが構造がシンプルになるからだ.
さらにwebサーバはアプリケーションとしてまた独立したスレッドにするべきだ. このようにサービスや処理単位ごとにスレッドを作成して分散処理すると, いかにも組み込みプログラムって感じがするなあ.