2016-06-11 61 views
1

在我的Atmel ASF項目中,我正嘗試構建以下內聯asm代碼。然而,我在編譯時遇到了不可能的約束。編譯時在asm中的不可約束

編譯指向這一行__asm__ __volatile__, 我錯過了什麼?

#define OUTPORT PORTD 
#define OUTBIT 3  // PD.3 
uint8_t rport ,rbits; 
uint8_t *buf = message; 
asm volatile( "in  __tmp_reg__, __SREG__    \n\t" // 1 Save SREG for later 
       "cli          \n\t" // 1 Clear interrupts 
       "in  %[rport], %[port]     \n\t" // 1 Move PORTB adress to rport 

       : //Outputs 
       [rport] "=&r" (rport) 

       : //Inputs 
       [port] "I" (_SFR_IO_ADDR(OUTPORT))  // Adress to port register, 6-bit positive constant 

       : //Clobber list (compiler must restore) 

       "r0"          // This is __tmp_reg__ 
); 
  1. 是什麼摧毀了這個版本?
  2. 我不知道asm語法是不正確的嗎?我一直在關注this manual
+0

這是非常高效的內聯彙編。確保你需要asm,如果你確實考慮把它放在一個單獨的asm文件中而不是內聯。會節省很多頭痛。 – Jester

+0

這是一個可笑的漫長的宏。爲什麼不把它作爲一個函數,並把它放在一個彙編文件中?那麼它甚至不需要變化。鑑於所有的呼籲和故意拖延,它怎麼可能受傷?然後你會得到合理的診斷。如果這被稱爲不止一次,你的代碼會變得更小。 – DigitalRoss

+0

_SFR_IO_ADDR(OUTPORT)實際上是介於0和63之間的值嗎? –

回答

1

PORTD,在ATxmega128A4U,在地址0x0660,在其62 datasheet, 頁陳述因此,端口不給in指令訪問。 您應該使用lds而是與約束

[port] "i" (_SFR_MEM_ADDR(OUTPORT)) 

注意小寫的「i」。

附錄:我只是想編譯如下:

#include <avr/io.h> 

void test(void) 
{ 
    uint8_t rport; 

    asm volatile(
     "in __tmp_reg__, __SREG__ \n\t" 
     "cli      \n\t" 
     "lds %[rport], %[port]  \n\t" 
     : [rport] "=&r" (rport)    // output 
     : [port] "i" (_SFR_MEM_ADDR(PORTD)) // input 
     : "r0"        // clobber 
    ); 
} 

使用AVR-GCC 4.9.2與我得到的 正確生成的代碼並沒有警告,甚至-Wall -Wextra選項-mmcu=atxmega128a4u -c

「我」約束是 documented 在表示「整數立即數」,而"I" means 「恆大於-1,小於64」。

+0

小寫「i」約束對於編譯器來說是不知道的,如果我在代碼段使用lds,它會抱怨操作數。 – Artec

+0

@Artec:avr-gcc 4.9.2確實支持「i」約束。看修改後的答案。 –

+0

由於這只是一個正常的負載,所以實際上並不需要內聯asm來從中加載。只是'volatile char * portd =(char *)_ SFR_MEM_ADDR(PORTD)'。 –