Using constrains: GCC vs ICCAVR (was: Assembly delay function: GCC vs ICCAVR)

I think I now understand what exactly each command of the below inline assembly code does (thanks to Tauno Voipio). But again, if someone with real knowledge of Atmel AVR assembly code finds a mistake, please correct my annotations. Now I rewrote this function for the ICCAVR. But since I didn't find out if and how this compiler uses constrains, I just omitted them. The result is, that the generated assembler code uses r16 instead of r24 (upper register), which is used when compiled with gcc. And the error output is: "Register 16 is not valid". How can I force ICCAVR to use upper register (e.g. the "w" constrain used with gcc)?

Thank you!

Following code works for gcc /************************************************************************* delay loop for small accurate delays: 16-bit counter, 4 cycles/loop

*************************************************************************/ static inline void _delayFourCycles(unsigned int __count) { if ( __count == 0 ) //delay of 2 cycles __asm__ __volatile__( "rjmp 1f\n 1:" );//relative jump to label 1 //(forward decelerated) //\n(linefeed)separates //inline assembly commands //1: is label 1,with no //following code->2cycl. else //__count is not equal 0 __asm__ __volatile__ ( //4 cycles/loop "1: sbiw %0,1" "\n\t" //label 1: sbiw (subtract //immediate 1 from count) "brne 1b" //compare the result from sbiw //with 0 and brne(branch if //not equal) to label 1 //(backward decelerated) //constrains for sbiw : "=w" (__count) //"="-enables write-permission //for this register //"w"-use upper reg. pairs //(r24, r26, r28, r30) : "0" (__count) //"0"-use the same reg. for //result as __count ); }

Following code does NOT work for ImageCrafts ICCAVR compiler /************************************************************************* delay loop for small accurate delays: 16-bit counter, 4 cycles/loop

*************************************************************************/ static inline void _delayFourCycles(unsigned int __count) { if ( %count == 0 ) //2 cycles asm( "rjmp 1" "\n" "1:"); else //4 cycles/loop asm( "1: sbiw %count,1" "\n" "brne 1"); }
Reply to
FilterPunk
Loading thread data ...

You appear to have got it all right, except maybe the use of the term "decelerated" in your description of the local labels. You seem to have got the idea right, but not the terminology.

That will automatically make the resulting code a less useful than the GCC version --- automatich register picking by GCC even for inline assembler is a big potential win. In particular, it means GCC can plan ahead, knowing it'll need 'count' in a particular type of register, and put it there a lot earlier, maybe even keep it there all the time. And if it doesn't, it'll know it has to move count into such a register before expanding the actual inline assembly.

Either you find out how to teach your assembler the same kind of tricks as used by GCC's "extended inline asm", or you have to do that manually. I.e. you may have to move %count to r24 by hand, rather than GCC doing that for you automagically.

I also strongly suspect your ICCAVR version of the forward vs. backward jump direction won't work as coded.

Without the "extended" features of GCC inline asm, there may not even be enough benefit left to warrant doing this in inline asm at all. Writing a non-inlined subroutine in a separate asm source file may thus very well end up being the best option.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.