Chinaunix首页 | 论坛 | 博客
  • 博客访问: 365964
  • 博文数量: 242
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1134
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-20 10:53
文章分类

全部博文(242)

文章存档

2015年(1)

2014年(10)

2013年(18)

2012年(213)

分类:

2012-11-06 14:57:43

原文地址:gnu C语言中嵌入式汇编 作者:bluedrum

Andrew Huang 转载请注明作者及出处

一.嵌入式汇编关健字 asm
  
   在所有C程序中,嵌入式汇编的写法有asm{} asm(), __asm__ __volatile__ ("");其中asm 和 __asm 含义是一样的.
  而ARM的C编译器中,主流是两大类,一类ARM公司出品的ARMCC,另一类用得更广的是gnu 的汇编,两者嵌入式汇编语法主和格式,有着很多细节微差别,这里主要讨论 Gnu格式的.

  ARM的嵌入式汇编是没有引号,用花括号包括进来,如下格式,多行之间直接采用回车分隔,语法采用ARM汇编格式.后文将不讨论
     asm { 
        nop 
       mvn r0,#0
    }
 
  __voliatie 主要主要让编译不要对读写进行优化.

  GNU 嵌入式汇编格式,用gcc编译的汇编必须满足如下格式
  •      一般以  __asm __volatile打头,用()包括起来,
  • 每句语句用""包括起来  
  • 多语句之间用 \n或\nt分隔
  • 专用寄存器用%%的打头表示,
以下就是一个简单的嵌入式汇编格式
     
  1. __asm__ __volatile__ (
  2. "mov %0, #55\n"
  3. "mov %1, #66\n"
  4. "xor %%eax, %%eax\n"
  5. )
 
  1. asm(
  2. "mov r0, r0\n\t"
  3. "mov r0, r0\n\t"
  4. "mov r0, r0\n\t"
  5. "mov r0, r0"
  6. );
 关于嵌入式汇编,可以参见如下文章
   <>
<>
  
  
二.嵌入式汇编与C的数据交互

  一般嵌入式汇编是一段特定代码,因此有可以从C语言变量中读取数据,或者把处理后的数据交给C程序.

  2.1 从C变量取值.
    一般是从局域变量中取值,按定义的先后,用%0到%9表示,最多10个变量.
   比如下代码
      asm("add %1,%2"); 
    
  2.2 向C程序返回结果.
    这里要用更复杂的分段式表达式.完整的嵌入式汇编分为四大部分:
      汇编代码部分(code),输出部分(output operand list ),输入部分(input operand list ),破坏段(clobber list)部分,每一部分用":"分开.
     
     其中汇编语句段就一般的汇编指令,可以是多句.

     其中输出部分即是向C变量赋值的部分.
     我们看如下示例
    
      asm("mov %0, %1, ror #1" : "=r" (result) : "r" (value));
     这里的语句部分是 "mov %0,%1,ror 1",这里把%1的值赋给%0,并且与1作位与.

     :后是输出部 "=r(result)", 
      而且"r" (value)是输入部,
     这里破坏部省略.

  2.3 输出部格式
     在上例中 =r(result), =表示只用输出,r表示通用寄存器的值赋给变量,result表示输出C变量名字.
    这个"=r(result)"的完整意思是把结果赋给result.
    其中除 =外,还有其它保留字
  •       = 只写/输出变量
  •       + 可读可写变量
  •       &  该输出操作数不能使用输入操作数相同的寄存器
     
    而输出部的关健字除r外,还有其它很多.它们用来表示输出变量与前一部分语句中操作寄存器的关系,
      
    r 把r0~r15的值赋给变量
    f 使用浮点的寄存器f0~f15
    m 任意内存地址
    a, b.c d 表示要求使用寄存器eax/ax/al, ebx/bx/bl, ecx/cx/cl或edx/dx/dl
    
这里有一个完整的表格
   
ConstraintUsage in ARM stateUsage in Thumb state
fFloating point registers f0 .. f7Not available
hNot availableRegisters r8..r15
GImmediate floating point constantNot available
HSame a G, but negatedNot available
IImmediate value in data processing instructions
e.g. ORR R0, R0, #operand
Constant in the range 0 .. 255
e.g. SWI operand
JIndexing constants -4095 .. 4095
e.g. LDR R1, [PC, #operand]
Constant in the range -255 .. -1
e.g. SUB R0, R0, #operand
KSame as I, but invertedSame as I, but shifted
LSame as I, but negatedConstant in the range -7 .. 7
e.g. SUB R0, R1, #operand
lSame as rRegisters r0..r7
e.g. PUSH operand
MConstant in the range of 0 .. 32 or a power of 2
e.g. MOV R2, R1, ROR #operand
Constant that is a multiple of 4 in the range of 0 .. 1020
e.g. ADD R0, SP, #operand
mAny valid memory address
NNot availableConstant in the range of 0 .. 31
e.g. LSL R0, R1, #operand
ONot availableConstant that is a multiple of 4 in the range of -508 .. 508
e.g. ADD SP, #operand
rGeneral register r0 .. r15
e.g. SUB operand1, operand2, operand3
Not available
wVector floating point registers s0 .. s31Not available
XAny operand

     
 
 
       常见实例
      :"=&r" (__val), "=m" (*mem) 
      
 2.4 输入部分格式
    可以看是输入变量的声明,格式:关系关健字(变量名) ,关系关健字与输入段类型,,所以这一个段经常可以省略.
   如 r(result)
   可以还可以加上%的限定,表示可以变量对应的%0,%1之类变量可以交换位置,比如add加数,放前放后均可.
  :"r"(result) 表示%0是C变量result的值
  : "%r"(x),"r"(y) 
  还有常量0表示与第一个输出数相同
 如下示例
    asm("mov %0, %0, ror #1" : "=r" (value) : "0" (value))
  

 2.5 破坏段(clobber list)格式
   表示汇编代码产生什么样后果,一般是"memory",表示内存发现变化
   :"memory"

   除此之多,还有cc,表示改变条件代码寄存器(condition  code register),如果一个寄存器名字,如r12,表示代码修改了r12.

  参见下面的代码,其中省略了输出段和输入段
   
  1. asm volatile("mrs r12, cpsr\n\t"
  2. "orr r12, r12, #0xC0\n\t"
  3. "msr cpsr_c, r12\n\t" ::: "r12", "cc");
   
  1. asm volatile("mrs r12, cpsr\n"
  2. "bic r12, r12, #0xC0\n"
  3. "msr cpsr_c, r12" :: "X" (c) : "r12", "cc"
  1. __asm__ __volatile__ (
  2. "loop:\n"
  3. "ldrb r1, [%0], #1\n"
  4. "strb r1, [%1], #1\n"
  5. "cmp r1, #0\n"
  6. "bne loop\n"
  7. :
  8. : "r" (a), "r" (b)
  9. : "r0", "r1", "memory"
  10. );
2.6 使用把汇编代码段定义成宏
  这时建议使用 __asm__来代替 __asm ,__volatile__代替 __valatile,这样在ANSI C没有编译警告
  
  1. #define BYTESWAP(val) \
  2. __asm__ __volatile__ ( \
  3. "eor r3, %1, %1, ror #16\n\t" \
  4. "bic r3, r3, #0x00FF0000\n\t" \
  5. "mov %0, %1, ror #8\n\t" \
  6. "eor %0, %0, r3, lsr #8" \
  7. : "=r" (val) \
  8. : "0"(val) \
  9. : "r3", "cc" \
  10. );
  2.7 代码段内部标签,
    这个可以在一个代码段使用标签,但是不能从一个段跳到另一个段的标签里.标签用1: 2:这样的定义方法.用b 语句跳转 ,如 bne 1b
   参见如下实例
    
  1. #define __arch_compare_and_exchange_val_64_rel(mem, newval, oldval) \
  2. ({ \
  3. __typeof (*(mem)) __tmp; \
  4. __typeof (mem) __memp = (mem); \
  5. __asm __volatile (__ARCH_REL_INSTR "\n" \
  6. "1: ldarx %0,0,%1" MUTEX_HINT_REL "\n" \
  7. " cmpd %0,%2\n" \
  8. " bne 2f\n" \
  9. " stdcx. %3,0,%1\n" \
  10. " bne- 1b\n" \
  11. "2: " \
  12. : "=&r" (__tmp) \
  13. : "b" (__memp), "r" (oldval), "r" (newval) \
  14. : "cr0", "memory"); \
  15. __tmp; \
  16. })
   
阅读(844) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~