新版FM音源プログラム (20)
Cortex-M4 用の結果では、フラッシュのキャッシュ機構の構成が同じ STM32F446 と STM32F407 とがほぼ同じ結果で、別のキャッシュ機構を持つ STM32F303 がやや異なる結果となりました。
PSoC5LP にはフラッシュのキャッシュのヒット/ミスの回数を計測するレジスタがあり、それを利用して測定すると、サイン波テーブルをフラッシュ上に置いた場合と、SRAM 上に置いた場合との差が非常にきれいに現れました。
ARMv7-M アーキテクチャ (Cortex-M3/M4) 用にコンパイルしたアセンブリ言語プログラムのオブジェクトを逆アセンブルしたものを下に示します。
新版FM音源プログラム (17)
armcc の「エンベデッド・アセンブラ」では、関数まるごとアセンブリ言語で記述し、関数冒頭のレジスタ・セーブや、関数最後のレジスタ・リストアやリターン命令まですべてを記述する必要がありました。
gcc の「インライン・アセンブラ」では、C 言語での記述に混ざって「asm 文」が存在し、関数のプロローグ/エピローグ・コードは asm 文内では記述する必要がなく、C 側で自動的に生成されます。
また、デフォルトでは最適化の対象になっています。 (最適化オフにも設定できます)
アセンブラ命令も「裸」で記述することはできず、文字列の中に「閉じ込め」られた形で記述します。
下に gcc のインライン・アセンブラ機能を使って書いたプログラム・リストを示します。 (2018 年 2 月 28 日追記: ラベルを「ローカル・ラベル」(数字のみで構成されるラベル) に変更しました)
(2018 年 3 月 2 日追記: パイプライン・ストール解消のためプログラムの一部を変更しました)
新版FM音源プログラム (16)
オペレータ処理をアセンブリ言語で書く場合、C プログラム・ソースの構造体アクセスの
o_p->ph_acc
のような表現は、アセンブリ言語ソースとしては最終的には
ldr r2, [r0, #4]
のように「定数オフセット」にまで変換される必要があります。
C プログラム・ソースと独立してソースをアセンブラに喰わせる場合には、C 側で構造体のメンバの配置に変更があった場合にはアセンブリ言語ソースでの定義を手作業で修正する必要があります。
そのような事態を避けるため、「インライン・アセンブラ」のような、C コンパイラの機能に含まれたアセンブリ言語機能を利用することにしました。
ARM/Keil の μVison (armcc)では「エンベデッド・アセンブラ」、gcc では「インライン・アセンブラ」を使っています。
armcc 版のソースを下に示します。 (2018 年 3 月 2 日追記: 2 ヵ所ある
ldrsh r3, [r5, r3]
の部分でパイプライン・ストールが生じていたのを命令の順序の入れ替えにより解消しました。)
続きを読む新版FM音源プログラム (14)
プログラムを動作させるマイコン・ボードとしては、オペレータ出力波形をオシロで手軽にチェックするために、手持ちの中で DAC を内蔵するチップを搭載している次のボードを選びました。
- Nucleo-F446RE (STM32F446RET6, Cortex-M4)
- STMF4-Discovery (STM32F407VGT, Cortex-M4)
- Nucleo-F303K8 (STM32F303K8T6, Cortex-M4)
- STM32 Value Line Discovery (STM3F100RBT6, Cortex-M3)
- PSoC 4200 Prototyping Kit (CY8C4245, Cortex-M0)
- PSoC 5LP Prototyping Kit (CY8C5888, Cortex-M3)
それに加え、単体の LPC1114FN28/102 (Cortex-M0) に SPI 接続の DAC、MCP4922 をつないだものを使いました。 (2018 年 2 月 26 日追記: PSoC4 / PSoC5LP を追加しました)
開発ソフトウェアとしては、ARM/Keil の μVision V5.21.1.0 (MDK-Lite V5.21a) と、Atollic TrueSTUDIO for STM32 v9.0.0 とを使いました。
PSoC については PSoC Creator 4.0 Update 1 (gcc 4.9.3) を使いました。
新版FM音源プログラム (13)
これまでのFM音源プログラムでは、オペレータ (スロット) ひとつ分を実現する関数を定義し、それをオペレータの個数だけ呼び出していました。
より効率化するために、ひとつの関数内ですべてのオペレータの計算を行なうように変更することを考えています。
8 K エントリのウェーブ・テーブルを使うタイプのプログラムと、3.75 K エントリのウェーブ・テーブルを使うタイプのプログラムとで、実行サイクル数に大きな差はありませんでした。
そこで、ウェーブ・テーブル・サイズの削減効果を重視して、2016 年 8 月 16 日付けの記事 (→こちら) で示している 3.75 K (3840) エントリのウェーブ・テーブルを使うことにしました。