Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Purpose of subsequent use of OR and AND compound assignment operators on registers

In C and C++ code, in particular that for embedded systems, I regularly stumble upon assignments that take the following shape:

A |= B;
A &= B;

Not sure if relevant, but A and B are registers here. See an example here: http://processors.wiki.ti.com/index.php/Interrupt_Nesting_on_C28x#Example_Code The following lines appear:

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

However, these subsequent assignments seem identical to the single assignment

A = B;

Except for the fact that, theoretically, the former can in some cases be interrupted between both lines, but this does not seem to play an important role in most codes.

Is there an advantage of using the former over the latter, or is there another difference that I fail to see?

like image 508
JJM Driessen Avatar asked Nov 16 '16 10:11

JJM Driessen


People also ask

What is the purpose of a compound assignment operator?

Compound-assignment operators provide a shorter syntax for assigning the result of an arithmetic or bitwise operator. They perform the operation on the two operands before assigning the result to the first operand.

What is the use of compound assignment operator in C++?

The compound assignment operators consist of a binary operator and the simple assignment operator. They perform the operation of the binary operator on both operands and store the result of that operation into the left operand, which must be a modifiable lvalue.

What is difference between assignment operator and compound operators?

The assignment statement stores a value in a variable. Compound assignment combines assignment with another operator.

What is compounded assignment statement?

The operator is applied to the target and source first, and then what results is assigned to the target. In a compound assignment, any subscripts or locator expressions specified in the target variable are evaluated only once. The function f is called only once. How multiple assignment are performed.


3 Answers

Of course, sequence of two following commands:

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

Is identical to:

A = 0x02;

Unless the A is not a variable, but a hardware register. In this case you need to refer to the MCU/CPU (or mapped peripheral) manual to check why exactly this sequence is required.


UPDATE

Variable vs Hardware register

In the comments above, OP asked how to distinguish between variables and registers.

This is quite easy. All you need to do is to look at the definition. While typical variable would be defined as something like:

unsigned char A;

Hardware register definition will look similar to:

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

Here, A is defined as a value of a hardware register, mapped to address at 0x1234. Every microcontroller or CPU has it's own unique set of hardware registers, and it will vary not only between different kind of architectures and models, but also between different manufacturers. If the source code is not well documented, the only way to tell what particular hardware register is about is to look into hardware datasheet. Also, some advanced architectures can map hardware registers from some peripherals into CPU address space, so that it is possible to access hardware registers of external components in the same way.

Note the volatile keyword. From the wiki:

This keyword prevents an optimizing compiler from optimizing away subsequent reads or writes and thus incorrectly reusing a stale value or omitting writes. Volatile values primarily arise in hardware access (memory-mapped I/O), where reading from or writing to memory is used to communicate with peripheral devices, and in threading, where a different thread may have modified a value.

like image 51
Andrejs Cainikovs Avatar answered Oct 18 '22 05:10

Andrejs Cainikovs


In case the variable is a hardware register, which seems to be the case, the variables are volatile. Writing a bit followed by clearing a bit, is then not the same thing as just writing a value.

Hardware registers don't always behave like plain RAM variables. It is not certain that writing a zero clears a bit. Flag and status registers in particular can have certain conditions, such as "this flag is cleared by writing to the bit, followed by a read to the register". In other cases, flags could be cleared by simply reading the register.

This is very common for flag/status registers user for serial communication peripherals such as SPI or UART.

Also, note that there's no guarantee that A = B; results in a single instruction. More likely it results in: "load B", "store B in A". If you need things to be atomic, you must always disassemble the code to see what you actually ended up with.

like image 40
Lundin Avatar answered Oct 18 '22 03:10

Lundin


There possibly are circumstances for hardware registers where certain bit sequences are necessary of have "special" behaviour, although it is hard to see what that might be in this particular instance.

Do not underestimate the probability of code you find on the Internet to be nonsense, even if it is from the chip vendor's site. Looking at the documentation it seems likley that the author has read this:

enter image description here

and has been confused by the reference to OR IER/AND IER - they do enable and disable interrupts but so does the MOV IER instruction atomically. which is what the direct assignment will do.

There is a later example on that same page:

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

Where the operands differ; so perhaps the author simply has a generalised pattern and is sticking with it.

like image 35
Clifford Avatar answered Oct 18 '22 04:10

Clifford