ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2009年2月16日 星期一

ARM GCC Inline Assembler

翻譯這一篇 : 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]"
   : [output] "=f" (result)
   : [angle] "f" (angle));
在operand 前可以用 [name] 寫出''將會用這'name'名字稱呼''。 然後在 code 區域就可以直接用 %[name] 來引用
大概可以這樣說: assembly code 中,要引用 C 宣告的部份,就要寫在 operand (in/out) 欄位,並且寫號 constrain. 然後用 %0, %1...來使用。 如果是直接存取 register,就直接用 r1, r2, r3... 但是要記得寫在 clobber 欄位。
ref:

沒有留言:

標籤

網誌存檔