последовательность выполнения компилятора - PullRequest
0 голосов
/ 04 мая 2018

Я программирую микроконтроллер на языке Си, и я столкнулся со следующей ситуацией: чтобы включить / отключить внутренний генератор тактовых импульсов, мне нужно сначала записать ключ защиты в определенный регистр, а затем выполнить операцию включения / выключения, запись в другом реестре. В руководстве пользователя указано следующее об этой операции: отрывок из руководства пользователя

Как видно из выделенной части текста, фрагмент кода, который выполняет эти две операции (ключ защиты от записи и включение генератора), очень чувствителен, потому что любая операция должна выполняться между этими двумя доступом к регистру. Поэтому я начинаю беспокоиться о любой ситуации, которая может привести к непоследовательному выполнению этих двух операций. Я знаю, что обычно временно отключать прерывание при выполнении чувствительного фрагмента кода, но мне было интересно, есть ли какая-либо оптимизация компилятора, которая могла бы вставить другую операцию между этими двумя доступом к регистру. Итак, в программировании на C есть какая-либо директива компилятора, чтобы гарантировать, что это не произойдет?

На самом деле, я даже не знаю, имеет ли смысл думать, что компилятор будет смешивать последовательность инструкций, написанных на языке Си. Я помню, что уже слышал, что это может происходить иногда, в процессе оптимизации скорости. Если я не прав, прошу прощения и заранее спасибо за разъяснения.

1 Ответ

0 голосов
/ 04 мая 2018

Процесс переключения битов в C включает в себя последовательность инструкций чтения-изменения-записи. Между этими инструкциями могут происходить некоторые нежелательные операции, и обычный подход состоит в том, чтобы либо отключить прерывания, либо использовать битовую полосу.

Что такое битовая полоса, она позволяет вам переключать биты, используя одну инструкцию (не вдаваясь в подробности, как это происходит).

Если ваш микроконтроллер позволяет использовать битовую полосу, то это должно решить все ваши проблемы.

Если вы не можете использовать битовую полосу, вам нужно сесть и подумать, какие прерывания могут вызвать у вас проблемы, и временно отключить их.

Чтобы вернуться к сути вопроса - вы должны объявить все свои регистры изменчивыми по двум основным причинам:

  1. В отличие от обычной памяти, которая изменяется только самой программой, значение, хранящееся в этих отображенных в памяти регистрах, может измениться в любое время, и компилятор просто оптимизирует все операции чтения и записи в регистр. Volatile предотвращает это. Объявляя переменную volatile, вы фактически просите компилятор быть настолько неэффективным, насколько это возможно, когда дело доходит до чтения или записи этой переменной. В частности, компилятор должен сгенерировать код для выполнения каждого чтения из энергозависимой переменной, а также каждой записи в энергозависимую переменную, даже если вы записываете ее дважды в строке или читаете и игнорируете результат. Ни одно чтение или запись не может быть пропущено. Другими словами, оптимизация компилятора не допускается в отношении изменчивых переменных.
  2. В двух словах, порядок доступа к изменчивым переменным A и B в объектном коде должен быть таким же, как порядок этих обращений в исходном коде. Компилятору не разрешается изменять порядок доступа к переменным переменным по любой причине. (Подумайте, что может пойти не так, если указанные области памяти были аппаратными регистрами, как в этом случае). Volatile гарантирует вам, что все происходит в последовательности, указанной вами в вашем коде, и никаких переупорядочений не производится.

Чтобы подвести итог - используйте битовую полосу и объявите регистры энергозависимыми.

...