Is volatile enough to allow the compiler to process machine registers with side effects when reading?

I work with microcontrollers, where sometimes there are machine registers that have actions that occur when reading a register. Yes, this is not a typo, there are many registers that cause actions when they are written, but in some cases, if you read the register, something happens.

The most common example of this is a UART receive register connected to one end of a FIFO; for example, let's say there is RXDATA. When you read RXDATA, it pulls one byte from the FIFO, and the next time you read RXDATA, it will get the next byte.

Is there enough information in volatileto make the compiler understand that there may be side effects from reading?

Example snippet in C:

#include <stdint.h>
#include <stdbool.h>

volatile uint8_t RXDATA;   
// there is some mechanism for associating this with a known hardware address
// (either in linker information, or in some compiler-specific attribute not shown)    

// Check that bit 0 is 1 and bit 7 is 0.
bool check_bits_1() 
{
   const uint8_t rxdata = RXDATA;
   return (rxdata & 1) && ((rxdata & 0x80) == 0);
}

// Check that bit 0 is 1 and bit 7 is 0.
bool check_bits_2() 
{
   return (RXDATA & 1) && ((RXDATA & 0x80) == 0);
}

// Check that bit 0 is 1 and bit 7 is 0.
bool check_bits_3() 
{
   const bool bit_0_is_1 = RXDATA & 1;
   const bool bit_7_is_0 = (RXDATA & 0x80) == 0;
   return bit_0_is_1 && bit_7_is_0;
}

If I ignore the C standard and pretend that the compiler does exactly what I think I'm asking for it to do ( DWIM ), then my intuition is that these three functions have different behavior:

  • In the first case, we read RXDATAonce, so we pull out one FIFO byte, and then do some math on it.
  • In the second case, we read RXDATAonce or twice (because it &&has short circuit behavior), doing the math directly by the value of the register, so we can either pull one or two bytes from the FIFO, and this has the wrong behavior.
  • RXDATA, FIFO, .

RXDATA volatile, .

C , volatile , ? , C?

+4
3

volatile, , ?

.

C . C11 5.1.2.3:

volatile, , - , .

, C11 5.2.3.4:

. , , ( volatile).

, , , .

... ,

, . , MISRA-C, volatile . UART , .

/ .

+4

, , , . C ISO/IEC 9899: 2011 §6.7.3 :

¶7 , , , . , , 5.1.2.3. , , , , , . 134) , , .


134) volatile , / , . , , " , .

- - , , . , , ; . , "".

5.1.2.3 :

¶1 , .

¶2 , , , , , 12) . , . lvalue .

¶4 . , , , ( ).

¶6 :

  • .

12 . ¶3 " " .. ¶5 . " ", .

, , , , volatile.

+3

, C. , , , . , , , , . , .

, , . . , API , , , , ( , . 1). , .

Speaking of this last bit, you need to consider the memory model. Just because the compiler is not creative with code reordering does not mean that the CPU cannot do whatever it wants. And it is definitely outside the standard C.

+1
source

Source: https://habr.com/ru/post/1679755/


All Articles