我尝试了几天后编写一个非常简单的内联汇编程序代码,但没有任何效果。我有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
介绍。我不知道我能做什么。
答案 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部分)。通过将此参数放在第一个冒号之后(并使用=
),您说这是一个输出。输出到常数是没有意义的。
此外:
x
,y
和z
列为asm的输入(通过将它们放在第二个冒号后面),但它们永远不会被赋值。从未赋予过值的输入毫无意义。还有更多,但我无法按照您认为此代码应该执行的操作。您可能需要花一些时间通过gcc docs查看asm以了解其工作原理。