簡體   English   中英

'asm'中不可能的約束:__asm__ __volatile__

[英]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 )。 通過將此參數放在第一個冒號之后(並使用= ),就表示這是一個輸出。 輸出為常量沒有任何意義。

也:

  • 您將xyz列出為asm的輸入(通過將它們放在第二個冒號之后),但是從未為它們分配值。 從未分配值的輸入沒有任何意義。
  • 您(顯然)正在修改寄存器29-31,但是您沒有告訴編譯器您正在這樣做嗎?

還有更多,但是我無法理解您認為此代碼應該執行的操作。 您可能需要花些時間瀏覽gcc 文檔以獲取asm,以了解其工作原理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM