Как найти флаг переноса

Перенос и переполнение – что они представляют собой на самом деле?

Дата публикации 27 июл 2003

Перенос и переполнение – что они представляют собой на самом деле? — Архив WASM.RU

Данная статья ни в коем случае не претендует на полноту описания, и представляет
собой лишь краткое дополнение к тем солидным учебным пособиям и справочникам,
которые должны быть под рукой у каждого программиста. Просто мне не удалось
найти ни в одном из подобных изданий тех элементарных сведений, которые будут
изложены ниже. Видимо, авторам этот вопрос кажется настолько тривиальным и
очевидным, что они не заостряют на нем внимания, полагая, что двух – трех строк
достаточно для полного понимания. Однако это далеко не так – вопрос выходит
далеко за те рамки, в которые его пытаются загнать авторы. А дело вот в чем.

Любой начинающий работать на языке Ассемблера программист рано или поздно
в своей деятельности доходит до изучения команд, изменяющих флаги переноса
и переполнения в соответствии с определенными правилами. К таковым относятся,
например, команды сложения, вычитания, умножения, логических и арифметических
сдвигов. Естественно, работа с этими командами требует четкого понимания понятий
переноса и переполнения. (Если быть более точным, следует осознавать, каким
образом знаковые или беззнаковые числа, сочетаясь в арифметических командах,
дают различные комбинации флагов переноса и переполнения. Это – азбука начинающего
программиста, и без ее освоения дальнейшая работа невозможна).

Раскроем любой учебник по языку Ассемблера, например, очень хороший учебник
В.Юрова “Ассемблер:
учебный курс”
. Какую информацию он содержит по
нашему вопросу?

В таблице “Флаги состояния” находим следующие сведения:
“… Флаг переноса CF … устанавливается в 1, если арифметическая операция
произвела перенос из старшего бита результата. Старшим является 7, 15 или 31-й
бит в зависимости от размерности операнда.”
“… Флаг переполнения OF … устанавливается в 1, если в результате операции
происходит перенос (заем) в(из) старшего, знакового бита результата (биты 7,
15 или 31 для 8, 16 или 32-разрядных операндов соответственно).”

Это интересно. Получается, что автор учебника предлагает нам согласиться с
тем, что:

1) Перенос происходит тогда, когда единица выносится за пределы разрядной
сетки (при операции сложения) или занимается из этих пределов (при операции
вычитания);

2) Переполнение происходит тогда, когда единица выносится в последний разряд
числа (при операции сложения) или занимается из этого разряда (при операции
вычитания).

Проверим, так ли это на самом деле. Сложим в программе два числа и проанализируем
получившийся код отладчиком, обращая особое внимание на состояние флагов
OF (переполнения) и CF (переноса) до и после выполнения команды. Например:

 mov al, 10000000b	;//Произошел вынос единицы ТОЛЬКО за 
mov bl, 10000000b ;//пределы разрядной сетки, однако...
add al, bl ;//...есть и переполнение (OF=1), ;//и перенос (CF=1) mov al, 11111111b ;//Имели место выносы единицы КАК за
mov bl, 00000001b ;//пределы разрядной сетки, так и в старший
add al, bl ;//бит, однако перенос есть, а переполнения нет

Налицо явное противоречие теории, изложенной в учебнике, и действительности,
открывшейся после манипуляций с отладчиком. Что же, продолжим изучение теории.
Что утверждают в своем учебнике “Язык Ассемблера
и организация ЭВМ”
В.Сорокин
и В.Сарычев
?
“… Флаг переноса CF устанавливается в единицу, если произошел перенос
из самого старшего разряда числа при команде сложения или если требуется заем
для самого старшего разряда уменьшаемого при вычитании.”
“… Флаг переполнения OF используется как индикатор переполнения при работе
с числами со знаком. Он устанавливается в 1, если результат операции над числами
со знаком выйдет за пределы допустимого диапазона результата и устанавливается
в 0 в противном случае.”

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

На уровне машинных команд между этими двумя видами чисел нет никакой разницы.
Находящийся в памяти или в одном из регистров операнд представляет собой (в зависимости
от используемой модели адресации) 8-,16- или 32-разрядное число, все разряды
которого абсолютно равноправны. Понятие знака введено исключительно для возможности
манипулирования (на логическом уровне) с отрицательными числами – для процессора
все числа одинаковы, а для программиста они отличаются тем, что для одних высший
разряд выступает в качестве информации о знаке числа (знаковые числа), а для
других все разряды несут информации о самом числе (беззнаковые числа). Естественно,
выделение одного разряда под знак приводит к уменьшению
возможной величины знакового
числа вдвое 1;
так, максимальное
значение беззнакового 8-разрядного числа равно 11111111b, или 255,
максимальное же (минимальное) значение аналогичного знакового
числа равно соответственно 01111111b, или 127 (-128, или 10000000b).
Если старший разряд знакового числа равен 1, число считается отрицательным, если
0 – положительным.
Чтобы определить величину знакового числа, следует обратить в нем все биты (изменить
их значения с 0 на 1 и наоборот), и приписать к полученному модулю (он считается
беззнаковым) знак (-), если старший бит искомого числа был равен 1 2. Исходя
из этого, становится понятным различие на 1 в диапазонах для положительных и
отрицательных
величин (127,-128) – для последних может использоваться старший бит, который
и дает единичную прибавку. Легко видеть, что больше 127 (меньше -128) знаковое
число быть не может, поскольку для этих величин все информационные разряды уже
взведены (сброшены), и дальнейшее увеличение (уменьшение) числа приведет к переносу
в знаковый разряд (заему из него) и, соответственно, изменению знака числа…
… а это и есть пересказ иными словами того, что написано по поводу флага переполнения
в учебнике “Язык Ассемблера и организация
ЭВМ”
. То есть и здесь авторы
не сообщили нам ничего нового – речь идет все о том же пресловутом переносе в
знаковый бит (старший разряд). А это, как мы уже убедились, не соответствует
действительности.

Популярные учебники не могут помочь нам в выяснении того, когда при выполнении
арифметических команд возникает перенос, а когда – переполнение. Остается выяснить
это самостоятельно, складывая между собой различные числа во всевозможных комбинациях,
и анализируя состояние флагов OF и CF. При этом каждая пара чисел будет интерпретироваться
дважды – сперва как две знаковых, затем как две беззнаковых величины.

 mov al, 00111111b  ;//Нет ни переполнения,ни переноса 
mov bl, 00000001b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: нет
add al, bl ;//Вынос за разрядную сетку - нет mov al, 11111101b ;//Перенос есть,переполнения нет
mov bl, 00000101b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 253 + 5 = 2 (неверно) ; ИЛИ -3 + 5 = 2 (верно)

mov al, 11111100b ;//Перенос есть,переполнения нет
mov bl, 00000101b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 252 + 5 = 1 (неверно) ИЛИ -4 + 5 = 1 (верно) mov al, 01000000b ;//Перенос есть,переполнения нет
mov bl, 11000000b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 64 + 192 = 0 (неверно) ИЛИ 64 - 64 = 0 (верно) mov al, 11100000b ;//Перенос есть,переполнения нет
mov bl, 01100000b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 224 + 96 = 64 (неверно) ИЛИ -32 + 96 = 64 (верно) mov al, 01100000b ;//Перенос есть,переполнения нет
mov bl, 11100000b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 96 + 224 = 64 (неверно) ИЛИ 96 - 32 = 64 (верно) mov al, 11100000b ;//Перенос есть,переполнения нет
mov bl, 11100000b ;//7-й бит: стал равен 1; перенос в 7-й бит:есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 224 + 224 = 192 (неверно) ИЛИ -32 - 32 = -64(верно) mov al, 11000000b ;//Перенос есть,переполнения нет
mov bl, 11000000b ;//7-й бит: стал равен 1 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 192 + 192 = 128 (неверно) ИЛИ -64 - 64 = -128(верно) mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 00000001b ;//7-й бит: стал равен 0 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 1 = 0 (неверно) ИЛИ -1 + 1 = 0 (верно) mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 10000001b ;//7-й бит: стал равен 1 ; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 129 = 128 (неверно) ИЛИ -1 - 127 = -128 (верно) mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 11000001b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 193 = 192 (неверно) ИЛИ -1 - 63 = -64 (верно) mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 01000001b ;//7-й бит: стал равен 0; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 65 = 64 (неверно) ИЛИ -1 + 65 = 64 (верно) mov al, 01000000b ;//Переполнение есть,переноса нет
mov bl, 01000000b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - нет
;// 64 + 64 = 128 (верно) ИЛИ +64 + +64 = -128(неверно) mov al, 01100000b ;//Переполнение есть,переноса нет
mov bl, 01100000b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - нет
;// 96 + 96 = 192 (верно) ИЛИ +96 + +96 = -64 (неверно) mov al, 01111111b ;//Переполнение есть,переноса нет
mov bl, 00000001b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - нет
;// 127 + 1 = 128 (верно) ИЛИ +127 + +1 = -128 (неверно) mov al, 10000000b ;//Есть и перенос,и переполнение
mov bl, 10000000b ;//7-й бит: стал равен 0; перенос в 7-й бит: нет
add al, bl ;//Вынос за разрядную сетку - есть
;// 128 + 128 = 0 (неверно) ИЛИ -128 - 128 = 0 (неверно)

Итак, установка флажков переноса и переполнения
производится по следующим правилам:

ПЕРЕНОС БЕЗ ПЕРЕПОЛНЕНИЯ (CF=1, OF=0)
– тогда,когда производится перенос единицы
в знаковый разряд (7,15,31-й) и перенос единицы
из разрядной сетки (из 7,15 или 31-го разрядов
в 8,16,32, несуществующие для регистра указанной
размерности).

Сложение БЕЗЗНАКОВЫХ чисел при возникновении
переноса протекает неправильно (ТОЛЬКО из-за переноса из разрядной сетки –
перенос в знаковый разряд роли не играет). При
интерпретации слагаемых как беззнаковых чисел перенос из разрядной сетки приводит
к потере старших разрядов числа, и результат оказывается неверным.

Сложение ЗНАКОВЫХ чисел при возникновении
переноса протекает правильно, так
как
при такой интерпретации слагаемые представляют собой ЛИБО пару “ПОЛОЖИТЕЛЬНОЕ
ЧИСЛО + ОТРИЦАТЕЛЬНОЕ ЧИСЛО”
(старший бит одного слагаемого равен
0, а второго – 1, и перенос из шестого (четырнадцатого, тридцатого) бита приводит
к переносу
в старший и переносу из разрядной сетки), и результат такого сложения не может
быть неправильным – он будет находиться в пределах -128 – +127; ЛИБО пару “ДВА
ОТРИЦАТЕЛЬНЫХ ЧИСЛА,СУММА КОТОРЫХ НЕ МЕНЬШЕ -128”
(это означает, что сочетания
единичных битов первого и второго слагаемых ОБЯЗАТЕЛЬНО приведут к переносу в
старший разряд в то время,как будет произведен перенос из разрядной сетки, и
знаковый бит не будет потерян; для этого и налагается условие на сумму – -127
– 1, -120 – 8, -64 – 64
, НО НЕ – -127 – 2, -64 – 65). В последних случаях возникает
перенос с переполнением, так как производится только перенос из разрядной сетки.

ПЕРЕПОЛНЕНИЕ БЕЗ ПЕРЕНОСА (OF=1, CF=0)
– тогда, когда производится ТОЛЬКО перенос единицы в знаковый разряд.

Сложение ЗНАКОВЫХ чисел при возникновении переполнения протекает неправильно,
так как слагаемые могут представлять собой ТОЛЬКО беззнаковые числа (иначе
при переносе единицы из шестого бита наличие единицы в знаковом разряде приведет
к переносу из разрядной сетки; в результате переполнения не будет,а будет
перенос). Поэтому перенос единицы в знаковый разряд приводит к появлению
знакового (отрицательного)
числа, что неправильно – сложение двух положительных чисел может иметь результатом
только положительное число.

Сложение БЕЗЗНАКОВЫХ чисел в данном
случае протекает правильно,так как для
этих чисел 7-й бит не играет особой роли и представляет собой лишь добавочный
разряд; перенос
в него не приводит к ошибке.

ПЕРЕНОС С ПЕРЕПОЛНЕНИЕМ (CF=1,OF=1) – тогда,когда производится ТОЛЬКО перенос
единицы из разрядной сетки.

Сложение БЕЗЗНАКОВЫХ чисел в данном случае протекает неправильно, так
как перенос единицы из разрядной сетки приводит к потере старшего разряда.

Сложение ЗНАКОВЫХ чисел ТОЖЕ протекает неправильно, так как в результате
переноса из разрядной сетки теряется знаковый бит,и сумма двух отрицательных
чисел (а
перенос с переполнением возможен только при сложении двух отрицательных
чисел,т.к. для переноса единицы из разрядной сетки без переноса в знаковый
бит необходимы
единицы в старших разрядах обоих слагаемых) превращается в положительное
число,что неправильно.

ОТСУТСТВИЕ ПЕРЕНОСА И ПЕРЕПОЛНЕНИЯ – тогда,
когда нет переносов ни в знаковый разряд, ни из разрядной сетки.

На основании всего вышеизложенного может быть составлена следующая

Истинная таблица установки флагов переноса и переполнения для сложения:
Перенос из разрядной сетки Перенос в знаковый бит Флаги
Есть Есть CF=1, OF=0
Есть Нет CF=1, OF=1
Нет Есть CF=0, OF=1
Нет Нет CF=0, OF=0

Совершенно аналогично операциям сложения можно произвести ряд операций вычитания
над знаковыми и беззнаковыми числами, отслеживая зависимость флагов OF и CF от
наличия заемов из старшего и из “запредельного” разрядов.

   mov al, 11100000b ;//Нет ни переполнения,ни переноса  
mov bl, 00100000b ;//Заем в 7-й бит: нет; заем из 7-го бита: нет
sub al, bl mov al, 00111111b ;//Перенос есть,переполнения нет
mov bl, 11111111b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl mov al, 10000011b ;//Перенос есть,переполнения нет
mov bl, 10011010b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl mov al, 10000000b ;//Перенос есть,переполнения нет
mov bl, 10000001b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl mov al, 10000000b ;//Перенос есть,переполнения нет
mov bl, 11000000b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl mov al, 10001010b ;//Перенос есть,переполнения нет
mov bl, 10100101b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl mov al, 10000000b ;//Переполнение есть,переноса нет
mov bl, 01000000b ;//Заем в 7-й бит: нет; заем из 7-го бита: есть
sub al, bl mov al, 10000000b ;//Переполнение есть,переноса нет
mov bl, 00000001b ;//Заем в 7-й бит: нет; заем из 7-го бита: есть
sub al, bl mov al, 01000000b ;//Есть и переполнение,и перенос
mov bl, 11000000b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub al, bl mov al, 01100000b ;//Есть и переполнение,и перенос
mov bl, 10100000b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub al, bl mov al, 01111111b ;//Есть и переполнение,и перенос
mov bl, 11111111b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub al, bl mov al, 01110011b ;//Есть и переполнение,и перенос
mov bl, 10110111b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub al, bl

Правила установки флагов переноса и переполнения для команды вычитания аналогичны
тем, что уже излагались для команды сложения; единственное различие – вместо
словосочетания “перенос в…” всюду следует подставить словосочетание “заем
из…”. А

Истинная таблица установки флагов переноса и переполнения для вычитания
Заем в 7-й(старший) бит Заем из 7-го(знакового) бита Флаги
Есть Есть CF=1, OF=0
Есть Нет CF=1, OF=1
Нет Есть CF=0, OF=1
Нет Нет CF=0, OF=0

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

(c) 2003, Чугайнов Н.Г.


1 Видимо автор имел
ввиду беззнаковое число. (прим. ред.)

2 Такое преобразование над числом так же называется
дополнением до двух. А само представление отрицательных чисел – дополнительным
кодом
. (прим. ред.)

© Чугайнов Н.Г.


archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532


WASM

Регистр флагов или слово состояния процессора (ССП) — специализированный регистр, отражающий текущее состояние процессора.

Архитектура x86[править | править код]

В микропроцессорах Intel 8086 имеет название FLAGS и является 16-разрядным. Расширенные регистры EFLAGS и RFLAGS, введённые в архитектурах IA-32 (процессоры 80386) и x86-64, являются 32-битными и 64-битными соответственно. Расширенные регистры сохраняют обратную совместимость.

Регистр флагов содержит группу флагов состояния, управляющий флаг и группу системных флагов[1]:

Регистр флагов Intel x86
Бит, № Обозначение Название Описание Тип флага Когда введён
FLAGS
0 CF Carry Flag Флаг переноса Состояние
1 1 Зарезервирован
2 PF Parity Flag Флаг чётности Состояние
3 0 Зарезервирован
4 AF Auxiliary Carry Flag Вспомогательный флаг переноса Состояние
5 0 Зарезервирован
6 ZF Zero Flag Флаг нуля Состояние
7 SF Sign Flag Флаг знака Состояние
8 TF Trap Flag Флаг трассировки (пошаговое выполнение) Системный
9 IF Interrupt Enable Flag Флаг разрешения прерываний Системный
10 DF Direction Flag Флаг направления Управляющий
11 OF Overflow Flag Флаг переполнения Состояние
12 IOPL I/O Privilege Level Уровень приоритета ввода-вывода Системный 80286
13
14 NT Nested Task Флаг вложенности задач Системный 80286
15 0 Зарезервирован
EFLAGS
16 RF Resume Flag Флаг возобновления Системный 80386
17 VM Virtual-8086 Mode Режим виртуального процессора 8086 Системный 80386
18 AC Alignment Check Проверка выравнивания Системный 80486SX
19 VIF Virtual Interrupt Flag Виртуальный флаг разрешения прерывания Системный Pentium
20 VIP Virtual Interrupt Pending Ожидающее виртуальное прерывание Системный Pentium
21 ID ID Flag Проверка на доступность инструкции CPUID Системный Поздние 80486[2]
22 0 Зарезервированы
31
RFLAGS
32 0 Зарезервированы
63

Значение некоторых флагов в регистре флагов можно изменять напрямую, с помощью специальных инструкций (например, CLD для сброса флага направления), но нет инструкций, которые позволяют обратиться (проверить или изменить) к регистру флагов как к обычному регистру. Однако, можно сохранять регистр флагов в стек или регистр (E)AX и восстанавливать регистр флагов из них с помощью инструкций LAHF, SAHF, PUSHF, PUSHFD, POPF и POPFD.

При приостановке задачи (используя многозадачные возможности процессора), процессор автоматически сохраняет значение флага регистров в TSS (task state segment), при активизации новой задачи процессор загружает регистр флагов из TSS новой задачи.

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

Флаги состояния в активном состоянии[править | править код]

Флаги состояния (биты 0, 2, 4, 6, 7 и 11) отражают результат выполнения арифметических инструкций, таких как ADD, SUB, MUL, DIV.

  • CF — устанавливается при переносе из/заёме в (при вычитании) старший значащий бит результата и показывает наличие переполнения в беззнаковой целочисленной арифметике. Также используется в длинной арифметике.
  • PF — устанавливается, если младший значащий байт результата содержит чётное число единичных (ненулевых) битов. Изначально этот флаг был ориентирован на использование в коммуникационных программах: при передаче данных по линиям связи для контроля мог также передаваться бит чётности (см., например: RS-232#Принцип работы) и инструкции для проверки флага чётности облегчали проверку целостности данных.
  • AF — устанавливается при переносе или заёме из бита 4 результата. Этот флаг ориентирован на использование в двоично-десятичной (binary coded decimal, BCD) арифметике.
  • ZF — устанавливается, если результат машинной операции по модулю 2 в степени k (где k — разрядность ячейки) равен нулю.
  • SF — равен значению старшего значащего бита результата, который является знаковым битом в знаковой арифметике.
  • OF — устанавливается, если целочисленный результат слишком длинный для размещения в целевом операнде (регистре или ячейке памяти). Этот флаг показывает наличие переполнения в знаковой целочисленной арифметике (в дополнительном коде).

Из перечисленных флагов только флаг CF можно изменять напрямую с помощью инструкций STC, CLC и CMC. Также, битовые инструкции (BT, BTS, BTR и BTC) копируют указанный бит во флаг CF.

Флаги состояния позволяют одной и той же арифметической инструкции выдавать результат трёх различных типов: беззнаковое, знаковое и двоично-десятично кодированное (BCD) целое число. Если результат считать беззнаковым числом, то флаг CF показывает условие переполнения (перенос или заём), для знакового результата (в дополнительном коде) перенос или заём показывает флаг OF, а для BCD-результата перенос/заём показывает флаг AF. Флаг SF отражает знак знакового результата, флаг ZF отражает и беззнаковый, и знаковый нулевой результат.

В длинной целочисленной арифметике флаг CF используется совместно с инструкциями сложения с переносом (ADC) и вычитания с заёмом (SBB) для распространения переноса или заёма из одного вычисляемого разряда длинного числа в другой.

Инструкции условного перехода Jcc (переход по условию cc — например, JNZ для перехода, если результат не ноль), SETcc (установить значение байта-результата в зависимости от условия cc), LOOPcc (организация цикла) и CMOVcc (условное копирование) используют один или несколько флагов состояния для проверки условия. Например, инструкция перехода JLE (jump if less or equal — переход, если «меньше или равен», ≤) проверяет условие «ZF=1 или SF ≠ OF».

Флаг PF был введён для совместимости с другими микропроцессорными архитектурами и по прямому назначению используется редко. Более распространено его использование совместно с остальными флагами состояния в арифметике с плавающей запятой[3]: инструкции сравнения (FCOM, FCOMP и т. п.) в математическом сопроцессоре устанавливают в нём флаги-условия C0, C1, C2 и C3 и эти флаги можно скопировать в регистр флагов. Для этого рекомендуется использовать инструкцию FSTSW AX для сохранения слова состояния сопроцессора в регистре AX и инструкцию SAHF для последующего копирования содержимого регистра AH в младшие 8 битов регистра флагов[4], при этом C0 попадает во флаг CF, C2 — в PF, а C3 — в ZF. Флаг C2 устанавливается, например, в случае несравнимых аргументов (NaN или неподдерживаемый формат) в инструкции сравнения FUCOM.

Управляющий флаг[править | править код]

Флаг направления (DF, бит 10 в регистре флагов) управляет строковыми инструкциями (MOVS, CMPS, SCAS, LODS и STOS): установка флага заставляет уменьшать адреса (обрабатывать строки от старших адресов к младшим), обнуление заставляет адреса увеличивать. Инструкции STD и CLD соответственно устанавливают и обнуляют флаг DF.

Системные флаги и поле IOPL[править | править код]

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

  • IF — обнуление этого флага запрещает отвечать на маскируемые запросы на прерывание.
  • TF — установка этого флага разрешает пошаговый режим отладки, когда после каждой выполненной инструкции происходит прерывание программы и вызов специального обработчика прерывания (см. также: Int3).
  • IOPL — показывает уровень приоритета ввода-вывода исполняемой программы или задачи: чтобы программа или задача могла выполнять инструкции ввода-вывода или менять флаг IF, её текущий уровень приоритета (CPL) должен быть ≤ IOPL.
  • NT — этот флаг устанавливается, когда текущая задача «вложена» в другую, прерванную задачу, и сегмент состояния TSS текущей задачи обеспечивает обратную связь с TSS предыдущей задачи. Флаг NT проверяется инструкцией IRET для определения типа возврата — межзадачного или внутризадачного.
  • RF — флаг маскирования ошибок отладки.
  • VM — установка этого флага в защищённом режиме вызывает переключение в режим виртуального 8086.
  • AC — установка этого флага вместо с битом AM в регистре CR0 включает контроль выравнивания операндов при обращениях к памяти — обращение к невыравненному операнду вызывает исключительную ситуацию.
  • VIF — виртуальная копия флага IF; используется совместно с флагом VIP.
  • VIP — устанавливается для указания наличия отложенного прерывания; используется совместно с флагом VIF.
  • ID — возможность программно изменить этот флаг в регистре флагов указывает на поддержку инструкции CPUID.[2]

Идентификация процессора[править | править код]

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

К примеру, в процессорах 8086 и 80186 биты 12-15 регистра флагов всегда установлены, в процессорах 80286 и новее биты 12-14 содержат поле IOPL и флаг NT и в реальном режиме всегда сброшены. Это позволяет в 16-битном коде различать процессоры 808x/8018x, 80286 и 80386 (и новее):

Код на языке ассемблера MASM для различения процессоров 8086 — 80386

	pushf			; (Сохранить исходное состояние регистра флагов)
	pushf			; Скопировать регистр флагов...
	pop ax			; ...в регистр AX
	xor ah,11110000b	; Поменять значение старших 4 битов
	push ax			; Скопировать регистр AX
	popf			; ...в регистр флагов
	pushf			; Скопировать регистр флагов...
	pop bx			; ...в регистр BX
	popf			; (Восстановить исходное состояние регистра флагов)
	xor ah,bh		; AH=0 (биты в регистре флагов не поменялись) → 808x-80286, иначе 80386+
	and bh,11110000b	; BH=F0h (все 4 бита установлены) → 808x/8018x, 0 → 80286

Также, флаг AC (бит 18), введённый в 80486, всегда сброшен в 80386, что и позволяет различить эти процессоры:

Код на языке ассемблера MASM для различения процессоров 80386 и 80486

        and sp,not 3		; Выравнять стек, чтобы не было ошибок выравнивания при обращении к нему
	pushfd			; (Сохранить исходное состояние регистра флагов)
	pushfd			; Скопировать регистр флагов...
	pop eax			; ...в регистр EAX
	xor eax,40000h		; Поменять значение бита 18 (флаг AC)
	push eax		; Скопировать регистр EAX
	popfd			; ...в регистр флагов
	pushfd			; Скопировать регистр флагов...
	pop ecx			; ...в регистр ECX
	popfd			; (Восстановить исходное состояние регистра флагов)
	xor eax,ecx		; EAX=0 (бит в регистре флагов не поменялся) → 80386

Аналогично, в старых моделях 80486, где инструкция CPUID ещё не введена, флаг ID (бит 21) всегда сброшен, что позволяет идентифицировать процессоры 80386 и старые модели 80486:

Код на языке ассемблера MASM для определения старых 80486

	pushfd			; (Сохранить исходное состояние регистра флагов)
	pushfd			; Скопировать регистр флагов...
	pop eax			; ...в регистр EAX
	mov ecx,eax		; ...и в регистр ECX
	or eax,200000h		; Установить бит 21 (флаг ID)
	push eax		; Скопировать регистр EAX
	popfd			; ...в регистр флагов
	pushfd			; Скопировать регистр флагов...
	pop eax			; ...в регистр EAX
	popfd			; (Восстановить исходное состояние регистра флагов)
	xor eax,ecx		; EAX=0 (бит в регистре флагов не устанавливался) → 80386/старые 80486

См. также[править | править код]

  • Флаг (компьютерная техника)

Примечания[править | править код]

  1. 3.4.3. EFLAGS Register // The IA-32 Intel Architecture Software Developer’s Manual. — Intel, 2004. — Т. 1: Basic Architecture. Order number: 253665-013
  2. 1 2 Инструкция CPUID была добавлена в поздних версиях процессора 80486 и процессоре Pentium. См.: CPUID — CPU Identification // The IA-32 Intel Architecture Software Developer’s Manual. — Intel, 2004. — Т. 2A: Instruction Set Reference, A-M. Order number: 253666-013
  3. 8.1.3. Branching and Conditional Moves on Condition Codes // The IA-32 Intel Architecture Software Developer’s Manual. — Intel, 2004. — Т. 1: Basic Architecture. Order number: 253665-013
  4. В архитектуре P6 были введены инструкции FCOMI, FCOMIP и т. п., которые в результате сравнения устанавливают флаги в регистре флагов напрямую. Ранее это было невозможно, поскольку сопроцессор реализовывался отдельной микросхемой, и только начиная с 80486DX сопроцессор начали встраивать в процессор.

Ф
лаговый
регистр FLAGS (FCH) содержит информацию о
текущем состоянии процессора. Флаги и
их расположение в регистре приведены
на рис.1.47. Состояние флагового регистра
после сброса является неопределенным.

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

Флаговый регистр
FLAGS содержит 6 флагов состояния, информация
в которых устанавливается в результате
работы процессора. Четыре флага (C, V, Z,
S) используются командами условного
перехода. Два флага (H и D) используются
командой десятичной коррекции. Оставшиеся
два бита могут быть использованы как
флаги пользователя (F1 и F2). Ниже подробно
рассмотрено назначение каждого из
основных флагов МК Z8.

1.3.2.1. Флаг переноса c (Carry Flag)

Флаг переноса
устанавливается в 1, если в результате
арифметической операции генерируется
“перенос из” или “заем в” старший
7-ой бит результата. В противном случае
флаг С очищается в 0.

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

Команды могут
устанавливать, сбрасывать или инвертировать
(дополнять) флаг переноса.

1.3.2.2. Флаг нуля z (Zero Flag)

Если в результате
арифметической или логической операции
получается нулевой результат, то флаг
Z устанавливается в 1, в противном случае
флаг Z очищается в 0.

Если результат
команды проверки бита в регистре равен
00Н,0то флаг нуля устанавливается в 1, в
противном случае — очищается в 0.

Если результат
выполнения команды циклического или
арифметического сдвига равен 00Н, флаг
Z устанавливается в 1, иначе —сбрасывается
в 0.

1.3.2.3. Флаг знака s (Sign Flag)

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

Для производства
арифметических операций над числами
со знаком в МК используется представление
информации в дополнительном коде.
Положительное число при этом
идентифицируется в старшем значащем
разряде и, соответственно, значение
флага знака также равно 0. Отрицательное
число идентифицируется 1 в старшем
значащем разряде и, соответственно,
флаг S также будет равен 1.

1.3.2.4. Флаг переполнения V (Overflow Flag)

Для знаковых
арифметических операций, операций
циклического и арифметического сдвигов
флаг переполнения V устанавливается в
1, если результат больше максимально
возможного положительного числа (+127)
или меньше минимально возможного
отрицательного числа (-128), представленного
8-битным дополнительным кодом. Флаг V
устанавливается в 0, если переполнение
отсутствует. В результате поразрядных
логических операций флаг V всегда
сбрасывается в 0.

1.3.2.5. Флаг десятичной коррекции d (Decimal Adjust Flag)

Флаг десятичной
коррекции D используется для
двоично-десятичной арифметики BCD (Binary
Coded Decimal). Поскольку алгоритм десятичной
коррекции различен для сложения и
вычитания, этот флаг сохраняет информацию
о последней выполненной команде, для
последующей команды десятичной коррекции
DA. После выполнения операциивычитания
флаг D устанавливается в 1, а после
операции сложения —очищается в 0.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Флаг процессора, указывающий, произошло ли беззнаковое арифметическое переполнение

В компьютерных процессорах флаг переноса (обычно обозначается как флаг C ) – это единственный бит в системном регистре состояния / регистре флага, используемом для указания, когда арифметическое перенос или заимствование было сгенерировано из самой значимой битовой позиции арифметико-логического блока (ALU). Флаг переноса позволяет добавлять / вычитать числа, превышающие ширину одного ALU, путем переноса (добавления) двоичной цифры из частичного сложения / вычитания в позицию младшего бита более значимого слова. Он также используется для расширения битовых сдвигов и вращается аналогичным образом на многих процессорах (иногда это делается с помощью специального флага X ). Для операций вычитания используются два (противоположных) соглашения, так как большинство машин устанавливают флаг переноса при заимствовании, в то время как некоторые машины (например, 6502 и PIC ) вместо этого сбрасывают флаг переноса. заимствовать (и наоборот).

Содержание

  • 1 Использует
  • 2 Vs. флаг заимствования
  • 3 См. также
  • 4 Ссылки
  • 5 Внешние ссылки

Использует

На флаг переноса влияет результат большинства арифметических (и обычно нескольких побитовых) инструкций и также используется в качестве входных данных для многих из них. Некоторые из этих инструкций имеют две формы, которые либо читают, либо игнорируют перенос. В языках ассемблера эти инструкции представлены мнемоникой, например ADD / SUB, ADC / SBC(ADD / SUBвключая перенос), SHL / SHR(битовые сдвиги ), ROL / ROR(биты вращаются), RCR / RCL( вращать через перенос) и т. д. Использование флага переноса таким образом позволяет выполнять операции сложения, вычитания, сдвига и поворота из нескольких слов слов.

Например, если сложить 255 и 255, используя 8-битные регистры. Результатом должно быть 510, что является 9-битным значением 111111110в двоичном формате. 8 младших значащих битов, всегда сохраняемых в регистре, будут 11111110двоичными (254 десятичных), но поскольку есть перенос бита 7 (восемь битов), перенос устанавливается, указывая, что результат требует 9 биты. Допустимый 9-битный результат – это соединение флага переноса с результатом.

Для x86 ALU размером 8 бит, 8-битной интерпретации дополнения до двух, операция сложения 11111111+ 11111111приводит к 111111110, Carry_Flagустановлен, Sign_Flagустановлен, а Overflow_Flagочищен.

Если 11111111представляет собой дополненное до двух целое число со знаком -1 (ADD al, -1), то интерпретация результата будет 11111110, потому что Overflow_Flagсброшен, а Carry_Flagигнорируется. Знак результата отрицательный, потому что установлен Sign_Flag. 11111110– это двоичное дополнение целого числа со знаком −2.

Если 11111111представляет собой целое двоичное число без знака 255 (ADD al, 255), то интерпретация результата, что Carry_Flagне может быть игнорируется. Overflow_Flagи Sign_Flagигнорируются.

Другим примером может быть 8-битный регистр с битовой комбинацией 01010101и установленным флагом переноса; если мы выполним команду поворота влево через перенос, результат будет 10101011с очищенным флагом переноса, потому что самый старший бит (бит 7) был повернут в перенос, а перенос был повернут в младший бит (бит 0).

Ранние микропроцессоры Intel 4004 и Intel 8008 имели особые инструкции для установки, а также явного сброса флага переноса. Однако в более поздних версиях Intel 8080 (и Z80 ) не было явного кода операции переноса сброса, поскольку это можно было сделать так же быстро с помощью одной из команд побитового AND, OR или XOR (которые не используйте флаг переноса).

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

Против. Флаг заимствования

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

Первый использует бит как флаг заимствования, устанавливая его, если инструкция SBB) вычислит a − b − C = a− ( b + C), а вычитание без заимствования (SUB) действует так, как если бы бит заимствования был очищен. Семейства 8080, Z80, 8051, x86 и 68k (среди прочих) используют бит заимствования.

Второй использует преимущество тождества, что -x = не (x) +1, и вычисляет a-b как a + not (b) +1. Флаг переноса устанавливается в соответствии с этим сложением, и вычитание с переносом вычисляет a + not (b) + C, в то время как вычитание без переноса действует так, как если бы был установлен бит переноса. В результате бит переноса устанавливается, если a≥b, и сбрасывается, если System / 360, 6502, MSP430, ARM <61.>и процессоры PowerPC используют это соглашение. 6502 – это особенно хорошо известный пример, поскольку в нем нет операции вычитания без операции переноса, поэтому программисты должны убедиться, что флаг переноса установлен перед каждой операцией вычитания, когда заимствование не требуется.

Сводка различных вариантов использования флага переноса при вычитании

Перенос или. бит заимствования Вычитание без. переноса / заимствования Вычитание. с заимствованием Вычесть. с переносом
C = 0 a – b. = a + not (b) + 1 a – b – 0. = a + not (b) + 1 a + not (b) + 0. = a – b – 1
C = 1 a – b – 1. = a + not (b) + 0 a + not (b) + 1. = a – b – 0

Чаще всего первая альтернатива называется «вычитание с заимствованием», а вторая – «вычитание с переносом». Однако есть исключения в обоих направлениях; Архитектуры VAX, NS320xx и Atmel AVR используют соглашение о битах заимствования, но называют свою операцию a-b-C «вычитание с переносом» (SBWC, SUBCи SBC). Архитектуры PA-RISC и PICmicro используют соглашение о битах переноса, но называют свою операцию a + not (b) + C «вычитание с заимствованием» (SUBBи SUBWFB).

8-битные микроконтроллеры ST6 / ST7, пожалуй, самые запутанные из всех. Хотя у них нет какой-либо инструкции «вычитание с переносом», у них есть бит переноса, который устанавливается инструкцией вычитания, и соглашение зависит от модели процессора. Процессор ST60 использует соглашение «переноса», в то время как процессоры ST62 и ST63 используют соглашение «заимствования».

См. Также

  • Двоичная арифметика
  • Флаг полупереноса
  • Регистр состояния

Ссылки

Внешние ссылки

  • Флаг переноса и флаг переполнения в двоичной арифметике
  • Бит переноса: как это работает?

Мы много сил и времени потратили на изучение того, как встроенная ЭВМ микроконтроллера работает а памятью. Пришло время сделать следующий шаг – начать знакомство с командами, которые собственно и работают с данным хранящимися в памяти.

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

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

Поэтому разрядность регистров состояния зачастую превышает восемь бит. А сами регистры называются PSW (processor status word), слово состояния процессора, или MSW (machine status word), слово состояния машины.

Однако, мы рассматриваем всего лишь 8 битные микроконтроллеры и здесь все гораздо проще.

Флаги, они же статусы

Давайте немного вспомним, как они называются в разных микроконтроллерах и посмотрим, какую информацию они хранят

Форматы регистров статуса/флагов различных микроконтроллеров. Иллюстрация моя
Форматы регистров статуса/флагов различных микроконтроллеров. Иллюстрация моя

Флаг С – перенос/заем

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

Но в нашем случае, когда ЭВМ работает данным размеров в один байт, установленный флаг С означает, что в результат операции занимает более одного байта и возник перенос из старшего разряда, или заем в старший разряд байта

Перенос из старшего разряда и заем в старший разряд. Иллюстрация моя
Перенос из старшего разряда и заем в старший разряд. Иллюстрация моя

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

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

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

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

Это очень часто используемый флаг.

Флаг DC или H – перенос между тетрадами

Это то самое единственное исключение, о котором я говорил. Нам доступно состояние переноса/заема внутри байта. А точнее, между его половинами, которые и называются тетрадами (тетра – четыре)

Микроконтроллеры для начинающих. Часть 14. Знакомство в системой команд. Флаги и статусы

Зачем же понадобился признак переноса внутри байта? Дело в том, что существует специальный формат представления информации, называемый BCD. При этом каждая тетрада хранит одну десятичную цифру. То есть, байт хранит два десятичных разряда. При выполнении арифметических операций над данными в таком формате может возникнуть ситуация, когда содержимое тетрады выходит за диапазон 0-9. Вот эта ситуация и отображается флагами DC или H.

Это редко используемый флаг.

Флаг Z – нулевой результат

Если в результате операции у нас получился байт, в котором все биты нулевые, то будет установлен флаг Z. Важно отметить, что установленный флаг Z вовсе не означает, что результат действительно равен 0! Ведь при этом может быть еще и установлен флаг С, а значит результат вполне может оказаться равным 100000000 (9 разрядов). Флаг Z показывает только то, что все 8 бит байта результата нулевые.

Это часто используемый флаг.

Флаг OV или V – переполнение

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

Как такое возможно? Что бы понять это, нужно разобраться, как в ЭВМ представляются не просто числа, а числа имеющие знак. То есть, положительные и отрицательные. Самый старший бит байта, если его содержимое считается знаковым, показывает знак числа. При этом отрицательные числа представлены в дополнительном коде.

Представление знаковых чисел в ЭВМ. Иллюстрация моя
Представление знаковых чисел в ЭВМ. Иллюстрация моя

То есть, для знакового числа выделяется не 8, а всего 7 бит в байте. Если знаковый бит равен 0, то число считается положительным и оставшиеся 7 бит и являются собственно числом. Если знаковый бит равен 1, то число считается отрицательным, при этом его значением является число, которое нужно прибавить к числу в оставшихся семи битах, что бы получился ноль.

Сложно? На самом деле все просто. Давайте посмотрим, как же нам разобраться с числом -59 из примера выше. Инвертируем все разряды нашего числа и получим 00111010. Теперь прибавим единицу и получим 00111011, то есть как раз 59. И наше отрицательное число и будет -59.

Точно так же выполняется и обратное “кодирование”. То есть, снова инвертируем все биты и прибавляем 1. Вот так все просто и легко.

А теперь собственно пример с возникновением переполнения

Возникновение переполнения при сложении знаковых чисел. Иллюстрация моя
Возникновение переполнения при сложении знаковых чисел. Иллюстрация моя

Видите? Мы выполняли сложение двух положительных чисел, но результат отрицательный. На самом деле переполнение это тоже межразрядный перенос/заем. Только перенос возник в знаковый бит, или заем из знакового бита. А если еще точнее, то флаг переполнения устанавливается в ситуации, когда количество переносов в знаковый разряд не равно количеству переносов из знакового разряда. И рассматривать флаг V нужно в совокупности с флагом C.

Еще раз подчеркну, что флаг переноса имеет смысл только при работе со знаковыми числами. Этот флаг используется относительно редко. И в большинстве случаем его установка означает ошибку. Не все микроконтроллеры имеют флаг переполнения, так в PIC (кроме PIC18), этот флаг отсутствует.

Флаг N – отрицательный результат

Этот флаг тоже имеет смысл только в случае работы со знаковыми числами. Фактически, его значение просто равно знаковому биту результата. По большому счету, вместо проверки данного флага мы можем с тем же успехом проверять бит 7 байта(знаковый). Однако, существуют команды условных переходов, которые работают как раз с флагом N и не выполняют дополнительных проверок байта данных.

Данный флаг иногда может использоваться и с беззнаковыми числами, например, вместе с командами сдвигов и циклических сдвигов. Но это нетипичное применение и используется редко. Данный флаг отсутствует в PIC (кроме PIC18), но проблем это не вызывает, в силу специфичности их системы команд.

Довольно часто используемый флаг.

Флаг S – знак

Этот флаг специфичен для AVR. Его значение равно результату операции Исключающее ИЛИ между битами N и V. Используется, например, в командах условных переходов, таких как BRGE (переход если больше или равно) при работе со знаковыми числами.

Флаг Т – хранилище копии

Еще один специфичный для AVR флаг. Используется в командах BLD и BSD позволяющих позволяющих загрузить в заданный бит регистра R0-R31 содержимое флага Т, или сохранить заданный бит регистра в флаге Т.

Заключение

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

До новых встреч!

Добавить комментарий