Is this a compiler error?

My nearly microscopic 8051-based embedded system has a serial debug port, and I wrote a simple serial port output function that worked fine until I made a couple of small changes to it to reduce memory. Then the next line, which works fine (and was not part of the changes) ...

dbg_TxBuf[(dbg_TxBufProduceCount++) & (sizeof(dbg_TxBuf) - 1)] = ch;

... stopped working correctly. Variables dbg_TxBufand dbg_TxBufProduceCountare global variables used only by the output function and serial port ISR (which has not been changed at all):

#define DBG_TX_BUFFER_SIZE 16 // MUST be a power-of-2 (this line is actually in a separate file, not that it matters)
volatile uint8_t xdata dbg_TxBuf[DBG_TX_BUFFER_SIZE]; // must be sized by a power-of-2, and MUST BE LESS THAN 256 since the 'count' vars are uint8
volatile uint8_t xdata dbg_TxBufProduceCount; // akin to a 'head' index but more useful since it allows use of every byte in the buf
volatile uint8_t xdata dbg_TxBufConsumeCount; // akin to a 'tail' index but more useful since it allows use of every byte in the buf

In particular, what happens is that the way the compiler now optimizes the line of code is that it dbg_TxBufProduceCountgrows (in memory) to the point at which it is chwritten to dbg_TxBuf. Then the ISR serial port “sometimes” (actually quite often) sees dbg_TxBufConsumeCount != dbg_TxBufProduceCountand reads dbg_TxBuf[(dbg_TxBufConsumeCount++) & (sizeof(dbg_TxBuf) - 1)]until the output function writes chto it. This way I get corrupted output on my serial port.

Here's the parsing 8051 of this line:

935>       dbg_TxBuf[(dbg_TxBufProduceCount++) & (sizeof(dbg_TxBuf) - 1)] = ch;
DC84: 9006D6   MOV   DPTR,#dbg_TxBufProduceCount
DC87: E0       MOVX  A,@DPTR    <--- loads the value in dbg_TxBufProduceCount into the A register
DC88: FE       MOV   R6,A       <--- saves a copy of it in R6
DC89: 04       INC   A          <--- increments it
DC8A: F0       MOVX  @DPTR,A    <--- writes the incremented value 
DC8B: EE       MOV   A,R6       <--- gets the original copy of ProduceCount back in A
DC8C: 7C00     MOV   R4,#00     Begin computing address of dbg_TxBuf[~]...
DC8E: 540F     ANL   A,#0F      <--- A = A & (sizeof(dbg_TxBuf) - 1)
DC90: 24D8     ADD   A,#0D8     <--- A is now the low byte of &dbg_TxBuf[~]
DC92: F582     MOV   DPL,A      <--- put that in DPL
DC94: EC       MOV   A,R4       <--- (an inefficient way of loading the...
DC95: 3406     ADDC  A,#06      <---   ...immediate value 0x06 into A)
DC97: F583     MOV   DPH,A      <--- DPTR now points to dbg_TxBuf[~]
DC99: EF       MOV   A,R7       <--- load 'ch' into A
DC9A: F0       MOVX  @DPTR,A    <--- write 'ch' to *DPTR

"" post-increment, dbg_TxBufProduceCount dbg_TxBuf, "" " , , , , dbg_TxBuf[], dbg_TxBufProduceCount volatile. dbg_TxBufProduceCount , ch ?

BTW Keil 8051 C, v7.10. , v7.10, , 2005 .

+4
1

dbg_TxBufProduceCount , ch ?

. . , . , - . , :

i = a++ + b++;

a b volatile, . , , .

+6

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


All Articles