ソフトウェアで何か計算を行う場合、だいたいのことは掛け算と足し算でできています。
WikipediaのディジタルフィルタにもFIRフィルタの絵が載っていますが、基本的にはこういう感じです。
for(i=0;i<N-1;i++){
z[i+1] = z[i];
}
z[0] = in;
out = 0;
for(i=0;i<N-1;i++){
out += z[i] * a[i];
}
8行目が注目ポイントですが、掛け算をして足し算をします。掛け算をして足し算をする、これを積和演算と言います。DSP機能がある、というCPUには、普通はこの積和演算を効率よく実行するための仕組みが備わっています。例えばARMの命令セットでいうと、Multiply Accumulate と説明があるMLA系の命令で、扱う数値のビット幅によって、16bitを2つ掛けた結果を32bitで保持するなど、いろいろなパターンが用意されています。
ここで大事なことは2つあります。
- 保持できる数値の桁数は上限がある
- 桁あふれの処理をうまくやらないといけない
こちらのページでも書きましたが、扱える数字の大きさは決まっています。固定です。
ところが、掛けて足してを繰り返していると、間違いなく桁あふれの恐れが出ます。9+9=18になるように、9*9=81になるように、掛け算も足し算も計算をすれば桁が増える可能性があります。というわけで、計算途中というのはゆとりのあるビット幅で値を保持しなければなりません。そういう理由から、32bitx32bitの計算をして64bitで結果を保持する、という命令が準備されています。
もうひとつは、桁あふれの処理です。9*9=81の結果を1桁であらわしたい場合、単に1桁目の数字を残すと1になってしまいますが、1桁で表現できるもっとも81に近い数字は9です。これは10進数で考えた場合なので、例えば4bitの2進数で考えると 1001*1001=1010001 となりますが、この結果をもとどおり4bitの値で表現するならば 1111 がもっとも近い数字ということになります。これをC言語で書こうとするとこうなります。
if(i>15){
i = 15;
}
値の大きさ比較をして、大きければ値を変更する、大きくなければ何もしない、という条件分岐を実行するととても時間がかかりますし、条件予想が外れるとパイプラインもストールしてしまうので、こういう場合のために用意されているのがSAT系の命令です。日本語では飽和演算と言います。こちらも扱う数値の大きさによっていろいろな種類が用意されています。
普通のCPUとDSP機能は何が違うのかというと、積和演算や飽和演算を高速に実行できる仕組みが備わっているか、というところが大きな違いです。これらの機能を有効活用しようとすると、C言語では書けないのでアセンブリ言語を使用することになります。
コメント