先週、 myos で hd audio に対応しましたが、波形メモリに直接波形を書き込むことで beep 音を生成していました。
この方法だと波形生成後のフィルター処理などが困難で、複数のアプリケーションで同時に音を鳴らすこともできませんでした。
ということで、複数のオーディオノードを接続してフィルタ処理をかけるスケジューラーを実装します。
デジタルオーディオデータは 16bit がよく使われますが、フィルタ処理の最中には 16bit の精度を超える計算をすることもあったりクリッピングの手間があるのでフィルタなどの計算は浮動小数演算で処理し、最終的に波形メモリに書き込む際に 16bit 値に丸めるようにします。
実は myos では結構前に SSE を解禁していますが、浮動小数演算を実際に使ったのは今回がはじめてでした。
QEMU で動いたので実機で試したところ、 Inexact-Result (Precision) Exception という謎の例外が発生しました。
調べてみると SIMD 例外の一種で、割り切れない演算をした際など演算結果に誤差が生じたときに発生する例外のようです。 多くの場合そこまで厳密な計算したいわけではないので、ほとんどのケースでこの例外はマスクされる想定のようです。
SSE では MXCSR というレジスタを使って浮動小数演算の動作を制御することができます。
このレジスタの下位 6bit は SSE 例外が派生した場合にどの例外が発生したかを示していて、 7bit 〜 12bit では例外を種類ごとにマスクするかどうか選択することができます。また丸め処理なども制御することができます。
ということで、スレッドの初期化時に LDMXCSR 命令を実行して 12bit 目の Precision Mask を 1 にセットすることでこの例外を抑制することができました。