Tooprogram.ru

Компьютерный справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Флаги в ассемблере

Регистр флагов

Регистр флагов – это очень важный регистр процессора, который используется при выполнении большинства команд. Регистр флагов носит название EFLAGS. Это 32-разрядный регистр. Однако старшие 16 разрядов используются при работе в защищённом режиме, и пока мы их рассматривать не будем. К младшим 16 разрядам этого регистра можно обращаться как к отдельному регистру с именем FLAGS. Именно этот регистр мы и рассмотрим в этом разделе.

Каждый бит в регистре FLAGS является флагом. Флаг – это один или несколько битов памяти, которые могут принимать двоичные значения (или комбинации значений) и характеризуют состояние какого-либо объекта. Обычно флаг может принимать одно из двух логических значений. Поскольку в нашем случае речь идёт о бите, то каждый флаг в регистре может принимать либо значение 0, либо значение 1. Флаги устанавливаются в 1 при определённых условиях, или установка флага в 1 изменяет поведение процессора. На рис. 2.4 показано, какие флаги находятся в разрядах регистра FLAGS.

Бит151413121110987654321
ФлагNTIOPLOFDFIFTFSFZFAFPF1CF

Рис. 2.4. Регистр флагов FLAGS.

Флаг установлен, если значение соответствующего ему бита равно 1.

Флаг сброшен, если значение соответствующего ему бита равно 0.

В таблице 2.6 приведено описание флагов регистра FLAGS.

Таблица 2.6. Описание флагов регистра FLAGS.

БитОбозначениеНазваниеОписание
CFCarry FlagФлаг переноса. Устанавливается в 1, если результат предыдущей операции не уместился в приёмнике и произошёл перенос из старшего бита или если требуется заём (при вычитании). Иначе установлен в 0. Например, этот флаг будет установлен при переполнении, рассмотренном в предыдущем разделе.
11Зарезервирован.
2PFParity FlagФлаг чётности. Устанавливается в 1, если младший байт результата предыдущей команды содержит чётное количество битов, равных 1. Если количество единиц в младшем байте нечётное, то этот флаг равен 0.
3Зарезервирован.
4AFAuxiliary Carry FlagВспомогательный флаг переноса (или флаг полупереноса). Устанавливается в 1, если в результате предыдущей операции произошёл перенос (или заём) из третьего бита в четвёртый. Этот флаг используется автоматически командами двоично-десятичной коррекции.
5Зарезервирован.
6ZFZero FlagФлаг нуля. Устанавливается 1, если результат предыдущей команды равен 0.
7SFSign FlagФлаг знака. Этот флаг всегда равен старшему биту результата.
8TFTrap FlagФлаг трассировки (или флаг ловушки). Он был предусмотрен для работы отладчиков в пошаговом выполнении, которые не используют защищённый режим. Если этот флаг установить в 1, то после выполнения каждой программной команды управление временно передаётся отладчику (вызывается прерывание 1).
9IFInterrupt Enable FlagФлаг разрешения прерываний. Если сбросить этот флаг в 0, то процессор перестанет обрабатывать прерывания от внешних устройств. Обычно его сбрасывают на короткое время для выполнения критических участков программы.
10DFDirection FlagФлаг направления. Контролирует поведение команд обработки строк. Если установлен в 1, то строки обрабатываются в сторону уменьшения адресов, если сброшен в 0, то наоборот.
11OFOverflow FlagФлаг переполнения. Устанавливается в 1, если результат предыдущей арифметической операции над числами со знаком выходит за допустимые для них пределы. Например, если при сложении двух положительных чисел получается число со старшим битом, равным единице, то есть отрицательное. И наоборот.
12
13
IOPLI/O Privilege LevelУровень приоритета ввода/вывода.
14NTNested TaskФлаг вложенности задач.
15Зарезервирован.

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

Сейчас вам будет понятно далеко не всё из того, что описано в таблице 2.4. Например, вы пока не знаете, что такое прерывания. Но всему своё время. Пока просто запомните страницу с описанием регистра флагов и возвращайтесь к ней по мере необходимости.

Системные флаги IOPL предназначены для управления операционной средой в защищённом режиме. Они не используются в прикладных программах.

Внутренние регистры: Регистр флагов

Регистр флагов EFLAGS отражает текущее состояние процессора, многие из его битов устанавливаются после выполнения операций и индицируют тип, полученного результата. Формат регистра флагов приведен на рис. 1.3.

Рис. 1.3. Формат регистра флагов

CF (Флаг переноса, бит 0)

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

PF (Флаг четности, бит 2)

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

AF (Флаг вспомогательного переноса, бит 4)

Флаг вспомогательного переноса фиксирует перенос (заем) из младшей тетрады, т.е. из бита 3 в старшую тетраду при сложении (вычитании). Используется только для двоично-десятичной арифметики, которая оперирует исключительно младшими байтами.

ZF (Флаг нуля, бит 6)

Флаг нуля сигнализирует о получении нулевого (ZF = 1) или ненулевого (ZF = 0) результата операции.

SF (Флаг знака, бит 7)

Флаг знака дублирует значение старшего бита результата, который при использовании дополнительного кода соответствует знаку числа (0 – положительное число, 1 – отрицательное).

TF (Флаг трассировки, бит 8)

При установке флага трассировки TF = 1, микропроцессор переходит в пошаговый режим работы, применяемый при отладке программ, когда автоматически генерируется особая ситуация отладки (#DB) после выполнения каждой команды. Прерывание отладки начнет генерироваться, если прикладная программа установит флаг TF с помощью команд POPF/POPFD или IRET/IRETD.

IF (Флаг разрешения прерываний, бит 9)

При установке флага разрешения прерываний IF = 1, микропроцессор воспринимает (распознает) и соответственно реагирует на запрос прерывания по входу INTR# (внешние маскируемые прерывания). При IF = 0, прерывания по этому входу запрещаются и микропроцессор игнорирует поступающие запросы прерываний.

Значение флага IF не влияет на восприятие внешних немаскируемых прерываний по входу NMI#, а также внутренних программных прерываний, выполняемых по команде INT.

Изменение этого флага командами CLI, STI, POPF/POPFD и IRET/IRETD возможно не всегда и определяется текущими:

При обычной обработке прерываний (CR4.PVI = 0 в защищенном режиме или CR4.VME = 0 в режиме V86), когда IOPL IOPL в защищенном режиме (а также всегда в режиме V86), производится дополнительная проверка доступности соответствующего порта ввода/вывода при любых операциях с ним. Такая проверка использует специальную карту разрешения ввода/вывода, которая расположена в верхней части сегмента состояния задачи TSS и определяет доступность всех портов ввода/вывода. В случае недоступности порта или при попытках разрешения/запрещения прерываний командами CLI, STI, когда CPL > IOPL, процессор генерирует ошибку общей защиты (#GP).

Изменение уровня привилегий ввода/вывода IOPL возможно командами POPF/POPFD и IRET/IRETD в защищенном режиме и только при выполнении команды на уровне привилегий, по крайней мере таком же (а для команды POPF/POPFD только на нулевом), как и текущий уровень привилегий ввода/вывода (режим реальной адресации эквивалентен нулевому уровню привилегий).

При работе в режиме V86 (EFLAGS.VM = 1) IOPL-чувствительными являются команды CLI, STI, POPF/POPFD, PUSHF/PUSHFD, IRET/IRETD, INT n. У каждой из этих команд имеется аналогичная зависимость от текущего значения поля IOPL. Например, команда INT n вызывает генерацию особой ситуации общей защиты (#GP), если IOPL (включается установкой флага CR4.VME = 1 в режиме V86 ), в котором возникает дополнительная специфика для IOPL-чувствительных команд. Во-первых, команда IRET в этом режиме вообще перестает быть IOPL-чувствительной и не генерирует особую ситуацию общей защиты (#GP) при IOPL устанавливаются равными 3, а бит IF записывается из текущего значения флага VIF.

В ранних моделях процессоров до Intel286 (8086/8088, Intel186) биты 12 и 13 регистра флагов FLAGS, соответствующие полю IOPL, считались зарезервированными, а их значения всегда были равны единице. В процессоре Intel286 в режиме реальной адресации невозможно изменять значения этих битов — они всегда остаются нулевыми (они сбрасываются в момент инициализации процессора), а вот более поздние модели процессоров, начиная с Intel386, такого ограничения уже не имеют, то есть поле IOPL можно изменять и в режиме реальной адресации. Указанная особенность использовалась в процедурах идентификации процессоров вплоть до появления команды CPUID в процессоре Pentium.

NT (Вложенная задача, бит 14: Intel286 …)

Процессор устанавливает и проверяет флаг вложенной задачи для контроля за прерванными задачами (задачи, во время исполнения которых имело место прерывание) и при вызове процедур. Флаг NT влияет на действия, производимые командой IRET/IRETD. Этот флаг может быть изменен командой POPF/POPFD и IRET/IRETD. Некорректные изменения этого флага могут привести к возникновению различных особых ситуаций в прикладных программах.

Читать еще:  К основным единицам системы си относятся

RF (Флаг возобновления, бит 16: Intel386 …)

Флаг возобновления RF временно выключает обработку особых ситуаций отладки (DB#) для того, чтобы команда, вызвавшая такую ситуацию, могла быть перезапущена и не стала бы причиной новой особой ситуации. Отладчик устанавливает этот флаг командой IRETD при возврате в прерванную программу. Команды POPF, POPFD (в режиме V86) и IRET на этот флаг не влияют.

VM (Виртуальный режим, бит 17: Intel386 …)

Установка флага виртуального режима VM переключает процессор в режим виртуального-8086 (специальный случай защищенного режима).

AC (Режим контроля выравнивания, бит 18: Intel486 …)

Установка флага режима контроля выравнивания (AC = 1) и бита AM регистра CR0 (CR0.AM = 1) включает контроль выравнивания при обращении к памяти. При этом только при текущем уровне привилегий равном 3 (CPL = 3) генерируется особая ситуация контроля выравнивания (#AC), если происходит обращение к невыровненному операнду (например, к слову по нечетному адресу или к двойному слову по адресу не кратному четырем).

Таблица 3.5. Условия контроля выравнивания

Флаги в ассемблере

Методики условных вычислений на самом нижнем (двоичном) уровне основаны на четырех основных операциях двоичной алгебры: И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и НЕ. Эти операции положены в основу работы логических схем компьютера, а также его программного обеспечения.

В системе команд процессоров семейства x 86 предусмотрены команды AND, OR, XOR, NOT, TEST и ВT, выполняющие перечисленные выше булевы операции между байтами, словами и двойными словами (табл.1).

Таблица 1. Логические команды процессора.

Выполняет операцию логического И между двумя операндами

Выполняет операцию логического ИЛИ между двумя операндами

Выполняет операцию исключающего ИЛИ между двумя операндами

Выполняет операцию логического отрицание (НЕ) единственного операнда

Выполняет операцию логического И между двумя операндами, устанавливает соответствующие флаги состояния процессора, но результат операции не записывается вместо операнда получателя данных

Копирует бит операнда получателя, номер n которого задан в исходном операнде, во флаг переноса ( CF ), а затем, в зависимости от команды, тестирует, инвертирует, сбрасывает или устанавливает этот же бит операнда получателя

8.2. Флаги состояния процессора.

Каждая команда, рассмотренная на этой лекции, влияет на состояние флагов процессора. Ранее вы узнали что, что после выполнения арифметических и логических команд процессор устанавливает соответствующее значение флагов нуля (ZF), переноса (CF), знака (ZF) и др., как описано ниже.

· Флаг нуля (Zero flag, или ZF) устанавливается, если при выполнении арифметической или логической операции получается число, равное нулю (т.е. все биты результата равны 0).

· Флаг переноса (Carry flag, или CF) устанавливается в случае, если при выполнении беззнаковой арифметической операции получается число, разрядность которого превышает разрядность выделенного для него поля результата.

· Флаг знака (Sign flag, или SF) устанавливается, если при выполнении арифметической или логической операции получается отрицательное число (т.е. старший бит результата равен 1).

· Флаг переполнения (Overflow flag, или OF) устанавливается в случае, если при выполнении арифметической операции со знаком получается число, разрядность которого превышает разрядность выделенного для него поля результата.

· Флаг четности (Parity flag, или PF) устанавливается в случае, если в результате выполнения арифметической или логической операции получается число, содержащее четное количество единичных битов.

Команда AND выполняет операцию логического И между соответствующими парами битов операндов команды и помещает результат на место операнда получателя данных:

AND получатель, источник

Существуют следующие варианты команды AND:

Команда AND может работать с 8-, 16- или 32-разрядными операндами, причем длина у обоих операндов должна быть одинаковой. При выполнении операции поразрядного логического И значение результата будет равно 1 только в том случае, если оба бита пары равны 1. В табл. 2 приведена таблица истинности для операции логического И.

Таблица 2. Таблица истинности для операции логического И.

Команда AND обычно используется для сброса отдельных битов двоичного числа (например, флагов состояния процессора) по заданной маске. Если бит маски равен 1, значение соответствующего разряда числа не изменяется (в этом случае говорят, что разряд замаскирован), а если равен 0 — то сбрасывается. В качестве примера на рис. 8.1 показано, как можно сбросить четыре старших бита 8 -разрядного двоичного числа.

Для выполнения этой операции можно воспользоваться двумя командами:

mov al, 00111011b

and al, 00001111b

Рис. 8.1. Сброс битов по маске с помощью команды AND .

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

Флаги. Команда AND всегда сбрасывает флаги переполнения (OF) и переноса (CF). Кроме того, она устанавливает значения флагов знака (SF), нуля (ZF) и четности (PF) в соответствии со значением результата.

Команда OR выполняет операцию логического ИЛИ между соответствующими парами битов операндов команды и помещает результат на место операнда получателя данных:

OR получатель, источник

В команде OR используются аналогичные команде AND типы операндов:

Команда OR может работать с 8-, 16- или 32-разрядными операндами, причем длина у обоих операндов должна быть одинаковой. При выполнении операции поразрядного логического ИЛИ значение результата будет равно 1, если хотя бы один из битов пары операндов равен 1. В табл. 3 приведена таблица истинности для операции логического ИЛИ.

Таблица 3. Таблица истинности для операции логического ИЛИ.

Команда OR обычно используется для установки в единицу отдельных битов двоичного числа (например, флагов состояния процессора) по заданной маске. Если бит маски равен 0, значение соответствующего разряда числа не изменяется, а если равен 1 — то устанавливается в 1. В качестве примера на рис. 8.2 показано, как можно установить четыре младших бита 8-разрядного двоичного числа, выбрав в качестве маски число 0Fh. Значение старших битов числа при это не меняется.

Рисунок 8.2. Установка битов по маске с помощью команды OR .

С помощью команды OR можно преобразовать двоичное число, значение которого находится в диапазоне от 0 до 9 в ASCII-строке. Для этого нужно установить в единицу биты 4 и 5. Например, если в регистре AL находится число 05h, то чтобы преобразовать его в соответствующий ASCII-код, нужно выполнить операцию OR регистра AL с числом 30h. В результате получится число 35h, которое соответствует ASCII-коду цифры 5 (рис. 8.3).

Рис. 8.3. Преобразование двоичного числа в ASCII-код

с помощью команды OR.

На языке ассемблера подобное преобразование можно записать так:

mov dl , 5 ; Двоичное число

or dl , 30 h ; Преобразуем в ASCII-код

Флаги. Команда OR всегда сбрасывает флаги переполнения (OF) и переноса (CF). Кроме того, она устанавливает значения флагов знака (SF), нуля (ZF) и четности (PF) в соответствии со значением результата. Например, с помощью команды OR можно определить, какое значение находится в регистре (отрицательное, положительное или нуль). Для этого вначале нужно выполнить команду OR, указав в качестве операндов один и тот же регистр, например:

а затем – проанализировать значение флагов, как показано в табл. 4.

Таблица 4. Определение значения числа по флагам состояния процессора.

Команда XOR выполняет операцию ИСКЛЮЧАЮЩЕГО ИЛИ между соответствующими парами битов операндов команды и помещает результат на место операнда получателя данных:

XOR получатель, источник

В команде XOR используются аналогичные командам AND и OR типы операндов:

Команда XOR может работать с 8-, 16- или 32-разрядными операндами, причем длина у обоих операндов должна быть одинаковой. При выполнении операции поразрядного ИСКЛЮЧАЮЩЕГО ИЛИ значение результата будет равно 1, если значения битов пары операндов различны, и 0 — если значения битов равны. В табл. 5 приведена таблица истинности для операции логического ИСКЛЮЧАЮЩЕГО ИЛИ.

Таблица 6.5. Таблица истинности для операции ИСКЛЮЧАЮЩЕГО ИЛИ.

Как следует из таблицы, при выполнении операции ИСКЛЮЧАЮЩЕГО ИЛИ с нулевым битом получается исходное значение бита, а с единичным битом — значение исходного бита инвертируется.

Операция ИСКЛЮЧАЮЩЕГО ИЛИ обладает свойством реверсивности — если ее выполнить дважды с одним и тем же операндом, то значение результата инвертируется. Как показано в табл. 6, если два раза подряд выполнить операцию ИСКЛЮЧАЮЩЕГО ИЛИ между битами X и Y , то в результате получится исходное значение бита X .

Читать еще:  Справочник по ассемблеру

Таблица 6. Демонстрация свойства реверсивности операции ИСКЛЮЧАЮЩЕГО ИЛИ.

Флаги. Команда XOR всегда сбрасывает флаги переполнения (OF) и переноса (CF). Кроме того, она устанавливает значения флагов знака (SF), нуля (ZF) и четности (PF) в соответствии со значением результата.

Проверка флага четности (PF). Флаг четности позволяет узнать, какое количество единичных битов (четное или нечетное) содержится в младшем байте результата выполнения логической или арифметической команды. Если этот флаг установлен, значит, в результате получилось четное количество единичных битов, а если сброшен, то нечетное. Количество единичных битов можно проверить, не меняя значения результата. Для этого сначала нужно выполнить команду XOR с нулевым значением (т.е. с числом, все биты которого равны нулю), а затем проверить флаг четности:

mov al , 10110101 b ; Число содержит нечетное (5) количество единиц битов

xor al , 0 ; Поэтому флаг четности ( PF ) не устанавливается ( PO )

mov al , 11001100 b ; Число содержит четное (4) количество единиц битов

xor al , 0 ; Поэтому флаг четности ( PF ) устанавливается ( PE )

В отладчиках часто для обозначения четного количества единиц в полученном результате используется аббревиатура РЕ (т.е. Parity Even), а для нечетного — РО (т.е. Parity Odd).

Четность в 16-разрядных словах. Выше мы уже говорили о том, что флаг четности PF устанавливается в зависимости от количества единиц, содержащихся в младших восьми разрядах результата. Для выполнения контроля по четности 16-разрядных операндов, нужно выполнить команду XOR между старшим и младшим байтами этого числа:

mov ax , 64 C 1 h ; 0110 0100 1100 0001

xor ah , al ; Флаг четности ( PF ) устанавливается ( PF )

Таким образом, 16-разрядный операнд разбивается на 2 группы по 8 битов. При выполнении команды XOR единичные биты, находящиеся в соответствующих позициях двух 8-разрядных операндов, не будут учитываться, поскольку соответствующий бит результата равен нулю. Эта команда удаляет из результата любые пересекающиеся единичные биты двух 8-разрядных операндов и добавляет в результат непересекающиеся единичные биты. Следовательно, четность полученного нами 8-разрядного операнда будет такой же, как и четность исходного 16-разрядного числа.

А если нам нужно оценить четность 32-разрядного числа? Тогда, пронумеровав его байты, соответственно, В, В1, В2 и В3, четность можно определить по следующей формуле: В XOR В1, XOR B 2 XOR В3.

Команда NOT позволяет выполнить инверсию всех битов операнда, в результате чего получается обратный код числа. В команде допускаются следующие типы операндов:

Например, обратный код числа F 0 h равен 0 Fh :

mov al, 11110000b

not al ; AL = 00001111b

Флаги. Команда NOT не изменяет флаги процессора.

8.7. Команда TEST.

Команда TEST выполняет операцию поразрядного логического И между соответствующими парами битов операндов и, в зависимости от полученного результата, устанавливает флаги состояния процессора. При этом, в отличие от команды AND, значение операнда получателя данных не изменяется. В команде TEST используются аналогичные команде AND типы операндов. Обычно команда TEST применяется для анализа значения отдельных битов числа по маске.

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

test al,00001001b ; Тестируем биты 0 и 3

Как показано в приведенных ниже примерах, флаг нуля ZF будет установлен только в том случае, если все тестируемые биты сброшены:

0 0 1 0 0 1 0 1

0 0 0 0 1 0 0 1

0 0 0 0 0 0 0 1

0 0 1 0 0 1 0 0

0 0 0 0 1 0 0 1

0 0 0 0 0 0 0 0

Флаги. Команда TEST всегда сбрасывает флаги переполнения (OF) и переноса (CF). Кроме того, она устанавливает значения флагов знака (SF), нуля (ZF) и четности (PF) в соответствии со значением результата выполнения операции логического И (как и команда AND).

Команда СМР вычитает исходный операнд из операнда получателя данных и, в зависимости от полученного результата, устанавливает флаги состояния процессора. При этом, в отличие от команды SUB, значение операнда получателя данных не изменяется.

СМР получатель, источник

В команде СМР используются аналогичные команде AND типы операндов.

Флаги. Команда СМР изменяет состояние следующих флагов: CF (флаг переноса), ZF (флаг нуля), SF (флаг знака), OF (флаг переполнения), AF (флаг служебного переноса), PF (флаг четности). Они устанавливаются в зависимости от значения, которое было бы получено в результате применения команды SUB. Например, как показано в табл. 7, после выполнения команды СМР, по состоянию флагов нуля (ZF) и переноса (CF) можно судить о величинах сравниваемых между собой беззнаковых операндов.

Таблица 7. Состояние флагов после сравнения беззнаковых операндов с помощью команды СМР.

Электроника для всех

Блог о электронике

AVR. Учебный курс. Флаги и условные переходы

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

SREG это регистр состояния ядра. Он так называется Status Register. В этом регистре находится независимых битов — флажков. Которые могут быть либо 1 либо 0, в зависимости от выполненных в прошлом операций.

И вот по тому какие флаги стоят, можно понять что произошло с процессором и что нам дальше делать.

Например, если флаг Z (Zero) выставлен в 1, значит в ходе вычисления предыдущей математической операции в результате образовался ноль.

А если выставлен флаг С (Carry — заем, перенос), то мы из меньшего числа отняли большее, или же прибавили такое число, что результат стал больше 255.

А теперь подробней по каждому флагу.

  • I — флаг разрешения прерываний. Когда установлен в 1 — прерывания разрешены.
  • T — пользовательский флаг. Можно юзать по своему назначению.

Кроме того, есть две команды которые позволяют в этот бит записать любой бит любого из 32 регистров общего назначения R0-R31 (далее буду их звать РОН). Это команды BLD Rn,bit и BST Rn,bit

Число в дополнительном коде с заемом — самая естественная форма представления числа во вселенной! Вот возьмем, например, число -61 как его получить? Ну не знаем мы про отрицательные числа! Просто! Вычтем его из нуля 00 — 61 = 39 Во как! Заняли из старшего разряда! Не похоже, да? Хорошо, проверим столбиком:
61
+
39

00 А единичка не влезла в разрядность!

ЧТД. (с) Лохов С.П. (Наш преподаватель по ассемблеру в универе)

Вот двоичный доп код работает точно по такому же принципу. А в процессоре есть команды для перевода числа из в доп код за одну команду.

Флаги, кроме автоматической установки, можно устанавливать и сбрасывать вручную. Для этого есть команды

SE* для установки и CL* для сброса. Вместо звездочки подставляется нужный флаг, например, CLI — запрет прерываний.

В даташите, в разделе Instruction Set Summary, написано какая команда что делает и на какие флаги влияет.

INC Rd Increment Rd = Rd + 1 Z,N,V DEC Rd Decrement Rd = Rd − 1 Z,N,V TST Rd Test for Zero or Minus Rd = Rd AND Rd Z,N,V CLR Rd Clear Register Rd = Rd XOR Rd Z,N,V SER Rd Set Register Rd = $FF None

Команда INC прибавляет к регистру 1, но несмотря на то, что она может добить регистр до переполнения, флаг переполнения С она не ставит. Такая особенность.

Зато она ставит флаги нуля, отрицательного значения и переполнения доп кода. Как инкремент может дать нуль? Элементарно, прибавив к -1 +1. Минус 1 в двоичной знаковой арифметике = FF. FF+1=1 00 ,но 1 не влезла в разрядность, поэтому 00 Логично же? 🙂

Или хотим мы, например, узнать в каком регистре число больше в R17 или R18

Нет ничего проще — к нашим услугам команда CP (нет, не детское порно, а Compare). Эта команда, у себя в уме, из R17 вычитает R18 при этом содержимое регистров не меняется, а меняются только флаги. И если, например, выскочил флаг С, значит при R17-R18 произошел заем, а значит R18 больше R17. Если флаг С не появился, то значит R17 больше чем R18. А коли у нас выскочил нуль, то значения равны. Есть еще команда CPI Rn,### работает также, но сравнивает регистр (только старшую группу) с произвольным числом. Используется чаще.

А потом смотрим флаги. И дальше в ход вступают команды условных переходов из группы BRANCH (ветвление). BR**

И вот в этом месте товарищей из ATMEL надо хватать за ноги и бить головой об стену. Потому что я не понимаю на кой хрен было так все запутывать, изобретая команды которых реально нет?

Суди сам. Флагов у нас 8, соответственно должно быть 16 возможных бранчей. 8 по условию — флаг есть, 8 по условию — флага нет. Бранчевых команд же у нас аж 20 штук.

BRBC # переход если бит # в регистре SREG=0 BRBS # переход если бит # в регистре SREG=1 BRCS переход если С=1 BRCC переход если С=0 BREQ переход если Z=1 BRNE переход если Z=0 BRSH переход если С=0 BRLO переход если С=1 BRMI переход если N=1 BRPL переход если N=0 BRGE переход если S=0 BRLT переход если S=1 BRHC переход если H=0 BRHS переход если H=1 BRTC переход если T=0 BRTS переход если T=1 BRVS переход если V=1 BRVC переход если V=0 BR >

Однако, если глубоко копнуть, поглядеть на реальные коды команд, то окажется, что BRCS=BRLO и BRCC=BRSH — у них вообще одинаковый код.

А таких команд как BRBS # и BRBC # вообще не существует. Это всего лишь иносказательная запись всех остальных бранчей, в зависимости от номера бита #.

А таких команд синонимов там дофига 🙂
Так что гордое «131 Powerful Instructions – Most Single-clock Cycle Execution» на самом деле является не более чем гнилым маркетинговым высером. Нет там 131 команды! Есть 131 мнемоника, а это несколько разные вещи. Потому как ты помидор не обзови — картошкой он от этого не станет.

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

Может быть, но как по мне — только ситуацию запутывают. Из-за этого я после ассемблера С51 долго плевался на систему команд AVR, потом привык и ничо так, вкатило.

Итак, как работает любой из бранчей (да, тому кто придумал переименовать родимый J** в BR** я тоже ежедневно посылаю лучи поноса, надеюсь в сортире он себе уже кабинет обустроил).

Проверяется условие и если оно верное делается переход.

Например, на входе у нас значение.

  • Если значение = 1, то делаем действие А
  • Если значение = 2, то делаем действие Б
  • А если значение меньше 13, то делаем действие ЦЭ
  • Во всех остальных случаях не делаем ничего

Нет ничего проще, пусть значение приходит через регистр R16

CPI R16,1 ; Сравниваем R16 с 1 BREQ ActionA ; Переход если равно (EQual, Z=1) ; Если не равно, то идем дальше CPI R16,2 ; Сравниваем R16 с 2 BREQ ActionB ; Переход если равно ; Если не равно, то идем дальше CPI R16,13 ; Сравниваем R16. т.е. R16-13 BRCS ActionC ; Если возник перенос, значит R16 меньше 13 ; Если не возник — идем дальше RJMP NoAction ; Переход на выход ActionA: NOP NOP ; Делаем наш экшн NOP RJMP NoAction ; Выходим, чтобы не влезть в ActionB ActionB: NOP NOP ; Делаем наш экшн NOP RJMP NoAction ; Выходим, чтобы не влезть в ActionC ActionC: NOP NOP ; Делаем наш экшн NOP NoAction: NOP ; Вместо NOP, разумеется, должны быть какие-нибудь полезные команды.

Сложно? Вот и я думаю, что делать нефиг :))))) Ничуть не сложней чем на Си забабахать из if then конструкцию или switch-case какой-нибудь.

Бег по граблям
У команд BR*** есть правда весьма ощутимое западло. Дальнобойность их составляет всего 63 команды. Т.е. это относительный переход. Поначалу ты этого не заметишь — короткая программа обычно не допускает переходов дальше 63.

Но вот, со временем, твоя программа распухнет, появится дофига кода и дальности бранча перестанет хватать. Вроде бы все работало, а добавил пару команд — и компилятор начал ругаться злыми словами — Error out of range или что то в этом духе. Как быть?

Перехватываться через промежуточные переходы. Т.е. находим ближайший к нам безусловный переход за который контроллер, как бы не старался залезть не сможет.

ActionA: NOP NOP NOP RJMP NoAction NOP ; То есть если я вот тут поставлю островок ; то он никогда не выполнится. Т.к. сверху ; Процессор перепрыгнет сразу по RJMP ; А снизу вход будет сразу же на ActionB ActionB: NOP NOP NOP RJMP NoAction И вот, в этом островке, мы создаем капсулу телепортер такого вида: ActionA: NOP NOP NOP RJMP NoAction ;———————————— Near: JMP FarFar_away ;———————————— ActionB: NOP NOP NOP RJMP NoAction

Т.е. бранчу теперь достаточно дострелить до островка Near, а там дальнобойный JMP зашлет его хоть в бутсектор на другой конец флеша.

В случае большой программы, чтобы не плодить островки, его лучше сделать один, сразу после пачки CP.

Test & Skip
Кроме Branch‘ей есть еще один тип команд: проверка — пропуск.
Работает она по принципу “Проверяем условие, если справедливо — пропускаем следующую команду”
Запомнить просто, первая буква это Skip — пропуск. Вторая условие — С=Clear, т.е. 0 S=Set, т.е. 1. Соответственно S**C пропуск если сброшено. S**S пропуск если установлено.

Указываешь ей какой РОН, и какой номер бита в этом регистре надо проверить. И если условие верное, то следующая команда будет пропущена.

SBRC R16,3 ; Если бит 3 в регистре R16 = 0, то прыжок через команду, на NOP RJMP bit_3_of_R16_Not_Zer0 NOP SBRS R16,3 ; Если бит 3 в регистре R16 = 1, то прыжок через команду, на NOP RJMP bit_3_of_R16_Zer0 NOP

SBIC/SBIS Но проверяет она не биты регистров РОН, а биты регистров периферийных устройств. Те самые,что идут в памяти между блоком РОН и оперативкой. Но есть у ней ограничение — она может проверить только первые 1F регистров ввода вывода. Если заглянешь в m16def.inc (для мега16, для других МК в их файл дефайнов)

То увидишь там это:

.equ UBRRH = 0x20 .equ UCSRC = 0x20 .equ EEARL = 0x1e AssemblerAVRПрограммированиеФлаги

48 thoughts on “AVR. Учебный курс. Флаги и условные переходы”

Начал изучать прерывания опять же на С. И вот какое дело, обработчик прерываний у меня срабатывает когда на линии PB5 меняется уровень, в обработчеке у меня простой код если PB5 = 0 и PB6= 0 то пишу ноль, исли PB6=1 пишу еденицу. Так вот за 100 ms
у меня проходит 100 едениц и нулей. Суть в чем если я просто посылаю по UART, то принимаю все биты. Но стоит мне записать биты в массив, а потом перевести их в число, как на выходе я получаю какую то биллиберду. Я вот думаю успевает ли выполнится обработчик прерывания, до возникновения другого прерывания? Или может я что не так делаю.

Тьфу ты не туда написал, как удалить не знаю ((

Посчитай такты за который выполняется обработчик прерывания. Прикинь время на выполнение. С учетом кварца. Потом позырь на то с какой скоростью у тебя прерывания вызваются — нет ли затыка.

Что то совсем у меня худо с прерываниями. Такое ощущений что программа постоянно перезапускается. Вот допустим в главной функции если после всей инициализации поставить UDR = ‘S’, при включении у меня, валится это S всех щелей. Что такое немогу ни как разобратся, отключаю прерывания, все нормально работает. Но вроде обработчик не вызывается до тех пор пока уровень не изменится на ножке PB5. Чудеса да и только)

чего-то я не пойму, флаг S и N одно и то же? ведь оба знак показывают
S это что главный флаг знака, а V и N частные случаи?
как вообще определить отрицательность числа по двоичноми коду, ведь может быть положительное число с 1 в 7 бите

По одним только флагам никогда ничего сказать определенно нельзя.

Только в контексте предыдущей выполненной команды. А вот уже она выставляет флаги в зависимости от результатов операции.

Знак у двоичного числа тоже никак нельзя определить в отрыве от контекста.

Ссылка на основную публикацию
Adblock
detector