P/ECE研究室〜S1C33分室


* Tue Jan 22 22:01:37 JST 2002 Naoyuki Sawa

前回、高速DMAに較べてインテリジェントDMAは理解しづらそうだ、と書きましたが、この推測は間違っていました。
実際に試したところ、単純に使うだけならば、高速DMAよりもインテリジェントDMAの方が簡単でした。
もっとも、実用的に使うならば割り込みが絡んできます。インテリジェントDMAの割り込みは、予想通り難解です。
実は、まだ理解できていません。ハードウェアトリガやDMA完了割り込みについては、今後の課題とさせてください。
なお、P/ECEのシステムプログラムは、インテリジェントDMAを全く使っていませんので、ぶつかる心配はありません。

インテリジェントDMAには、次のような特徴があります。
  1. 設定情報をメモリ上に置いて使う。
  2. 128チャネルものDMAが利用できる。
  3. 一回のトリガで複数のチャネルを起動できる(リンク機能)。
1.の特徴により、構造体で指示を与える、メモリコピー関数の呼び出しのように扱うことができます。 例えるなら、pclSprite系関数みたいな感じです。 メモリ上に作成する設定情報の構造体は、c33208.hでIDMA_ST構造体として定義されています。 128チャネル分すべての構造体を用意する必要はありません。チャネル0〜必要なチャネルまでの配列だけで充分です。 2.の特徴。インテリジェントDMAは高速DMAと違い、チャネルによってトリガ要因が決めうちとなっています。 決めうちなので、高速DMAのように割り込み要因の選択を行う必要がありません。
チャネル トリガ要因
0 ソフトウェアトリガ
1〜4 ポート入力、またはソフトウェアトリガ
5〜6 高速DMA完了、またはソフトウェアトリガ
7〜18 16ビットタイマ、またはソフトウェアトリガ
19〜22 8ビットタイマ、またはソフトウェアトリガ
23〜26 シリアル送受信、またはソフトウェアトリガ
27 A/D変換完了、またはソフトウェアトリガ
28〜31 ポート入力、またはソフトウェアトリガ
32〜127 ソフトウェアトリガ
ちなみに、c33208.hのコメントには、次のように記述されていました。
チャネル トリガ要因
0 予約
1〜4 ポート入力、またはソフトウェアトリガ
5〜6 高速DMA完了、またはソフトウェアトリガ
7〜18 16ビットタイマ、またはソフトウェアトリガ
19〜22 8ビットタイマ、またはソフトウェアトリガ
23〜26 シリアル送受信、またはソフトウェアトリガ
27 A/D変換完了、またはソフトウェアトリガ
28〜31 ポート入力、またはソフトウェアトリガ
32〜39 ソフトウェアトリガ
想像ですが、S1C33208からS1C33209に変わった時に、機能強化としてIDMAチャネルが増えたのではないでしょうか。 チャネル0が予約となっていること、S1C33209のマニュアルではチャネル0について特に説明がないのが気になりますが、 今回実験したところ、チャネル0をソフトウェアトリガで問題なく使うことができました。 3.の特徴を利用すると、一回のトリガで複数のDMA転送を行うことができます。 注意が必要なのは、一つ目のチャネルの転送が完了しなくても、次のチャネルが起動するという点です。 言い換えると、一つ目のチャネルの転送完了(カウンタ=0)によって二つ目のチャネルが起動するのではなく、 一つ目のチャネルへのトリガが同時に二つ目、三つ目、...のチャネルへのトリガにもなる、ということです。 今回の実験でリンク機能も試してみましたが、実用的に使うにはちょっとくふうが必要かも知れません。 それでは、実験です。ソース まず、前回、高速DMAでやったのと同じことを、インテリジェントDMAのチャネル0を使って行ってみました。 高速DMAでの結果と同じですね。 次に、リンク機能の実験です。チャネル0〜5をリンクして、各チャネルで2バイト(全角1文字)ずつ転送します。 転送元の文字列データは、こんな感じです。
/* 0 1 2 3 4 5 6 7 8 9*/ char msg_new[] = "あいうえおかきくけこ" /*0x*/ "さしすせそたちつての" /*1x*/ "なにぬねのはひふへほ" /*2x*/ "まみむめもやゆよらり" /*3x*/ "るれろわをん"; /*4x*/
ここから2バイトづつ抽出して、一回だけのトリガで「せいてんなり」という文字列を作ってみます。 このプログラムでは、リンク機能のほかに、ハーフワード単位の転送も試してみました。 各チャネルは2バイトづつ転送しているのですが、1バイト×2ではなく、2バイト×1と設定しました。 ところでハーフワード単位の転送を行う場合、転送元や転送先アドレスがハーフワード境界に整列していないとどうなるのでしょうか? 考えられるのは、
  1. 何らかの例外が発生
  2. 間違ったアドレスに転送
といったところです。実際に試してみたところ、どうやら2.の動作となるようです。 具体的には、転送単位をハーフワードとした場合、転送元と転送先アドレスのビット0は、設定情報に書いた値にかかわらず"0"と見なされます。 例えば、アドレス0x0010〜に"0123456789"という文字列があり、アドレス0x0011から3ハーフワードを転送しようとしたとしましょう。 その結果、転送されるのは、期待した"123456"ではなく、"012345"となります。0x0011のビット0の"1"が無視され、0x0010と見なされたからです。 ここでは転送元アドレスについて説明しましたが、転送先アドレスについても同様でした。 もうひとつ、自分自身にリンクしたらどうなるか?の実験もやってみました。 すなわち、チャネル0のリンクフィールドにチャネル0を指定したらどうなるか?ということです。 結果を申しますと、期待通り、ハングアップしました。自分自身にリンクしてはいけません。 P/ECEのシステムプログラムはインテリジェントDMAを使っていないので、「カーネルいちゃもんコーナー」はお休みです。 その代わりに、c33208.hの間違い記述らしきものを指摘しておきます。 設定情報の構造体IDMA_STの定義において、次のような記述がありますが、
union { volatile struct { unsigned int TC : 24; /* Data transfer counter */ unsigned int LINKCHN : 7; /* IDMA link field */ unsigned int LINKEN : 1; /* IDAM link enable */ } bBLK; volatile struct { unsigned int BLKLEN : 8; /* Block size */ unsigned int TC : 16; /* Data transfer counter */ unsigned int LINKCHN : 7; /* IDMA link field */ unsigned int LINKEN : 1; /* IDMA link enable */ } bSIN; volatile unsigned int uiTC; } rTC;
明らかにbBLKとbSINが逆です。 ブロックモードでbBLKを使おうとすると、BLKLENフィールドがないのでコンパイルエラーとなって気づきますが、 シングルや連続転送モードでbSINを使うと、必要なフィールドは全てそろってしまっている(ただし位置は違う)ので、気づかない恐れがあります。 危険度は中、といったところでしょうか。 次回は、16ビットタイマかシリアルコントローラを試してみたいと思います。 (続きます...)

nsawa@piece-me.org