我需要加载18h并将其输出到端口60h,以下工作(在asm(“”)内)。
ldi r1, 0x18 ; 0x18 -> r1
sts 0x60, r1 ; output r1 -> 0x60
我不在乎寄存器r1或其他任何用途。是否有一种简单的方法让编译器决定使用哪个寄存器?
我可以使用外部r / w变量,但它会产生一些不必要的开销:
register uint8_t tmp;
asm volatile (
"ldi %[tmp], 0x18 \n\t"
"sts 0x60, %[tmp]"
: [tmp] "=r"(tmp) :);
这适用于AVR atmega(8位)处理器。使用GCC 4.3.2
答案 0 :(得分:1)
我不知道为什么我之前看到了开销,但使用外部register
临时变量即使使用-O0(无优化)也无需开销。所以我正在使用:
register uint8_t tmp;
asm volatile (
"ldi %[tmp], 0x18 \n\t"
"sts 0x60, %[tmp]"
: [tmp] "=r"(tmp) :);
它仍然需要声明一个变量,而不是在asm语句的输出块中描述,但它确实创建了我想要的汇编代码(没有开销)。
答案 1 :(得分:0)
我认为你应该使用" =&"输出操作数的约束。
机制是这样的:
对于任何输入操作数,编译器将提供一些寄存器,并在内联汇编开始之前使用其操作数的值加载它们。输入操作数是只读,这意味着编译器将进一步期望您在程序集中保持寄存器不变。也就是说,编译器在组装后期望寄存器具有相同的值,因为它可能决定随后使用这些值。
对于输出操作数,编译器也会为您分配一系列寄存器。在内联汇编结束时,您应该已经将这些寄存器与结果一起加载,因为编译器希望在那里找到它们。 警告:您为输出操作数提供的寄存器可能与您为输入操作数提供的寄存器重合!然而,这完全有道理:编译器在组装之前为某些寄存器提供输入,并在组装之后在同一个寄存器中收集结果。 / p>
您可以使用仅输出修饰符('&')来防止这种情况发生。编译器保证仅输出寄存器永远不会兼作输入寄存器。
您可以使用输入输出修饰符(' +')明确要求编译器使用相同的寄存器来输入和输出操作数。这实际上为您提供了对操作数的透明访问。重述相反的情况:不使用此修饰符不阻止编译器使用同一寄存器加倍 - 使用仅输出修饰符。
所以基本上,你的选择很简单:
使用输入输出还可以为您提供安全寄存器。但是,操作数需要初始化(因为编译器假定您将其作为输入读取),并且如果在内联汇编的多个片段中使用相同的操作数,则需要还原(出于同样的原因)。相反,当使用仅输出修饰符时,编译器可以很容易地发现该变量永远不会被读取。