翻譯這一篇 : arm gcc inline assembler cookbok
但是這一篇(GCC-inline assembly Howto)說得比較仔細。
GCC 的 inline assembly 基本格式是:
asm(code : output operand list : input operand list : clobber list);
也就是一堆用 ':'分開的字串。
其中 'code' 的部份要存取 output operand list , input operand 的內容,是用 % 符號:
%0 代表存取 output operand
%1 代表存去 input operand
最後的'clobber' 是要告訴 compiler 有哪些 register 被這段 assembly code 修改了。
為了防止 compiler 把這一段 inline assembly code optimize 掉,通常都會加上 volatilr:
asm voltaile("mov %0, ror #01" : "-r" (result) : "r" (value));
這段 inline assembly,如果之後的部份都沒有資料,就可以不寫,舉例來說:
asm volatile("mov r0, r0");
這只是用來delay的code,沒有input, output,也沒有 register 會被修改,所以後面的 部份都不用寫。
但是如果有資料一定要寫,他的前面部份就不可以省略,舉例來說:
asm volatile("" : : : "memory");
這段inline assembly 不包含任何 code,只是告訴 compiler memory 有可能會被修改。
一般為了好看,建議將一堆 assembly 寫成這樣:
asm volatile(
"mov r0,r0\n\t"
"mov r0,r0\n\t"
"mov r0,r0\n\t"
);
也就是說,分行寫,但是要記得加上 "\n\t" - 這是要讓 compiler listing 時,比較好看。
Input Output Operand
這兩個區域是要告訴 compiler operand 的資料,利用以下 "Constraint" 來通知:
Operand Register 的類型:
- f : 是floating point register (有些 cpu 有專屬的 floating point register)
- I : 立即定址 immediate operands
- J : Indexing constants
- K : negative value in rhs
- L: negative value in rhs
- M : for shift
- r : General registers -- ARM 一般用這個
Operand Register 的 in/out:
- = : Write-only (通常所有的 output operand 都會加這個符號)
- + : Read-Write (inline assemnly 不支援這個符號)
- & : Output only - 這個register 只做 output 使用
Output Operand 一定要是 Write-Only。
Input Operand 一定要是 Read-Only。
但是如果要把 input operand 修改後,作為 output operand 的話,要怎麼辦呢?
inline assembly 又不支援 '+' 符號..
用"數字" 來告訴 complier 這一個 operand 共用哪一個 operand,例如:
asm volatile("mov %0, %0, ror #1" : "=r" (value) : "0" (value));
這個 code 是將'value" right shit 1 bit。
但是用同一個 register 來作就可以。
input operand 用 "0" 告訴 compiler ,使用 第0個operand (就是 output operand)。
所以 input, output 都會用同一個 register (mov %0, %0..)。
Clobbers
把被修改的部份寫在這
asm volatile(
"amsd r3, %1, #3 \n\t"
"eor %0, %0, r3 \n\t"
"addne %0, #4"
: "=r" (len)
: "0" (len)
: "cc","r3"
);
例子使用了 r3 作scratch register,所以做完這段 code 後,r3的值會被修改,以在clobber的區域要列出 "r3"。
另外,作邏輯運算後,status 區域也會修改,所以要把"cc"也列上。
還有另一個例子:
asm volatile(
"ldr %0, [%1] \n\t"
"str %2, [%1, #4] \n\t"
: "=&r" (rdv)
: "r" (&table), "r" (wdv)
: "memory"
);
這一段code會update table 的內容,所以要在....
有一點沒寫到,就是 c variable name 都寫在 operand 後面,用括號( )括起來..
在 "Assembler Instruction with C expression operand" ,範例:asm ("fsinx %[angle],%[output]"在operand 前可以用 [name] 寫出''將會用這'name'名字稱呼''。
: [output] "=f" (result)
: [angle] "f" (angle));
然後在 code 區域就可以直接用 %[name] 來引用
大概可以這樣說:
assembly code 中,要引用 C 宣告的部份,就要寫在 operand (in/out) 欄位,並且寫號 constrain.
然後用 %0, %1...來使用。
如果是直接存取 register,就直接用 r1, r2, r3... 但是要記得寫在 clobber 欄位。
http://r40eubuntu.blogspot.com/2009/02/arm-gcc-inline-assembler.html
ARM GCC Inline Assembler Cookbook
http://www.ethernut.de/en/documents/arm-inline-asm.html
http://blog.yam.com/registry/article/16464253
留言列表