dsPIC33FJ64GP802 (12) --- IIR フィルタ関数と Yデータ・メモリ・アクセス (1)

 dsPIC の libdsp に含まれている IIR フィルタ関数 (IIRCanonic()、IIRTransposed()) では、割り当てられた Y データ・メモリの範囲外へ (不要な) アクセスを行っているため、場合によってはプログラムの停止、リセットの繰り返しなどを生じるおそれがあることが判明しました。
 ただし、対策は容易に行えます。
 FIR() 関数については範囲外のアクセスはなく、問題は生じません。 その他の FIR / IIR 系のフィルタ関数については調べていません。
 「問題」の直接的な原因は、不要 (余分) な Y データ・メモリ・リード・アクセスが RAM の実装されていない領域に対して行われ、(マスクできない) 「アドレス・エラー・トラップ」が生じることによります。
 アドレス・エラーに対処できないうちに再度ハード・トラップが生じると、強制的にデバイス・リセットがかかります。 (Trap Conflict Reset)
 この状態になると、

リセット → プログラムを先頭から実行 → IIR 関数の実行 → トラップ・コンフリクト → リセット → …

という無限ループに陥ってしまいます。
 「アドレス・エラー」が起きる条件としては、

  • IIRCanonic() 関数では、IIRCanonicStruct の delayBase フィールドが指し示す遅延要素の配列が RAM の最後尾に配置されること
  • IIRTransposed() 関数では、 IIRTransposedStruct の delayBase1 フィールドが指し示す遅延要素の配列が RAM の最後尾に配置されること

があります。
 いずれの場合も、 RAM の実装されていないエリアに対して余分な RAM 読み出しアクセスが行われ、アドレス・エラーを引き起こします。
 XC16 コンパイラでの変数のマッピングの説明のために、図を下に示します。

 アドレスの数値は dsPIC33FJ64GP802 の場合を示しています。 dsPIC のデバイスごとに RAM 容量が異なっていて実際のアドレスに違いはありますが、割り付けの方法は同様になっています。
 dsPIC は「ハーバード・アーキテクチャ」で、プログラム・メモリの空間とデータ・メモリの空間とは分離されています。
 データ・メモリの空間は 64 K バイトの大きさを持ち、dsPIC33FJ64GP802 では 16 K バイトの RAM がアドレス 0x0800 ~ 0x47FF に配置されています。
 アドレス 0x0000 ~ 0x07FF までは SFR (Special Function Register) に割り付けられています。
 まず、RAM は 2 分割され、前半が「X データ・メモリ」、後半が「Y データ・メモリ」として扱われます。
 XC16 では、「xmemory」の属性が指定されている変数およびメモリ配置の属性が特に指定されていない変数は、RAM 領域の先頭から割り付けられていきます。
 「ymemory」の属性を持つ変数は、 RAM 領域の後ろ側から詰められていくようです。
 すべての変数の配置が終わると、RAM の中間部にまだ割り付けられていない領域が残りますが、その先頭側を (もしあれば) ヒープ領域に、その後ろ側をスタック領域に割り当てるようです。
 「ymemory」属性の変数の配置の順序を制御する方法は不明のため、運悪く前述の遅延要素配列が RAM の最後尾に配置された場合には、RAM の配置されていない 0x4800 以降のアドレスをアクセスしてアドレス・エラーを発生させてしまいます。
 これは、標準のフィルタ設計プログラム「dsPICFD」(dsPIC Filter Designer) で生成されるアセンブリ言語ファイルでは、自然に回避されるようです。
 Code Example の 「CE01_ ADC_DSP_lib_filter」に含まれているファイルでは、IIRTransposed() 用として、遅延要素の配列が

; ...................................................................
;    File   ExampleHPF.s
; ...................................................................

        .equ ExampleHPFNumSections, 5

; ...................................................................
; Allocate states buffers in (uninitialized) Y data space

        .section .ybss, ymemory, bss

ExampleHPFStates1:
        .space ExampleHPFNumSections*2

ExampleHPFStates2:
        .space ExampleHPFNumSections*2

のように定義されています。
 「ExampleHPFStates1」と「ExampleHPFStates2」とは、この順番で連続するブロックとして ymemory 内に配置されるため、delay1 側が RAM の最後尾に配置されることは決してなく、問題となることはありません。
 IIRCanonic() 関数について dsPICFD がどう扱っているかは、Code Example にプログラム例がなく、不明です。
 次回は、問題に対する対策について説明します。