技術情報・開発日誌

MacでルネサスのRX631マイコンの開発〜CS+のMAIN関数が実行されるまでを理解しよう〜

おはようございます。青木です。
MacでルネサスのRX631マイコンの開発のブログが思っていた以上に見られていたので、朝から記事を書いていますw。

第1回目は、クロスコンパイラを作るためのコンパイラを作る方法を紹介しました。
第2回目は、RXマイコンのクロスコンパイラを作る方法を紹介しました。

第3回目は、C言語のMAIN関数までの道のりを説明しようと思います。
前回までで、アセンブリ言語での環境は整っています。
しかし、今の時代、CPUの処理が速くなったので特別な処理以外は、C言語で記述するのが普通になっています。
そこで、CS+の環境と同じような仕組みでC言語の開発環境を構築する方法を紹介します。

まずは、マイコンの動作とC言語の動作の違いを再確認します。
マイコンは、電源投入時(Power On Reset)またはリセットを行うとプログラムの先頭アドレスから開始します。RX631は0xFFFF_FFFCからベクタ(飛び先のアドレス)を取得してプログラムカウンタにセットして処理を開始します。
C言語は、MAIN関数から始まります。
変数に関しては、マイコンの場合、電源投入時のメモリの値は、不定値です。0かもしれないし、1かもしれない状態です。しかし、C言語は、変数を初期化しない場合、一般的には、0に初期化されています。
目に見えて違うのは、この2点だけですが、他にも、割り込みの設定など細かいことがあります。

では、CS+の動作を見てみましょう。
CS+では、MAIN関数に行く前に、resetprg.cのファイルを実行してからMAIN関数を実行しています。
resetprg.cでは、PowerOn_Reset_PC(void)関数が用意されており、そのなかで、

set_intb(__sectop("C$VECT"));
set_fpsw(FPSW_init | _ROUND | _DENOM);
_INITSCT()
set_psw(PSW_init);
main();
brk();

が実行されています。

上記で何をしているかは、ルネサスのwebにRXファミリ用コンパイラスタートアップの紹介の資料があり、これを一読すると上記の流れがなんとなくわかります。

1行目のset_intb関数ですが、CS+の組み込み関数として提供されています。他にもいろいろあるので、一度ルネサスのwebページの組込関数の一覧を見ておくと良いかもしれません。
set_intb関数では、可変ベクタテーブルの先頭アドレスを設定しています。詳しくは、ルネサスのwebで説明されていますので、そちらを見て下さい。
set_intbの引数の__sectop(“C$VECT)は、CS+のCC-RXビルド・ツールの共通オプション内のセクションの開始アドレスの変数です。

これには、いろいろとからくりがありまして、先ほどのルネサスの可変ベクタの説明のところで、ベクタ毎に番号が割り振られていると記載されています。そのベクタの番号がvect.hのファイル内で(vect==16)のようにベクタ番号を指示しているところがあります。

さすがに、これを、そのままGCC環境に使うことができないため、GCC環境では、少し工夫をしています。
C言語には、配列の中に関数のアドレスをいれてジャンプする機能(関数ポインタ配列)がありますね。この機能をつかって実現しています。詳しくは、次回紹介します。

2行目のset_fpsw関数もCS+の組み込み関数です。set_fpswは、浮動小数点ステータスワードレジスタの値を書き換える関数です。
FPSW_initの値は、オールゼロです。これを基準にいろいろと設定を追加していく形になっています。
_ROUNDは、浮動小数点の丸めの設定になります。初期値は近似値へ丸められます。CS+の浮動小数点の丸めの設定で0か近似の2種類が選択できるようになっています。CS+の初期値は近似になっているため、ここでは、_ROUNDの値は0(=近似)にします。
_DENOMは、浮動小数点定数に非正規化数を記述したときの扱いをどうするかの設定になります。CS+の浮動小数点定数に非正規化数の設定では、0として扱うか非正規化数として扱うの2種類が選択できるようになっています。CS+の初期値は、0として扱うになっているため、ここでは、_DENOMの値は0x00000100(=0として扱う)にします。

3行目の_INITSCT()関数は静的変数の初期化を行っています。これもCS+の組み込み関数です。

4行目のset_psw関数もCS+の組み込み関数です。set_pswは、プロセッサステータスワードレジスタの値を書き換える関数です。ここでは割り込み許可をしています。この割り込みを許可しいないとモジュールで割り込みを許可しても割り込みができない現象になります。つまり、割り込みイネーブルの親分ですね。

5行目でmain()関数をコールしています。

次回は、この内容をGCC環境に合わせた記述を紹介します。

タイトルとURLをコピーしました