[轉]MIPS GCC 嵌入式匯…

Elta提示


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 %0, $25/t/n" : "=r" (rst) ); return rst; }
"=r" 中,'=' 爲修飾符,表示該操作對象只寫,一般用於修飾輸出參數列表中。'r' 表示任意一個通用寄存器。由於我們只要取得一個值,故而只用到了輸出列表。代碼中也沒修改一些寄存器的值gcc不知道,(輸出、輸入列表中的寄存器gcc是知道的)故而被改變的操作對象列表亦可省去。 如果我們要重設CP0 24 號硬件計數器之控制寄存器的值,則: unsigned int op = 0x80f; asm volatile( "mtc0 %0, $24" : :"r"(op) );

volatile 關鍵字表示讓GCC優化生成代碼時,不要移動、刪除我們的彙編碼。另外 __volatile__與其含義相同,引入的目的與__asm__是一樣的。
如果我們重設後,立即讀取CP0 24號寄存器的值,則:
       unsigned int rst;
       unsigned int op = 0x80f;


       asm volatile(
                   "mtc0   %1, $24/t/n"
                   "mfc0   %0, $25/t/n"
                   : "=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"
"ldc1 $f2, %2/n/t"
"pmullh $f2, $f2, $f0/n/t"
"sdc1 $f2, %0/n/t"
         ".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 (a constant 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 one instruction (‘m’ is preferable for asm statements)
R Memory reference that can be loaded with one instruction (‘m’ is preferable for asm statements)
S Memory reference in external OSF/rose PIC format (‘m’ is preferable for asm statements)


轉自:http://blog.csdn.net/comcat/article/details/1557963
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章