スパイス  組み込み制御装置の受注製作

Hitech-Cコンパイラを組み込み用に移植する
平成26年4月16日

組み込みの準備
 コンパイラのROM化まで一通りの確認が終わりました。
この確認過程でも、幾つか小さな制約が見つかりました。共にCプログラム中のアセンブラ記述に関してです。
  追加の制約
 ・アセンブラの記述は#asm〜#endasmは通るが、もう一つの方法として説明書に記載されているasm("");ではエラーとなり記述できない。
 ・#asm〜#endasm方式でも特定のアセンブラ命令は上手くコンパイルできない。
 asm("");方式の記述は、このV3.09より後のコンパイラで追加されたものかもしれません。多少の文書ミスを疑って”()”や’”’などを削除してみましたが、結果はだめでした。
 もう一つの制約は主にジャンプ系のオペランドにアドレスを配置する命令が対象です。(JP, RSTなど)
このコンパイラには特有の機能としてテンポラリーラベルを管理してくれる機能があります。どうもこの機能との兼ね合いで部分的に不都合を抱えているようです。テンポラリーラベルに関する記述は説明書Z80DOC.TXTのP37にあります。
 まず、JP命令のオペランドに直接アドレスを記述することが出来ません。必ずそのアドレスにラベルを定義して、そのラベルを書く必要があります。
 もう一つはRST命令のオペランドの扱いが最適化のON/OFFで変わってしまい、プログラムのコンパイルが通らない現象があります。最適化を禁止した状態でコンパイルを通すと最適化ONでエラーを起こし、最適化ONの状態でコンパイルを通すと最適化OFFではエラーになります。この現象も最適化の前後でオペランドを番号からラベルとして認識を変えるためにエラーを起こしているようです。これはRST命令部分をサブルーチンとして(Cのソースリストに埋め込むのではなく)アセンブラとして記述することで回避できます。

 このようにしてみると、あまりC言語のプログラム内でアセンブラを多用しない方が良いと思われます。本当に必要ならその部分だけを小さなサブルーチンとしてアセンブラで記述し、それ以外の部分をC言語で記述します。C言語の中では、精々Nop命令程度にしておいた方が安全かもしれません。
 これはC言語とアセンブラの混在に関する基本的な姿勢として重要な気がします.。「混在できる」のは間違い無いのですが、「何でも出来る」訳でもないし、「混在する」ことでコンパイラでのエラーチェックが甘くなることを考えると、むしろあえて混在できない(またはワーニングを出して使用を控えさせる)ようにしてアセンブラによる関数記述方法の説明に注力する方が良い選択ではないかと思えます。


 ここからが本題になります。
  利用価値
 まず、心配なのはこのHitech Cコンパイラは果たして現在の組み込み装置用に使用する価値があるのかという点です。結論としては「多少の制約はあるものの、選択肢の少なくなった80系Cコンパイラとしては十分に利用価値がある」と判断します。GAIO Cコンパイラとの比較でも、幾つかの側面ではHitech Cの方が出来が良い部分も見られます。これら二つのCコンパイラを比較してみます。
 ・アセンブルリストはHitechの方がが読みやすい
 Hitech Cでは最適化を禁止した状態でアセンブルリストを出力させるとリスト中にCのソースコードをコメントとして残してくれます。これはデバッグ中にコンパイラの動作を検証したいときには非常に役立ちます。残念ながら最適化を許可するとアセンブラ出力からCソースのコメントが削除されてしまいます。これは最適化によってCソースの各行とアセンブラ出力の対応が一対一で無くなるためと思われます。
 対してGAIO Cではアセンブラ出力にはCソースの行番号のみがコメントとして含まれます。Cのソースコードをつき合わせれば良いのですが、画面上や紙の上でも二つのリストを突き合わせるのはそれなりに面倒で、この形式では結局やらないことの方が多い。

 ・エラーメッセージはHitechの方が素気ない
 古いコンパイラのため、エラーメッセージは非常に簡素です。プロジェクト設定によって日本語によるエラー表示ができるGAIOの方に分があります。

 ・Hitechの言語仕様が古い分、多少の注意が必要になる
 言語仕様が古いので、その分だけ注意が必要です。とはいえ、実際に問題になるのは”//”によるコメント入力が出来ない点くらいです。これは他のコンパイラでも同じ問題があったので”//コメント”を”/* コメント*/”に変換する簡単なフィルタを使用し対処しています。const, volatileキーワードが無いのは実用上影響はありません。多分、その分最適化で見劣るのでしょうが。

 実際に小さなプログラムを書いてみても両者にそれほどの差異を感じません。

 作業開始
  インクルードファイルの変更
 このコンパイラはインクルードファイルの書き方が現在のコンパイラとは異なっており、2度読みするとエラーを起こします。全てのインクルードファイルに対して下記を追加します。
 インクルードファイルの変更(STDIO.Hの例)
#ifndef __STDIO_H
#define __STDIO_H
/* ここにファイルの本体がくる */

/* ファイル本体の終了 */
#endif  /*__STDIO_H*/
 つまり、ファイルの本体の始めに2行を終わり部分に1行を追加して、2度目以降の重複読み込みでは本体を読み込まないように変更します。

 スタートアップファイルの検討
 OS管理下での動作が確認できたので、次の段階ではOSの管理を離れた環境でプログラムを実行するために必要な作業内容を検討します。これらの大半はスタートアップファイル(CRT)で行われます。一般的にz80における組み込みC言語での作業内容は下記のようになります。
1.スタックポインタに初期値を設定する
2.割り込み処理アドレスに割り込み処理関数へのジャンプ命令を配置する。
3.初期値のある(初期値が非ゼロの)変数の初期値を変数領域にコピーする。
4.初期値の無い(初期値がゼロである)変数の変数領域をゼロにクリアする。

 これらの内で3.の作業の意味がROM化の要点になります。これらの作業の目的とそのような作業が必要になる背景について少しずつ書いていくようにします。

タイトル先頭へ 前へ 次へ タイトル末尾へ