こんにちわ、青木です。
毎週、更新し続けている個人的に進めていたプロジェクト「MacでRXマイコンの開発環境を構築する」も4回目となりました。
第1回目は、クロスコンパイラを作るためのコンパイラを作る方法を紹介しました。
第2回目は、RXマイコンのクロスコンパイラを作る方法を紹介しました。
第3回目は、CS+のMAIN関数が実行されるまでの流れを紹介しました。
第4回目は、第3回目で紹介したCS+のおまじない的な文法をGCC環境に合わせて記述し直します。
まずは、おさらいです。忘れていたら、第3回目の記事をみて下さい。
MAIN関数に行く前に、PowerOn_Reset関数が実行され、そのPowerOn_Reset関数では以下のことが実行されていましたね。
set_intb(__sectop("C$VECT")); set_fpsw(FPSW_init | _ROUND | _DENOM); _INITSCT() set_psw(PSW_init); main(); brk();
1行目は、関数ポインタ配列で実現しますと前回紹介しました。
そしてset_intbはアセンブリ言語でしか記述できないコードです。なんとなく予想をしていたと思いますが、今回紹介する内容は、アセンブリ言語です。といっても、難しいことはしておらず、ベクタ(intb)の設定、浮動小数点ステータスワード(fpsw)の設定、プロセッサステータスワード(psw)の設定、メモリの初期化をアセンブリ言語で記述するだけです。すべてをアセンブリ言語で記述するわけではないので安心してください。
さて、set_intbはアセンブリ言語では、以下のように記述します。
mvtc #_Relocatable_Vectors, intb
mvtcは、制御レジスタに値を転送するコマンドです。制御レジスタは、
PC:プログラムカウンタ
ISP:割り込みスタックポインタ
USP:ユーザースタックポインタ
INTB:割り込みテーブルレジスタ
PSW:プロセッサステータスワード
BPC:バックアップPC
BPSW:バックアップPSW
FINTV:高速割り込みベクタレジスタ
FPSW:浮動小数点ステータスワード
の9種類です。お気づきの方もいると思いますが、set_intbのほかに、set_fpswとset_pswも同じように記述することができるということです。記述すると以下のようになります。
#set_fpsw() DENOM bit set mvtc #0x100,fpsw #set_psw() I bit set mvtc #0x10000,psw
注意点として、RX631マイコンの動作モード(プロセッサモード)が2種類(ユーザーモードとスーパバイザモード)があり、
ユーザモードの場合は、mvtcコマンドでレジスタに転送できないものもあります。リセット直後はスーパバイザモードです。CS+のデフォルト環境では、スーパバイザモードのままなので、必要なければ、ユーザモードに移行する必要はないと思います。
割り込みテーブルレジスタintbの話に戻って、#_Relocatable_Vectorsの変数らしきものは、どこで設定しているのかというと、ほかのファイルで定義してます。そのため、「外部に変数があるよ」という記述をプログラムの初めに記述しています。
外部変数の参照は以下のように記述します。
.extern _Relocatable_Vectors
この記述は、C言語に似ていますね。
Relocatable_Vectorsの所在や内容については次回紹介します。
残りの_INITSCT()は、メモリの初期化をしています。パワーオンリセット時、RAMの値は不定です。C言語ではbssセクションは、0で初期化する必要があります。初期値つき変数の初期化も必要です。ここでは、RAM全体を0で初期化しています。実装すると以下のコードになります。
mov #0,r1 mov #0,r2 mov #__istack,r3 sub r1,r3 sstr.b
参考したものは、以下のGNUtoolsのサンプルプログラム(start.S)になります。
mov命令は、ソースオペランド(src)にある値をデスティネーションオペランド(dest)に値を転送します。
ここでのsrcは、#0です。destはr1になります。
sub命令は、C言語的表現で記述すると dest = dest -src の引き算になります。つまり、r3 = r3 -r1 になります。
sstr.b命令は、r3で示される回数分、r2の内容(ここでは”0″)をr1で示される転送先番地へ、アドレス加算方向にr2の値がコピーされます。
言い換えると、r1のアドレスからr3のアドレスのまで、r2の値で埋め尽くすということです。
RX631のRAMのアドレスは、64Kbyteの場合、0x0000_0000から0x0000_FFFFです。
気になるのが、#__istackの存在だと思います。#__istackは、割り込みスタックポインタ(ISP)のアドレスを示しています。この変数も外部のファイルで定義しています。この他に、RX631はユーザースタックポインタ(USP)があります。スタックポインタは、スタックを管理するポインタで、スタックとは、割り込み要求が発生した場合、割り込みが発生する直前まで実行していたプログラムのフラグやフログラムカウンタを一時的に退避する場所です。詳細は、スタックポインタ、プッシュ、ポップのキーワードで調べてください。
__istackのアドレスは、0x0001_0000にしています。スタックポインタは、アドレスの減算方向に進むため、RAMの一番終わりの値にしています。このスタックポインタも設定する必要があります。
GNUtoolsのサンプルプログラムを参考に必要なところのみ抽出するとスタートアップファイルは以下のコードになります。
.text .global _start .global _exit .global _PowerON_Reset_PC .extern _Relocatable_Vectors .extern __ustack #ユーザースタックポインタ .extern __istack #割り込みスタックポインタ _PowerON_Reset_PC: _start: mvtc #__istack, isp mvtc #__ustack, usp mvtc #_Relocatable_Vectors, intb #set_fpsw() DENOM bit set mvtc #0x100,fpsw # RAM 全領域のゼロクリア mov #0, r1 mov #0, r2 mov #__istack, r3 sub r1, r3 sstr.b #set_psw() I bit set mvtc #0x10000,psw #mainへジャンプする mov.l #0,r1 ; argc mov.l #0,r2 ; argv bra _main _exit: wait bra _exit
次回は、割り込みベクタのファイルの修正について紹介します。