Регистры процессора
Строго говоря, приведенное ниже описание относится только к процессорам 8086 и 80286, для которых были характерны 16-разрядные регистры. В современных процессорах типа Pentium почти все регистры 32-разрядные, что существенно увеличивает возможности компьютера. Однако младшие половины регистров этих процессоров совпадают и по названиям и по назначению с 16-разрядными регистрами процессора 8086. Поэтому программы, написанные для выполнения под управлением MS-DOS, т. е. для 16-разрядного процессора, прекрасно работают и с 32-разрядным, хотя и не используют все его возможности. Поначалу будет рассмотрена 16-разрядная архитектура процессора 8086 или, точнее, та часть современных процессоров, которая предназначена для использования в программах для системы MS-DOS. Этот гипотетический процессор будет называться МП 86.
МП 86 содержит двенадцать 16-разрядных программно-адресуемых регистров, которые принято объединять в три группы: регистры данных, регистры-указатели и сегментные регистры. Кроме того, в состав процессора входят счетчик команд и регистр флагов. Регистры данных и регистры-указатели часто называют регистрами общего назначения.
В группу регистров данных включаются регистры АХ, ВХ, СХ и DX. Программист может использовать их по своему усмотрению для временного хранения любых объектов (данных или адресов) и выполнения над ними требуемых операций. При этом регистры допускают независимое обращение к старшим (АН, ВН, СН и DH) и младшим (AL, BL, CL и DL) половинам. Так, команда
mov BL,AH
пересылает старший байт регистра АХ в младший байт регистра ВХ, не затрагивая при этом вторых байтов этих регистров. Еще раз отметим, что сначала указывается операнд-приемник, а после запятой - операнд-источник, т. е. команда выполняется как бы справа налево. В качестве средства временного хранения данных все регистры общего назначения (да и все остальные, кроме сегментных и указателя стека) вполне эквивалентны, однако многие команды требуют для своего выполнения использования вполне определенных регистров. Например, команда умножения mul требует, чтобы один из сомножителей был в регистре АХ (или AL), а команда организации цикла loop выполняет циклический переход СХ раз.
Индексные регистры SI и DI так же, как и регистры данных, могут использоваться произвольным образом. Однако их основное назначение - хранить индексы (смещения) относительно некоторой базы (т. е. начала массива) при выборке операндов из памяти. Адрес базы при этом обычно находится в одном из базовых регистров (ВХ или ВР). Примеры такого рода будут приведены ниже.
Регистр ВР служит указателем базы при работе с данными в стековых структурах, о чем будет речь впереди, но может использоваться и произвольным образом в большинстве арифметических и логических операций или просто для временного хранения каких-либо данных.
Последний из регистров-указателей, указатель стека SP, стоит особняком от других в том отношении, что используется исключительно как указатель вершины стека и будет подробно описан позже.
Регистры SI, DI, ВР и SP, в отличие от регистров данных, не допускают побайтовую адресацию.
Четыре сегментных регистра CS, DS, ES и SS хранят начальные адреса сегментов программы и, тем самым, обеспечивают возможность обращения к этим сегментам.
Регистр CS обеспечивает адресацию к сегменту, в котором находятся программные коды, регистры DS и ES - к сегментам с данными (таким образом, в любой точке программа может иметь доступ к двум сегментам данных, основному и дополнительному), а регистр SS - к сегменту стека. Сегментные регистры, естественно, не могут выступать в качестве регистров общего назначения.
Указатель команд IP (Instruction Pointer) "следит" за ходом выполнения программы, указывая в каждый момент относительный адрес команды, следующей за исполняемой. Регистр IP программно недоступен ; наращивание адреса в нем выполняет микропроцессор, учитывая при этом длину текущей команды.
Регистр флагов, эквивалентный регистру состояния процессора других вычислительных систем, содержит информацию о текущем состоянии процессора. Он включает 6 флагов состояния и 3 бита управления состоянием процессора, которые, впрочем, тоже обычно называются флагами.
Флаг переноса CF (Carry Flag) индицирует перенос или заем при выполнении арифметических операций, а также (что для прикладного программиста гораздо важнее!) служит индикатором ошибки при обращении к системным функциям.
Флаг паритета PF (Parity Flag) устанавливается в 1, если младшие 8 бит результата операции содержат четное число двоичных единиц.
Флаг вспомогательного переноса AF (Auxiliary Flag) используется в операциях над упакованными двоично-десятичными числами. Он индицирует перенос в старшую тетраду (четверку битов) или заем из старшей тетрады.
Флаг нуля ZF (Zero Flag) устанавливается в 1, если результат операции равен нулю.
Флаг знака SF (Sign Flag) показывает знак результата операции, устанавливаясь в 1 при отрицательном результате.
Флаг переполнения OF (Overflow Flag) фиксирует переполнение, т. е. выход результата операции за пределы допустимого для данного процессора диапазона значений.
Флаги состояния автоматически устанавливаются процессором после выполнения каждой команды. Так, если в регистре АХ содержится число 1, то после выполнения команды декремента (уменьшения на единицу)
dec AX
содержимое АХ станет равно нулю и процессор сразу отметит этот факт, установив в регистре флагов бит ZF (флаг нуля).
Если попытаться сложить два больших числа, например 58 000 и 61 000, то установится флаг переноса CF, так как число 119 000, получающееся в результате сложения, должно занять больше двоичных разрядов, чем помещается в регистрах или ячейках памяти, и возникает "перенос" старшего бита этого числа в бит CF регистра флагов.
Индицирующие флаги процессора дают возможность проанализировать, если это нужно, результат последней операции и осуществить "разветвление" программы: например, в случае нулевого результата перейти на выполнение одного фрагмента программы, а в случае ненулевого - на выполнение другого. Такие разветвления осуществляются с помощью команд условных переходов, которые в процессе своего выполнения анализируют состояние регистра флагов. Так, команда
jz zero
осуществляет переход на метку zero, если результат выполнения предыдущей команды окажется равен нулю (т. е. флаг ZF установлен), а команда
jnc okey
выполнит переход на метку okey, если предыдущая команда сбросила флаг переноса CF (или оставила его в сброшенном состоянии).
Управляющий флаг трассировки TF (Trace Flag) используется в отладчиках для осуществления пошагового выполнения программы. Если TF=l, то после выполнения каждой команды процессор реализует процедуру прерывания 1 (через вектор прерывания с номером 1).
Управляющий флаг разрешения прерываний IF (Interrupt Flag) разрешает (если равен единице) или запрещает (если равен нулю) процессору реагировать на прерывания от внешних устройств.
Управляющий флаг направления DF (Direction Flag) используется особой группой команд, предназначенных для обработки строк. Если DF=0, строка обрабатывается в прямом направлении, от меньших адресов к большим; если DF=1, обработка строки идет в обратном направлении.
Таким образом, в отличие от битов состояния, управляющие флаги устанавливает или сбрасывает программист, если он хочет изменить настройку системы (например, запретить на какое-то время аппаратные прерывания или изменить направление обработки строк).