В наборе инструкций Cortex-M3 существует семейство инструкций LDREX / STREX, такое что, если местоположение считывается с помощью инструкции LDREX, следующая инструкция STREX может писать по этому адресу, только если известно, что адрес не был изменен. Как правило, результат состоит в том, что STREX завершится успешно, если с момента LDREX не возникло никаких прерываний («исключения» на языке ARM), но в противном случае произойдет сбой.
Что? Самый практичный способ имитировать такое поведение в Cortex M0? Я хотел бы написать код C для M3 и перенести его на M0. На M3 можно сказать что-то вроде:
__inline void do_inc(unsigned int *dat) { while(__strex(__ldrex(dat)+1,dat)) {} }
для выполнения атомарного приращения. Единственные способы, которые я могу придумать для достижения аналогичной функциональности на Cortex-M0, это либо:
В зависимости от того, как используются функции ldrex / strex, отключение прерываний может работать разумно, но кажется неприятным изменять семантику «load-excluded», чтобы вызвать плохие побочные эффекты, если от него отказаться. Идея исправления кода кажется, что она достигнет желаемой семантики, но она кажется неуклюжей.
(Кстати, побочный вопрос: мне интересно, почему STREX на M3 сохраняет индикацию успеха / неудачи в регистре, а не просто устанавливает флаг Для его фактической работы требуется четыре дополнительных бита в коде операции, требуется, чтобы регистр был доступен для хранения индикации успеха / неудачи, и требуется, чтобы для определения успешности операции использовалось выражение «cmp r0, # 0». Ожидалось ли, что компиляторы не смогли бы разумно обращаться с внутренним STREX, если бы они не получить результат в реестре? Для переноса в регистр требуется две короткие инструкции.)