GCC(AVR Studio)のアセンブリセクションの一部である文字列リテラルに逐語的に挿入される#defined integerシンボルの値を取得することは可能ですか?
以下のasm()ブロック内の文字列リテラル内で「LED」を48に置き換えたい。
#define LEDS 48 //I only want ONE mention of this number in the source
int x = LEDS; //I'm using the value directly too
void DrawFrame()
{
asm(
"ldi R27, 0x00 \n\t"
"ldi R26, 0x00 \n\t"
"ldi R18, LEDS \n\t" //<-- substitution needed here
...
}
しかし、コンパイラー/アセンブラー(プリプロセッサーがそれを実行した後)にこれを見てもらいたい...
#define LEDS 48 //I only want ONE mention of this number in the source
int x = LEDS; //I'm using the value directly too
void DrawFrame()
{
asm(
"ldi R27, 0x00 \n\t"
"ldi R26, 0x00 \n\t"
"ldi R18, 48 \n\t" //<-- substitution needed here
...
}
これまでのところ、考えられるすべてのマクロトリック(#stringification、arg置換、さらに値と二重引用符のさまざまな組み合わせを含む#includeファイルなど)を試しました。
私は、AVRアセンブリコードをAVR StudioのGCCコンパイラーにインライン化する魔法にはまったく精通していません。
プリプロセッサがこの置換を実行できる場合は、ソースに "48"リテラルが複数出現しないようにしています。
編集:これはマイクロコントローラーファームウェアプロジェクト用です-人生を面白くするためだけに、新しいコードを追加する余地はほとんどありません。
Utilsヘッダーに文字列化マクロを含めるのは良いことだと思います。
#define STR_IMPL_(x) #x //stringify argument
#define STR(x) STR_IMPL_(x) //indirection to expand argument macros
次に、マクロを数値に保ち、その場で文字列化できます。
#define LEDS 48
int x = LEDS;
void DrawFrame()
{
asm(
"ldi R27, 0x00 \n\t"
"ldi R26, 0x00 \n\t"
"ldi R18, "STR(LEDS)" \n\t"
...
}
上記は、次の前処理を行います。
int x = 48;
void DrawFrame()
{
asm(
"ldi R27, 0x00 \n\t"
"ldi R26, 0x00 \n\t"
"ldi R18, ""48"" \n\t"
...
}
これは、隣接する文字列リテラルが連結されるという事実に依存しています。
制約を使用すると、文字列化マクロの混乱を回避できます。
#define LEDS 48
void DrawFrame()
{
asm volatile(
"ldi R18, %[leds]"
: : [leds] "M" (LEDS) : "r18");
}
これを機能させるには、2つの補助マクロが必要です。次に、自動文字列連結を利用できます。
#define STR(x) #x
#define EXPAND(x) STR(x)
#define LEDS 48
int x = LEDS;
void DrawFrame()
{
asm(
"ldi R27, 0x00 \n\t"
"ldi R26, 0x00 \n\t"
"ldi R18, " EXPAND(LEDS) " \n\t"
...
}
2つのマクロを使用する理由は、最初のマクロだけでは渡されたパラメーターが展開されないためです。
あなたがこれをやっただけなら:
printf("LEDS = " STR(LEDS) "\n");
これは次のように拡張されます。
printf("LEDS = " "LEDS" "\n");
EXPAND
マクロを使用すると、渡されたパラメーターを置換することもできます。
それでこれは:
printf("LEDS = " EXPAND(LEDS) "\n");
これに拡張されます:
printf("LEDS = " "48" "\n");