Невозможное ограничение в ‘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 для своего controllerа, где вы можете найти что-то вроде #define PORTB _SFR_IO8(0x05) .)

Кроме того, не все регистры ввода-вывода могут быть доступны через out / in ; особенно большие controllerы имеют более 64 регистров ввода-вывода, но только первые 64 могут быть доступны как таковые. Тем не менее, все регистры ввода-вывода могут быть доступны по адресу, lds памятью, через lds / sts . Таким образом, в зависимости от того, какой регистр, на котором вы хотите получить доступ к controllerу, возможно, не сможет использовать out для этого регистра, но вы всегда можете использовать sts . Если вы хотите, чтобы ваш код был портативным, вам следует принять это во внимание, например, здесь, например, здесь .

Если вы знаете, что PORTB является одним из первых 64 регистров ввода-вывода на вашем controllerе, вы можете использовать

"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 )) ); 

должен избавить вас от этой ошибки «невозможного ограничения». Хотя код по-прежнему не имеет никакого смысла, в основном потому, что вы используете «случайные», неинициализированные данные в качестве входных данных. Вы clobber регистры r29-r31, не объявляя их, и я совершенно не уверен, что вы намерены со всем кодом перед lpm .

Как говорит EOF, ограничение I используется для постоянных параметров (см. Раздел AVR на странице https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html ). Поместив этот параметр после первого двоеточия (и используя an = ), вы говорите, что это результат. Вывод в константу не имеет смысла.

Также:

  • Вы перечисляете x , y и z как входы в asm (путем помещения их после второго двоеточия), но никогда не получают назначенного значения. Вход, который никогда не назначался, не имеет смысла.
  • Вы (видимо) меняете регистры 29-31, но вы не говорите компилятору, что это так?

Там больше, но я просто не могу следовать тому, что, по вашему мнению, должен делать этот код. Возможно, вам понадобится некоторое время, чтобы посмотреть через gcc docs для asm, чтобы понять, как это работает.