Impossible constraint in 'asm': __asm__ __volatile__

心不动则不痛 提交于 2019-12-25 07:21:30

问题


I trying since a few days to write a very simple inline assembler code, but nothing worked. I have as IDE NetBeans and as compiler MinGW. My latest code is:

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;
}

But I get everytime the same message "error: impossible constraint in 'asm'". I tried to write all in a single line or to use different asm introductions. I have no idea what I can do otherwise.


回答1:


Notice that gcc's inline assembly syntax is

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

After the assembler instructions first come the output operands, then the inputs.

As @DavidWohlferd said, I is for "constant greater than −1, less than 64 "constants ("immediates").

While the out instruction in fact requires a constant value from that range, PORTB is not that constant value. (You can see that for yourself if you look into the corresponding avr/ioXXXX.h file for your controller, where you may find something like #define PORTB _SFR_IO8(0x05).)

Also, not all IO registers may be accessible via out/in; especially the bigger controllers have more than 64 IO registers, but only the first 64 can be accessed as such. However, all IO registers can be accessed at their memory-mapped address through lds/sts. So, depending on which register on which controller you want to access you may not be able to use out for that register at all, but you can always use sts instead. If you want your code to be portable you'll have to take that into account, like suggested here for example.

If you know that PORTB is one of the first 64 IO registers on your controller, you can use

"I" (_SFR_IO_ADDR( PORTB )) with out, else use

"m" ( PORTB ) with sts.

So this:

__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 ))

);

should get you rid of that "impossible constraint" error. Although the code still does not make any sense, mostly because you're using "random", uninitialized data as input. You clobber registers r29-r31 without declaring them, and I'm totally not sure what your intention is with all the code before the lpm.




回答2:


As EOF says, the I constraint is used for parameters that are constant (see the AVR section at https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html). By putting this parameter after the first colon (and by using an =), you are saying this is an output. Outputting to a constant makes no sense.

Also:

  • You list x, y, and z as inputs to the asm (by putting them after the second colon), but they never get assigned a value. An input that has never been assigned a value makes no sense.
  • You are (apparently) modifying registers 29-31, but you don't tell the compiler that you are doing so?

There's more, but I just can't follow what you think this code is supposed to do. You might want to take some time to look thru the gcc docs for asm to understand how this works.



来源:https://stackoverflow.com/questions/38492250/impossible-constraint-in-asm-asm-volatile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!