[英]Impossible constraint in 'asm': __asm__ __volatile__
幾天以來,我一直試圖編寫一個非常簡單的內聯匯編代碼,但是沒有任何效果。 我有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
簡介。 我不知道該怎么辦。
請注意,gcc的內聯匯編語法為
asm [volatile] ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
在匯編指令之后,首先是輸出操作數,然后是輸入。
正如@DavidWohlferd所說, I
是“常數大於-1,小於64”的常數(“立即數”)。
盡管out
指令實際上需要該范圍內的恆定值,但PORTB
不是該恆定值。 (如果您查看控制器的相應avr/ioXXXX.h
文件,則可以自己看到,在其中可以找到類似#define PORTB _SFR_IO8(0x05)
。)
同樣,並非所有IO寄存器都可以通過out
/ in
來訪問; 特別是較大的控制器具有64個以上的IO寄存器,但只能訪問前64個IO寄存器。 但是,可以通過lds
/ sts
在其內存映射地址訪問所有IO寄存器。 因此,取決於您要訪問哪個控制器的哪個寄存器,您可能根本無法out
該寄存器,但是您始終可以使用sts
代替。 如果您希望代碼具有可移植性,則必須考慮到這一點,例如此處建議的那樣。
如果您知道PORTB
是控制器上的前64個IO寄存器之一,則可以使用
"I" (_SFR_IO_ADDR( PORTB ))
用out
,否則使用
帶sts
"m" ( PORTB )
。
所以這:
__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
之前的所有代碼的意圖。
正如EOF所說, I
約束用於恆定的參數(請參閱AVR部分, 網址為https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html )。 通過將此參數放在第一個冒號之后(並使用=
),就表示這是一個輸出。 輸出為常量沒有任何意義。
也:
x
, y
和z
列出為asm的輸入(通過將它們放在第二個冒號之后),但是從未為它們分配值。 從未分配值的輸入沒有任何意義。 還有更多,但是我無法理解您認為此代碼應該執行的操作。 您可能需要花些時間瀏覽gcc 文檔以獲取asm,以了解其工作原理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.