Hi there All, I have a problem which seemed to be defying explanation, but I have come up with a theory. Could I possibly have some feedback on whether the following is likely, plausible, possible, untrue or downright rubbish? If one reads the contents of a CAN or ADC chip register at a particular address, then the label volatile is placed upon that address to prevent the compiler optimising out repeat readings of the address. If one reads the contents of the address into a variable, then the compiler would automatically treat the contents of this variable with similar care. Is it possible that there has been an oversight with statements where the contents of a variable depend on the contents of a volatile by way of an if statement, ie...
normal_var=volatile_var;
normal_var=voltile_var; if (normal_var=0x00) { another_normal_var+=1; }
This assumption of yours: If one reads the contents of the address into a variable, then the compiler would automatically treat the contents of this variable with similar care. is false. "Volatile" is a property of the variable, not of its current value at any time.
Cheers Hans, a fair point. I guess what I should be saying is, I'm assuming the compiler automatically treat a variable as volatile if it sees that the contents of an address 'labelled' as volatile are being read into the variable. Is this a reasonable assumption? Yours, Richard.
Is this a reasonable assumption? No it is not. To do this the compiler would have to be very clever indeed as sometimes the variable would contain data from a volatile source and sometimes not. Anyway, what would be the point, once a value has been read from a volatile source and placed in a variable, I cannot see any reason why the compiler should not do whatever optimisation it pleases.
Hi there Graham, I see what you're getting at. I'm considering, for example, the case where perhaps you read from a volatile address into a variable. Then manipulate the variable, then maybe output to a DAC. From what's been said here, the variable must also be defined as volatile, otherwise the optimised code would always read from the address (as a volatile is envolved in the procedure), but that the repeat manipulations of the variable could be optimised out so that they only happened once, with only one value possibly being written to the DAC. To do this the compiler would have to be very clever indeed... ...which in some case is not possible, hence the reason for the inclusion of volatile in the C language I guess. Anyway, cheers for the help. Yours, Richard.
Hi Richard, I followed the discussion, and I got a feeling that perhaps you are mistaken in your assumptions. I can't exactly point out where though, since I'm not sure what you mean, but I can try. I'm considering, for example, the case where perhaps you read from a volatile address into a variable. Then manipulate the variable, then maybe output to a DAC. From what's been said here, the variable must also be defined as volatile, otherwise the optimised code would always read from the address (as a volatile is envolved in the procedure), but that the repeat manipulations of the variable could be optimised out so that they only happened once, with only one value possibly being written to the DAC. A small code snippet in C would explain a lot better, I think. Example:
extern int volatile ADC; int i; for (;;) { i = ADC; i *= 2; write_to_dac(i); }
extern int volatile ADC; int i; i = ADC; i *= 2; for (;;) { write_to_dac(i); }
Hi Mike, Cheers for this. Taking your example code...
i = ADC;
i *= 2; write_to_dac(i);
My question is what will happen to the lines...
Well, I can't really see what you mean. Give us a piece of code in C with a real-world example of whatever undesirable optimizations you think the compiler could apply, and we can discuss that. Because in my example I can't see what optimization with side effects the compiler could apply to the i variable, apart from replacing maltiplication with shift, but that has nothing to do with volatile, of course. - mike
Hi Hans, You suggest that it should be untouched by the optimiser. No. Nobody was suggesting that. In Mike's message is says... You are suggesting that the compiler might optimize it...Well, it's not going to happen because ADC is volatile. ...which I took to mean that Mike was suggesting it would be untouched by the optimiser. You somehow seem to believe that there's no middle ground between constant and volatile... - ordinary variables. I am happy with the fact that variable may, well vary (for want of a better word). I am also happy with the opimiser optimising algorithms where all the numbers start off within the code. I am less happy (in the knowledge sense) or what happens to algorithms which manipulate variables that have been loaded with numbers from external sources such as ADC's and CAN chips. From what I can make out... 1) We assign the volatile qualifier to anything coming from an external source. 2) The compiler will not assume a variable is volatile unless you explicitly define it as such. ...so given this piece of code...
for (;;) { i = ADC; }
for (;;) { i *=2; write_to_DAC(i); }
You've broken your original code into pieces in a way the optimizer is already forbidden to do it, regardless of any usages of the "volatile" keyword. The two parts of the code that really exist are:
i = ADC
i += 2; write_do_DAC(i)
The meaning of volatile is NOT (do not optimize). The meaning of volatile is (ALWAYS read this variable from its storage location -- do not use a compiler-generated temporary copy - even one stored in a register). The following examples may help to demonstrate this. The following while loop (using a volatile ADC)...
extern int volatile ADC; . . . while (ADC < 0x0800);
extern int ADC; . . . while (ADC < 0x0800);
Volatility is not contagious. A variable not explicitly declared as volatile will be treated however the optimizer treats it, regardless of where its value came from. (This is a good thing, as it allows you to sample a volatile register into a variable, and then carry that one sample around without having to worry that it will be re-read.)
In Mike's message is says... You are suggesting that the compiler might optimize it...Well, it's not going to happen because ADC is volatile. ...which I took to mean that Mike was suggesting it would be untouched by the optimiser. Wrong. Words taken out of context. I still suggest that you come up with a real-world example of C code and possibly undesirable optimizations by the compiler on that code. Then there would be a basis for discussion. If it's not possible to think of such an example, then the problem does not exist. Regards, - mike
Hi there Mike, Cheers for your patience. Stripping out all the unnecesary stuff, the code which I am working with is as shown below. Note that it is for testing for successful transmission and reception of CAN messages. The aim being to pass one of four suitable values to a set of lights on the CAN card to set them green or red to say if CAN messages are being successfully sent of received...
//define the addresses on the CAN chip containing the send and receive flags #define TransmitA (*((volatile unsigned char far*)0x200008)) #define TransmitB (*((volatile unsigned char far*)0x200009)) #define ReceiveA (*((volatile unsigned char far*)0x200004)) #define ReceiveB (*((volatile unsigned char far*)0x200005)) // define the address which governs the CAN card LED's and the values which could be assigned to it. #define CAN_board_LEDs (*((volatile unsigned char far*)0x20002E)) #define Transmit_OK 0x05 #define Receive_OK 0x0A #define RESET 0x00 //define the variables unsigned char CAN_LED_status; unsigned char temp_a; unsigned char temp_b; unsigned char test; //piece of code located in the main function Start_timing(); TransmitB=0x47; TransmitA=0xff; ReceiveB=0; ReceiveA=0; Timing_pause(); \\waits for end of 100Hz cycle time to be flagged test=0x00; while (test!=0xb8)//test for at least one CAN message being received { Read_signals();//fills CAN message registers with fresh data from ADC's temp_b=TransmitB; temp_a=TransmitA; TransmitB=0x47; TransmitA=0xff; CAN_LED_status=RESET; if ((temp_a==0x00)&&(temp_b==0x00)) { CAN_LED_status+=Transmit_OK; } temp_b=ReceiveB; temp_a=ReceiveA; ReceiveB=0; ReceiveA=0; if ((temp_a==0x00)&&(temp_b==0xb8)) { CAN_LED_status+=Receive_OK; } CAN_board_LEDs=CAN_LED_status; test=temp_b; Watchdog(); Timing_pause(); }
CAN_LED_status+=Transmit_OK; CAN_LED_status+=Receive_OK;
while(1) { Watchdog(); }
PS I ought to add about this piece of code, that if the loop to detect if any CAN messages are received is repeated further down the piece of code. If these further repeats are removed (by for example the use of the lines...