В предыдущей части учебного курса мы использовали флаг CF, чтобы вернуть из процедуры информацию об ошибке. Чтобы у вас сложилась полная картина, я решил в этой части подробнее рассказать о командах управления флагами.
Как вы, наверно, помните флаги изменяются в результате выполнения арифметических и логических команд, а также команд сдвига. Регистр флагов можно сохранить в стек с помощью команды PUSHF [1] и восстановить из стека с помощью команды POPF [2]. Кроме того, в процессоре существуют специальные команды, которые позволяют явно установить или сбросить флаги CF, DF и IF. Это очень простые команды: у них нет операндов и результатом является только изменение значения соответствующего флага.
Флаг переноса CF
Команда CLC [3] сбрасывает флаг CF.
Команда STC [4] устанавливает флаг CF в единицу.
Команда CMC [5] инвертирует значение флага CF.
Флаг направления DF
Этот флаг определяет направление обработки данных цепочечными командами (о них подробно расскажу в отдельной статье). Он должен устанавливаться или сбрасываться перед использованием этих команд.
Команда CLD [6] сбрасывает флаг DF.
Команда STD [7] устанавливает флаг DF в единицу.
Флаг прерывания IF
Этот флаг определяет, разрешены в данный момент прерывания или нет (о прерываниях тоже будет отдельная статья).
Команда CLI [8] сбрасывает флаг IF (запрещает прерывания).
Команда STI [9] устанавливает флаг IF в единицу (разрешает прерывания).
Команды LAHF и SAHF
Команда LAHF [10] загружает младший байт регистра флагов в AH. Её удобно использовать, когда нужно получить значения сразу нескольких флагов. Порядок расположения флагов представлен на рисунке:

Команда SAHF [11] выполняет обратную операцию — загружает содержимое AH в младший байт регистра флагов. Это позволяет одновременно изменить значения нескольких флагов. При этом биты 1, 3, 5 регистра AH игнорируются.
Пример программы
В качестве примера использования команды LAHF [10] я написал процедуру, которая получает и выводит на консоль значения флагов SF, ZF, AF, PF и CF. Подобную процедуру можно использовать в отладочных целях. Достаточно добавить её вызов в то место программы, где хочется проверить состояние флагов.
Чтобы выводить значения отдельных битов удобно написать отдельную процедурку для печати флага CF в виде символа. Нужный бит будет помещаться в флаг CF при помощи команды сдвига SHL [12].
;Процедура вывода значения флага CF в виде символа
print_cf:
push ax
push dx
mov ah,2 ;Функция DOS 02h - вывод символа
mov dl,'0' ;DL = '0'
adc dl,0 ;Если CF = 1, то в DL будет символ '1'
int 21h ;Обращение к функции DOS
pop dx
pop ax
ret
А вот собственно процедура вывода флагов. Как видите, здесь нет ничего сложного 🙂 Процедура сохраняет регистр флагов и восстанавливает его перед возвратом управления, поэтому можно вызывать её где угодно, не волнуясь, что она нарушит выполнение основной программы.
;Процедура вывода состояния флагов на консоль
print_flags:
push ax
push cx
push dx
pushf ;Сохранение регистра флагов
lahf ;Загрузка младшего байта FLAGS в AH
mov cl,ah ;CL = AH
mov ah,9 ;Функция DOS 09h - вывод строки
mov dx,s_sf ;DX = адрес строки 'FLAGS: SF='
int 21h ;Обращение к функции DOS
shl cl,1 ;Сдвиг CL влево на 1 бит
call print_cf ;Печать выдвинутого бита
mov dx,s_zf
int 21h ;Вывод строки ' ZF='
shl cl,1 ;Сдвиг CL влево на 1 бит
call print_cf ;Печать выдвинутого бита
mov dx,s_af
int 21h ;Вывод строки ' AF='
shl cl,2 ;Сдвиг CL влево на 2 бита
call print_cf ;Печать выдвинутого бита
mov dx,s_pf
int 21h ;Вывод строки ' PF='
shl cl,2 ;Сдвиг CL влево на 2 бита
call print_cf ;Печать выдвинутого бита
mov dx,s_cf
int 21h ;Вывод строки ' CF='
shl cl,2 ;Сдвиг CL влево на 2 бита
call print_cf ;Печать выдвинутого бита
mov dx,s_endl
int 21h ;Вывод конца строки
popf ;Восстановление регистра флагов
pop dx
pop cx
pop ax
ret
Полный исходный код примера — printflags.asm [13]. Вывод программы выглядит так:

Упражнение
Чтобы потренироваться в работе с флагами напишите следующую программу. Вычислите сумму значений флагов CF, SF, ZF и выведите на консоль результат сложения. Если результат больше 1, инвертируйте значение флага CF 🙂
Следующая часть » [14]