Приведу самый простой пример их использования. Если записать в регистр r0 число 1 (0b00000001), а затем последовательно выполнять 7 инструкций сдвига влево (LSL r0) и 7 вправо (LSR r0), получится эффект «бегущего огня».
Ещё об одном распространённом варианте применения операции сдвига. Вы наверняка заметили из Рисунка 9, что единичный сдвиг влево равноценен умножению на 2, а вправо — делению на 2. Учитывая, что сдвиг исполняется МК быстрее, чем умножение/деление, программисты зачастую используют первую операцию взамен второй, когда скорость работы программы критична.
Операция сдвига влево, наряду с операцией НЕ, используется, помимо прочего, для формирования битовых масок, о чём — ниже.
↑ Оптимизация маски, запись в регистр
Если в вопросе безопасного изменения состояния требуемого бита мы избавились от головных болей, то формирование самой битовой маски всё ещё остаётся хлопотным делом, особенно в случае с ARM, когда нужно без ошибок набрать число из 32 нулей и единиц. Однако, есть приёмы, позволяющие свести процесс формирования двоичного числа любой длины к комфортному минимуму, чем и займёмся.
Раз уж мы стали использовать инструкции МК, познакомимся ещё с одной — записи числа в регистр. На Рисунке 20 приведён пример инструкции записи в регистр r1 маски включения красной лампы для обоих ядер МК.
Мнемоники (LDI и LDR) инструкции схожи, поскольку в их основе лежит одно и то же слово «load». Поэтому впредь наряду с «запись в регистр» будем использовать выражение «загрузка в регистр».
Глядя на число в правой части Рисунка 20. попытайтесь оценить, сколько непередаваемых эмоций может принести вам работа в лоб с 32-битными масками. Вообще то, общепринятые правила позволяют не отражать незначащие разряды, т. е. число 16 можно записать в обоих случаях как 0b10000, а компилятор сам дополнит недостающие слева нули в соответствии с разрядностью МК.
Ну, а если, всё же, все разряды значащие? Тогда никуда не денешься: придётся набирать этих 8- или 32-главых монстров в тексте программы или на калькуляторе, чтобы получить их десятичный (шестнадцатеричный) аналог. В любом случае риск поставить не туда 0 или 1 остаётся.
Попробуем обойтись малой кровью.
Начать следует с того, что компилятор переводит в двоичное представление не только десятичные и шестнадцатеричные числа, попадающиеся на его пути, но и числа, выраженные в форме записи логических операций. Если хотите понять, что это значит на нормальном человеческом языке, вернёмся к Таблице 1 и вспомним, что 4-кратный сдвиг влево числа 1 выражается формой и даёт результат, представленные на Рисунке 21.
Приглядевшись повнимательнее к Рисунку 21, вы заметите две вещи:
1. В результате операции получилось число 16 (0b00010000), т. е. маска для включения красной лампы.
2. Число n в форме записи (т.е. — 4) фактически указывает на номер бита, в котором должен оказаться после операции младший бит сдвигаемого числа (в нашем случае — единица). В этом контексте можно сказать, что результатом операции n-кратного сдвига влево числа 1 всегда будет число, в котором n-й бит равен единице, а остальные — нулю. Имейте в виду, что все эти фокусы не проходят со сдвигом вправо.
Так вот, мы можем в инструкциях МК из Рисунка 20 вместо двоичного представления числа 16 записать форму 4-кратного сдвига влево числа 1:
,
а компилятор, встретив такую конструкцию, заменит её на число, в котором 4-й бит равен единице, а остальные — нулю, т. е. приведёт всё к виду на Рисунке 20.
Как быть с маской для погашения красной лампы — числом 0b11101111? Вы, скорее всего, уже поняли, что оно — инверсия предыдущей маски 0b00010000. Это позволяет использовать конструкцию
при компиляции, которой, с учётом скобок, определяющих последовательность действий, произойдёт следующее:
1. Формирование числа 0b00010000.
2. Инверсия числа из п. 1 в искомую маску 0b11101111.
В случае, если необходимо менять состояние одновременно несколько битов, не затрагивая остальные, соответствующие числа для маски выражается так:
Принимая во внимание скобки, компилятор в первом случае:
1. Сформирует число, в котором k-й бит равен 1, а остальные — 0.
2. Сформирует число, в котором m-й бит равен 1, а остальные — 0.
3. Сформирует число, в котором n-й бит равен 1, а остальные — 0.
4. Применит операцию ИЛИ между числами из п. п.1 и 2., в результате чего получится новое число с единицами в битах k и m и нулями — в остальных.
5. Применит операцию ИЛИ между числами из п. 3 и 4. с получение окончательного числа с единицами в битах k, m и n и нулями — в остальных.
Во втором случае шестым пунктом добавится инверсия числа из п. 5.
Do'stlaringiz bilan baham: |