Цель последующего использования операторов регистров 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

Другие вопросы по тегам