最近、FPGAに作り込んだロジックの評価のために、
テスト用プログラムを使って、レジスタを叩いて動作確認をしている。
この順番でレジスタを叩けば、こういう動作になる。
というのをプログラムで書くのだが、なかなか期待通りに行かずに困った。
原因はいろいろあるんだけど……
まず、初歩的なところではコンパイラの最適化で書いた通りのアクセスが起きないというもの。
unsigned long *ptr; unsigned long dummy; ptr = REG1_PTR; *ptr = REG1_VAL; ptr = REG2_PTR; *ptr = REG2_VAL;
レジスタに書き込んで、別のレジスタに書くという操作だが、
こういう書き方をすると順番が変わって想定通りの動きにならないことがある。
ptrポインタの宣言時にvolatileを付けておけば、書いた通りに読み書きしてくれる。
こういうのは組み込みソフトウェアでは一般的なことですね。
さらに今回面倒だったのが、異なるブロックへのレジスタ操作があったこと。
Aブロックへのレジスタライトが反映後にBブロックのレジスタライトをしたいが、
アクセススピードが違うため、単に順番に書いても思った動作にならないと。
確実にするためにはレジスタライト後に同レジスタをリードすればよい。
こういうのもしばしばあることだけど。
このようにレジスタへのライトを保証するための操作がいろいろ必要になる。
あと、これも面倒だったのがスタックへのアクセスである。
RAMへの意図しないアクセスを止めたいテストがあって、
スタックへのアクセスが発生しないコードが生成されているか、
コンパイル結果のアセンブラ表記を見て確認したり……というのもあった。
それでも、意外な形でスタックへのアクセスに妨害されて大変だった。
冒頭にCのコードを書いたように、テストプログラムはCで書いている。
ただ、あまりに思ったようなコードが生成できないもんだから、
この部分のテストプログラムはアセンブラで書いた方がよいのでは?
なんて思いながらも、アセンブラも面倒だしと思いとどまったのである。
正しく書けばCでも回避出来る問題が大半だったので。
アセンブラで書けば思った通りの順番で命令を並べられるので、
その点では苦労は少ないが、実際書くとなると大変なんだよな。
条件分岐やループを書くのが面倒で、注意を要するというのはあるが、
今回問題の部分は一本道で書けるので、そこの問題はないが。
どちらかというと定数の取扱が面倒なのを嫌ったと。
命令に直接書ける定数はいいけど、そういうのは限定的なので。
アセンブラで書いたところでパイプライン処理を意識する必要はあるし……
出来上がったテストコードを見てみると、
本質的に必要な操作の2~3倍ぐらいのコードに膨れあがってしまった。
ただ、Cなので何を意図してこういう書き方をしているというのはわかりやすいかな。
苦労はあったけど、やっぱりこれでよかったと思いますね。
他にもこれはアセンブラじゃないと書けないのでは?
と思うものはあったけど、ほとんどはCで書きましたね。
ここがアセンブラじゃないと書けないと思ったのはスタックとの関係だが、
コンパイラへの指示とプログラム構造の工夫でなんとか回避出来た。
これはデバッグに手を焼きそうだなと思っていたけど、予想以上にきつかった。
想定外の制約事項もあって、想定外のスタックアクセスとの競合と苦しめられた。
ただ、プログラムは1回書けば、何度でも動かせますからね。
このタイミングで正しく作り込めたのはよかったんじゃないかね。