Hi, my problem is rather theoretical, but I think it is interesting to others. Let's assume I want to access 16-bit register, for example ADC. I can use int a=ADC, and it works perfectly. I can use int a=ADCL | (ADCH<<8); and it should work ok if the compiler will not reorder the sequence of ADC readings. So my question is "“ according to C standard is it possible that optimizer will reorder the ADC read sequence, so ADCH will be read first and ruin ADC result?
Theoretical problem with accessing to 16-bit register
When you tell the compiler witch chip it's for, it will (should) know that kind of traps and make the correct code.
Edit I stay corrected sorry.
When
you tell the compiler witch chip it's for, it will (should) know that kind of traps and make the correct code.
int a = ADCL + (ADCH << 8);
the compiler is free to access the two registers in whatever order it wants. The line:
int a = ADC;
it is guaranteed that the access is in the correct order,
If "ADC" did not exist then I'll bet the compiler does not generate any more code for:
int a = ADCL; a |= (ADCH << 8);
than it does for
int a = ADCL | (ADCH << 8);
Carriage returns cost nothing when writing clear C code. Programmers are far too often tempted to make complex compound statements because they don't trust the optimiser.
If "ADC" did not exist then I'll bet the compiler does not generate any more code for:int a = ADCL; a |= (ADCH << 8);than it does for
int a = ADCL | (ADCH << 8);Carriage returns cost nothing when writing clear C code. Programmers are far too often tempted to make complex compound statements because they don't trust the optimiser.
Otherwise, if you have a compound expression, "the order of evaluation
of subexpressions and the order in which side effects takeplace are both unspeciï¬ed." (6.5.#4). This may have surprising consequences for the unaware not only with volatile (peripheral) accesses, see C-faq's http://c-faq.com/expr/precvsooe.... or better the whole chapter http://c-faq.com/expr/index.html .
JW
Jan,
Yes I know that - but what I meant is that it doesn't hurt to break down a compound statement into separate parts on new lines (by implication that means ending each with ; ). People should get into the habit of looking at the generated Asm. In this case:
#includevoid use_var(uint16_t); int main(void) { uint16_t a; a = ADCL; a |= (ADCH << 8); use_var(a); a = ADCL | (ADCH << 8); use_var(a); a = ADC; use_var(a); }
generates:
a = ADCL; 6c: 24 b1 in r18, 0x04 ; 4 6e: 30 e0 ldi r19, 0x00 ; 0 a |= (ADCH << 8); 70: 45 b1 in r20, 0x05 ; 5 use_var(a); 72: 94 2f mov r25, r20 74: 80 e0 ldi r24, 0x00 ; 0 76: 82 2b or r24, r18 78: 93 2b or r25, r19 7a: 0e 94 4b 00 call 0x96 ; 0x96
and
a = ADCL | (ADCH << 8); 7e: 24 b1 in r18, 0x04 ; 4 80: 45 b1 in r20, 0x05 ; 5 use_var(a); 82: 94 2f mov r25, r20 84: 80 e0 ldi r24, 0x00 ; 0 86: 30 e0 ldi r19, 0x00 ; 0 88: 82 2b or r24, r18 8a: 93 2b or r25, r19 8c: 0e 94 4b 00 call 0x96 ; 0x96
In this case clarity and guaranteed order of access "costs" just an "ldi r19,0"
The use of GCC's "ADC" is the most efficient though:
a = ADC; 90: 84 b1 in r24, 0x04 ; 4 92: 95 b1 in r25, 0x05 ; 5 use_var(a); 94: 0e 94 4f 00 call 0x9e ; 0x9e
But the problem is that you are still not garanteed that the code will stay in order! (Remember the CLI SEI problem) .
But the problem is that you are still not garanteed that the code will stay in order!
But that's not true of C when the source/destination is volatile - the problem is just asm("") inserted in amongst the C where "volatile" doesn't mean what we think at all.
Sorry I could be wrong, but my impression was just that volatile means that it has to read/store the correct place, but not necessarily following the order!
[...]what I meant is that it doesn't hurt to break down a compound statement into separate parts on new lines (by implication that means ending each with ; ).
What I meant is that it is *necessary* to do so (the CR stuff was just some extra hair splitting :-) )
Jan
Sorry I could be wrong, but my impression was just that volatile means that it has to read/store the correct place, but not necessarily following the order!
"the order of evaluation
of subexpressions and the order in which side effects takeplace are both unspeciï¬ed." (6.5.#4)
---
That avr-gcc handles "correctly" the 16-bit SFRs is an extension; in the light of C99 it IMHO falls into the "what is volatile access is implementation defined".
However it should be said explicitly and loudly in the documentation (if there would be any... :-( ), to avoid possible confusion when somebody ports/moves to a different AVR C compiler.
JW
Ok, so as I understood the conclusion is that int a=ADC; is always safe and is a recommended way of reading a 16-bit register. It is implemented as compiler extension. Reading separately ADCL and ADCH should work ok, as ADCL and ADCH are volatile, and compiler cannot reorder the sequence of access to ADC. But if I put everything in one line like int a=ADCL | (ADCH<<8)); it can work, but it is not guaranteed, and it should be avoided? Correct? I have some dubts, because if volatile is a barrer and compiler cannot reorder access to volatile register, it should worke exactly in the same way in case like int a=ADCL | (ADCH<<8));. Or compiler can reorder volatile subexpressions in one expression?
I have some dubts, because if volatile is a barrer
"barrier" is only a word. There is no mention of this word in the standard.
and compiler cannot reorder access to volatile register,
Who said that?
Or compiler can reorder volatile subexpressions in one expression?
the order of evaluation of subexpressions and the order in which side effects take place are both unspeciï¬ed. (6.5.#4)
If you read up in the standard what "side effects" mean (volatile access is the prime example of "side effects"), I don't think this can be any clearer.
JW
Ok, so the only 100% legal way of accessing ADC is int a=ADC; everything else could work, but it is not guaranteed? Correct?
Correct?
Incorrect. C statments with volatile source/destination will be executed in the order given. The "split" solution will always work. But why bother when "ADC" exists and is proven to be the most efficient solution?
The "split" solution will always work
everything else could work, but it is not guaranteed? Correct?
No. Volatile accesses are guaranteed to be completed at the access points - I wrote about this above in this thread too. Please re-read my posts and the relevant chapters in the standard before you post further questions to this topic.
But why bother when "ADC" exists and is proven to be the most efficient solution?
Are 3 minority reasons enough?
JW
Quote:Who gave you that warranty?The "split" solution will always work
5.1.2.3#2