Everything
4.2.6.14 制御レジスタへの書き込みの検出,同期化処理挿入 【Professional 版のみ】 【V1.06.00 以降】

RH850のストア命令によって複数の制御レジスタを連続して更新するとき,制御レジスタの更新順序がソース・ファイルの記述順と一致しない場合があります。更新する順序を制御したい場合は,同期化処理を挿入する必要があります。

CC-RHでは,制御レジスタへの書き込みを検出して,書き込み処理の情報を表示させることや,定型の同期化処理を挿入することができます。

 

制御レジスタへのアクセスを示す記述は,以下の条件をすべて満たすものを対象とします。

-

1つの整数定数をvolatile修飾型へのポインタにキャストし,単項*演算子や->演算子で間接参照している式。

*(volatile int*)0xffff0000 = x;
((volailte struct ST*)0xffff0004)->member = y;

このとき,整数定数が制御レジスタのアドレスを示します。

整数定数ではなく,変数を含む式や,複数のキャストを含む式である場合は対象にならない場合があります。

-

上記の整数定数が#pragma register_groupで指定された範囲内である。

 

制御レジスタのアドレス範囲とグループの情報を,#pragma register_groupで指定します。

#pragma register_groupは次の形式で指定します。

#pragma register_group 開始アドレス, 終端アドレス[, id="グループID"]

-

開始アドレス,終端アドレスは符号なし整数で指定します。8進,10進,16進整数を使用できます。

終端アドレスは,その番地がグループに所属するものとして扱います。

0x100番地から始まる16バイトの領域は次のように指定します。

#pragma register_group 0x100, 0x10f

-

グループIDは,制御レジスタが所属するグループを指定するための識別子です。

グループIDに使用できる文字は,アルファベット(a-z,A-Z,大文字小文字を区別します),数字(0-9),アンダースコア(_)のみです。

グループIDの長さに制限はありません。

-

アドレス空間上で連続していない同一のグループを指定するために,複数の#pragma register_groupに同じグループIDを指定することができます。

-

グループIDは省略することができます。省略した場合,その領域への書き込みは他のどの書き込みとも連続しないものとして扱います。

-

次の場合はエラーを出力します。

-

開始アドレスが終了アドレスより大きい場合

-

グループIDに使用できない文字を使用している場合

-

複数の#pragma register_groupで指定したアドレス範囲が重複している場合

 

以下の入力ソース例をもとに,使用方法を説明します。

入力ソース例

#pragma register_group 0xfedf0000, 0xfedfffff, id="CPU"
#pragma register_group 0xfee00000, 0xfee0ffff, id="0"
 
#define REG1 (*(volatile unsigned char*)0xfedf0000)    /* CPUグループの制御レジスタ */
#define REG2 (*(volatile unsigned char*)0xfedf0001)    /* CPUグループの制御レジスタ */
#define REG_Z (*(volatile unsigned short*)0xfee00000)  /* 0グループの制御レジスタ */
 
void func(void) {
   REG1  = 0;
   REG2  = 1;
   REG_Z = 2;
}

(a)

制御レジスタへの書き込みを検出する方法

上記の例を-store_reg=listオプションを指定してコンパイルすると,次のように判定し,書き込み処理があることのメッセージを標準エラー出力へ出力します。

-

REG1とREG2は同じグループなので,REG1への書き込みに対する同期化処理は不要である。

-

REG2とREG_Zは異なるグループなので,REG2への書き込みに対する同期化処理は必要である。

-

REG_Zへの書き込みの後,同じグループへの書き込みがあるかどうか不明なので,REG_Zへの書き込みに対する同期化処理は必要である。

src.c(10):M0536001:制御レジスタを更新します。(id=CPU, 0xfedf0001)
src.c(11):M0536001:制御レジスタを更新します。(id=0, 0xfee00000)

なお,ある制御レジスタへの書き込みの後に,関数呼び出しや,書き込み先アドレスが不明なメモリアクセスなど,制御レジスタへの書き込みと判定できない記述が現れた場合も,同期化処理が必要である,と判定します。

 

(b)

制御レジスタへの全ての書き込みを検出する方法

同じ例を-store_reg=list_allオプションを指定してコンパイルすると,同じグループへの連続する書き込みかどうかを判断せず,#pragma register_groupで指定したすべての制御レジスタへの書き込みに対してメッセージを出力します。

src.c(9):M0536001:制御レジスタを更新します。(id=CPU, 0xfedf0000)
src.c(10):M0536001:制御レジスタを更新します。(id=CPU, 0xfedf0001)
src.c(11):M0536001:制御レジスタを更新します。(id=0, 0xfee00000)

 

(c)

制御レジスタへの書き込みの後に,同期化処理を挿入する方法

同じ例を-store_reg=syncオプションを指定してコンパイルすると,(a)と同じ判定を行い,メッセージを出力するかわりに,出力コード中に同期化処理を挿入します。同期化処理には,同じ制御レジスタからのロードと,syncp命令を組み合わせて出力します。

出力例

_func:
        .stack _func = 0
        movhi 0x0000FEDF, r0, r2
        st.b r0, 0x00000000[r2]
         ; 同じグループへの書き込みが後ろにあるので,同期化処理を挿入しない
        movhi 0x0000FEDF, r0, r2
        mov 0x00000001, r5
        st.b r5, 0x00000001[r2]
        ld.bu 0x00000001[r2], r10  ; 同期化処理を挿入する
        syncp                      ;
 
        movhi 0x0000FEE0, r0, r2
        mov 0x00000002, r5
        st.h r5, 0x00000000[r2]
        ld.hu 0x00000002[r2], r10  ; 同期化処理を挿入する
        syncp                      ;
        jmp [r31]

[注意事項]

-

-Xmerge_fileオプションと同時に#pragma registr_groupを使用する場合,ソース・ファイル間で矛盾する#pragma register_groupを指定してもエラーとならず,意図しない結果になる可能性があります。#pragma register_groupはインクルード・ファイルに記述して,各ソース・ファイル間で共有することを推奨します。

-

制御レジスタへの書き込みと同期化処理の間に例外が発生する可能性がある場合は,必要に応じて,例外ハンドラ内に手動で同期化処理を記述してください。

-

コンパイル状況により,同じグループに属する制御レジスタへの書き込みが連続していることを検出できない場合があります。この場合,冗長に検出メッセージを出力したり,不要な同期化処理を挿入します。