'asm'中不可能的约束:__ asm__ __volatile__

时间:2016-07-20 23:02:08

标签: c compiler-errors inline-assembly mingw32 att

我尝试了几天后编写一个非常简单的内联汇编程序代码,但没有任何效果。我有IDE NetBeans和编译器MinGW。 我的最新代码是:

uint16 readle_uint16(const uint8 * buffer, int offset) {
    unsigned char x, y, z;
    unsigned int PORTB;
    __asm__ __volatile__("\n"
        "addl r29,%0\n"
        "addl r30,%1\n"
        "addl r31,%2\n"
        "lpm\n"
        "out %3,r0\n"
        : "=I" (PORTB)
        : "r" (x), "r" (y), "r" (z)
    );
    return value;
}

但我每次都得到同样的信息“错误:'asm'中不可能的约束”。 我尝试在一行中编写所有内容或使用不同的asm介绍。我不知道我能做什么。

2 个答案:

答案 0 :(得分:1)

请注意,gcc的内联汇编语法为

asm [volatile] ( AssemblerTemplate
                      : OutputOperands
                      [ : InputOperands
                      [ : Clobbers ] ])

汇编程序指令首先出现输出操作数,然后输入。

正如@DavidWohlferd所说,I"constant greater than −1, less than 64 "常数(“immediates”)。

虽然out指令实际上需要该范围内的常量值,但PORTB 该常量值。 (如果您查看控制器的相应avr/ioXXXX.h文件,您可以自己查看,您可能会在其中找到#define PORTB _SFR_IO8(0x05)之类的内容。)

此外,并非所有IO寄存器都可以通过out / in访问;特别是较大的控制器有超过64个IO寄存器,但只有前64个可以访问。但是,可以通过lds / sts在其内存映射地址访问所有IO寄存器。因此,根据您要访问哪个控制器的寄存器,您可能根本无法使用out,但您始终可以使用sts。如果您希望代码可移植,则必须考虑到这一点,例如建议的here

如果您知道PORTB是控制器上的前64个IO寄存器之一,则可以使用

<{> "I" (_SFR_IO_ADDR( PORTB ))out,否则使用

"m" ( PORTB )sts

所以这个:

__asm__ __volatile__("\n"
    "addl r29,%0\n"
    "addl r30,%1\n"
    "addl r31,%2\n"
    "lpm\n"
    "out %3,r0\n"
    : /* No output operands here */
    : "r" (x), "r" (y), "r" (z), "I" (_SFR_IO_ADDR( PORTB ))

);

应该让你摆脱那个“不可能的约束”错误。虽然代码仍然没有任何意义,主要是因为你使用“随机”,未初始化的数据作为输入。你破坏了r29-r31而没有声明它们,我完全不确定你对lpm之前的所有代码的意图是什么。

答案 1 :(得分:0)

正如EOF所说,I约束用于常量参数(参见https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html处的AVR部分)。通过将此参数放在第一个冒号之后(并使用=),您说这是一个输出。输出到常数是没有意义的。

此外:

  • 您将xyz列为asm的输入(通过将它们放在第二个冒号后面),但它们永远不会被赋值。从未赋予过值的输入毫无意义。
  • 您(显然)正在修改寄存器29-31,但是您没有告诉编译器您这样做了吗?

还有更多,但我无法按照您认为此代码应该执行的操作。您可能需要花一些时间通过gcc docs查看asm以了解其工作原理。