名前付きレジスタ変数を使用したレジスタへのアクセスに対するコンパイラサポート

コンパイラを使用すると、名前付きレジスタ変数を使用して、ARM アーキテクチャベースのプロセッサのレジスタにアクセスできます。

名前付きレジスタ変数は register キーワードと __asm キーワードを組み合わせて宣言されます。__asm キーワードは、レジスタの名前を示す文字列からなるパラメータを 1 つ使用します。例えば、以下の例では、R0 をレジスタ r0 の名前付きレジスタ変数として宣言しています。

register int R0 __asm("r0");

名前付きレジスタ変数はグローバル変数として宣言できます。一部の名前付きレジスタ変数だけをローカル変数として宣言することができます。通常は、ベクタ浮動小数点(VFP)レジスタおよび主要なレジスタをローカル変数として宣言しません。R0 などの caller-save レジスタはローカル変数として宣言しないで下さい。caller-save レジスタは、サブルーチンが完了した後にレジスタの値を必要とする場合に呼び出し元がその値を保存する必要があるレジスタです。これらのレジスタをローカルに宣言したプログラムがコンパイルされた場合でも、実行時に予期しない動作が発生する可能性があります。

名前付きレジスタ変数の代表的な用途は、アプリケーションプログラムステータスレジスタ(APSR)内のビットにアクセスすることです。例 3-3 は、名前付きレジスタ変数を使用して、APSR にサチュレーションフラグ Q を設定する方法を示しています。

Example 23. 名前付きレジスタ変数を使用して APSR 内にビットを設定する

#ifndef __BIG_ENDIAN // APSR のビットフィールドのレイアウトはエンディアン方式の影響を受ける
typedef union
{
    struct
    {
        int mode:5;
        int T:1;
        int F:1;
        int I:1;
        int _dnm:19;
        int Q:1;
        int V:1;
        int C:1;
        int Z:1;
        int N:1;
    } b;
    unsigned int word;
} PSR;
#else /* __BIG_ENDIAN */
typedef union
{
    struct
    {
        int N:1;
        int Z:1;
        int C:1;
        int V:1;
        int Q:1;
        int _dnm:19;
        int I:1;
        int F:1;
        int T:1;
        int mode:5;
    } b;
    unsigned int word;
} PSR;
#endif /* __BIG_ENDIAN */

/* PSR を "apsr" レジスタのレジスタ変数として宣言する */
register PSR apsr __asm("apsr");

void set_Q(void)
{
    apsr.b.Q = 1;
}

Example 24 も参照して下さい。

Example 24. 名前付きレジスタ変数を使用して APSR 内の Q フラグをクリアする

register unsigned int _apsr __asm("apsr");

__forceinline void ClearQFlag(void)
{
    _apsr = _apsr & ~0x08000000; // Q フラグをクリアする
}

逆アセンブリ:

ClearQFlag
    MRS    r0,APSR ; 以前は CPSR
    BIC    r0,r0,#0x80000000
    MSR    APSR_nzcvq,r0; 以前は CPSR_f
    BX     lr

Example 25も参照して下さい。

Example 25. 名前付きレジスタ変数を使用してスタックポインタを設定する

register unsigned int _control __asm("control");
register unsigned int _msp     __asm("msp");
register unsigned int _psp     __asm("psp");

void init(void)
{
    _msp = 0x30000000;        // メインスタックポインタを設定
    _control = _control | 3;  // プロセススタックでユーザモードに切り替え
    _psp = 0x40000000;        // プロセススタックポインタを設定
}

逆アセンブリ(--cpu=7-M を使用したコンパイル):

init
    MOV    r0,0x30000000
    MSR    MSP,r0
    MRS    r0,CONTROL
    ORR    r0,r0,#3
    MSR    CONTROL,r0
    MOV    r0,#0x40000000
    MSR    PSP,r0
    BX     lr


また、名前付きレジスタ変数を使用して、コプロセッサ内のレジスタにアクセスすることもできます。宣言内の文字列構文は、変数の使用方法に対応します。例えば、MCR 命令で使用する変数を宣言するには、この命令の命令構文を参照し、変数を宣言するときにこの構文を使用します。詳細については、Example 26を参照して下さい。

Example 26. 名前付きレジスタ変数を使用してコプロセッサレジスタ内にビットを設定する

register unsigned int PMCR __asm(”cp15:0:c9:c12:0”);

__inline void __reset_cycle_counter(void)
{
    PMCR = 4;
}

逆アセンブリ:

__reset_cycle_counter PROC
    MOV    r0,#4
    MCR    p15,#0x0,r0,c9,c12,#0      ; r0 から c9 に移動する
    BX     lr
    ENDP


Example 26 では、cp15 コプロセッサに関連付けられた unsigned int 型のレジスタ変数として PMCR が宣言されています。MCR または MRC 命令には、CRn = c9CRm = c12opcode1 = 0、および opcode2 = 0 が使用されます。逆アセンブリの MCR エンコーディングは、レジスタ変数宣言に対応します。

物理コプロセッサレジスタは、2 つのレジスタ番号(CRnCRm)および 2 つのオペコード番号の組み合わせを使用して指定されています。これは、単一の物理レジスタにマップされます。

レジスタ内の個々のビットを操作する場合は同じ原則が適用されますが、C で通常の変数算術を記述します。すると、コンパイラによって、コプロセッサレジスタの読み出し-変更-書き込みが行われます。詳細については、Example 27を参照して下さい。

Example 27. 名前付きレジスタ変数を使用してコプロセッサレジスタ内でビットを操作する

register unsigned int SCTLR __asm(”cp15:0:c1:c0:0”);

/* システムコントロールレジスタのビット 11 を設定する */
void enable_branch_prediction(void)
{
    SCTLR |= (1 << 11);
}

逆アセンブリ:

__enable_branch_prediction PROC
    MRC    p15,#0x0,r0,c1,c0,#0
    ORR    r0,r0,#0x800
    MCR    p15,#0x0,r0,c1,c0,#0
    BX     lr
    ENDP

Show/hide関連項目

Copyright © 2010 ARM. All rights reserved.ARM DUI 0472BJ
Non-ConfidentialID011811