Подтвердить что ты не робот

Почему Read-Modify-Write необходима для регистров встроенных систем?

Я читал http://embeddedgurus.com/embedded-bridge/2010/03/different-bit-types-in-different-registers/, в котором говорилось:

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

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

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

Итак, почему read-modify-write? Это все еще необходимо?

4b9b3361

Ответ 1

Это в некоторой степени зависит от архитектуры вашего конкретного встроенного устройства. Я приведу три примера, которые охватывают общие случаи. Однако основная его суть состоит в том, что принципиально ядро ​​ЦП не может работать непосредственно на регистрах устройств ввода-вывода, за исключением того, что они считывают и записывают их побайтно или даже по-словски.

1) серия 68HC08, 8-разрядный автономный микроконтроллер.

Это включает в себя инструкцию "бит бит" и "бит чистую". Они, если вы внимательно прочитаете руководство, фактически сами выполняете цикл чтения-изменения-записи самостоятельно. У них есть преимущество в том, что они являются атомарными операциями, поскольку в качестве отдельных инструкций они не могут быть прерваны.

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

2) ARM или PowerPC, обычные 32-разрядные RISC-процессоры (часто встречающиеся также в микроконтроллерах высокого класса).

Они не содержат никаких инструкций, которые могут одновременно обращаться к памяти и выполнять вычисление (и/или) сразу. Если вы пишете в C:

*register |= 0x40;

он превращается в следующую сборку (для этого примера PowerPC, r8 содержит адрес регистра):

LBZ r4,r8
ORI r4,r4,#0x40
STB r4,r8

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

3) IA32 (x86) и AMD64. Почему вы использовали их для "встроенных", выходят за рамки меня, но они находятся на полпути между двумя другими примерами.

Я забываю, есть ли в x86 бит-бит и бит-очистка в одной инструкции. Если нет, то см. Раздел RISC выше, он просто принимает только две команды вместо трех, потому что x86 может загружать и изменять в одной инструкции.

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

Честность в том, что x86 (в отличие от HC08) может быть прерван на шине памяти в середине транзакции мастером шины, а не только обычным прерыванием CPU. Таким образом, вы можете вручную добавить префикс LOCK к инструкции, которая должна выполнить несколько циклов памяти для завершения, как в этом случае. Вы не получите это от простого C, хотя.

Ответ 2

Дело в том, что вы не хотите изменять другие биты в регистре, которые должны знать, что они есть, прежде чем писать что-то. Следовательно, read/modiy/write. Обратите внимание: если вы используете оператор C, например:

*pRegister |= SOME_BIT;

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

Обратите внимание, что регистры аппаратного обеспечения с отображением памяти обычно помечены как volatile специально, так что эти оптимизации не могут выполняться (в противном случае многие процедуры регистрации оборудования не будут работать должным образом).

Наконец, иногда есть аппаратная поддержка регистров, которые специально устанавливают или очищают биты в аппаратном обеспечении, не требуя последовательности чтения/изменения/записи. Некоторые микроконтроллеры Atmel ARM, с которыми я работал, имеют это с конкретными регистрами, которые очищают или устанавливают биты на аппаратном уровне только те биты, которые устанавливаются при записи в регистр (оставляя только один незаписанный бит). Кроме того, процессор Cortex M3 ARM поддерживает доступ к одному биту (для чтения или записи) в памяти или в аппаратных регистрах через доступ к конкретному адресному пространству с помощью метода, который они называют 'бит-полосатость'. Алгоритм битовой полосы выглядит с первого взгляда сложным, но на самом деле это просто простая арифметика для сопоставления смещения бит в одном адресе с другим "конкретным" адресом.

В любом случае, суть в том, что есть некоторые процессоры, где вы можете обойтись без серии read/modify/write, но это отнюдь не универсально.

Ответ 3

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

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

Ответ 4

Современные процессоры могут либо устанавливать, либо очищать биты с одной инструкцией. Однако эти инструкции не могут одновременно устанавливаться и очищаться. Бывают случаи, когда некоторые биты порта ввода-вывода все должны меняться вместе и не влиять на другие биты. Пока последовательность чтения-модификации-записи не может быть нарушена, проблем нет.

Ситуация, когда r-m-w может стать проблемой, требует трех условий.

  • Переменная должна быть доступна глобально, например, порт IO или регистр специальных функций или глобально определенная переменная.

  • Глобальная переменная может быть изменена в функции, которая может быть выгружена.

  • То же глобальная переменная изменяется при обслуживании предварительного использования.

Единственный способ разрешить несколько битовых модификаций с использованием неатомной последовательности r-m-w - это защита последовательности инструкций путем отключения прерывания для процедуры обслуживания прерываний, которая также может изменять переменную или регистр. Это похоже на эксклюзивный доступ к цифровым ресурсам, таким как LCD или последовательный порт.

Ответ 5

Когда я хочу установить/очистить бит, я всегда просто или /nand с битовой маской.

Для некоторых регистров это достаточно хорошо. В этом случае прошивка процессора все еще будет делать чтение-изменение-запись.

На мой взгляд, это решает любой потокобезопасный проблемы, так как я полагаю, что установка (либо путем присвоения, либо mask) регистр занимает всего один цикл.

Если вы позволяете прошивке процессора делать чтение-модификацию-запись для вас, очевидно, что она включает в себя как минимум цикл чтения и цикл записи. Теперь большинство процессоров не будут прерывать эту команду посередине, поэтому ваш поток выполнит всю эту инструкцию до того, как ваш процессор потоков проверит прерывания, но если вы не заблокировали шину, тогда другие процессоры могут изменить один и тот же регистр. Ваша нить и другие потоки все равно могут перемещаться друг над другом.