EmbeddedRelated.com
Forums

how to prevent timer code firmware running on Microblaze from being optimised

Started by Unknown June 9, 2008
Hi all,
   thanks for your reply. I have tried some suggestions:

1)
> >> int timer_value =3D * (volatile int *) TIMED_REG_ADDRESS; > >> volatile int result =3D doSomething(); > >> timer_value =3D (* (volatile int *) TIMED_REG_ADDRESS) - timer_value;
this doesnt work. 2) Hi David, you said this:
> You can't make a function itself "volatile", but you can use the > "noinline" function attribute to ensure it is not inlined - that's > probably enough to make sure it is called properly.
how do you make an inline function? can kindly provide give a brief example? kindly help. I have already tried to dump out the assembly instructions from the compiled binary file beforehand using mb- objdump. I already know that the smart compiler reorders the timer enable and puts it some where at the bottom just before the read back of timer value and timer disabled. so i get something like this ( in C terms for easy reading): void main() { Xuint32 countvalue; // enable_timer(); <=3D=3D=3D=3D=3D=3D it dun do it here :( // do some stuff on Microblaze ... //some lines of code .... countvalue =3D readback_timer(); enable_timer(); <=3D=3D=3D=3D=3D=3D the stupid compiler reshuffles the = code here disable_timer(); //send count value back to serial port ... return1; } this is really disaster. :( kindly help Chris On Jun 10, 12:47=A0am, David Brown <da...@westcontrol.removethisbit.com> wrote:
> PFC wrote: > > >> int timer_value =3D * (volatile int *) TIMED_REG_ADDRESS; > >> volatile int result =3D doSomething(); > >> timer_value =3D (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > > >> The compiler can call doSomething(), storing the result in a temporary > >> register, then read TIMED_REG_ADDRESS, store the result in "result", > >> then re-read TIMED_REG_ADDRESS - all without violating the volatile > >> requirements. > > > =A0 =A0 Does the compiler know that doSomething() will never access any > > volatile variable ? > > =A0 =A0 (the generated assembly code was correct last time I checked). > > > =A0 =A0 Anyway you can always put your timer code in functions. I don't > > think gcc reorders function calls ?... > > >>> =A0 =A0 =A0 =A0 "volatile int x" is a contradiction so gcc optimized a=
way
> >>> which is the > >>> expected behaviour. > > >> How is it a contradiction? > > >> You can still get it's address and modify or examine it that way > >> behind the compiler's back, so the compiler must assume that when you > >> say it's volatile, you might mean it. =A0Granted you want to be careful=
> >> that you only do this during a time when the compiler is obligated to > >> ensure that the variable exists, but that's not unreasonable within > >> the scope, or when playing with a hardware-based debugger. > > > =A0 =A0 Sounds like a big shiny foot-gun. > > =A0 =A0 But you're right... C is so perverse, lol. > > In answer to this and the other replies to my post: > > You are right that the compiler can only re-order "doSomething()" around > volatile accesses if it knows that doSomething() does not make volatile > accesses itself. =A0But the compiler can be surprisingly knowledgeable > about such things - if the doSomething() function is in the same source > file, and you have at least some optimisations enabled, then it probably > has this knowledge. =A0In fact, in many common cases when you are writing > test code like this, the doSomething() function is not only in the same > file, but it is only used the one time, and the compiler may well inline > the function. =A0Thus even if it *does* use volatile accesses, > non-volatile accesses in doSomething() can be shuffled around about and > below the timer accesses. =A0Just to add to the fun, the compiler might > also figure out that parts of the code in doSomething() can be > calculated at compile time, and eliminated from the object code. > > You can't make a function itself "volatile", but you can use the > "noinline" function attribute to ensure it is not inlined - that's > probably enough to make sure it is called properly. > > As has been said, check the assembly listing to make sure you are > measuring the code you want to measure.- Hide quoted text - > > - Show quoted text -
chrisdekoh@gmail.com wrote:
> Hi all, > thanks for your reply. I have tried some suggestions: > > 1) >>>> int timer_value = * (volatile int *) TIMED_REG_ADDRESS; >>>> volatile int result = doSomething(); >>>> timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > > this doesnt work. > > 2) > > Hi David, you said this: > >> You can't make a function itself "volatile", but you can use the >> "noinline" function attribute to ensure it is not inlined - that's >> probably enough to make sure it is called properly. > > how do you make an inline function? can kindly provide give a brief > example? >
Making an inline function is easy (assuming you have the compiler flags set to accept the C99 "inline" keyword, or are compiling C++ - I have no idea which version of gcc the Microblaze uses): static inline int doSomething(void) { } If you are compiling with a reasonably recent version of gcc, and have optimisations enabled, then any single-use static function will be inlined automatically. But what you really want here is a non-inlined function: static int attribute((__noinline__)) doSomething(void) { }
> kindly help. I have already tried to dump out the assembly > instructions from the compiled binary file beforehand using mb- > objdump. I already know that the smart compiler reorders the timer > enable and puts it some where at the bottom just before the read back > of timer value and timer disabled. >
Set your compiler flags to generate a listing file from the C code - it's much easier to follow than using objdump. Alternatively, load the code in the debugger and switch to mixed C and disassembly mode.
> > so i get something like this ( in C terms for easy reading): > > void main() { > Xuint32 countvalue; > > > // enable_timer(); <====== it dun do it here :( > // do some stuff on Microblaze > > > ... //some lines of code .... > > > countvalue = readback_timer(); > enable_timer(); <====== the stupid compiler reshuffles the code > here > disable_timer(); > //send count value back to serial port > ... > > > return1; > } >
This looks like your enable_timer() and readback_timer() (and probably disable_timer()) definitions are wrong - they should be using volatile accesses to read and write the hardware timer registers. If they were doing that correctly, the compiler would not reorder them. mvh., David