随后在寄存器上使用OR和AND复合赋值运算符的目的

时间:2016-11-16 10:47:49

标签: c embedded compound-assignment

在C和C ++代码中,特别是对于嵌入式系统,我经常偶然发现具有以下形状的作业:

A |= B;
A &= B;

不确定是否相关,但A和B是寄存器。在这里查看示例: http://processors.wiki.ti.com/index.php/Interrupt_Nesting_on_C28x#Example_Code 出现以下行:

IER |= 0x002;
IER &= 0x002;

但是,这些后续分配似乎与分配相同

A = B;

除了理论上,前者在某些情况下可以在两条线之间中断,但这似乎在大多数代码中都不起作用。

使用前者优于后者是否有优势,还是我看不到其他差异?

4 个答案:

答案 0 :(得分:6)

当然,以下两个命令的顺序:

A |= 0x02;
A &= 0x02;

与:

相同
A = 0x02;

除非A不是变量,而是硬件寄存器。在这种情况下,您需要参考MCU / CPU(或映射外设)手册来检查为什么需要这个序列。

更新

变量与硬件寄存器

在上面的评论中,OP询问如何区分变量和寄存器

这很容易。您需要做的就是查看定义。虽然典型的变量将被定义为:

unsigned char A;

硬件寄存器定义类似于:

#define A (*(volatile uint16_t *)(0x1234))

这里,A被定义为硬件寄存器的值,映射到0x1234的地址。每个微控制器或CPU都有自己独特的硬件寄存器集, 不仅会在不同类型的架构和模型之间变化,而且会在不同制造商之间变化。如果没有详细记录源代码,告诉硬件数据表的唯一方法是查看硬件数据表。此外,一些高级架构可以将来自某些外设的硬件寄存器映射到CPU地址空间中,因此可以以相同的方式访问外部组件的硬件寄存器。

请注意volatile关键字。来自wiki

  

此关键字可防止优化编译器优化后续读取或写入,从而错误地重用过时值或省略写入。易失性值主要出现在硬件访问(内存映射I / O)中,其中读取或写入内存用于与外围设备通信,以及在线程中,其中不同的线程可能已修改了值。

答案 1 :(得分:1)

如果变量是硬件寄存器(似乎是这种情况),则变量为volatile。写一点然后清除一点,就像写一个值一样。

硬件寄存器的行为并不总是普通的RAM变量。写零的不确定是否有点清楚。标志和状态寄存器尤其可以具有某些条件,例如“通过写入该位来清除该标志,然后读取寄存器”。在其他情况下,只需读取寄存器即可清除标志。

这对于串行通信外设(如SPI或UART)的标志/状态寄存器用户来说非常常见。

另请注意,无法保证A = B;会产生单条指令。更有可能导致:“加载B”,“将B存储在A中”。如果你需要原子的东西,你必须总是反汇编代码,看看你实际上最终得到了什么。

答案 2 :(得分:1)

可能存在硬件寄存器的情况,其中某些位序列必须具有“特殊”行为,尽管很难看出在这个特定实例中可能存在什么。

不要低估您在互联网上找到的代码无意义的可能性,即使它来自芯片供应商的网站。看一下文档,似乎作者已经读到了这个:

enter image description here

并且对OR IER / AND IER的引用感到困惑 - 它们启用和禁用中断,但MOV IER指令原子也是如此。这是直接任务的作用。

在同一页面上有一个后来的例子:

IER |= M_INT2;
IER &= MINT2;                         // Set "global" priority

操作数不同的地方;所以也许作者只是有一个普遍的模式并坚持下去。

答案 3 :(得分:-2)

A | = 0x02; 和...一样 A = 0x02;

A& = 0x2仍然等于零(A = 0假设)

如果A和B都是一个字节值。但是在某些情况下,它不等于一个字节,在这些情况下,所有这些运算符都具有不同的属性。

我以4字节值为例。

A = 0x12345600

A | = 0x2等于0x12345602 而 A& = 0x2等于0x12345600 和 A = 0x2等于0x00000002