Э. Таненбаум - Архитектура компьютера (1127755), страница 106
Текст из файла (страница 106)
Бит переноса нельзя путать с битом переполнения. Проверка бита переноса необходима для вычислений с повышенной точностью (то есть когда целое число представлено двумя или более словами). Проверка на ноль очень важна при выполнении циклов и в некоторых других случаях. Если бы все команды условного перехода проверяли только 1 бит, то тогда для проверки определенного слова на равенство О нужно было бы поочередно проверять каждый бит, чтобы убедиться, что ни один из них не равен 1.
Чтобы избежать подобной ситуации, многие машины поддерживают команду, которая проверяет слово целиком и выполняет переход, если оно равно О. Конечно же, в этом решении все равно проверяется каждый бит, просто ответственность за проверку перекладывается на микроархитектуру. На практике в число устройств обычно включается регистр, все биты которого соединяются операцией ИЛИ, чтобы получить в результате бит, показывающий, имеются ли в регистре единичные биты. Бит Х на рис.
4.1 обычно вычисляется следующим образом: сначала все выходные биты АЛУ соединяются операцией ИЛИ, а затем полученный результат инвертируется. Операция сравнения слов или символов очень важна, например, при сортировке. Чтобы выполнить сравнение, требуется три адреса: два нужны для данных, а по третьему адресу будет совершаться переход в случае выполнения условия. В тех компьютерах, где форматы команд позволяют иметь три адреса в команде, проблем не возникает.
Но если такие форматы не предусмотрены, нужно что-то делать, чтобы обойти проблему. Одно из возможных решений — ввести команду, которая выполняет сравнение и записывает результат в виде одного или нескольких битов условий. Следующая команда может проверять биты условия и совершать переход, если два сравниваемых значения были равны, или если они были неравны, или если первое из них было больше второго и т. д.
Такой подход применяется в Репгшш 4 и ПггаЯРАВС П1. Типы команд 425 В операции сравнения двух чисел есть некоторые тонкости. Сравнение — это не такая простая операция, как вычитание. Если очень большое положительное число сравнивается с очень большим отрицательным числом, операция вычитания приведет к переполнению, поскольку результат вычитания будет невозможно представить. Тем не менее команда сравнения и в этом случае должна определить, удовлетворяется ли условие, и возвратить правильный ответ.
При сравнении переполнения возникать не должно. Кроме того, при сравнении чисел нужно решить, считать ли числа числами со знаком или числами без знака. 3-разрядные бинарные числа можно упорядочить двумя способами. От самого маленького к самому большому: + Без знака; 000, 001, 010, 011, 100, 101, 110, 111. + Со знаком: 100, 101, 110, 111, 000, 001, 010, 011. В первой строке по возрастанию перечислены положительные числа от 0 до 7, во второй — целые числа со знаком от -4 до «3 в дополнительном двоичном коде (тоже по возрастанию). Ответ на вопрос: «Какое число больше: 011 или 100?»вЂ” зависит от того, считаются ли числа числами со знаком. В большинстве архитектур есть команды для обработки обоих вариантов упорядочения.
Команды вызова процедур Процедурой называют группу команд, которая решает определенную задачу и которую можно вызывать из разных мест программы. Вместо термина «процедура» часто используется термин «подпрограмма», особенно когда речь идет о программах на языке ассемблера. Когда процедура заканчивает решение задачи, она должна вернуться к оператору, расположенному в программе следом за оператором вызова процедуры. Следовательно, адрес возврата должен как-то передаваться процедуре или сохраняться где-либо таким образом, чтобы можно было определить, куда возвращаться после решения задачи. Адрес возврата может помещаться в одном из трех мест: в памяти, в регистре или в стеке.
Самое худшее решение — поместить этот адрес в фиксированную ячейку памяти. Тогда, если процедура вызовет другую процедуру, второй вызов приведет к потере первого адреса возврата. Более удачное решение — сохранить адрес возврата в первом слове процедуры, а первой выполняемой командой сделать второе слово процедуры. После завершения процедуры будет происходить переход к первому слову, а если аппаратно в первом слове наряду с адресом возврата предоставить код операции, произойдет непосредственный переход к этой операции, Процедура может вызывать другие процедуры, поскольку в каждой процедуре имеется пространство для одного адреса возврата.
Но если процедура вызывает сама себя, эта схема не сработает, поскольку первый адрес возврата будет уничтожен вторым вызовом. (Способность процедуры вызывать саму себя, называемая рекурсией, очень важна и теоретически, и практически,) Более того, если процедура А вызывает процедуру В, процедура В вызывает процедуру С, а процедура С вызывает процеду- руА (непосредственная, или цепачечная, рекурсия), эта схема сохранения адреса возврата также не сработает. 426 Глава 5. Уровень архитектуры набора команд Еще более удачное решение — поместить адрес возврата в регистр. Тогда если процедура рекурсивна, ей придется помещать адрес возврата в другое место каждый раз, когда она вызывается.
Самое лучшее решение — поместить адрес возврата в стек. Тогда при завершении процедуры, она должны выталкивать адрес возврата из стека. При такой форме вызова процедур рекурсия не порождает никаких проблем; адрес возврата будет автоматически сохраняться таким образом, чтобы не уничтожить предыдущий адрес возврата. Мы рассматривали такой способ сохранения адреса возврата в машине (1'е'М (см. рис. 4.10). Управление циклами Часто возникает необходимость выполнять некоторую группу команд фиксированное количество раз, поэтому некоторые машины для управления этим процессом содержат специальные команды.
Во всех схемах подобного рода имеется счетчик, который увеличивается или уменьшается на какую-либо константу каждый раз при выполнении цикла. Кроме того, этот счетчик каждый раз проверяется. В случае удовлетворения проверяемого условия цикл завершается. Счетчик запускается вне цикла, и затем сразу начинается выполнение цикла.
Последняя команда цикла обновляет счетчик, и, если условие завершения цикла еще не удовлетворено, происходит возврат к первой команде цикла. Если условие удовлетворено, цикл завершается и начинается выполнение команды, расположенной сразу после цикла. Цикл такого типа с проверкой в конце цикла представлен в листинге 5.3. (Мы не могли здесь использовать язык дача, поскольку в нем нет оператора добро). Листинг 5.3.
Цикл с проверкой в конце 1 = 1. 'с1: первей оператор; последний оператор; т=1т1: 1т' 11пп1 пото с1; Цикл такого типа всегда будет выполнен хотя бы один раз, даже если и < О. Представим программу, которая поддерживает базу данных о персонале компании. В определенном месте программа начинает считывать информацию о конкретном работнике. Она считывает число п — количество детей у работника, и выполняет цикл и раз, по одному разу на каждого ребенка.
В цикле она считывает его имя, пол и дату рождения, так что компания сможет послать ему (или ей) подарок точно в срок. Однако если у работника нет детей и значение и равно О, цикл все равно будет выполнен один раз, что даст ошибочные результаты. В листинге 5.4 представлен другой способ проверки, который дает правильные результаты даже при п ( О. Отметим, что если и увеличение счетчика, и проверка условия выполняются в одной команде, разработчикам придется выбирать один из двух методов.
Типы команд 427 Листинг 5.4. Цикл с проверкой в начале т'=1, 11. т Г(тип) дота 12: первый оператор, паспедний оператор: т-т т1; доте Ь1: Ь2: Рассмотрим код, который породит компилятор при обработке следующей строки: тот (т = 0; тип; 1++) ( операторы ) Если у компилятора нет никакой информации о числе и, ему, чтобы корректно обработать случай и ( О, придется действовать так, как показано в листинге 5.4.