встроенная сборка в avr

void save_context(uint8_t index) {
    context *this_context = contextArray + index;
    uint8_t *this_stack = this_context->stack;


    asm volatile("st %0 r0":  "r"(this_stack));
}

У меня есть что-то вроде этого.

!!! Я хотел бы сохранить регистры r0 r1 r2... в мой массив stack[].

Я программирую переключатель контекста. Контекст имеет такую ​​структуру:

typedef struct context_t {
   uint8_t stack[THREAD_STACK_SIZE];
   void *pstack;
   struct context_t *next;
}context;

Моя проблема в том, что я не могу передать переменную c this_stack во встроенную сборку. Моя цель - хранить все регистры, указатель стека и SREG в моем стеке.

После компиляции выдает ошибку: Описание Путь к ресурсу Расположение Тип

`,' required    5_multitasking      line 754, external location: C:\Users\Jiadong\AppData\Local\Temp\ccDo7xn3.s C/C++ Problem

Я посмотрел учебник по встроенной сборке avr. Но я не совсем понимаю. Кто-нибудь может мне помочь?


person jiadong    schedule 02.06.2016    source источник
comment
"label" не имеет смысла, это должно быть ограничением. Также нет смысла пытаться сохранить указатель стека в массив. Возможно, имеет смысл загрузить указатель стека адресом этого массива, но это не save_context.   -  person Jester    schedule 02.06.2016
comment
@Jester, если вы посмотрите на ограничения для lds, это r, label. пожалуйста, взгляните на ссылку atmel.com/webdoc/AVRLibcReferenceManual/inline_asm_1io_ops.html   -  person jiadong    schedule 02.06.2016
comment
@jester на самом деле я делаю так, чтобы сохранить указатель стека в структуре. но задач много, допустим 3 задачи. У каждой задачи есть стек, поэтому я создал массив для контекста.   -  person jiadong    schedule 02.06.2016
comment
Но я предполагаю, что каждая задача имеет свой собственный контекст, не так ли? Таким образом, каждый контекст должен хранить только 1 указатель стека, а не их массив.   -  person Jester    schedule 02.06.2016
comment
да, каждая задача имеет 1 указатель стека. И теперь у меня много задач, например у меня 3 задачи. Легко создать массив для их хранения. Разве это не   -  person jiadong    schedule 02.06.2016
comment
Ваше редактирование вопроса, в котором asm volatile("lds r26 %0": : "label"(this_stack)); заменено на asm volatile("st %0 r0": "r"(this_stack));, по-прежнему недействительно. Это входное ограничение. Возможно, вы имели в виду "=m"(*this_stack), чтобы компилятор выбрал режим адресации. Передача ему указателя в регистре не говорит ему, что память, на которую указывает, предполагается записанной.   -  person Peter Cordes    schedule 16.01.2019
comment
У вас также, кажется, слишком много разыменований. Если this_context->stack является указателем uint8_t*, который вы хотите изменить, вам нужно взять его адрес, например uint8_t **this_stack = &this_context->stack;. В противном случае вы просто устанавливаете локальную переменную или разыменовываете указатель, загруженный из глобальной структуры. Это может быть то, что вам нужно: godbolt.org/z/_Ra5_M   -  person Peter Cordes    schedule 16.01.2019


Ответы (2)


"label" не имеет смысла, это должно быть ограничением. Также нет смысла пытаться сохранить указатель стека в массив. Возможно, имеет смысл загрузить указатель стека адресом этого массива, но это не save_context.

В любом случае, чтобы получить значение SPL, которое является указателем стека, вы можете сделать что-то вроде этого:

asm volatile("in %0, %1": "=r" (*this_stack) : "I" (_SFR_IO_ADDR(SPL)));

(Есть ограничение q, но, по крайней мере, моей версии gcc оно не нравится.)

Чтобы получить истинные регистры, например r26, вы можете сделать:

register uint8_t r26_value __asm__("r26");
asm volatile("": "=r" (r26_value));
person Jester    schedule 02.06.2016
comment
ну, this_stack это uint8_t*, а не uint8_t - person jiadong; 02.06.2016
comment
да, я знаю, что метка не является правильным ограничением. а вы ссылку выше смотрели? Как вы объясните этот ярлык - person jiadong; 02.06.2016
comment
нет, я не хотел получать значение r26. Я хочу сохранить все значения регистров в файле this_stack. - person jiadong; 02.06.2016
comment
Они были пьяны. В первой таблице четко перечислены доступные ограничения, поэтому во второй таблице лучше их использовать :) И они даже упоминают символы ограничений, которых label явно нет. - person Jester; 02.06.2016
comment
Я обновил свой вопрос. Пожалуйста, посмотрите на код еще раз. Спасибо - person jiadong; 02.06.2016

Существует ограничение "m", описанное в руководстве GCC. , но это не всегда работает на AVR. Вот пример того, как это должно работать из sanguino/bootloaders/atmega644p/ATmegaBOOT

asm volatile("...
    ...
    "sts    %0,r16      \n\t"
    ...
    : "=m" (SPMCSR) : ... );

Однако я обнаружил, что «м» является хрупким. Если функция использует переменную в коде C, вне встроенного ассемблера, компилятор может поместить ее в регистр Z, и он также попытается использовать Z в ассемблере. Это вызывает ошибку ассемблера при использовании инструкции sts. Просмотр ассемблерного вывода компилятора C — лучший способ отладки такого рода проблем.

Вместо того, чтобы использовать ограничение «m», вы можете просто поместить буквальный адрес, который вы хотите, в свой код на ассемблере. Например, см. pins_teensy.c, где timer_0_fract_count равен не входит в состав:

asm volatile(
    ...
    "sts    timer0_fract_count, r24"    "\n\t"
person Alan Green    schedule 16.01.2019
comment
"m" — это операнд памяти, общий для всех архитектур. gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html. Документы по машинным ограничениям не дублируют документы в каждом разделе. (И gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html документирует "M"для AVR, так что вы имеете в виду не это.) - person Peter Cordes; 16.01.2019
comment
Проблема с вводом буквального адреса в asm заключается в том, что оптимизаторы gcc не смогут его увидеть. Вероятно, выделение можно было бы отбросить как неиспользуемое, если бы оно использовалось только в ассемблерных блоках. - person David Wohlferd; 17.01.2019