ARM cortex-m3 assembly - 1


收錄於 : 關於Ameba的一百篇

Found one slide about cortex-M assembly language programming

http://www.slideshare.net/GonzaloSantiago/assembly-language-programming-arm-cortexm3-vincent-mahout


組合語言的相關資料很多. 這篇主要簡單介紹一下怎麼在 Arduino 下寫組合語言.
Ameba 為例 ( 其他板子也可以 )

組合語言, 其實就是直接寫 CPU 要做的指令. 因為 CPU 聽得懂的話和 人說的話不同.
所以得用所謂的組合語言來溝通. 所有這顆 CPU 懂得的指令, 就叫做指令集.

( 現在網路發達, 直接 link 別人寫的 : 什麼是指令集 )


第一種:

    直接寫 .s 檔. 透過 compiler (gcc as ) 編譯.
 
    這個可以像 之前介紹 libos 的方式. 修改 makefile 讓他編譯 .s

    不過一般 user 可能比較難拿其他Arduino 板子來做. 侷限性比較大..

    可能下回再詳細介紹

第二種:

    arduino 和 ARM mbed 一樣, 都可以用 GCC 來當 compiler.

    所以自然地, 我們可以寫 GCC inline assembly 來做.

    這篇針對這個來介紹

網路上 GCC inline assembly 寫法說明也很多人寫.

英文版 :
   http://www.ethernut.de/en/documents/arm-inline-asm.html
   http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s3

中文版 :

   個人覺得這篇還算清楚

   http://r40eubuntu.blogspot.tw/2009/02/arm-gcc-inline-assembler.html




為什麼要用組合語言, 其實關於這策略, 有些人會覺得全部用 C / C++ 寫就好了,
而且現在的最佳化做得很好, 也不一定要用組合語言.

不過在開發效能上, assembly 有時候的確是比用 C 來寫快速,
尤其是當 CPU 有這個指令的時候.

譬如做 byteswap
( byteswap 通常用在 endian 的轉換, endian 說明可以參考 wiki )


一般寫法可能是 C 的 macro 寫法, 做相對應的 shift / and operation

/* Swap bytes in 32 bit value.  */
#define __bswap_constant_32(x) \
  ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) | \
   (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))

#define __bswap_32(x) __bswap_constant_32 (x)

或 static inline function 寫法

static inline uint32_t __builtin_bswap32(uint32_t x)
{
 return ((x << 24) & 0xff000000) |
        ((x <<  8) & 0x00ff0000) |
        ((x >>  8) & 0x0000ff00) |
        ((x >> 24) & 0x000000ff);
}


但 ARM 有針對這開發指令 : REV 
我們可以這麼寫 一個 bswap1 function
static inline int bswap1(int x)

{

  asm volatile (

    "rev %0, %1"

    : "=r" (x) 

    : "r" (x)

  );



  return x; 

}

說明 : 
    基本格式 : asm(code : output operand list : input operand list : clobber list);
    
    %0 : 代表存取 輸出部分 (output operand)
    %1 : 代表存取 輸入部分 (input operand) 
    此項沒有 clobber list

    output operand "=r" (x) 
    = : write only , 一般 output 都會加
    r  : general register 
    x : C function 的變數. 用括號括起來
同樣的, 我們可以設計一個 RBIT. (整個 bit 反置)
大家可以想想如果沒有 RBIT 指令, 要做 bit 反轉, 用 C 寫要做多少動作.. 
這也是硬體指令集的優點. 
更多體現在 FPU (浮點運算 ) / DSP / 繪圖 (e.g. NEON) 等指令集, 來做這些一般更複雜的運算. 當然這些通常會做在 toolchain library, 一般使用者只要呼叫使用正確的 library (e.g. ARM newlib)  /intrinsic functions 即可. 
如這份文件所說 : 
完整 Arduino 程式: 
----
int thisByte; static inline int bswap1(int x) {   asm volatile (     "rev %0, %1"     : "=r" (x)      : "r" (x)   );   return x;  } static inline int bit_reverse1(int x) {   asm volatile (     "rbit %0, %1"     : "=r" (x)      : "r" (x)   );   return x;  } void setup() {   //Initialize serial and wait for port to open:   Serial.begin(9600);   while (!Serial) {     ; // wait for serial port to connect. Needed for native USB port only   }   thisByte = 0x11223344;    Serial.print("Original data : 0x");   Serial.println (thisByte, HEX);   thisByte = bswap1(thisByte);   Serial.print("REV : 0x");   Serial.println (thisByte, HEX);   thisByte = bit_reverse1(thisByte);   Serial.print("RBIT : 0x");   Serial.println (thisByte, HEX); } void loop() { } ---- 執行結果:  一開始值是 : 0x11223344 做 byte swap (endian convert) 變為 0x44332211 用  0x44332211 整個做 bit 反轉 , 變為 0x8844CC22 ( 0x44332211 = 0b 0100 0100 0011 0011 0010 0010 0001 0001 ) ( 0x8844CC22 = 0b 1000 1000 0100 0100 1100 1100 0010 0010 ) 



留言

熱門文章