PersCom — Компьютерная Энциклопедия Компьютерная Энциклопедия

Процессор

Управление вычислительным процессом

Управление вычислительным процессом

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

  1. Условное ветвление. Необходимость разветвления в алгоритме: в зависимости от того, каким получился некий промежуточный результат, следует выполнить одно из двух различных действий. Пример: поиск заданной фамилии в списке студентов. Если очередная фамилия совпала с искомой, поиск следует прекратить, если нет — поиск надо продолжить.
  2. Программный цикл. Выполнение одной и той же последовательности действий с несколькими экземплярами данных. Для этого можно написать последовательность команд так, чтобы она могла обрабатывать элементы данных, находящиеся в задаваемых адресах. В конце такой последовательности следует организовать разветвление. Если еще не все элементы данных обработаны, следует, нарушив порядок команд "подряд", перейти к началу последовательности команд, одновременно изменив адреса обрабатываемых данных. Если же все требуемые данные обработаны, — продолжить выполнение программы далее.
  3. Модульная иерархическая структура программы.

Проверка условий, флаги и набор команд ветвления

Сравнение в ЭВМ используется для организации последующего ветвления алгоритма (условного перехода в программе) в зависимости от результата сравнения. Сравнение можно производить по условиям:

  • а) равно / неравно;
  • б) больше / меньше.

Условие а) всегда осмысленно и формально означает, что все биты сравниваемых операндов одинаковы. Семантика условия б) понятна для данных, которые неким образом упорядочены, таких, как числа или символы алфавита. Для такого вида данных, как битовые поля, не всегда понятно, что такое "больше / меньше".

Сравнение в процессоре происходит по одной из двух схем:

  1. Сравнение операнда с нулем (его можно произвести специальной командой “проверка”: в системе команд х86 — команда test a, b).
  2. Сравнение двух операндов между собой (вычитанием и последующим сравнением результата с нулем)

Для сравнения двух чисел можно использовать команды вычитания. Кроме того, обычно в системе команд есть специальные команды для сравнения. В i*86 это команда cmp a,b — она делает вычитание a — b, по результату операции модифицируются все 4 основных флага — cf, of, zf, sf, после чего результат вычитания теряется, а операнды сохраняются неизменными.

Для сравнения с нулем есть специальные команды "проверить операнд" (в i*86 — команда test a, b), а, кроме того, — флаги zf и sf могут устанавливаться при выполнении других команд (таких, как загрузки и пересылки).

После выполнения команды, осуществляющей сравнение (и переустанавливающей флаги), надо осуществить ветвление. Для этого в процессоре обычно существует большая группа команд условного ветвления, которое происходит (или нет) в зависимости от состояний тех или иных флагов. В группе команд ветвления можно выделить три подгруппы (Таблица 1, Таблица 2, Таблица 3).

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

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

Организация в программе циклических конструкций

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

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

Один из вариантов цикла предусматривает заранее (до начала выполнения цикла) определенное количество повторений. В этом случае:

  1. заводят специальную переменную;
  2. перед началом цикла заносят в нее требуемое количество повторений;
  3. выполняют команды цикла;
  4. в конце цикла уменьшают переменную цикла на 1;
  5. проверяют переменную цикла на равенство нулю и, если не равно, повторяют, начиная с п.3

В системе команд процессоров х86 есть команда организации цикла loop. Ее недостаток состоит в том, что она в качестве переменной-счетчика цикла позволяет использовать только регистр процессора ECX. Это ее свойство затрудняет организацию вложенных циклических конструкций.

Организация иерархической структуры программы

Современные "большие" программы содержат и более команд. Для того чтобы можно было в такой программе разобраться (не говоря уже о том, что ее надо перед этим написать и отладить), программа должна быть структурирована. Основное средство структурирования на уровне системы команд процессора — это поддержка аппаратным уровнем (система команд, способы адресации) организации подпрограмм.

В 60...70 годах развилась манера, называемая "структурным программированием", которая широко использовала подпрограммную структуру и еще ряд договоренностей. Структурное программирование позволило значительно увеличить производительность труда при написании сложных программ и повысить их надежность. Сущность понятия подпрограмма (ПП) состоит в следующем.

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

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

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

При этом необходимо обеспечить несколько дополнительных действий:

  1. После выполнения ПП управление надо вернуть в место вызова (каждый раз оно может быть разным, т.е. требуется при каждом вызове запоминать адрес возврата) — будем называть это действие связью по управлению.
  2. При передаче управления ПП надо передать ей также и исходные данные (при суммировании элементов массива это могут быть начальный адрес массива и число элементов), а при возврате управления в место вызова надо туда также вернуть и результат (в приведенном примере это сумма массива) — это действие будем называть связью по данным.
  3. Вызываемый фрагмент кода (подпрограмма) может использовать при своей работе ресурсы, такие как регистры процессора и т.п. К моменту вызова эти регистры могут содержать результаты работы предшествующих команд, которые будут нужны в дальнейшем. Совокупность переменных величин (содержимых регистров процессора, ячеек памяти), полностью характеризующих состояние программы, будем называть контекстом программы. При вызове подпрограммы нужно сохранить ту часть контекста вызывающей программы, которую подпрограмма при своей работе может изменить (испортить).
  4. Подпрограмме для работы могут потребоваться локальные переменные величины. Часть из них может располагаться в регистрах, другая часть — в ячейках памяти. Эти переменные нужны только до окончания работы подпрограммы (до возврата в вызывающую программу). При возврате занятую память хорошо бы освободить.
  5. В некоторых случаях одновременно может существовать несколько экземпляров одной подпрограммы, каждая со своим контекстом. Соответственно нужно несколько экземпляров локальных переменных. Простейший пример — рекурсивный вызов, когда подпрограмма вызывает сама себя.

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

Обращение к подпрограммам — передача управления

Для работы с подпрограммами в составе системы команд любого процессора есть две команды (см. рисунок ниже):

  1. Команда обращения к подпрограмме ОП (для этой команды используются мнемоники call, jsr). Эта команда должна автоматически запоминать адрес возврата, т.е. адрес команды, следующей за командой call. В современных процессорах при выполнении команды обращения к ПП адрес возврата запоминается автоматически в стеке.
  2. Команда возврата из ПП (используются мнемоники ret, rts).

Связь с подпрограммой по управлению