I need to load 18h and output it to port 60h, following works (inside asm("")).
ldi r1, 0x18 ; 0x18 -> r1
sts 0x60, r1 ; output r1 -> 0x60
I don't care if register r1 or any other is used for this. Is there an easy way to let compiler to d开发者_Go百科ecide which register to use?
I could use an external r/w variable, but it creates some unnecessary overhead:
register uint8_t tmp;
asm volatile (
"ldi %[tmp], 0x18 \n\t"
"sts 0x60, %[tmp]"
: [tmp] "=r"(tmp) :);
this is for AVR atmega (8-bit) processor. Using GCC 4.3.2
I think you should use the "=&" constraint for an output operand.
The mechanics goes like this:
For any of the input operands, the compiler will provide some registers and it will load them with the value of their operands before your inline assembly starts. Input operands are read only, which means that the compiler will further expect you to leave the registers untouched within your assembly. That is, the compiler expects that the registers have the same values after your assembly as it might decide to use these values subsequently.
For output operands, the compiler assigns you a arange of registers as well. At the end of your inline assembly you should have loaded these registers with your results as the compiler expects to find them right there. Caveat: The registers that you're given for output operands may coincide with the registers you're provided for input operands! Yet, this perfectly makes sense: The compiler provides you the input in some register before your assembly and collects your result in the very same register after your assembly, for example.
You can use the output-only modifier ('&') to prevent exactly this to happen. The compiler guarantees that an output-only register never doubles as an input register.
You can use the input-output modifier ('+') to explicitely ask the compiler to use the very same register for input and output of an operand. This virtually gives you transparent access to the operand. Recapitulate that the opposite does not hold: Not using this modifier does not prevent the compiler from double using the same register -- use the output-only modifier for that.
So basically, your choice is straightforward:
- Don't request an input operand for a temporary variable due to its read-only nature and the compiler's assumptions. For example, if you create a temporary variable and initialize it with some value (probably zero) the compiler might reuse the register it provides you whenever it needs its value (zero) again later.
- Don't request an output operand as it may coincide with some input operand. You might accidentally clash your input operands when you use the alleged temporary.
- Use an output with the output-only modifier. This way, the compiler will assign you some registers that you can safely scratch (as it expects some output from you there).
Using the input-output also provides you with a safe register. However, the operand needs initialization (as the compiler assumes you're reading it as an input) and if you use the same operand in multiple snippets of inline assembly it needs restoration (for the same reason). In contrast, when using the output-only modifier the compiler can easily figure out that the variable is never read.
I don't know why I saw the overhead before, but using external register
temp variable works with no overhead even with -O0 (no optimization). So I am using:
register uint8_t tmp;
asm volatile (
"ldi %[tmp], 0x18 \n\t"
"sts 0x60, %[tmp]"
: [tmp] "=r"(tmp) :);
It still requires a variable to be declared and than described in the output block of the asm statement, but it does create assembly code I want (no overhead).
精彩评论