PIC32MXで"Reserved Instruction"例外が発生した

卒研でPICを扱っていた際に詰まったのでメモ.

 

環境

PIC:PIC32MX270F256B
コンパイラ:XC32 v2.10
ライタ:PicKit3
という環境で,USB通信を行いながらECDSAなどを扱うプログラムを作成し,PicKit3を用いたデバッグを行っていた.
 

例外発生

しかし,ある場所まで達すると例外が発生した.
調べてみるとこれは”Reserved Instruction”というもので,MIPS32のユーザマニュアルでは以下のように記述されている.
“A reserved instruction exception occurs when a reserved or undefined major opcode or function field is executed.”
よくわからない.
よくわからないが,変な命令を実行しようとした場合にこの例外が起こりそうだという雰囲気は伝わってくる.
しかし,私はCしか書いてないし,アセンブリで高速化するようなこともしていない.
 

対策の検討

検索してみても情報は乏しかったが,FreeRTOSのフォーラムで割込みを禁止すると治るという書き込みがあったため,割込みに関する部分を触ってみたが,ダメだった.
仕方ないからstackとheap領域のサイズを変えてみたが,これもダメだった.
 
いろいろ調べてみたところ,xc32-ldの”Remove unused sections”にチェックが入っていたことが原因だとわかった.
これは,Harmony Configuratorで設定を生成するとチェックされるらしい.
”Remove unused sections”というのはリンカのオプションで,参照されていない不要なセクションを削除するというもの.
これにより割込みベクターテーブルが削除されたようだ.
そして,削除された割り込みベクターテーブルを参照することにより,未定義の命令に到達するのではないかと推測できる.
 
そのため,対策としては2つ挙げられる.
1つはリンカの最適化を抑え,不要なセクションの削除を行わないようにすること.これはプロジェクトのプロパティからgcc-ldの設定を変更するだけで完了するため簡単に実行できる.しかし,最適化を行わないためプログラムメモリを必要以上に消費する.
もう1つはリンカスクリプトの書き換えで,ベクターテーブルのセクションに対してKEEP()をつけることにより,不要なセクションとして削除されないようにする.これはリンカスクリプトを書き換えるため面倒だが,プログラムメモリの消費を最低限に抑えることができる.
 
なお,私はリンカによる最適化をoffにして解決を行った.
その結果,プログラムのサイズはおよそ2倍となったが,例外は発生しなくなった.
 

結論

xc32-ldの”Remove unused sections”をはずす.
あるいはリンカスクリプトにKEEP()をつけて割り込みベクターテーブルが削除されないようにする.