Что такое флаг процессора
Регистр флагов содержит различные биты, отражающие текущее состояние процессора и частично управляющие его работой.
История
Регистр флагов был уже в первом 16-разрядном микропроцессоре Intel — 8086. Он носил имя FLAGS и имел длину 16 бит. Появление микропроцессора 80286 добавило в регистр FLAGS бит NT и битовое поле IOPL, однако сам регистр оставался 16-разрядным.
С выходом микропроцессора 80386 регистр был расширен до 32 бит и стал называться EFLAGS. В нём появились ещё два дополнительных бита: VM и RF. В последующих поколениях 32-разрядных микропроцессоров были добавлены биты AC, VIF, VIP и ID. Тем не менее, сохранялась полная совместимость «снизу вверх»: любая старая программа, которая корректно работала с регистром EFLAGS, не модифицируя «неизвестные» ей биты, оставалась работоспособной и на последующих процессорах.
Расширение разрядности процессора до 64 бит, первоначально произведённое компанией AMD (технология AMD64) и позже скопированное Intel (EM64T), удвоило и размер регистра флагов, получившего название RFLAGS. Однако его старшая половина (биты с 32-го по 63-й включительно) пока не используется и является зарезервированной, поэтому формат «значащей» части RFLAGS полностью совпадает с форматом EFLAGS.
Зачем нужны флаги
Главная задача флага в программировании — показать, что что-то изменилось и что нужно на это отреагировать. Например:
- кубик вылез за игровое поле и нужно остановить игру;
- пользователь слишком много раз ввёл неправильный пароль — тогда программа поставит флаг и в ближайший час не пустит его в систему;
- процедура закончила рисовать интерфейс и установила свой флаг — в этом случае система поймёт, что можно разрешить пользователю нажимать на кнопки;
- система заметила подозрительную активность и установила специальный флаг — в этом случае она будет записывать все действия пользователя, пока флаг не снимется.
Флаг — удобный способ передать информацию внутри алгоритма, чтобы в нужный момент принять верное решение.
Этот рекламный блок сообщает, что после обучения в «Яндекс Практикуме» вы можете получить высокооплачиваемую работу разработчика, тестировщика, аналитика, менеджера и дата-сайентиста.
Содержание
Флаг направления
Этот флаг может изменяться любыми программами с помощью специальных инструкций CLD и STD, а также загрузкой нового содержимого регистра флагов.
Регистр статуса (регистр состояния или регистр флагов) - это специальный регистр, который есть в любом процессоре, микропроцессоре или микроконтроллере.
Регистр состояния (Status Register) содержит данные об итоге выполнения последней арифметической или логической операции. Эти данные можно использовать для управления ходом программы с инструкциями условного перехода.
Обратите внимание, что регистр состояния обновляется после всех операций ALU, как указано в справочнике по набору команд. Это во многих случаях устраняет необходимость использования инструкций сравнения, что позволяет создавать менее объёмный и более быстрый код.
Регистр состояния не сохраняется автоматически при входе в процедуру прерывания, и перезаписывается при возвращении из прерывания. Поэтому программист сам должен позаботиться о сохранении регистра статуса перед вызовом прерывания.
Флаг Z (бит 1): Zero Flag (Флаг нуля)
Флаг Z указывает на то, что результат арифметической или логической операции равен нулю. Более подробно об этом в описании набора команд процессора.
Откуда такое название
В программирование флаги пришли из армии и флота, когда с помощью разноцветных флагов корабли передавали сигналы друг другу. Также флаги используют военные, когда подают сигналы для управления техникой — например, поднятый красный флаг запрещает движение.
Флаг C (бит 0): Carry Flag (Флаг переноса)
Флаг C указывает на перенос при арифметической или логической операции. Более подробно об этом в описании набора команд процессора.
Начиная с модели 80386 процессоры Intel предоставляют 16 основных регистров для пользовательских программ и ещё 11 регистров для работы с мультимедийными приложениями (MMX) и числами с плавающей точкой (FPU/NPX). Все команды так или иначе изменяют содержимое регистров. Как уже говорилось, обращаться к регистрам быстрее и удобнее, чем к памяти. Поэтому при программировании на языке Ассемблера регистры используются очень широко.
В этом разделе мы рассмотрим основные регистры процессоров Intel. Названия и состав/количество регистров для других процессоров могут отличаться. Итак, основные регистры процессоров Intel.
Таблица 2.1. Основные регистры процессора.
Название | Разрядность | Основное назначение |
EAX | 32 | Аккумулятор |
EBX | 32 | База |
ECX | 32 | Счётчик |
EDX | 32 | Регистр данных |
EBP | 32 | Указатель базы |
ESP | 32 | Указатель стека |
ESI | 32 | Индекс источника |
EDI | 32 | Индекс приёмника |
EFLAGS | 32 | Регистр флагов |
EIP | 32 | Указатель инструкции (команды) |
CS | 16 | Сегментный регистр |
DS | 16 | Сегментный регистр |
ES | 16 | Сегментный регистр |
FS | 16 | Сегментный регистр |
GS | 16 | Сегментный регистр |
SS | 16 | Сегментный регистр |
Регистры EAX, EBX, ECX, EDX – это регистры общего назначения. Они имеют определённое назначение (так уж сложилось исторически), однако в них можно хранить любую информацию.
Регистры EBP, ESP, ESI, EDI – это также регистры общего назначения. Они имеют уже более конкретное назначение. В них также можно хранить пользовательские данные, но делать это нужно уже более осторожно, чтобы не получить «неожиданный» результат.
Регистр флагов и сегментные регистры требуют отдельного описания и будут более подробно рассмотрены далее.
Пока для вас здесь слишком много непонятных слов, но со временем всё прояснится)))
Когда-то процессоры были 16-разрядными, и, соответственно, все их регистры были также 16-разрядными. Для совместимости со старыми программами, а также для удобства программирования некоторые регистры разделены на 2 или 4 «маленьких» регистра, у каждого из которых есть свои имена. В таблице 2.2 перечислены такие регистры.
Вот пример такого регистра.
Из этого следует, что вы можете написать в своей программе, например, такие команды: Обе команды поместят в регистр AX число 1. Разница будет заключаться только в том, что вторая команда обнулит старшие разряды регистра EAX, то есть после выполнения второй команды в регистре EAX будет число 1. А первая команда оставит в старших разрядах регистра EAX старые данные. И если там были данные, отличные от нуля, то после выполнения первой команды в регистре EAX будет какое-то число, но не 1. А вот в регистре AX будет число 1. Сложно? Ну это пока… Со временем вы к таким вещам привыкните.
Мы пока не говорили о разрядах (битах). Эту тему мы обсудим в разделах, посвящённых системам счисления. А сейчас пока вам достаточно знать, что нулевой разряд (бит) – это младший бит. Он крайний справа. Старший бит – крайний слева. Номер старшего бита зависит от разрядности числа/регистра. Например, в 32-разрядном регистре старшим битом является 31-й бит (потому что отсчёт начинается с 0, а не с 1).
Ниже приведён список регистров общего назначения, которые можно поделить описанным выше способом и при этом к «половинкам» и «четвертинкам» этих регистров можно обращаться в программе как к отдельному регистру.
Таблица 2.2. «Делимые» регистры..
На этом мы закончим наше краткое знакомство с регистрами. Если вам пока не всё понятно – просто прочитайте этот раздел, чтобы более-менее представлять себе, что такое регистры. По мере приобретения новых знаний вы можете вернуться к этому разделу и уже на новом уровне воспринять эту информацию. А в следующем разделе мы коротко опишем процесс выполнения команды.
Регистр флагов – это очень важный регистр процессора, который используется при выполнении большинства команд. Регистр флагов носит название EFLAGS. Это 32-разрядный регистр. Однако старшие 16 разрядов используются при работе в защищённом режиме, и пока мы их рассматривать не будем. К младшим 16 разрядам этого регистра можно обращаться как к отдельному регистру с именем FLAGS. Именно этот регистр мы и рассмотрим в этом разделе.
Каждый бит в регистре FLAGS является флагом. Флаг – это один или несколько битов памяти, которые могут принимать двоичные значения (или комбинации значений) и характеризуют состояние какого-либо объекта. Обычно флаг может принимать одно из двух логических значений. Поскольку в нашем случае речь идёт о бите, то каждый флаг в регистре может принимать либо значение 0, либо значение 1. Флаги устанавливаются в 1 при определённых условиях, или установка флага в 1 изменяет поведение процессора. На рис. 2.4 показано, какие флаги находятся в разрядах регистра FLAGS.
Бит | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Флаг | 0 | NT | IOPL | OF | DF | IF | TF | SF | ZF | 0 | AF | 0 | PF | 1 | CF |
Рис. 2.4. Регистр флагов FLAGS.
Флаг установлен, если значение соответствующего ему бита равно 1.
Флаг сброшен, если значение соответствующего ему бита равно 0.
В таблице 2.6 приведено описание флагов регистра FLAGS.
Таблица 2.6. Описание флагов регистра FLAGS.
Бит | Обозначение | Название | Описание |
0 | CF | Carry Flag | Флаг переноса. Устанавливается в 1, если результат предыдущей операции не уместился в приёмнике и произошёл перенос из старшего бита или если требуется заём (при вычитании). Иначе установлен в 0. Например, этот флаг будет установлен при переполнении, рассмотренном в предыдущем разделе. |
1 | 1 | - | Зарезервирован. |
2 | PF | Parity Flag | Флаг чётности. Устанавливается в 1, если младший байт результата предыдущей команды содержит чётное количество битов, равных 1. Если количество единиц в младшем байте нечётное, то этот флаг равен 0. |
3 | 0 | - | Зарезервирован. |
4 | AF | Auxiliary Carry Flag | Вспомогательный флаг переноса (или флаг полупереноса). Устанавливается в 1, если в результате предыдущей операции произошёл перенос (или заём) из третьего бита в четвёртый. Этот флаг используется автоматически командами двоично-десятичной коррекции. |
5 | 0 | - | Зарезервирован. |
6 | ZF | Zero Flag | Флаг нуля. Устанавливается 1, если результат предыдущей команды равен 0. |
7 | SF | Sign Flag | Флаг знака. Этот флаг всегда равен старшему биту результата. |
8 | TF | Trap Flag | Флаг трассировки (или флаг ловушки). Он был предусмотрен для работы отладчиков в пошаговом выполнении, которые не используют защищённый режим. Если этот флаг установить в 1, то после выполнения каждой программной команды управление временно передаётся отладчику (вызывается прерывание 1). |
9 | IF | Interrupt Enable Flag | Флаг разрешения прерываний. Если сбросить этот флаг в 0, то процессор перестанет обрабатывать прерывания от внешних устройств. Обычно его сбрасывают на короткое время для выполнения критических участков программы. |
10 | DF | Direction Flag | Флаг направления. Контролирует поведение команд обработки строк. Если установлен в 1, то строки обрабатываются в сторону уменьшения адресов, если сброшен в 0, то наоборот. |
11 | OF | Overflow Flag | Флаг переполнения. Устанавливается в 1, если результат предыдущей арифметической операции над числами со знаком выходит за допустимые для них пределы. Например, если при сложении двух положительных чисел получается число со старшим битом, равным единице, то есть отрицательное. И наоборот. |
12 13 | IOPL | I/O Privilege Level | Уровень приоритета ввода/вывода. |
14 | NT | Nested Task | Флаг вложенности задач. |
15 | 0 | - | Зарезервирован. |
Значения некоторых флагов можно изменять напрямую с помощью специальных команд. Однако нет инструкций, которые бы позволяли обращаться к регистру флагов как к обычному регистру по имени. Некоторые флаги устанавливаются автоматически и предназначены только для чтения.
Сейчас вам будет понятно далеко не всё из того, что описано в таблице 2.4. Например, вы пока не знаете, что такое прерывания. Но всему своё время. Пока просто запомните страницу с описанием регистра флагов и возвращайтесь к ней по мере необходимости.
Системные флаги IOPL предназначены для управления операционной средой в защищённом режиме. Они не используются в прикладных программах.
Когда мы писали тетрис на JavaScript, то использовали в нём флаг остановки игры:
// ставим флаг окончания
gameOver = true;
В тот раз мы не останавливались на флагах подробно, поэтому сделаем это сегодня — расскажем, что такое флаг в программировании и для чего он нужен.
Флаг H (бит 5): Half Carry Flag (Флаг половинного переноса)
Флаг полупереноса H указывает на полуперенос в некоторых арифметических операциях. Полуперенос полезен в арифметике BCD.
Флаг полупереноса ведёт себя также, как флаг обычного переноса, только он связан с младшей тетрадой. Например,
При выполнении этой операции будет установлен флаг полупереноса, так как произошёл перенос из третьего бита (старшего бита младшей тетрады).
Более подробно об этом в описании набора команд процессора.
Флаг V (бит 3): Two’s Complement Overflow Flag (Флаг переполнения дополнительного кода)
Флаг V поддерживает арифметику дополнения до двух. Более подробно об этом в описании набора команд процессора.
Флаги состояния
Эти флаги отражают результат, полученный в предыдущей арифметико-логической операции. Многие из них могут использоваться в дальнейшем для выполнения условных переходов или условных пересылок.
Флаги этой группы могут изменяться любыми программами с помощью команд, заносящих в регистр флагов новое значение (SAHF, POPF/POPFD/POPFQ).
CF | Флаг переноса (бит 0). На самом деле он имеет разное назначение в зависимости от выполняемой инструкции. В арифметических операциях над целыми числами этот флаг, будучи установленным, показывает наличие переноса или заёма (это можно рассматривать как «беззнаковое переполнение»), а будучи сброшеннм — отсутствие переноса или заёма. Кроме того, этот флаг применяется в некоторых других инструкциях и тем или иным образом характеризует полученный результат. Подробно использование этого флага в каждой конкретной инструкции указывается в её описании |
PF | Флаг чётности (бит 2). Устанавливается, если младший байт результата содержит чётное число единичных битов, в противном случае сбрасывается |
AF | Флаг вспомогательного переноса (бит 4). Устанавливается при возникновении переноса или заёма из 4-ого раззряда в 3-ий разряд. Сбрасывается при отсутствии такового. Используется командами десятичной коррекции. |
ZF | Флаг нуля (бит 6). Устанавливается при получении нулевого результата, сбрасывается в противном случае. |
SF | Флаг знака (бит 7). Устанавливается, если в результате операции получено отрицательное число, т.е. если старший разряд результата равен единице. В противном случае сбрасывается |
OF | Флаг переполнения (бит 11). Устанавливается, если в результате арифметической операции зафиксировано знаковое переполнение, то есть если результат, рассматриваемый как число со знаком, не помещается в операнд-приёмник. Если знакового переполнения нет, этот флаг сбрасывается |
Назначение разрядов
Формат регистра EFLAGS выглядит следующим образом:
Заметим, что все неиспользуемые биты равны нулю. Исключением является бит 1, который всегда имеет единичное значение.
Далее описывается назначение каждого бита, входящего в состав регистра флагов.
Аппаратный флаг — регистр в процессоре
Процессор — это микросхема из миллиардов транзисторов, но ему тоже иногда нужны флаги, чтобы понять:
- перед ним чётное число или нет;
- произошло ли переполнение буфера;
- есть ли что-то в стеке, куда нужно вернуться после этой операции;
- в каком режиме работать.
Для этого в процессоре есть специальные регистры — хранилища данных, которые могут принимать различные значения. Технически это тоже как бы виртуальные переменные, только они влияют не на одну программу, а на весь процессор.
Аппаратные флаги в процессоре обрабатываются автоматически, в зависимости от используемых команд.
Программный флаг — это переменная
В случае с тетрисом мы взяли логическую переменную gameOver и присвоили ей значение true — это называется «установить флаг». Эта переменная показывает, закончилась игра или нет: если true, то да, закончилась, а если false — можно играть дальше.
Но флаг сам по себе бесполезен, если на него никто не смотрит. Если мы просто установим флаг, то игра не закончится сама по себе — нам нужно периодически проверять, в каком состоянии флаг. Для этого в код в нужных местах добавляют проверку флага: смотрят, чему равен флаг, и если он сработал — выполняют определённые действия. В тетрисе мы делаем это в самом начале обработчика нажатия клавиш — если флаг сработал, то сразу останавливаем игру и выводим надпись Game Over.
Флаги регистра SREG
Флаг N (бит 2): Negative Flag (Флаг отрицательного значения)
Флаг N указывает на то, что результат арифметической или логической операции был отрицательным. Более подробно об этом в описании набора команд процессора.
Регистр SREG
Каждый бит (флаг) доступен как для чтения, так и для записи. При инициализации все биты равны нулю.
Адрес регистра SREG - 0x3F (в шестнадцатеричной системе).
Каждый из битов (флагов) этого регистра можно установить, сбросить или проверить отдельно с помощью команд общего назначения или специально предусмотренных для этого команд, которые работают только с определённым флагом.
Флаг S (бит 4): Sign Bit (Флаг знака)
S = N (+) V (исключающее или между флагами N и V)
Флаг S равен итогу операции исключающего или между флагом отрицательного результата N и флагом переполнения V. Более подробно об этом в описании набора команд процессора.
Флаг — это индикатор
Когда водитель садится за руль машины, то он видит много индикаторов — приборов и лампочек, которые:
- показывают нам состояние различных узлов в машине (обороты двигателя);
- показывают, включён или выключен какой-то прибор (например, кондиционер или ближний свет);
- напоминают, что нужно что-то сделать (пристегнуться);
- сигнализируют о неисправности (контрольная лампа давления масла, если уровень масла в двигателе слишком низкий).
Глядя на эти индикаторы, водитель понимает, что ему нужно сделать — пристегнуться, остановиться, чтобы долить масло в двигатель или ничего делать не нужно.
Флаги в программировании делают то же самое — показывают, что происходит в программе, чтобы алгоритм или человек мог принять решение.
Программные флаги — это переменные, а аппаратные флаги используются в процессорах.
Флаг T (бит 6): Bit Copy Storage (Хранение Копируемого Бита)
Инструкции копирования бита (Bit Copy), то есть инструкции BLD (Bit LoaD) и BST (Bit STore), используют флаг T как источник или приёмник при операциях с битом. Бит из регистра в Регистре Файла (Register File) можно скопировать в бит Т с помощью инструкции BST, а состояние флага Т можно скопировать в бит регистра Регистра Файла при помощи команды BLD.
Флаг I (бит 7): Global Interrupt Enable (Флаг глобального разрешения прерываний)
Для включения прерываний флаг I должен быть установлен. Затем управление включением отдельных прерываний выполняется в отдельных регистрах управления. Если флаг I сброшен, ни одно из прерываний не включено, независимо от настроек отдельного прерывания. Флаг I очищается аппаратным обеспечением после завершения прерывания (автоматически сбрасывается), а устанавливается инструкцией RETI для включения последующих прерываний. Флаг I также может быть установлен и очищен инструкциями SEI и CLI, как описано в документации.
Благодаря автоматическому сбросу этого флага во время выполнения подпрограммы обработки прерывания запрещается (и исключается) возникновение других прерываний. Если бы это не делалось, то могло бы возникнуть очень большое количество рекурсивных вызовов (что в итоге привело бы к зависанию).
Разрешаются прерывания обычно вручную при возврате из обработчика прерываний.
Читайте также: