なんとかHOS-H8hは動き出しました。しかし、これまでの作業で、もうちょっ と手を加えられる余地も見えてきました。300Hでありながら300Hでない、いさ さか中途半端な3664の為にもう一手間かけてみます。
そしてもう一つ。HOS-H8hのsample、WEB上で公開されている各種情報の斜め読 み、書店での立ち読み等から、大雑把ですがμITRONプログラミングのカタチ を想像してみました。それを元に、「簡易モニタ」を作成します。
3664はROM/RAMともに容量が小さいので、日立謹製モニタとHOSの共存が 難しい(というか、ソースが手に入らない現状では不可能?な)ため、スタック の伸び具合を見たりするのも気軽には出来ません。ここは一つ、「デバッグや チューンの為にも役立つようなもの」という大きな看板を掲げてしまいましょ う。
2001.02.15記 新井
2001.02.20更新
さて、「最適化」なんて言うとなんか凄そうな気がしますね。当然これは私の 身の丈に合った、もっと限定的で(普遍に対しての)特殊なものです。一言で述 べると、
「h8300-hms-gcc(以後、単にgcc)に-mh -Sを付けてコンパイルした出力から、 3664用に削れる部分を削る」
ということです。
取り敢えず危険性の少ないと思われる例を挙げてみましょう。
細淵さんのrelaxを賢くするpatchを適用し、周辺I/Oレジスタのアドレス定義 を0xff?? → 0xffff??としておけば、それらに対しては:8になりますが、他は :24のままになってしまいます。
これは悲しい。即値は0xffXXならば:8し、それ以外は:16したいものです。こ れにより命令長/実行ステート数で4/4(:8)、2/2(:16)の節約が出来ます。
無駄ですね。これは4/4の節約になります。デカイ。
もう少し冒険できるなら、というのも考えてみました。
しかし、もしアドレスレジスタとしての演算でなかったら…。
しかし、もしアドレスレジスタとしての演算でなかったら…。
そうそう、どーしてもあとXXX bytes欲しい!そんな時のために少し手間のか かる小技も一つ。
これを実現するには多少の手間が必要です。C言語プログラムのレベルで2個以 上呼ばれる関数について、
のように規則的な別名を付け、リンカスクリプト内でvector sectionを 割り込みベクタ範囲から更に広げて(最大の場合、sectionの長さ0x0100)、
#define <function1> __vfunc1a /*は任意の関数名 */ #define <function2> __vfunc1b (略) #define <function3> __vfunc7f /* 最大は127番まで */
とします。そして-Sして出力させたアセンブラソースで、「jsr @___vfuncXX → jsr @@YY:8 (但し、YY = XX << 1)」と置換を実行すれば完了です。
SHORT(DEFINED(int18)?ABSOLUTE(int18):ABSOLUTE(_int_default)) SHORT(DEFINED(int19)?ABSOLUTE(int19):ABSOLUTE(_int_default)) + SHORT(___vfunc1a) + SHORT(___vfunc1b) (略) + SHORT(___vfunc7f) } > vectors
余談ですが、この「メモリ間接」についての3664ハードウェアマニュアル(少 なくとも第2版迄)の記述は間違っています。「メモリ上のオペランドはロング ワードサイズで指定します」なんて書いてありますが、きっとそれはアドバン スドモードの話でしょう。
基本的な方針は決まりました。後はこれをいかに特別な操作無しに今ま でのmake一発な環境に突っ込むか、です。
とにかく、gccのアセンブラ出力に前述の処理を加える、一種のフィルタプロ グラムを書きます。サクっとrubyとかperlなんかでやればキャッチーなのです が、どちらも不案内なので、ベタベタのCで書きました。ソースは見ない方が 身の為です。
uso3664.c (8612 bytes)これを適当にコンパイルします。普通のregex libraryがあるCならコンパイル 可能だと思いますが、FreeBSDでしか試してはいません。
これをMakefileに組み込みます。uso3664は、入出力ファイル名を指定する事 も出来ますが、標準入出力を使うフィルタとしても動作するようにしてありま すので、以下のように書き換えます。
frodo% gcc -O -o uso3664 uso3664.c frodo% strip uso3664
sampleのmakeに使ってみて、その効果を検証してみます。生成バイナリの大き さを調べてみましょう。
+SOPTMIZ = <uso3664を置いたディレクトリ>/uso3664 -.c.o: - ${CC} $< ${CFLAGS} -c +.c.o: + ${CC} $< ${CFLAGS} -S -o - | ${SOPTMIZ} | ${ASM} ${AFLAGS} -o $@ -.s.o: - ${ASM} $< ${AFLAGS} -o $@ +.s.o: + ${SOPTMIZ} $< | ${ASM} ${AFLAGS} -o $@
おお!548bytesも削減できました。笑わないで下さい。3664の限界に挑戦した システムを作る時、32KBが33.6KBになるとしたら…まさに血の1.6KBになるで しょう…。そうウマくいくとは限りませんが、アセンブラに走るよりは低コス トで多少の効果は期待できます。
h8300-hms-size sample の出力 素のまま: text data bss dec hex filename 9550 0 1072 10622 297e sample sample/Makefileにuso3664を組み込む: text data bss dec hex filename 9358 0 1072 10430 28be sample 更にsrc/Makefileにもuso3664を組み込む: text data bss dec hex filename 9002 0 1072 10074 275a sample
こうしてみると、更に省サイズ化したくなってきました。以前から課題として いたsrc/以下のファイル分割に手を着ける時が来たようです。
方針は、「一関数一ファイル」。これだけです。itron.hから インクルードされるヘッダだけでは定義されないモジュール内部だけの関数、 例えばeventflg.c内の__chk_flg()とか、task.c内の__rel_stp()があるので、 それらのために内部的なヘッダファイルを書く必要はありますが。
ファイル数が激増するので、src/task.cなるtask.cは分割して、 src_div/task/<関数名>.cとします。src_div/objも作っておけば、.oの 海に溺れることもありません。
そのように作業し、Makefileを書き換えたものが、
hos-h8-v0.07-gnu-src_div.tar.gz (14014 bytes)です。src/と同じディレクトリで展開して使います。
それでは、このsrc_divにもuso3664を適用してsampleをmakeしてみましょう。結果 は…、
おお!使っているサービスコールが少ないせいか、とんでもなく小さくなった ようです。素のままに比べ、40%も小さくなりました。
text data bss dec hex filename 5648 0 1072 6720 1a40 sample
あ、勿論、sampleとしては(多分)正常動作していますよ。念の為。
こんな事を書いて良いのだろうか?ちょっとこのセクションは書いていて怖い。 自分の無知を世に曝してるよ〜な気がしないでもありません。まぁ、それは 「今更」なので、気にせず行ってみましょう。
図に描くとこう。
![]()
| ||
|
んで、メッセージ/フラグ/セマフォでタスク間の同期をとったり、データのや り取りをしたりすると。
割り込みハンドラに関しては非タスクですが、これまたフラグ等を通じて連係 をとれるので、タスクとともに協調動作を実現できます。
何かを監視するタスクとか、何かを動かすタスクとか、外部からの要求に応じ たシステムの行動方針を決めるタスクとか、そんなタスクの集合体がアプリケー ションになるということでしょうか。
そういうスタイルだと、並列に複数の処理を行なうようなプログラムであって も相互の連係作業はOSまかせで済み、タスクの記述はとてもシンプルになり、 開発効率も上がるということのようです。
他にも「リアルタイム」と名乗るには、応答時間がどうこうとかいうのもある らしいですが、性能を保証しなければならないという話でもないので、気にす るのはよしておきます。
まぁこんなところがHOS-H8歴1ヶ月ちょっとの認識です。ここから更に一歩進 み出す為にも、絵に描いたような構造で習作モニタを作ってみます。
基本的に必要そうな機能を考えます。まずは低レベルな部分。
即ち、アプリケーション開発の際、これらのタスクを組み込んでしまえ ば、そのまま確保すべきスタック容量の見極めとか、デバッグに使える(とい いなぁ…位かもしれませんが)からです。こういうことが出来るのも、OSたる HOSを利用する利点なのでしょう。
「Minimum MONITOR」(ミニモニ^^;)の構造を描いていきます。
基本的にはSCI3を使って文字列入出力を受け持つ、「コンソールドライバタス ク」と、受け取ったコマンドを解析して実行、結果を作成する「コマンドシェ ルタスク」の2つのみです。
![]() | ||
| ||
![]() |
「コンソールドライバタスク」は、他タスクからの要求(mail)を待ち、要求が 来たらそれに応じた処理をして待ちに戻るループで成っています。文字送信/ 受信とも割り込みを使い、タスク内部ではSCI3の実際の読み書きは行なわず、 それぞれのバッファ(に積む|から取る)だけです。(送信バッファに積む|一行 読み込み開始の)際に、それぞれの割り込みを許可し、タスクとは別の割り込 み処理の方で、バッファのデータを実際にSCI3に対して読み書きし、(バッファ が空に|一行入力終了に)なればその割り込みを終了します。割り込み処理との 連係はイベントフラグを通じて行ないます。
![]() |
コマンドシェルタスクの図 |
そうして出来たのが、
mini-moni-v0.01.tar.gz (11898 bytes)です。h8300-hms-sizeの出力は、
となり、既にHOS本体が含まれている事を考えれば十分に小さいものが出来た のではないかと思います。
text data bss dec hex filename 9570 22 776 10368 2880 m0
それでは、ミニモニを使ってみます。
ささやかな起動メッセージとヘルプです。ヘルプは、不正なコマンドや空の改 行で出力されます。
Minimum Monitor V0.01 (on HOS-H8h v0.07) % 0 : Display TIME 1 XXXX XXXX : Dump #START #END 2 XXXX : BYTE write #START 3 : Event flag status 4 : MailBOX status 5 : TASK status 6 XXXX : Wait mail #ID 7 XXXX XXXX : Wait flag #ID #PTN 8 XXXX : Wait semaphor #ID
システム時刻の表示です。やっぱりあまり意味がありません。せめて10進で日 時分秒の表示にすれば?まぁいいでしょう。
% 0 0001D75D
メモリダンプでI/O領域を表示してみました。
% 1 ffa0 fff0 FFA0 : 00 10 FF FF 00 E2 13 DF 00 19 B0 30 00 0D FF F3 | ...........0.... FFB0 : 00 00 00 00 00 00 00 00 00 7E FF FF FF FF FF FF | .........~...... FFC0 : AA 00 FF FF 01 00 01 00 80 3F FF FF F3 5F FF FF | .........?..._.. FFD0 : 08 00 FF FF 08 FF FF FF 3F FF 8F 01 FF FE FF FF | ........?....... FFE0 : 0E 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ FFF0 : 00 00 70 C0 50 FF 30 FF C0 00 FF FF FC FF FF FF | ..p.P.0.........
1byte書き込みです。空の改行を入れるか、不正な行でプロンプトへ戻ります。 現在でもデバッグ用のLEDがport10に接続されているので、0xffd4番地への書 き込みで点灯、消灯の確認が出来ました。(PMR1/PCR1はミニモニでPORT1出力 に初期化されている)
% 2 ffd4 FFD4 : 08 > ff FFD5 : FF > %
スタックを観察してみました。スタックのアドレスはマップファイルで調べら れます。↓から、Stack2が0xf8c0〜0xf920に存在することが分ります。
% 1 f8c0 f920 F8C0 : 00 00 00 00 00 00 F8 DE 00 00 00 08 00 00 00 08 | ................ F8D0 : 00 00 00 00 F8 EC 00 00 00 00 00 00 00 00 00 00 | ................ F8E0 : F9 70 1D EE 00 00 FA 78 00 00 F9 50 00 00 F9 02 | .p.....x...P.... F8F0 : 1C 40 00 00 00 00 00 00 00 00 00 01 00 00 00 00 | .@.............. F900 : F9 50 00 00 F9 0C 0E 54 00 00 F9 E0 00 00 0D FA | .P.....T........ F910 : 1E AC 00 01 00 00 00 00 00 00 00 00 00 00 00 00 | ................ F920 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
タスクのスタック領域はbssに確保され、bssはスタートアップで0に初期化されるので、汚れ具合からスタックがどの程度まで伸びるのかが分ります。
(略) COMMON 0x0000f8b0 0x1d4 cfg_c.o 0x0000f8b0 mcbtbl 0x0000f8c0 Stack2 0x0000f920 scbtbl 0x0000f930 msgbuf0 0x0000f950 tcbtbl 0x0000f990 spcbtbl 0x0000f99c StackPool1 0x0000f9a0 Stack1 0x0000fa20 rdyque 0x0000fa60 fcbtbl (略)
これは既に減量されているので、さほど無駄にはなっていません。
フラグ状態の一覧です。FID_SCI3_RX,FID_SCI3_TX,FID_Consoleの状態が見ら れました。
% 3 Flag ID : Ex.inf. Wait task Flag pattern 0001 0000 0000 0000 0002 0000 0000 0000 0003 0000 0000 0000
メイルボックスの状態です。
% 4 MBOX ID : Ex.inf. Wait task Packet addr. 0001 0000 0000 F9E0
タスク状態の一覧です。あれ?ConsoleタスクがRDYですね…多分、Console内 のset_flgでディスパッチが起こって、ループの先頭のwai_msgまで辿り着いて いないからでしょう。こんな風に、多少は流れを掴む助けになるかな?
% 5 TASK ID : Ex.inf. Priority Status 0001 0000 0001 TTS_RUN 0002 0000 0002 TTS_RDY
次こそは本当に何かSCI3以外のデバイスを…。