近況
先週ぐらいから MCU のソースに手を入れて専用ソフトで通信するプロトコルの策定とそれの C ソースの実装をしています. memory read, memory write に関してはそれでできています.
flash memory programming になると、programming の空き時間があるので2つのバスで並列に動かす仕様にしてます. 通信プロトコルなりコマンド詳細は頭の中ではできてるのですが、複雑になっているので準拠した C のソースを MCU で動かしてもデバッグが困難になっていきます.
リモートデバッガでもステップ実行などはできるのですがそんなに早くないとかブレークポイントの制限がつきまとっていたり、CPU は待ってくれても周辺デバイスが待ってくれないのでうまいこと調べられないことがあります.
今回作った C のソースは MCU のレジスタはいじらないものの大量のクラスもどき変数があるという状態なので、シミュレータを作ることにしました. このソースは PC 用にコンパイルできますので、入出力は別途作ってリンクします. リンクの部分など本当に C で書く必要がある所以外は mruby で作って試行錯誤している状態です.
もう何度かやってるのですがグルー言語を組み込んだデバッグはリンクが通るまでは煩雑ですが、動き出すと C 特有のルール(static とか配列サイズを超えないようにするとか struct の宣言とか typedef struct{}name だとポインタだけ宣言がやりづらいとかなど多数)から開放されてやりやすくなります. 作り込む C のソースはローカルの gdb で好きなだけデバッグ情報も取れます.
本題
今日は MCU から PC に USB でデータを送る部分のソースを見直しました. MCU の仕様上そのデータのポインタのアドレスは alignment 4 bytes を守る必要になり下記のコードを書きました.
uintptr_t addr = (uintptr_t) t->data_buffer.top; uintptr_t mask = 0b11; if(addr & mask){ addr &= ~mask; addr += 4; t->data_buffer.top = (uint8_t *) addr; } t->data_buffer.length = (t->input.top + BUFFER_SIZE) - t->data_buffer.top;
uintptr_t は標準ライブラリの inttypes.h (か stdint.h) で定義されている CPU の address を整数にする場合の型です. 当初は uint32_t で書いていたのですが、 MCU 用のコンパイラでは通り、 PC 用のコンパイラでは警告が出ました(-Werror でエラー扱い). 理由を考えると MCU のアドレスバスは 32 bit, PC のアドレスバスは 64 bit なので正しく計算できなくて当然です.
そういうときに inttypes.h 検索したらそれ用の型があって助かりました. 他目的だと uintptr_t はどういう目的で必要があるのでしょうか??
あとは.. 2種類ぐらいのコンパイラで同じソースをコンパイルすると Warning 出ずにたまたま動いていた所がでてきて、結果として信頼性があがる気がします. (気がするだけ)