当前位置:首页 > 工业控制 > 电子设计自动化
[导读]作者:刘洪涛,华清远见嵌入式培训中心高级讲师,ARM ATC授权培训讲师。 __asm__ __volatile__内嵌汇编用法简述 在阅读C/C++原码时经常会遇到内联汇编的情况,下面简要介绍下__asm__ __volatile__内嵌汇编用法。因为

作者:刘洪涛,华清远见嵌入式培训中心高级讲师,ARM ATC授权培训讲师。

__asm__ __volatile__内嵌汇编用法简述 在阅读C/C++原码时经常会遇到内联汇编的情况,下面简要介绍下__asm__ __volatile__内嵌汇编用法。因为我们华清远见教学平台是ARM体系结构的,所以下面的示例都是用ARM汇编。

带有C/C++表达式的内联汇编格式为:

__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);

其中每项的概念及功能用法描述如下:

1、 __asm__

__asm__是GCC 关键字asm 的宏定义:

#define __asm__ asm

__asm__或asm 用来声明一个内联汇编表达式,所以任何一个内联汇编表达式都是以它开头的,是必不可少的。

2、Instruction List

Instruction List 是汇编指令序列。它可以是空的,比如:__asm__ __volatile__(""); 或 __asm__ ("");都是完全合法的内联汇编表达式,只不过这两条语句没有什么意义。但并非所有Instruction List 为空的内联汇编表达式都是没有意义的,比如:__asm__ ("":::"memory");

就非常有意义,它向GCC 声明:“内存作了改动”,GCC 在编译的时候,会将此因素考虑进去。 当在"Instruction List"中有多条指令的时候,可以在一对引号中列出全部指令,也可以将一条 或几条指令放在一对引号中,所有指令放在多对引号中。如果是前者,可以将每一条指令放在一行,如果要将多条指令放在一行,则必须用分号(;)或换行符(n)将它们分开. 综上述:(1)每条指令都必须被双引号括起来 (2)两条指令必须用换行或分号分开。

例如: 在ARM系统结构上关闭中断的操作

int disable_interrupts (void)

{

unsigned long old,temp;

__asm__ __volatile__("mrs %0, cpsrn"

"orr %1, %0, #0x80n"

"msr cpsr_c, %1"

: "=r" (old), "=r" (temp)

:

: "memory");

return (old & 0x80) == 0;

}

3. __volatile__

__volatile__是GCC 关键字volatile 的宏定义

#define __volatile__ volatile

__volatile__或volatile 是可选的。如果用了它,则是向GCC 声明不允许对该内联汇编优化,否则当 使用了优化选项(-O)进行编译时,GCC 将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。

4、 Output

Output 用来指定当前内联汇编语句的输出

例如:从arm协处理器p15中读出C1值

static unsigned long read_p15_c1 (void)

{

unsigned long value;

__asm__ __volatile__(

"mrc p15, 0, %0, c1, c0, 0 @ read control regn"

: "=r" (value) @编译器选择一个R*寄存器

:

: "memory");

#ifdef MMU_DEBUG

printf ("p15/c1 is = %08lxn", value);

#endif

return value;

}

5、 Input

Input 域的内容用来指定当前内联汇编语句的输入Output和Input中,格式为形如“constraint”(variable)的列表(逗号分隔)

例如:向arm协处理器p15中写入C1值

static void write_p15_c1 (unsigned long value)

{

#ifdef MMU_DEBUG

printf ("write %08lx to p15/c1n", value);

#endif

__asm__ __volatile__(

"mcr p15, 0, %0, c1, c0, 0 @ write it backn"

:

: "r" (value) @编译器选择一个R*寄存器

: "memory");

read_p15_c1 ();

}

6.、Clobber/Modify

有时候,你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改,希望GCC在编译时能够将这一点考虑进去。那么你就可以在Clobber/Modify域声明这些寄存器或内存。这种情况一般发生在一个寄存器出现在"Instruction List",但却不是由Input/Output操作表达式所指定的,也不是在一些Input/Output操作表达式使用"r"约束时由GCC 为其选择的,同时此寄存器被"Instruction List"中的指令修改,而这个寄存器只是供当前内联汇编临时使用的情况。

例如:

__asm__ ("mov R0, #0x34" : : : "R0");

寄存器R0出现在"Instruction List中",并且被mov指令修改,但却未被任何Input/Output操作表达式指定,所以你需要在Clobber/Modify域指定"R0",以让GCC知道这一点。

因为你在Input/Output操作表达式所指定的寄存器,或当你为一些Input/Output操作表达式使用"r"约束,让GCC为你选择一个寄存器时,GCC对这些寄存器是非常清楚的——它知道这些寄存器是被修改的,你根本不需要在Clobber/Modify域再声明它们。但除此之外, GCC对剩下的寄存器中哪些会被当前的内联汇编修改一无所知。所以如果你真的在当前内联汇编指令中修改了它们,那么就最好在Clobber/Modify 中声明它们,让GCC针对这些寄存器做相应的处理。否则有可能会造成寄存器的不一致,从而造成程序执行错误。

如果一个内联汇编语句的Clobber/Modify域存在"memory",那么GCC会保证在此内联汇编之前,如果某个内存的内容被装入了寄存器,那么在这个内联汇编之后,如果需要使用这个内存处的内容,就会直接到这个内存处重新读取,而不是使用被存放在寄存器中的拷贝。因为这个 时候寄存器中的拷贝已经很可能和内存处的内容不一致了。

这只是使用"memory"时,GCC会保证做到的一点,但这并不是全部。因为使用"memory"是向GCC声明内存发生了变化,而内存发生变化带来的影响并不止这一点。

例如:

int main(int __argc, char* __argv[])

{

int* __p = (int*)__argc;

(*__p) = 9999;

__asm__("":::"memory");

if((*__p) == 9999)

return 5;

return (*__p);

}

本例中,如果没有那条内联汇编语句,那个if语句的判断条件就完全是一句废话。GCC在优化时会意识到这一点,而直接只生成return 5的汇编代码,而不会再生成if语句的相关代码,而不会生成return (*__p)的相关代码。但你加上了这条内联汇编语句,它除了声明内存变化之外,什么都没有做。但GCC此时就不能简单的认为它不需要判断都知道 (*__p)一定与9999相等,它只有老老实实生成这条if语句的汇编代码,一起相关的两个return语句相关代码。

另外在linux内核中内存屏障也是基于它实现的include/asm/system.h中

# define barrier() _asm__volatile_("": : :"memory")

主要是保证程序的执行遵循顺序一致性。呵呵,有的时候你写代码的顺序,不一定是最终执行的顺序,这个是处理器有关的。

“本文由华清远见http://www.embedu.org/index.htm提供”



来源:华清远见0次

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

为解决使用现有接装纸分离装置生产“视窗烟支”时出现的安装调整难度大、耗时长、稳定性差,烟支接装纸外观质量缺陷率高等问题,设计了一种接装纸三级分离和控制装置。通过接装纸初步分离、分离定位控制和最终定位输送装置模块化设计,且...

关键字: 视窗烟支 接装纸 分离 控制

构建了机载电源特性测试系统 , 包括硬件平台和软件平台:硬件平台用于产生电源特性测试所需激励信号 , 软件 平台实现电源特性测试架构的 自动切换和电源特性的数据采集;硬件平台由APS15000线性功放 、LVA2500线...

关键字: 电源特性测试 测试切换 数据采集 自动控制

作为业内持续专注于物联网(IoT)芯片开发的厂商,Silicon Labs(芯科科技)自2021年剥离基础设施与汽车(I&A)业务后,全力聚焦物联网领域。而随着物联网迈向全场景无缝连接与人工智能(AI)端侧赋能的新阶段,...

关键字: 芯科科技 IoT BLE AoA Sub-G AI

永磁同步电机具有高效节能 、低噪声 、高功率密度等显著优点 ,特别适用于新能源电动汽车行业 。针对城市用轻型 低速电动汽车的应用 , 分析了一款内置式永磁同步电机的设计方法及特点 , 对汽车驱动电机的基本性能及设计策略进...

关键字: 永磁同步电机 新能源汽车 有限元计算 电机设计 内置式

介绍了“W ”型锅炉的燃烧特性 ,深度调峰过程中常见的问题及风险点 。结合某电厂630 MW超临界机组在200 MW负 荷深度调峰过程中给煤机断煤引起的燃烧恶化工况 ,对燃烧恶化后的现象 、处理过程及原因进行了全面分...

关键字: “W”型锅炉 深度调峰 燃烧恶化 稳燃措施

在地铁供电系统中 ,直流牵引系统故障可能会导致地铁列车失电 ,对运营服务造成严重影响 。地铁出入场(段)线 的部分直流牵引供电设备处于露天环境 , 与正线隧道内较为封闭的环境相比 , 易因外部环境影响 ,导致设备故障 。...

关键字: 出入段线 牵引直流开关 电流变化率保护 跳闸

在现代电力系统中 , 无论是大电流 、高电压 、快速运行的电源开关系统 , 还是高速电机的驱动系统 , 电磁干扰的传 播一直是系统设计的难点 。鉴于此 ,介绍了通过控制高速开关核心模块PWM(脉宽调制)的展频方式来减少E...

关键字: 电磁干扰(EMI) 脉宽调制(PWM) 展频

水厂作为城市供水系统的重要组成部分 , 其电气设计的合理性和高效性直接关系到整个供水系统的稳定性和经 济性 。鉴于此 ,从供配电系统 、设备选型 、电缆敷设 、节能措施及智慧化平台等五个维度 , 结合现行规范与工程实践...

关键字: 水厂 电气设计 供配电系统 智慧化平台

由于负载的特殊性和运行条件的复杂性 ,海上油气平台的电气系统功率因数普遍较低 。这种低功率因数会对电力 系统造成一系列负面影响 , 包括电能损耗增加 、设备运行效率降低及对平台电力系统的冲击 。鉴于此 , 结合具体项目案...

关键字: 油气平台 静止无功发生器(SVG) 功率因数 无功补偿 改造案例

在电子制造领域,DFM(Design for Manufacturability,可制造性设计)作为连接研发与量产的桥梁,通过在设计阶段预判制造风险,已成为提升产品良率、降低成本的核心工具。以手机摄像头模组封装工艺为例,...

关键字: DFM BSOB
关闭