ユーザ・ドライバに複数の引数を与える方法 [ColdFire V2]
おおやけには、ユーザ・ドライバには、引数を一つしか渡すことが出来ないとされています。 何とか複数の引数を渡す方法は無いでしょうか。
スタック・フレームと引数構造体
CodeWarrior のコンパイラが生成するコードは、 A6 レジスタを使用して、スタック・フレームの管理を行っています。 たとえば、ユーザが記述したユーザ・ドライバ "uint32 driver(uint32 arg)" が呼び出されると、 "driver" 関数に与えられた引数とそこで使用される局所変数へは、 A6 レジスタを介してアクセスすることができます。
また、スタック・フレームには、呼び出し元のスタック・フレームへのポインタも含まれています。 そのため、スタック・フレームをさかのぼると、次々と呼び出し元の関数のスタック・フレームにアクセスすることが出来ます。
また、 SilentC は、インタプリタなので、字句解析を行ったのち、該当する関数に相当するコンパイル済み関数を呼び出します。 たとえば、 "UserDriver" 関数の場合には、 "UserDriverSub" という関数が呼び出されます。 この呼び出しの際には、 SilentC の引数を表現した引数構造体へのポインタが渡されます。 そこで、この構造体を介して、ユーザ・ドライバに複数の引数を渡すことが出来ます。
UserDriver 関数の引数をコピーするプログラム
さっそく、プログラムを作って試してみます。 このプログラムは、 UserDriver 関数に与えられた引数構造体を 0x20007F80 からの空きエリアに単純にコピーするプログラムです。
#include "support_common.h" /* include peripheral declarations and more */ #include "silentmoon.h" // // Stack frame structure // struct stack_frame { struct stack_frame *invoker; void *return_value; uint32 args[0]; }; // // SilentC's argument structure // struct arguments { uint32 mode; uint32 args[0]; }; // // VECTOR #0 : main // uint32 main(uint32 arg) { #pragma unused(arg) struct stack_frame *this_frame; struct stack_frame *invoker_frame; struct arguments *silentc_args; uint32 *table = (uint32 *)0x20007f80; asm { move a6,this_frame } invoker_frame = this_frame->invoker; silentc_args = (struct arguments *)invoker_frame->args[0]; BufCopy(table, silentc_args, 64); return (uint32)0; } // // Jump table for vectors // __declspec(jump_table) asm void jump_table(void) { jmp main // Driver #0 }
書き込んで実行してみます。 9個の引数が、 0x20007F88 から 0x20007FA7 まで並んでいるのがわかります。
OK UserDriver(0,1,2,3,4,5,6,7,8) OK m::d(0x20007f80) 20007f80 41 00 00 09 00 00 00 00 A....... 20007f88 00 00 00 01 00 00 00 02 ........ 20007f90 00 00 00 03 00 00 00 04 ........ 20007f98 00 00 00 05 00 00 00 06 ........ 20007fa0 00 00 00 07 00 00 00 08 ........ 20007fa8 00 00 6e e8 00 00 65 c0 ..n...e. 20007fb0 02 00 00 00 00 02 00 00 ........ 20007fb8 00 00 00 00 00 00 00 00 ........
違う引数を与えると、こうなりました。 7個の引数が、 0x20007F88 から 0x20007F9F まで並んでいるのがわかります。
OK UserDriver(0,256,257,258,259,260,261) OK m::d(0x20007f80) 20007f80 41 00 00 07 00 00 00 00 A....... 20007f88 00 00 01 00 00 00 01 01 ........ 20007f90 00 00 01 02 00 00 01 03 ........ 20007f98 00 00 01 04 00 00 01 05 ........ 20007fa0 00 00 01 00 00 00 01 01 ........ 20007fa8 00 00 01 02 00 00 01 03 ........ 20007fb0 00 1d 00 07 00 00 00 06 ........ 20007fb8 00 00 00 00 00 00 01 00 ........
この結果から、 "UserDriver" 関数の第二引数が args[1] に格納され、第三引数が args[2] に格納され、以下、順に格納されていることがわかります。 また、 mode の下8ビット、ダンプ・リストでいう所の 0x20007f83 番地には、 "UserDriver" 関数に与えられた引数の数も保存されています。 この仕掛けを使えば、可変長の引数をユーザ・ドライバに渡すことも出来ますね。
プロジェクト・アーカイブ
ユーザ・ドライバのプロジェクトは、これを CFCQ06.zip という名前で保存すると再現できます。
参考文献
Interface (インターフェース) 2008年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/10/25
- メディア: 雑誌
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
コメント 0