Цель последующего использования операторов регистров OR и AND в регистрах
В коде C и C++, в частности, для встроенных систем, я регулярно сталкиваюсь с заданиями, которые принимают следующую форму:
A |= B;
A &= B;
Не уверен, если это уместно, но A и B являются регистрами здесь. Смотрите пример здесь: http://processors.wiki.ti.com/index.php/Interrupt_Nesting_on_C28x Появляются следующие строки:
IER |= 0x002;
IER &= 0x002;
Тем не менее, эти последующие назначения кажутся идентичными одному назначению
A = B;
За исключением того факта, что теоретически первое может быть в некоторых случаях прервано между обеими линиями, но это, похоже, не играет важной роли в большинстве кодов.
Есть ли преимущество в использовании первого по сравнению со вторым, или есть другое отличие, которое я не вижу?
4 ответа
Конечно, последовательность из двух следующих команд:
A |= 0x02;
A &= 0x02;
Идентично:
A = 0x02;
Если только A
это не переменная, а аппаратный регистр. В этом случае вам нужно обратиться к руководству по MCU/CPU (или подключенному периферийному устройству), чтобы проверить, почему именно эта последовательность требуется.
ОБНОВИТЬ
Переменная против аппаратного регистра
В комментариях выше OP спросил, как отличить переменные от регистров.
Это довольно просто. Все, что вам нужно сделать, это посмотреть на определение. В то время как типичная переменная будет определена как что-то вроде:
unsigned char A;
Определение аппаратного регистра будет выглядеть примерно так:
#define A (*(volatile uint16_t *)(0x1234))
Вот, A
определяется как значение аппаратного регистра, сопоставленного с адресом в 0x1234
, Каждый микроконтроллер или процессор имеет свой собственный уникальный набор аппаратных регистров, и он будет различаться не только между различными типами архитектур и моделей, но и между разными производителями. Если исходный код плохо документирован, единственный способ узнать, о чем идет речь о конкретном аппаратном регистре, - заглянуть в таблицу технических данных. Кроме того, некоторые усовершенствованные архитектуры могут отображать аппаратные регистры от некоторых периферийных устройств в адресное пространство ЦП, так что можно получить доступ к аппаратным регистрам внешних компонентов таким же образом.
Обратите внимание volatile
ключевое слово. Из вики:
Это ключевое слово не позволяет оптимизирующему компилятору оптимизировать последующее чтение или запись и, таким образом, неправильно повторно использовать устаревшее значение или пропускать записи. Изменчивые значения в основном возникают в аппаратном доступе (ввод-вывод с отображением в память), где чтение или запись в память используется для связи с периферийными устройствами, а также в потоке, где другой поток может изменить значение.
Если переменная является аппаратным регистром, как представляется, переменные volatile
, Запись битов с последующей очисткой, это не то же самое, что просто запись значений.
Аппаратные регистры не всегда ведут себя как простые переменные RAM. Не уверен, что запись нуля немного очищает. В частности, регистры флагов и состояний могут иметь определенные условия, такие как "этот флаг сбрасывается путем записи в бит с последующим чтением в регистр". В других случаях флаги можно очистить, просто прочитав регистр.
Это очень распространено для регистров флага / статуса пользователя для периферийных устройств связи, таких как SPI или UART.
Кроме того, обратите внимание, что нет никакой гарантии, что A = B;
приводит к одной инструкции. Скорее всего, это приводит к: "загрузить B", "хранить B в A". Если вам нужно, чтобы вещи были атомарными, вы всегда должны дизассемблировать код, чтобы увидеть, чем вы в действительности оказались.
Возможно, существуют обстоятельства для аппаратных регистров, где необходимы определенные последовательности битов, которые имеют "особое" поведение, хотя трудно понять, что это может быть в данном конкретном случае.
Не стоит недооценивать вероятность того, что код, который вы найдете в Интернете, будет чепухой, даже если он с сайта производителя чипов. Глядя на документацию, кажется, что автор прочитал это:
и был сбит с толку ссылкой на ИЛИ IER/ И IER - они действительно включают и отключают прерывания, но так же делает инструкцию MOV IER атомарно. что будет делать прямое назначение.
На этой же странице есть более поздний пример:
IER |= M_INT2;
IER &= MINT2; // Set "global" priority
Где операнды различаются; так что, возможно, автор просто имеет обобщенную модель и придерживается ее.
A |= 0x02; такой же, как A = 0x02;
A &=0x2 равно нулю (предположение A = 0)
если и A, и B являются однобайтовыми значениями. Но есть случаи, когда оно не равно одному байту, в этих сценариях все эти операторы имеют разные свойства.
Я беру пример 4-байтового значения.
A = 0x12345600
A | = 0x2 равняется 0x12345602, тогда как A &=0x2 равняется 0x12345600, а A = 0x2 равняется 0x00000002