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; }
I would like to have this snippet of code get failed... Your code as shown may just be too simple to fail. If this has never failed you yet, that only proves you either didn't really check strictly enough, or that you got lucky everytime. Neither of which would justify relying on such behaviour for future projects.
I would like to have this snippet of code get failed... No guarantee this will work for you. Once when I had to sort out someone elses mess and the person refused to believe me, I managed to show the problrm by setting the timer complete bit while stopped at the mainline routine in the emulator. I doubt a simulator will blow as well as an emulator, but if you do not have an ICE, you can try it. Erik
something more .... dissasembly... some snippets of this code... ////void timer_isr interrupt 1//// 280: global_refresh=1; C:0x66AD 755001 MOV global_refresh(0x50),#refr_en(0x01) 281: if(global_refresh==1)LED=1; C:0x66B0 E550 MOV A,global_refresh(0x50) ////////////////////////////////// ///////////void main////////////// /////while() 56: if(global_refresh==1) C:0x03EB E550 MOV A,global_refresh(0x50) C:0x03ED 6401 XRL A,#refr_en(0x01) .................................... .................some code.......... 317: global_refresh=0; C:0x1367 E4 CLR A C:0x1368 F550 MOV global_refresh(0x50),A 350: if(global_refresh==0) LED=0; C:0x141E E550 MOV A,global_refresh(0x50) //////////////////////////////////// Here one can see - nothing has been put in the register and in all cases it has been read from the same data location memory!(D:0050H PUBLIC global_refresh). Additionaly, what I didn't say before, the timer was not declared with "using x", it means , it uses the same bank as the main(). I think, the main point, why it works that, there is nothing to optimize! with best regards, S.
Why wouldn't one just use a critical section for a variable shared amongst multiple priority ISRS and main run code?... or have ownership flags..... I'm a little confused on how using a volatile type qualifier protects you when using a shared resource?
Why wouldn't one just use a critical section for a variable shared amongst multiple priority ISRS and main run code? Because C doesn't have critical sections. or have ownership flags.. Because the objects in question are not owned by any of the threads of execution alone. They are shared by definition. Volatile is needed because, by default, a C compiler is supposed to know everything that's going on in a C program, so it can optimize things. If that presumption is broken, i.e. during the execution of a given code fragment, the state of any object used by it can change for a reason other than what's written out in that particular code fragment, you have to tell the compiler about that. And the volatile qualifier is the way you do that.
some snippets of this code... Here one can see - nothing has been put in the register Here. In this particular case. So yes, this is an example that omitting volatile where you should have used it doesn't automatically guarantee your code to fail. So what else is new? Examples don't prove anything, period. Let me repeat that: PROOF BY EXAMPLE DOESN'T WORK. [Sorry for the shouting, everybody, but it seems there's no other way we'll get the message into this person's mind.]
Examples don't prove anything, period. Let me repeat that: PROOF BY EXAMPLE DOESN'T WORK. [Sorry for the shouting, everybody, but it seems there's no other way we'll get the message into this person's mind.] Hans-Bernhard, I do not know how many posts we have seen stating "it tested" and I am frustrated, just like you, that so many believe in "testing". Succesful testing does not prove the abscence of bugs, it only proves the abscence of known bugs. The analogy would be that because when you did not stop at a stop sign you did not cause an accident it can be concluded that there is no risk ignoring that stop sign. I wonder how this point can get across and really do appreciate to see you phrasing it in a different form, so maybe one of the many can understand that form. Erik
I'm a little confused on how using a volatile type qualifier protects you Volatile does not provide mutual exclusion. It does not "protect" you in that sense. Volatile informs the code generator that this value may change for reasons unknown to the code generator, and thus many common optimizations are unsafe. The variable address should always be read or written. Masking interrupts to provide mutual exclusion can help avoid some problems by making sure the flawed code never executes in a manner that will expose the flaw. In other cases, though, it won't help. Consider the hoisting of global_refresh example I posted earlier in the thread. Even if you make some mutex function calls inside the loop, there's still no reason for the compiler not to hoist the read completely outside the loop (and the mutex), and you can get the wrong results despite the "protection" from the critical section. The only way the compiler can understand the usage of the variable is if you declare it volatile In other cases there's no substitute. The classic example would be something like a programmed I/O register. You copy a frame out of the single PIO address by reading it multiple times in a loop. For an ordinary variable at an ordinary address, most code generators will generate only one actual read, and then reuse the value kept in a register. But to make the hardware work correctly, you need actual physical transitions on the bus. Each read has to actually hit that memory address, and each value read from the "same" PIO port will be different. The compiler can't just use the old value, because that's a different byte in the frame. Volatile is not an optimization hint that can be ignored, like register. It is necessary to specify a constraint on the code generator to get correct code.
hello, the question was not to proof by example that's work! It's clear that one should use Volatile declaration. About "when" and "how" one can read in many helps. The question was how it worked in this concrete case without this declaration and without "may be" or it was a miracle or luck and so on. I would hear it like , it works so because... or it has been read from the same memory location each time, because... I would't need common explanation which are clear for everybody, I would need it a little more deeper in the problem. Sorry, if somehow straight. With best wishes to all and thank you very much. S.