Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

УНІВЕРСИТЕТ 6 страница



Необходимо также иметь небольшое число дополнительных команд (например, команды условных переходов), но они легко подходят под формат 3. Например, можно приписать один код операции каждому (условному) переходу, вызову процедуры и т. д., тогда останется 24 бита для смещения по счетчику команд. Если предположить, что это смещение считается в словах, период будет составлять ± 32 Мбайт. Несколько кодов операций можно зарезервировать для команд LOAD и STORE, которым нужны длинные смещения из формата 3. Они не будут общими (например, только регистр R0 будет загружаться и сохраняться), и использоваться будут довольно редко.

Теперь рассмотрим разработку для двухадресной машины, в которой в каче-

стве любого операнда может использоваться слово из памяти (рис. 5.17). Такая машина может прибавлять слово из памяти к регистру, прибавлять регистр к слову из памяти, складывать два регистра или складывать два слова из памяти. В настоящее время осуществлять доступ к памяти довольно дорого, поэтому данный проект не очень популярен, но если с развитием технологий доступ к памяти в будущем станет дешевле, такой подход будет считаться простым и эффективным. Машины PDP-11 и VAX были очень популярны и доминировали на рынке мини-компьютеров в течение двух десятилетий. В этих машинах использовались форматы, сходные с тем, который изображен на рис. 5.17.

Здесь мы снова имеем 8-битный код операции, но теперь у нас есть 12 битов

для определения источника и 12 битов для определения пункта назначения. Для каждого операнда 3 бита дают метод адресации, 5 битов дают регистр и 4 бита дают смещение. Имея 3 бита для установления метода адресации, мы можем поддерживать непосредственную, прямую, регистровую, косвенную регистровую индексную и стековую адресации, и при этом еще остается место для двух дополнительных методов, которые, возможно, появятся в будущем. Это простая разработка, которую легко компилировать; она достаточно гибкая, особенно если счетчик программ, указатель стека и указатель локальных переменных находятся среди регистров общего назначения, к которым можно получить доступ.

Единственная проблема, которая здесь есть, - это то, что при прямой адресации нам нужно большее количество битов для адреса. В машинах PDP-11 и VAX к команде было добавлено дополнительное слово для адреса каждого прямо адресуемого операнда. Мы тоже могли бы использовать один из двух доступных способов адресации для индексной адресации с 32-битным смещением, которое следует за командой. Тогда в худшем случае при прибавлении слова из памяти к слову из памяти, когда обращение к обоим операндам производится с помощью прямой адресации, или при использовании длинной индексной формы команда была бы 96 битов в длину и занимала бы 3 цикла шины (один - для команды и два – для данных). С другой стороны, большинству разработок типа RISC потребовалось бы по крайней мере 96 битов, а может и больше, для прибавления произвольного

слова из памяти к другому произвольному слову из памяти, и тогда нужно было бы по крайней мере 4 цикла шины.

Помимо форматов, изображенных на рис. 5.17, возможны и другие варианты.

В данной разработке можно выполнять операцию с помощью одной 32 битной команды, при условии что i HJ находятся среди первых 16 локальных переменных. Для переменных после 16 нам приходится переходить к 32-битным смещениям. Можно сделать другой формат с одним 8-битным смещением вместо двух 4-битных и правилом, что это смещение может использоваться либо источником, либо пунктом назначения, но не тем и другим одновременно. Варианты компромиссов не ограничены, и разработчики должны учитывать многие факторы, чтобы получить хороший результат.

Способы адресации процессора Pentium II

Способы адресации процессора Pentium II чрезвычайно нерегулярны и зависят от того, в каком формате находится конкретная команда - 16-битном или 32-битном. Мы не будем рассматривать 16-битные команды. Вполне достаточно 32-битных. Поддерживаемые способы адресации включают непосредственную, прямую, регистровую, косвенную регистровую индексную и специальную адресацию для обращения к элементам массива. Проблема заключается в том, что не все способы применимы ко всем командам и не все регистры могут использоваться при всех способах адресации. Это сильно усложняет работу составителя компилятора. Байт MODE на рис. 5.9 управляет способами адресации. Один из операндов

определяется по комбинации полей MOD и R/M. Второй операнд всегда является регистром и определяется по значению поля REG. В таблице 5.7 приведен список 32 комбинаций значений 2-битного поля MOD и 3-битного поля R/M. Например, если оба поля равны 0, операнд считывается из ячейки памяти с адресом, который содержится в регистре ЕАХ.

Колонки 01 и 10 включают способы адресации, при которых значение регистра прибавляется к 8-битному или 32-битному смещению, которое следует за командой. Если выбрано 8-битное смещение, оно перед сложением получает 32-битное зьэковое расширение. Например, команда ADD с полем R/M=011, полем MOD=01 и смещением, равным 6, вычисляет сумму регистра ЕВХ и 6, и в качестве одного из операндов считывает слово из полученного адреса памяти. Значение регистра ЕВХ не изменяется.

При MOD=11 предоставляется выбор из двух регистров. Для команд со словами берется первый вариант, для команд с байтами — второй. Отметим, что здесь не все регулярно. Например, нельзя осуществить косвенную адресацию через ЕВР или прибавить смещение к ESP.

Иногда вслед за байтом MODE следует дополнительный байт SIB (Scale, Index, Base - масштаб, индекс, база) (см. рис. 5.9). Байт SIB определяет масштабный коэффициент и два регистра. Когда присутствует байт SIB, адрес операнда вычисляется путем умножения индексного регистра на 1, 2, 4 или 8 (в зависимости от SCALE), прибавлением его к базовому регистру и, наконец, возможным прибавлением 8- или 32-битного смещения, в зависимости от значения поля MOD. Практически все регистры могут использоваться и в качестве индекса, и в качестве базы. Форматы SIB могут пригодиться для обращения к элементам массива. Рассмотрим следующее выражение на языке Java: for (i=0; i<n; i++) a[i]=0;

где а - это массив 4-байтных целых чисел, относящийся к текущей процедуре. Обычно регистр ЕВР используется для указания на базу стекового фрейма, который содержит локальные переменные и массивы, как показано на рис. 5.18. Компилятор должен хранить i в регистре ЕАХ. Для доступа к элементу a[i] он будет использовать формат SIB, в котором адрес операнда равен сумме 4хЕАХ, ЕВР и 8. Эта команда может сохраняться в a[i] за одну команду. А стоит ли применять такой способ адресации? На этот вопрос трудно ответить. Без сомнения, эта команда при надлежащем использовании сохраняет несколько циклов. Насколько часто она используется, зависит от компилятора и от приложения. Проблема здесь в том, что эта команда занимает определенное количество пространства микросхемы, которое можно было бы использовать для других целей, если бы этой команды не было. Например, можно было бы сделать больше кэш-память первого уровня. Мы представили несколько возможных компромиссов, с которыми постоянно сталкиваются разработчики. Обычно перед тем как воплотить какую-либо идею в кремнии, производятся обширные моделирующие прогоны, но для этого нужно иметь представление о том, какова рабочая нагрузка. Можно быть уверенным, что разработчики машины 8088 не включили web-браузер в набор тестов. Решения, принятые 20 лет назад, могут оказаться абсолютно неудачными с точки зрения

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

Способы адресации процессора UltraSPARC II

В архитектуре команд процессора UltraSPARC все команды используют непосредственную или регистровую адресацию, за исключением тех команд, которые обращаются к памяти. При регистровом способе адресации 5 битов просто сообщают, какой регистр нужно использовать. При непосредственной адресации данные обеспечивает 13-битная константа со знаком. Для арифметических, логических и подобных команд никакие другие способы адресации не используются. К памяти обращаются команды трех типов: команды загрузки (LOAD), команды сохранения (STORE) и одна команда синхронизации мультипроцессора. Для команд LOAD и STORE есть два способа обращения к памяти. Первый способ' вычисляется сумма двух регистров, а затем через полученное значение производится косвенная

адресация. Второй способ представляет собой обычное индексирование с 13-битным смещением со знаком.

Способы адресации машины JVM

У машины JVM нет общих способов адресации в том смысле, что каждая команда содержит несколько битов, которые сообщают, как нужно вычислить адрес (как в Pentium II, например). Вместо этого здесь с каждой командой связан один особый способ адресации. Поскольку в JVM нет видимых регистров, регистровая и косвенная регистровая адресация здесь невозможна. Несколько команд, например BIPUSH, используют непосредственную адресацию. Единственный оставшийся доступный способ - индексная адресация. Она используется командами LOAD, ISTORE, LDCW, а также несколькими командами, которые определяют переменную, связанную с каким-нибудь неявным регистром, обычно LV или СРР. Команды перехода тоже используют индексную адресацию, при этом PC рассматривается как регистр.

Сравнение способов адресации

Мы только что рассмотрели несколько способов адресации. Способы адресации машин Pentium II, UltraSPARC II и JVM изложены в табл. 5.8. Как мы уже говорили, не каждый способ может использоваться любой командой.

На практике для эффективной архитектуры команд вовсе не требуется боль-

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

Поэтому самые простые архитектуры используют очень небольшое число

способов адресации, причем на каждый из этих способов накладываются жесткие ограничения. Обычно практически для любых применений достаточно непосредственной, прямой, регистровой и индексной адресации. Каждый регистр (включая указатель локальных переменных, указатель стека и счетчик программ) должен быть пригоден к употреблению всякий раз, когда этот регистр требуется. Более сложные способы адресации могут сократить число команд, но при этом придется ввести последовательности операций, которые трудно будет выполнять параллельно с другими последовательными операциями. Мы рассмотрели возможные компромиссы между кодами операций и адресами и между различными способами адресации. Когда вы сталкиваетесь с новым компьютером, вы должны изучить все команды и способы адресации не только для того, чтобы знать, какие из них имеются в наличии, но и для того, чтобы понять, почему был сделан именно такой выбор и каковы были бы последствия при другом выборе.

Лекция 14. Команды управления.

1. Бинарные и унарные операции.

2. Последовательный поток управления и переходы.

3. Процедуры и сопрограммы.

4. Ловушки и прерывания

1.Бинарные операции

Бинарные операции - это такие операции, которые берут два операнда и получают из них результат. Все архитектуры команд содержат команды для сложения и вычитания целых чисел. Команды умножения и деления целых чисел также имеются практически во всех случаях. Думаю, нет необходимости объяснять, почему компьютеры оснащены арифметическими командами.

Следующая группа бинарных операций содержит булевы команды. Существует 16 булевых функций от двух переменных, но есть очень немного машин, в которых имеются команды для всех 16. Обычно присутствуют И, ИЛИ и НЕ; иногда кроме них еще есть ИСКЛЮЧАЮЩЕЕ ИЛИ, НЕ-ИЛИ и НЕ-И. Важным применением команды И является выделение битов из слов. Рассмотрим машину со словами длиной 32 бита, в которой на одно слово приходится четыре 8-битных символа. Предположим, что нужно отделить второй символ от остальных трех, чтобы его напечатать. Это значит, что нужно создать слово, которое содержит этот символ в правых 8 битах с нулями в левых 24 битах (так называемое выравнивание по правому биту).

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

10110111 10111100 11011011 10001011 А

00000000 11111111 00000000 00000000 В (маска)

00000000 10111100 00000000 00000000 АИВ

Затем результат сдвигается на 16 битов вправо, чтобы нужный символ находился в правом конце слова. Важным применением команды ИЛИ является помещение битов в слово. Эта операция обратна операции извлечения. Чтобы изменить правые 8 битов 32-битного слова, не повредив при этом остальные 24 бита, сначала нежелательные 8 битов надо заменить на нули, а затем новый символ соединить операцией ИЛИ с полученным результатом, как показано ниже:

10110111 10111100 11011011 10001011 А

11111111 11111111 11111111 00000000 В (маска)

10110111 10111100 ПОПОИ 00000000 АИ В

00000000 00000000 00000000 01010111 С

10110111 10111100 ПОПОИ 01010111 (АИВ) ИЛИ С

Операция И убирает единицы, и в полученном результате никогда не бывает

больше единиц, чем в любом из двух операндов. Операция ИЛИ вставляет единицы, и поэтому в полученном результате всегда по крайней мере столько же единиц, сколько в операнде с большим количеством единиц. Команда ИСКЛЮЧАЮЩЕЕ ИЛИ, в отличие от них, симметрична в отношении единиц и нулей. Такая симметрия иногда может быть полезной, например при порождении случайных чисел.

Большинство компьютеров сегодня поддерживают команды с плавающей точкой, которые в основном соответствуют арифметическим операциям с целыми числами. Большинство машин содержит по крайней мере 2 варианта таких чисел: более короткие для скорости и более длинные на тот случай, если требуется высокая точность вычислений. Существует множество возможных форматов для чисел с плавающей точкой, но сейчас практически везде применяется единый стандарт IEEE 754. Числа с плавающей точкой и этот стандарт обсуждаются в приложении Б.

Унарные операции

Унарные операции используют один операнд и производят один результат. Поскольку в данном случае нужно определять на один адрес меньше, чем в бинарных операциях, команды иногда бывают короче, хотя часто требуется определять другую информацию. Команды для сдвига и циклического сдвига очень полезны. Они часто даются в нескольких вариантах. Сдвиги - это операции, при которых биты сдвигаются налево или направо, при этом биты, которые сдвигаются за пределы слова, утрачиваются. Циклические сдвиги - это сдвиги, при которых биты, вытесненные с одного конца, появляются на другом конце. Разница между обычным сдвигом и циклическим сдвигом показана ниже:

00000000 00000000 00000000 01110011 А

00000000 00000000 00000000 00011100 сдвиг вправо на 2 бита

11000000 00000000 00000000 00011100 циклический сдвиг вправо на 2 бита

Обычные и циклические сдвиги влево и вправо очень важны. Если п-битное

слово циклически сдвигается влево на к битов, результат будет такой же, как при циклическом сдвиге вправо на n-k битов.

Сдвиги вправо часто выполняются с расширением по знаку. Это значит, что

позиции, освободившиеся на левом конце слова, заполняются изначальным знаковым битом (0 или 1), как будто знаковый бит перетащили направо. Кроме того, это значит, что отрицательное число останется отрицательным. Ниже показаны сдвиги на 2 бита вправо:

1111111 11111111 11111111 11110000А

0011111 11111111 11111111 11111100 А сдвинуто без знакового расширения

1111111 11111111 11111111 11111100 А сдвинуто со знаковым расширением

Операция сдвига используется при умножении и делении на 2. Если положи-

тельное целое число сдвигается влево на к битов, результатом будет изначальное число, умноженное на 2к. Если положительное целое число сдвигается вправо на к битов, результатом будет изначальное число, деленное на 2к. Сдвиги могут использоваться для повышения скорости выполнения некоторых арифметических операций. Рассмотрим выражение 18хп, где п - положительное целое число. 18xn=16xn+2xn. 16xn можно получить путем сдвига копии п на 4 бита влево. 2хп можно получить, сдвинув п на 1 бит влево. Сумма этих двух чисел равна 18хп. Таким образом, это произведение можно вычислить путем одного перемещения, двух сдвигов и одного сложения, что обычно гораздо быстрее, чем сама операция умножения. Конечно, компилятор может применять такую схему, только если один из множителей является константой. Сдвиг отрицательных чисел даже со знаковым расширением дает совершенно другие результаты. Рассмотрим, например, число -1 в обратном двоичном коде. При сдвиге влево на 1 бит получается число -3. При сдвиге влево еще на 1 бит получается число -7:

11111111 11111111 11111111 11111110 число-1 в обратном двоичном коде

11111111 11111111 11111111 11111100 число-1 сдвигается влево на 1 бит (-3)

11111111 11111111 11111111 11111000 число-1 сдвигается влево на2бита(-7)

Сдвиг влево отрицательных чисел в обратном двоичном коде не умножает число на 2. Однако сдвиг вправо производит деление корректно.

А теперь рассмотрим число -1 в дополнительном двоичном коде. При сдвиге

вправо на 6 бит с расширением по знаку получается число - 1, что неверно, поскольку целая часть от -1/64 равна 0:

11111111 11111111 11111111 11111111 число -1 в дополнительном двоичном

коде

11111111 11111111 11111111 11111111 число-1, сдвинутое влево на 6 битов,

равно -1

Как мы видим, сдвиг вправо вызывает ошибки. Однако при сдвиге влево число умножается на 2.

Операции циклического сдвига нужны для манипулирования последователь-

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

В некоторых бинарных операциях очень часто используются совершенно определенные операнды, поэтому в архитектуры команд часто включаются унарные операции для их быстрого выполнения. Например, перемещение нуля в память или регистр чрезвычайно часто выполняется при начале вычислений. Перемещение нуля - это особый случай команды перемещения данных. Поэтому для повышения производительности часто вводится операция CLR с единственным адресом той ячейки, которую нужно очистить (то есть установить на 0). Прибавление 1 к слову тоже часто используется при различных подсчетах. Унарная форма команды ADD - это операция INC, которая прибавляет 1. Другой пример - операция NEG. Отрицание X - это на самом деле бинарная операция вычитания 0-Х, но поскольку операция отрицания очень часто применяется, в архитектуру команд вводится команда NEG. Важно понимать разницу между арифметической операцией NEG и логической операцией NOT. Операция NEG производит аддитивную инверсию числа (такое число, сумма которого с изначальным числом дает 0).

Операция NOT просто инвертирует все биты в слове. Эти операции очень похожи, а для системы, в которой используется представление в обратном двоичном коде, они идентичны. (В арифметике дополнительных кодов для выполнения команды NEG сначала инвертируются все биты, а затем к полученному результату прибавляется 1.)

Унарные и бинарные операции часто объединяются в группы по функциям,

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

Сравнения и условные переходы

Практически все программы должны проверять свои данные и на основе результатов изменять последовательность команд, которые нужно выполнить. Рассмотрим функцию квадратного корня Ох. Если число х отрицательное, процедура сообщает об ошибке; если число положительное, процедура вычисляет квадратный корень. Функция sqrt должна проверять х, а затем совершать переход в зависимости от того, положительно число х или отрицательно. Это можно сделать с помощью специальных команд условного перехода, которые проверяют какое-либо условие и совершают переход в определенный адрес памяти, если условие выполнено. Иногда определенный бит в команде указывает, нужно ли осуществлять переход в случае выполнения условия или в случае невыполнения условия соответственно. Часто целевой адрес является не абсолютным, а относительным (он связан с текущей командой).

Самое распространенное условие, которое нужно проверить, - равен ли определенный бит нулю или нет. Если команда проверяет знаковый бит числа и совершает переход к метке (LABEL) при условии, что бит равен 1, то если число было отрицательным, будут выполняться те утверждения, которые начинаются с метки LABEL, а если число было положительным или было равно 0, то будут выполняться те утверждения, которые следуют за условным переходом.

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

В некоторых процессорах есть специальный разряд (бит) переноса, который

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

Проверка на ноль очень важна при выполнении циклов и в некоторых других

случаях. Если бы все команды условного перехода проверяли только 1 бит, то тогда для проверки определенного слова на 0 нужно было бы отдельно проверять каждый бит, чтобы убедиться, что ни один бит не равен 1. Чтобы избежать подобной ситуации, во многие машины включается команда, которая должна проверять слово и осуществлять переход, если оно равно 0. Конечно же, это решение просто перекладывает ответственность на микроархитектуру. На практике аппаратное обеспечение обычно содержит регистр, все биты которого соединяются операцией ИЛИ, чтобы выдать на выходе один бит, по которому можно определить, содержит ли регистр биты, равные 1. Бит Z на рис. 4.1 обычно вычисляется следующим образом: сначала все выходные биты АЛУ соединяются операцией ИЛИ, а затем

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

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

Одно из возможных решений - ввести команду, которая выполняет сравнение

и записывает результат в один или несколько битов условия. Следующая команда может проверить биты условия и совершить переход, если два сравниваемых значения были равны, или неравны, или первое из них было больше второго и т. д. Такой подход применяется в Pentium II и UltraSPARC II. В сравнении двух чисел есть некоторые тонкости. Сравнение - это не такая

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

В колонке слева приведены положительные числа от 0 до 7 по возрастанию.

В колонке справа показаны целые числа со знаком от -4 до +3 в дополнительном двоичном коде. Ответ на вопрос: «Какое число больше: 011 или 100?» зависит от того, считаются ли числа числами со знаком. В большинстве архитектур есть команды для обращения с обоими типами упорядочения.

Команды вызова процедур

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

Адрес возврата может помещаться в одном из трех мест: в памяти, в регистре

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

Более удачное решение - сохранить адрес возврата в первом слове процедуры. Тогда первой выполняемой командой будет второе слово процедуры. После завершения процедуры происходит переход к первому слову, а если аппаратное обеспечение в первом слове наряду с адресом возврата дает код операции, то происходит непосредственный переход к этой операции. Процедура может вызывать другие процедуры, поскольку в каждой процедуре имеется пространство для одного адреса возврата. Но если процедура вызывает сама себя, эта схема не работает, поскольку первый адрес возврата будет уничтожен вторым вызовом. Способность процедуры вызывать саму себя, называемая рекурсией, очень важна и для теоретиков, и

для практиков. Более того, если процедура А вызывает процедуру В, процедура В вызывает процедуру С, а процедура С вызывает процедуру А (непосредственная или цепочечная рекурсия), эта схема сохранения адреса возврата также не работает.

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

Самое лучшее решение - поместить адрес возврата в стек. Когда процедура

завершена, она выталкивает адрес возврата из стека. При такой форме вызова процедур рекурсия не порождает никаких проблем; адрес возврата будет автоматически сохраняться таким образом, чтобы избежать уничтожения предыдущего адреса возврата. Мы рассматривали такой способ сохранения адреса возврата в машине ПУМ(см.рис.4.10).

Управление циклом

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

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

выполнение цикла. Последняя команда цикла обновляет счетчик, и если условие завершения цикла еще не выполнено, то происходит возврат к первой команде цикла. Если условие выполнено, цикл завершается и начинается выполнение команды, идущей сразу после цикла. Цикл такого типа с проверкой в начале представлен в листинге 5.3. (Мы не могли здесь использовать язык Java, поскольку в нем нет оператора goto.)

Цикл такого типа всегда будет выполняться хотя бы один раз, даже если п<0.

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





Дата публикования: 2014-10-17; Прочитано: 655 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.007 с)...