MIPS GCC 嵌入式彙編

轉自   http://www.eefocus.com/bbs/article_866_188666.html

1. GCC 內嵌彙編的基本格式

asm("assembly code");

如:

     asm("syscall");      //觸發一個系統調用


如果有多條指令,則需在指令尾部添加'\t'和'\n',如:

     asm("li      v0, 4011\t\n" "syscall");


括號裏的字符串 GCC 前端不作分析,直接傳給彙編器 as ,故而相聯指令間需插入換行符。

'\t' 加入只爲排版對齊一些而已,可以使用 gcc -S tst.c -o tst.s 查看生成的 tst.s

因爲 GCC 並不對 asm 後括號中的指令作分析,故而如果指令修改一些的寄存器的值,GCC是
不知道的,這個會引入一些問題。

另外 asm 可以替換爲 __asm__ ,效果等價。__asm__ 一般用於頭文件中,防止關鍵字 asm
可能與一些變量、函數名衝突。  
   

內嵌彙編如何與 C 變量交換數據?


2. GCC 內嵌彙編擴展格式

asm (     
 
          "assembly code"
 
          : output_operand                  /* 輸出參數列表 */
 
          : input_operand                        /* 輸入參數列表 */
 
          : clobbered_operand                  /* 被改變的操作對象列表 */
 
    );


以一個例子來說明:

如果我們要讀取CP0 25 號硬件計數寄存器的值,並返回之,可以這樣:

int get_counter()
{
  
   int rst;

     asm(                                          /* mfc0 爲取cp0 寄存器值的指令 */
 
          "mfc0      %0, $25\t\n"            /* %0 表示列表開始的第一個寄存器 */
 
          : "=r" (rst)                        /* 告訴gcc 讓rst對應一個通用寄存器 */
 
          );

     return rst;
}


"=r" 中,'=' 爲修飾符,表示該操作對象只寫,一般用於修飾輸出參數列表中。'r' 表示任意
一個通用寄存器。

由於我們只要取得一個值,故而只用到了輸出列表。代碼中也沒修改一些寄存器的值gcc不知道,
(輸出、輸入列表中的寄存器gcc是知道的)故而被改變的操作對象列表亦可省去。


如果我們要重設CP0 24 號硬件計數器之控制寄存器的值,則:

  unsigned int op = 0x80f;

     asm volatile(
 
                            "mtc0 %0, $24"
 
                                                  /* 沒有輸出,列表爲空 */
 
                            :"r"(op)            /* 輸入參數,告訴gcc 讓op對應一個通用寄存器 */
 
                      );


volatile 關鍵字表示讓GCC優化生成代碼時,不要移動、刪除我們的彙編碼。
另外 __volatile__與其含義相同,引入的目的與__asm__是一樣的。


如果我們重設後,立即讀取CP0 24號寄存器的值,則:

     unsigned int rst;
 
unsigned int op = 0x80f;

     asm volatile(
 
                            "mtc0      %1, $24\t\n"      /* %1 表示 op 對應的寄存器 */
 
                            "mfc0      %0, $25\t\n"      /* %0 表示 rst 對應的寄存器 */
 
                            : "=r" (rst)
 
                            : "r" (op)
 
                      );

 

如果我們要操作的對象位於存儲器中,我們可以使用 'm' 來修飾輸入輸出參數,如:

unsigned short data[] = {
  0x0, 0x0, 0x0, 0x0,
 
0x1, 0x3, 0x5, 0x7,
 
0x1, 0x3, 0x5, 0x7,
};

void pmullh()
{
  
   asm volatile
 
     (
 
          ".set mips3\n\t"
 
          ".set noreorder\n\t"

           "ldc1 $f0, %1\n\t"                  /* 取 data+4 處的四個數組元素值到 f0 中 */
 
          "ldc1 $f2, %2\n\t"                  /* 對應輸入列表的 *(data+8)      */
 
                                                    /* %2 編譯後會替換成類似 16($12) 的形式 */
 
                                                   

           "pmullh $f2, $f2, $f0\n\t"      /* 按16位爲單位數據相乘,取結果的低位 */

           "sdc1 $f2, %0\n\t"                  /* 將結果寫入data的前四個位置 */

           ".set reorder\n\t"
 
          ".set mips0\n\t"

           : "=m"(*data)
 
          : "m"(*(data+4)), "m"(*(data+8))
 
          : "$f0", "$f2", "memory"
 
     );
}


注意到使用'm'修飾的操作數,後面括號裏跟的不是指針,而是開始的第一個元素值。
%0,%1, %2 依次對應輸出列表的一個,輸入列表的兩個操作數,編譯後會被gcc替換
成類似 0($12),8($12),16($12)的形式,其中$12置數組首地址,即: %0等價於0($12)

由於我們嵌入的代碼改變了 $f0, $f2 的值,而他們不在輸出、輸入列表中,故而要將其陳列
於被改變操作數列表(clobbered operand list)中,以告訴gcc 我們改變了他們的值,以免gcc 誤判。

因爲代碼中我們改變了內存中數據的值,如果此前gcc生成的代碼讀取了該內存處的值,並保
存於寄存器中的話,由於我們更新了這段數據,所以需要告訴gcc在後面要重新加載數據,這
個需要在被改變操作數列表中(clobbered operand list)寫入 "memory"。


3. 修飾符

=      只寫,常用於修飾所有輸出操作數     
     只讀
     只用於輸出,一般和'='一起用,如:"=&r" (val)


4. 其他對輸入、輸出對象的操作符

d General-purpose integer register
f Floating-point register (if available)
h ‘Hi’ register
ll ‘Lo’ register
x ‘Hi’ or ‘Lo’ register
y General-purpose integer register
z Floating-point status register
I Signed 16-bit constant (for arithmetic instructions)
J Zero
K Zero-extended 16-bit constant (for logic instructions)
L Constant with low 16 bits zero (can be loaded with lui)
M 32-bit constant which requires two instructions to load (aconstant which is not ‘I’, ‘K’, or ‘L’)
N Negative 16-bit constant
O Exact power of two
P Positive 16-bit constant
G Floating point zero
Q Memory reference that can be loaded with more than oneinstruction (‘m’ is preferable for asm statements)
R Memory reference that can be loaded with one instruction (‘m’ ispreferable for asm statements)
S Memory reference in external OSF/rose PIC format (‘m’ ispreferable for asm statements)



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章