I mov ax,a │ Фрагмент программы,
i+4 ADD AX,B │ состоящий из трех
i+8 MOV C,AX │ команд
… …
i+N Число А │
… … │
i+M Число B │ Данные для программы
… … │
i+K Число C │
Рис. 5.3. Программа для выполнения операции С ← [А] + [В]
Выполнение каждой команды производится в два этапа. На первом этапе, называемом фазой выборки команды, из памяти извлекается команда, хранящаяся по адресу, указанному в регистре PC. Эта команда помещается в регистр команды (Instruction Register, IR). После этого начинается второй этап, называемый фазой выполнения команды. На этом этапе процессор анализирует команду в регистре IR, чтобы узнать, какое действие ему следует выполнить. Затем он производит это действие, для чего обычно требуется выбрать операнды из памяти или из регистров, выполнить арифметическую или логическую операцию и сохранить результаты по указанному адресу. В ходе этой двухфазной процедуры содержимое регистра PC в определенный момент увеличивается таким образом, чтобы он указывал на следующую команду. Когда выполнение команды завершается, регистр PC содержит адрес следующей команды, то есть можно начинать этап выборки новой команды. В большинстве процессоров фаза выполнения делится, в свою очередь, на несколько фаз, соответствующих выборке операндов, выполнению операции и сохранению результатов.
Ветвление
Ниже будет рассмотрена процедура сложения n чисел. Программа, приведена на рис. 5.4. Адреса, по которым хранятся n чисел, символически обозначены как NUM1, NUM2,..., NUMn. Для сложения каждого из этих чисел с содержимым регистра R0 используется отдельная команда Add. После того как все числа сложены, результат записывается в память по адресу SUM.
Адреса Имена Команды/данные Комментарий программы
памяти ячеек
памяти
I mov eax,num1 │
i+4 ADD EAX,NUM2 │ Команды программы
i+8 ADD EAX,NUM3 │
… … │
i+4n-4 ADD EAX,NUMn │
MOV SUM,EAX │
… … │ Данные для программы
i+4K SUM DEF 00000000h │ Сумма, начальное значение = 0
NUM1 def │ 1-е число
NUM2 def │ 2-е число
NUM3 def │ 3-е число
… … │
i+4K+4n NUMn def │ n-е число
Рис. 5.4. Прямолинейная программа для сложения n чисел
Но вместо того чтобы использовать длинный список команд Add, можно поместить всего одну такую команду в программный цикл (рис. 5.5). Цикл — это последовательность команд, выполняемых необходимое количество раз. В нашей программе цикл начинается по адресу STARTLOOP и заканчивается командой JUMP>0. На каждом шаге этого цикла определяется адрес следующего числа, и это число извлекается из памяти и добавляется к содержимому регистра R0. Адрес операнда можно задать разными способами, о которых подробно рассказывается в разделе «Режимы адресации». А пока мы должны сосредоточить внимание на том, как создаются и выполняются программные циклы.
Предположим, что количество складываемых чисел n, хранится в памяти по адресу N (рис. 5.5). Регистр ECX используется в качестве счетчика, определяющего количество повторений цикла. Поэтому в начале программы в регистр ECX загружается содержимое памяти, находящееся по адресу N. В теле цикла команда DEC ECX (decrement) уменьшает значение ECX на единицу. (Например, команда INC ECX (Increment), увеличивает свой операнд на единицу.) Тело цикла выполняется раз за разом до тех пор, пока результат операции Decrement остается большим нуля.
MOV ECX,N ; Загрузка значения счетчика
ADD EAX,0 ; Обнуление регистра суммы
STARTLOOP Определение адреса следующего
числа и прибавление этого
числа к EAX
DEC ECX : Уменьшение на 1 счетчика ECX
JUMP>0 STARTLOOP
MOV SUM,EAX : Пересылка суммы по адресу SUM
… …
SUM DEF 00000000h : Сегмент данных программы
N DEF n
NUM1 def
NUM2 def
NUM3 def
… …
NUMn def
Рис. 5.5. Цикл для сложения n чисел
Теперь введем понятие команда перехода. Указанная команда загружает в счетчик команд (IP) заданное значение. Процессор выбирает из памяти и выполняет команду, хранящуюся по адресу и определяемую командой перехода, а не следующей командой в порядке увеличения адресов, как в случае прямолинейной программы. Вызов команды условного перехода приводит к переходу в другую точку программы только в случае выполнения заданного условия. Если это условие не выполняется, значение в регистре PC увеличивается обычным образом и из памяти выбирается и выполняется очередная команда в порядке увеличения адресов.
В программе, представленной на рис. 5.5., команда
JUMP>0 STARTLOOP
«переход, если больше нуля» является командой условного перехода, выполняющей перемещение по адресу STARTLOOP в том случае, если результат предыдущей инструкции, уменьшившей значение в регистре ECX, больше нуля. Это означает, что цикл повторяется до тех пор, пока в списке чисел остаются необработанные элементы, которые следует добавить к содержимому регистра EAX. В конце n-го прохода по циклу команда Decrement возвращает значение 0, поэтому переход на начало цикла не осуществляется, а выполняется следующая по порядку команда — Move. Команда Move перемещает окончательный результат суммирования из регистра EAX в память по адресу SUM.
Проверка условия с последующим выбором одного из нескольких альтернативных путей реализации программы, называемая ветвлением, выполняется гораздо чаще, чем просто программные циклы. Такая возможность имеется в системах команд любых компьютеров, поскольку ветвления и циклы относятся к числу фундаментальных операций, без которых невозможно запрограммировать сколько-нибудь нетривиальную задачу.
Флаги кодов условий регистра состояния
Процессор отслеживает результаты выполнения различных операций, и сохраняет их для использования в последующих инструкциях условного перехода. Эту информацию он записывает в специальные биты регистра состояния, называемые флагами кодов условий. В зависимости от результата выполненной операции отдельные флаги устанавливаются в 1 или 0. Флаги процессора Intel:
CF – флаг переноса;флаг переполнения;
PF – флаг четности;
AF – флаг дополнительного переноса;
ZF – флаг нуля;
SF – флаг знака;
TF – флаг перехвата;
IF – флаг разрешения прерывания;
DF – флаг направления обработки строк;
OF – флаг переполнения.
CF (Carry Flag - флаг переноса). Устанавливается в 1, если результат предыдущей операции не уместился в приемнике и произошел перенос из старшего бита или если требуется заем (при вычитании), иначе устанавливается в 0.
PF (Parity Flag - флаг четности). Проверяет младшие восемь битов результатов операций над данными. Нечетное число битов приводит к установке этого флага в 0, а четное - в 1. Не следует путать флаг четности с битом контроля на четность. 1
AF (Auxiliary Carry Flag - вспомогательный флаг переноса). Устанавливается в 1, если арифметическая операция приводит к переносу четвертого справа бита (бит номер 3) в регистровой однобайтовой команде. Данный флаг имеет отношение к арифметическим операциям над символами кода ASCII и к десятичным упакованным полям.
ZF (Zero Flag - флаг нуля). Устанавливается в качестве результата арифметических команд и команд сравнения. Как это ни странно, ненулевой результат приводит к установке нулевого значения этого флага, а нулевой - к установке единичного значения. Кажущееся несоответствие является, однако, логически правильным, так как 0 означает "нет" (т.е. результат не равен нулю), а единица означает "да" (т.е. результат равен нулю). Команды условного перехода JE и JZ проверяют этот флаг.
SF (Sign Flag - флаг знака). Устанавливается в соответствии со знаком результата (старшего бита) после арифметических операций:
положительный результат устанавливает 0, а отрицательный - 1. Команды условного перехода JG и JL проверяют этот флаг. .
TF (Trap Flag - флаг трассировки). Этот флаг устанавливается, если используется команда Т в отладчике DEBUG. Если этот флаг установлен в единичное состояние, то процессор переходит в режим пошагового выполнения команд, т.е. в каждый момент выполняется одна команда под пользовательским управлением.
IF (Interrupt Flag - флаг прерывания). При нулевом состоянии этого флага прерывания запрещены, при единичном - разрешены.
DF (Direction Flag - флаг направления). Используется в строковых операциях для определения направления передачи данных. При нулевом состоянии команда увеличивает содержимое регистров SI И DI, вызывая передачу данных слева направо, при нулевом - уменьшает содержимое этих регистров, вызывая передачу данных справа налево.
OF (Overflow Flag - флаг переполнения). Фиксирует арифметическое переполнение, т.е. перенос в(из)) старший (знаковый) бит при знаковых арифметических операциях.
Ниже приводятся наиболее часто используемые из них:
Флаги S и Z указывают, является результат арифметической операции отрицательным или нулевым. Кроме арифметических команд на эти флаги воздействует команда TST, анализирующая значение в регистре или в памяти компьютера и устанавливающая либо очищающая флаги S и Z в соответствии с этими значениями. Флаг O указывает на то, что произошло переполнение. Как вы помните, переполнение происходит, когда результат арифметической операции превышает значение, которое можно представить с помощью количества битов, выделенного операнду. Процессор устанавливает флаг O для того, чтобы программист мог определить, что произошло переполнение, и перейти к подпрограмме, способной исправить данную ошибку. Кроме того, в результате установки бита O в большинстве компьютеров может автоматически выполняться программное прерывание, позволяющее решить эту проблему средствами самой операционной системы.
Флаг С устанавливается в 1, если в ходе арифметической операции осуществляется перенос из позиции старшего бита. Этот флаг позволяет выполнять арифметические операции над операндами, длина которых больше длины слова процессора. Такие операции реализуются в арифметике с многократно увеличенной точностью.
Примером команды условного перехода, проверяющей один или более флагов условий, может служить команда JGT (Переход если >0, описанная раньше. Она выполняет переход к другой точке программы в том случае, если проверяемое значение не отрицательно и не равно нулю. Это означает, что переход возможен, если ни S, ни Z не равен 1. Существует и множество других команд условного перехода, позволяющих проверять самые разнообразные условия. Задаются такие условия в виде логических выражений, включающих флаги их кодов.
В процессорах Intel флаги кодов условий автоматически устанавливаются командами, которые выполняют арифметические и логические операции.
Однако это не всегда так. Многие компьютеры поддерживают две версии команды Add. Одна из них, Add, не воздействует на флаги, а другая, AddSetCC (Adscc), воздействует. Благодаря этому программисты и компиляторы могут проявлять большую гибкость при создании программ, предназначенных для конвейерного выполнения. В процессоре I-32 и команда ADD и команда ADC, устанавливают флаги условия, но команда ADC при сложении прибавляет еще и значение флага CF.
Пример выполнения команд устанавливающих флаги регистра состояний.
Команда сложения. Перед выполнением команды, значение CF=1
Фрагмент программы:
MOV CX,1110001101000101b
MOV AX,1111111000011001b
ADD AX,CX
После выполнения команды ADD:
Регистр AX содержит: 1110000101011111;
флаги регистра состояния следующие:
OF=0
CF=1
SF=1
ZF=0
DF=0
IF =0
TF=0
AF=0
PF=1