Автор работы: Пользователь скрыл имя, 11 Января 2011 в 19:34, лекция
Язык ассемблера - это один из самых старых из всех существующих языков программирования. Когда-то это был один из основных языков программирования, без знания которого нельзя было заставить компьютер сделать что-либо полезное. Появились более удобные средства общения с компьютером. Но в отличии от других языков ассемблер не умирал, более того он это не смог сделать в принципе.
При работе в различных средах программирования, основанных на языках высокого уровня (например, Си или Паскаль), во время создания проекта, как правило, предоставляется возможность выбора одного из трех вариантов стандартной библиотеки:
Первый вариант (библиотека эмулятора) используется по умолчанию. Программы, которые используют библиотеку эмуляции, будут работать как при наличии в системе сопроцессора, так и при его отсуствии. В последнем случае вычисления с плавающей точкой выполняются специальными подпрограмами, которые присоединяются к вашей программе на этапе линковки (что, разумеется, влечет увеличение размеров программы). Кроме того, в код программы включается вфункция, определяющая наличие сопроцессора, которая при запуске приложение определит факт наличия (или отсуствия) сопроцессора и выберет соответствующий способ выполнения вычислений - либо с использованием сопроцесора, либо с использованием подпрограмм эмуляции сопроцессора.
Второй вариант библиотеки рассчитан на наличие сопроцессора. Если сопроцессора нет, программа работать не будет. Но если известно, что сопроцессор есть (например, процессор Pentium всегда содержит блок арифметики), то имеет смысл использовать именно этот вариант как самый быстродействующий (иногда, например, при одновременном использовании инструкций MMX и сопроцессора, чтобы существенно не замедлять работу программы, для математических вычислений бывает выгоднее использовать библиотеку альтернативной математики).
Третий вариант не использует сопроцессор совсем (даже если он присутствует в системе). Все вычисления выполняются специальными подпрограммами, входящими в состав библиотеки альтернативной математики и подключающимися к вашей программе автоматически на этапе линковки.
К сожалению, есть программы, в которых использование библиотеки эмуляции невозможно или крайне затруднительно:
В
случае с резидентными программами
невозможность использования
Механизм вызова программ эмуляции основан на использовании прерываний с номерами 34h - 3Eh. Перед тем как оставить программу резидентной, функция _dos_keep восстанавливает содержимое указанных векторов прерываний, делая невозможным доступ резидентной программе к модулям эмулятора. Да и самих этих модулей уже нет в памяти - на их место может быть загружена новая программа.
Поэтому в руководстве по языку программирования Си рекомендуется для резидентных программ применять библиотеку альтернативной математики. Но эта библиотека, увы, не использует сопроцессор.
Ситуация с драйверами аналогична - драйверы, как правило, составляются на языке ассемблера, поэтому средства эмуляции библиотек Си недоступны.
Выходом может быть непосредственное программирование сопроцессора на языке ассемблера. При этом вы можете полностью использовать все возможности сопроцессора и добиться от программы наибольшей эффективности вычислений.
Для составления программ на языке ассемблера можно использовать компиляторы MASM и TASM, либо интегрированную среду программирования, содержащую встроенный ассемблер.
Вот пример простой программы, которая выполняет вычисления по следующей несложной формуле:
z = x + y;
В этой программе значения x и y задаются в виде констант.
; ==============================
; Простейшая программа для работы с арифметическим
; сопроцессором
; Синтаксис MASM
;
; ==============================
...
.DATA
; Здесь находятся константы с одинарной
; точностью x и y
x real4 1.0
y real4 2.0
; Резервируем четыре байта для результата
.data?
z real4 ?
.CODE
...
; инициализируем сопроцессор
finit
; Записываем в стек численных регистров
; значение x
fld x
; Складываем содержимое верхушки стека
; с константой y
fadd y
; Записываем результат в ячейку z
fstp z
; синхронизируем вычисления
fwait
...
Удобнее
всего изучать команды
Вот как выглядит предыдущий пример в контексте языка Си (в зависимости от среды программирования может возникнуть необходимость в модификации примера):
...
float x=1.0;
float y = 2.0;
float z;
asm {
finit
fld x
fadd y
fstp z
fwait
}
printf ("x= %f \r\n", x);
printf ("y= %f \r\n", y);
printf ("z= %f \r\n", z);
...
В приведенном выше тексте программы можно заменить команду сложения на любую другую допустимую команду сопроцессора, производящую необходимые вычисления.
В
арифметическом сопроцессоре имеются
два механизма обработки
Первый механизм основан на генерации так называемого прерывания особого случая (INT 10h). Это прерывание вырабатывается в том случае, когда происходит какая-нибудь ошибка (например, деление на нуль) при условии, что соответствующие биты масок особых случаев в регистре управления не установлены.
При втором способе обработки ошибок все особые случаи маскируются (соответствующие биты управляющего регистра устанавливаются в единицу) и в случае ошибки сопроцессор в качестве результата возвращает некоторое заранее известное особое значение (нечисло, неопределенность или бесконечность).
Программист может выбирать между этими способами обработки ошибок, маскируя или разрешая прерывание по особому случаю. Если прерывание особого случая замаскировано, можно использовать такой способ обнаружения ошибки:
После выполнения команды сопроцессора, производящей какие-либо вычисления, бывает полезно проверить получившийся результат на принадлежность к множеству особых значений.
В результате выполнения некоторых операций может возникнуть такая ситуация, когда невозможно точно представить результат. Например, при делении числа 1.0 на 3.0 результатом является бесконечная периодическая двоичная дробь 0.010101.. (или десятичная бесконечная дробь 0.333...). Такое число не может быть представлено точно ни в одном формате вещественных чисел.
Обычно неточный результат является результатом округления и может не рассматриваться как ошибка.
Если результат выполнения операции слишком велик и не может быть представлен в формате приемника результата, фиксируется особый случай переполнения.
Этот особый случай обязательно произойдет, например, при сложении максимального числа расширенной точности самим с собой или при преобразовании этого числа в формат с двойной или одинарной точностью.
Так
как для хранения промежуточных
результатов используется 80-битовое
представление, при выполнении операций
над числами с одинарной или
двойной точностью
Антипереполнение
возникает тогда, когда результат
слишком мал для его
Если вы используете числа только с двойной или одинарной точностью, а для хранения промежуточных результатов используете формат с расширенной точностью, особый случай антипереполнения, как правило, не возникает.
Этот особый случай возникает при попытке выполнить деление конечного ненулевого числа на нуль.
В
афинном режиме при делении конечных
(положительных или
В проективном режиме, а также при попытке деления нуля на нуль возникает особый случай недействительной операции, который будет рассмотрен ниже.
Этот особый случай возникает при попытке выполнения таких запрещенных команд, как деление нуля на нуль, извлечения корня из отрицательного числа, обращение к несуществующему регистру сопроцессора или при попытке использования в качестве операндов команд нечисел, неопределенностей или бесконечности (для трансцендентных функций).