畳み込み演算二態

畳み込み演算は非常に重要なのでどのようなDSPでも高速に実行できるように考えてあります。最近の高速化の手段はたいていSIMDをはじめとする並列演算によっており、その上にFIRフィルタで説明した最適化を施します。以下ではADSP-2191とは異なるアーキテクチャーのDSPの畳み込み演算を見てみましょう。

Blackfin

Analog DevicesのADSP-21535、Blackfinは16ビットDSPでありながら32ビットRISCとしても利用できるアーキテクチャーを持っています。また、高速の演算を行うためにMAC演算器を二つ持っています。

高速な畳み込みを行うには、この二つのMACを同時に動作させます。Blackfinは積和演算についてかなり柔軟な命令を組める構造になっていますが、いちばん簡単な使い方は二つのMAC演算器に同時に積和を行わせることです。以下の例では二つのFIRフィルタを同時に処理しています。つまりこれは2ch同時処理になります。

ループ設定命令は他のプロセッサとやや異なっています。古い型のループ命令は直後からループが始まりますが、loop命令はループ本体より離れた位置でループの設定を行います。これによってストールなしでループを開始することができます。

ロード命令は32ビットオペランドをロードします。このオペランドには16ビットデータが二つパックされていますので、1命令で2データをロードできます。Blackfinは二つのロード命令を同時に実行できますので、都合4データを同時ロードできます。

循環バッファ( Circular Buffer )に対するアクセスはADSP-2191と同様、BxレジスタとLxレジスタを使って暗黙的に行います。

ループ本体は1行からなります。この命令行は1サイクルで実行できますが、実際には三つの命令をパックして一度に発行しています。ADSP-2191と異なるのは1命令の中で複数動作を実行しているのではなく、3命令をパックして実行する点です。この点でBlackfinのアーキテクチャーはVLIWに似ており、それぞれの命令に対する制限を緩和することができます。ADSP-2191は命令長が48ビットしかないため、演算とデュアル・ロードなどの複合命令に関しては動作にきつい制約がかかっていました。

    p0=TAPS-1;                    // 繰り返し回数
    loop fir lc0=p0;              // ループの設定

    r0=[i0++] || r1=[i1++];       // プリロード
LOOP_BEGIN fir;
    a0+=r0.h*r1.h, a1+=r0.l*r1.l || r0=[i0++] || r1=[i1++];
LOOP_END fir;
    r2.l=(a0+=r0.h*r1.h), r2.h=(a1+=r0.l*r1.l);
    

TigerSHARC

ADSP-TS101S, TigerSHARC DSPはSIMD演算可能なVLIWプロセッサです。同じ形をした演算ブロックを二つもち、それぞれをSIMD的に動かすことも独立して動かすこともできます。また、同じ演算ブロックの中では二つの異なる種類の演算を行えます。たとえば、加算とシフトの同時実行が可能です。

TigerSHARCはオペランド単位が32ビットになっており、命令もデータもこれを単位として扱います。ただし、計算対象となるデータは16/8ビットが可能で、32ビットワードの中にパックして計算します。計算オペランド長は通常32または64ビットなので16ビット演算は2/4個同時に行えます。そしてこれをXY両演算ブロックで行えば1命令で4/8個の並列演算を行えます。さらに、VLIWを利用して2演算を同時実行できますので、16ビット演算を16個同時に行えることになります。

TigerSHARCはこれらの特徴から、1サイクルで積和演算を8個同時に行うことができます。これは8chのFIRフィルタを一度に処理できることを表します。

強力で高速なプロセッサとして設計される代わりに、TigerSHARCにはレイテンシのペナルティが課されました。ADSP-2191やBlackfinはFIRフィルタの実行時にはストールなしの計算が可能です。しかし、ADSP-TS101Sはデータのロードから演算に2クロックのレイテンシがあるため、ロード直後に演算をおこなうと1サイクルのストールが発生します。

以下のサンプルはこれを避けるためにループアンロールを施しています。このループは1回の繰り返しで8チャンネルに対して2タップ分の演算をおこないます。

ロード命令は128bitのデータを一度にもってくることができます。以下の例ではこのデータをXY両ブロックに64bitずつ分配します。この命令を二つ同時に実行できますので、16bitのデータが16個一度にロードされます。演算は8積和同時実行ですので1サイクルで8TAPを処理することができます。

なおTigerSHARCにはループ命令がありません。その代わりにBTB( Branch Target Buffer )を使った分岐命令を実行します。VLIWであることを生かして演算をしながら条件ジャンプを行うことで、ループ本体でのオーバーヘッドを最小に押さえます。なお、オーバーヘッドは0になりません。ループの最初の繰り返しではBTBがミスヒットし、最後の繰り返しでは分岐予測に失敗するからです。その他の繰り返しではオーバーヘッドが0になります。

        lc0=TAPS/2-1;                                           // ループ回数の設定

        xyR1:0=cb q[j0+=4];             xyR3:2=cb q[k0+=4];;    // プリロード
        xyR5:4=cb q[j0+=4];             xyR7:6=cb q[k0+=4];;
        
fir_body:       
                mr3:0+=r1:0*r3:2;       xyR1:0=cb q[j0+=4];     xyR3:2=cb q[k0+=4];;    
        if nlc0e, jump fir_body(p);
                mr3:0+=r5:4*r7:6;       xyR5:4=cb q[j0+=4];     xyR7:6=cb q[k0+=4];;    
        
        mr3:0+=r1:0*r3:2;;
        mr3:0+=r5:4*r7:6;;      
        sr1:0=compact mr3:0;;

まとめ

最近のDSPは深くパイプライン化され、SIMDであることがあたりまえの雰囲気があります。比較的パイプラインが浅く、SIMD化されていないADSP-2191と畳み込み演算の速度を比べてみると以下のようになります。

DSP 周波数[MHz] MMAC/秒
ADSP-2191 160 160
ADSP-21535 300 600
ADSP-TS101S 300 2400

ここまで圧倒的な差がつくと援護する気にもなりません。性能が必要ならばBlackfinやTigerSHARCを選ぶべきです。ただしADSP-2191はアセンブリ言語を使っても気楽にプログラムを組めるので、絶対的な演算速度がそれほど重要ではない場合は手軽に使えます。BlackfinやTigerSHARCの能力を搾り出すにはそれなりに周到な準備が必要となります。

⇒次はDSP

2191空挺団 | プログラム | EZ-KIT | こぼれ話 | アーキテクチャー | 命令 | レジスタ | DSP掲示板 | FAQ |