ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.


Информация кормоизмельчитель бытовой икб 003 кормоизмельчитель у нас на сайте.

 

Часть 19

Глава 18. Вычисления
----------------------------------------------------------------
18.1 Средства программирования
----------------------------------------------------------------
В этой главе дано описание вычислительных возможностей
процессора i486(TM) для программистов, работающих с языками
высокого уровня и на ассемблере ASM386/486.
Уровень детализации этой главы дает программистам понимание
основных навыков, которые могут быть использованы для
программирования вычислений, но эта информация не является
полной документацией по описанию всех возможностей процессора.
Полная документация поставляется с каждым программным продуктом.
18.2 Языки высокого уровня
----------------------------------------------------------------
Большое количество языков высокого уровня, которые по
необходимости автоматически используют множество вычислительных
команд, создано для процессоров фирмы Intel(R). Эти
языки включают C-386/486 и PL/M-386/486. Но многие
компиляторы языков высокого уровня поставляются независимыми
организациями, разрабатывающими программное обеспечение.
Каждый из языков высокого уровня имеет специальные числовые
библиотеки, позволяющие программам воспользоваться возможностями
модуля обработки операций с плавающей точкой. При
программировании численных операций в любом из этих языков для
использования этого модуля не нужны никакие программные
добавления.
Программисты, работающие на PL/M-386/486 и на ассемблере
ASM386/486, также могут использовать многие из
программ, содержащихся в библиотеке поддержки языка. Эти
библиотеки включают многие функции, поддерживаемые языками
высокого уровня, включая обработчики исключенций,
преобразователи кодов ASCII в числа с плавающей точкой, и более
сложное множество трансцендентных функций, чем то множество
числовых операций, которое поддерживает процессор i486.
18.1.2 Программы на языке Си
----------------------------------------------------------------
Программисты, работающие на языке Си, при использовании типов
данных double или float автоматически используют для
генерирования числовых операций i486 процессора компилятор языка
Си. Тип float соответствует обычному вещественному формату; тип
double соответствует вещественному формату двойной точности.
Команда #include  вызывает математические функции, такие
как sin, cos для получения величин типа double. Рисунок 18
иллюстрирует пример программы на Си, демонстрирующий
использование возможностей процессора i486.
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і     /********************************************             і
і     *                                           *             і
і     *             Пример программы на Си        *             і
і     *                                           *             і
і     *********************************************/            і
і                                                               і
і   /** по необходимости подключить /usr/include/stdio.h  **/   і
і   /** для трансцендентных функций подключить math **/         і
і                                                               і
і   #include                               і
і   #define Pi 3.1415926535897943                               і
і                                                               і
і   main()                                                      і
і   {                                                           і
і     double       sin_result, cos_result;                      і
і     double       angle_deg = 0.0, angle_rad;                  і
і     int          i, no_of_trail = 4;                          і
і                                                               і
і           for ( i = 1; i <= no_of_trail; i++){                і
і                angle_rad = angle_deg * Pi / 180.0;            і
і                sin_result = sin (angle_rad);                  і
і                cos_result = cos(angle_result);                і
і     printf("синус %f градусов равен %f\n",angle_deg,          і
і             sin_result);                                      і
і     printf("косинус %f градусов равен %f\n",angle_deg,        і
і             cos_result);                                      і
і                angle_deg = angle_deg + 30.0;                  і
і               }                                               і
і      /**  так далее  **/                                      і
і   }                                                           і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
         Рисунок 18-1. Пример программы на языке Си-386/486.
18.1.3 PL/M-386/486
----------------------------------------------------------------
Программисты, работающие на языке PL/M-386/486, могут получить
доступ к очень полезному подмножеству возможностей
процессораi486. Тип данных REAL языка PL/M-386/486 соответствует
обычному вещественному формату (32 бита). Этот тип данных дает
диапазон чисел порядка 8.43 x 10**(-37) <= іXі <= 3.38 x
10**(38) и имеет около семи значимых десятичных цифр. Такое
представление чисел отвечает многим применениям
микрокомпьютеров. Преимущество при использовании типа данных
REAL в том, что промежуточные результаты при вычисленииях
представляются компилятором языка PL/M-386/486 в расширенном
вещественном формате. Это означает, что полный диапазон
представления чисел и точности процессора используется для
промежуточных вычислений. Переполнение, отрицательное
переполнение, ошибки округления более вероятны во время
промежуточных вычислений, чем при получении конечного
результата. Представление промежуточных результатов в
вещественном формате с расширенной точностью уменьшает
вероятность переполнения, отрицательного переполнения и
исключает ошибки округления, как серьезные ошибки, до достижения
конца вычислений.
Компилятор генерирует команды по обработке чисел с плавающей
точкой для вычисления выражений, содержащих тип данных REAL в
виде переменных или констант. Это означает, что сложение,
вычитание, умножение, деление, сравнение и присваивание чисел
типа REAL осуществляется модулем обработки данных с плавающей
точкой. С другой стороны, выражения типа INTEGER вычисляются
модулем обработки целочисленных операций.
Пять встроенных процедур (Таблица 18-1) дают программисту,
работающему на языке PL/M-386/486 доступ к командам управления
модулем по обработке данных с плавающей точкой. Перед любой
арифметической операцией обычная программа на PL/M-386/486 будет
инициализировать модуль, используя процедуру INIT$REAL$MATH$
UNIT, а затем для настройки конфигурации установит режим
SET$REAL$MODE. Процедура SET$REAL$MODE загружает управляющее
слово модуля обработки данных с плавающей точкой, и его
16-разрядный параметр имеет формат, указанный для управляющеего
слова в Главе 14. Рекомендуемая величина этого параметра - 033H
(округление до ближайшего, точность 64 бита, блокировка
исключений устраняет ошибочные команды). Другие процедуры могут
использоваться по усмотрению программиста.
Если любая исключение не заблокировано, то обработчик
исключений должен иметь процедуру обработки в форме процедуры
прерывания, которая вызывается через вектор прерывания номер 16.
Обработчик может использовать процедуру GET$REAL$ERROR для
получения младшего байта слова состояния модуля обработки
операций с плавающей точкой и затем очистить флаги маски
исключения. Байт, возвращаемый процедурой GET $REAL $ERROR
cодержит флаги маски, которые могут быть проанализированы для
определения номера исключения.
Процедуры SAVE$REAL$STATUS и RESTORE$REAL$STATUS обеспечивают
многозадачный режим работы, в котором выполняемая задача,
использующая модуль обаботки операций с плавающей точкой, может
быть прервана другой задачей, также использующей модуль
обработки операций с плавающей точкой. Операционная система
отвечает за выполнение процедуры SAVE$REAL$STATUS перед
выполнением любой команды, которая может повлиять на модуль
обработки операций с плавающей точкой. Это процедуры INIT$REAL$
MATH$UNIT и SET$REAL$MODE, а также арифметические команды.
Процедура SAVE$REAL$STATUS сохраняет состояние модуля обработки
операций с плавающей точкой (регистры, статус, управляюще слово
и так далее) в стеке памяти. Процедура RESTORE$ REAL$STATUS
восстанавливает информацию о состоянии; прерванная задача может
вызвать эти процедуры для восстановления состояния модуля
обработки операций с плавающей точкой во время выполнения. Это
дает возможность прерванной задаче начать выполнение с того
места, когда задача была прервана.
    Тавблица 18-1.Встроенные процедуры языка PL/M-386/486
ЪДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                     і  Команда   і                            і
і      Процедура      і управления і          Описание          і
і                     і    FPU     і                            і
ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і INIT$REAL$MATH$UNIT і   FINIT    і Инициализирует FPU         і
і STE$REAL$MODE       і   FLDSW    і Устанавливает маски исклю- і
і                     і            і чений,  точность  округле- і
і                     і            і ния и управление бесконеч- і
і                     і            і ностью                     і
і GET$REAL$ERROR      і   FNSTSW   і Сохраняет, а затем очищает і
і                     і   &FNCLEX  і значение флагов            і
і SAVE$REAL$STATUS    і   FNSAVE   і Сохраняет состояние FPU    і
і RESTORE$REAL$STATUS і   FRSTOR   і Восстанавливает состояние  і
і                     і            і           FPU              і
АДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
18.1.4 Ассемблер ASM386/486
----------------------------------------------------------------
Ассемблер ASM386/486 дает программисту полный доступ ко всем
возможностям процессора.
18.1.4.1 Определение данных
----------------------------------------------------------------
Директивы ассемблера ASM386/486, указанные в таблице 18-2,
выделяют память для числовых переменных и констант. Как и другие
директивы по распределению памяти, ассемблер связывает тип с
любой переменной, определенной с помощью этих директив. Величина
типа измеряется в единицах памяти - байтах(10 для DT, 8 для DQ).
Ассемблер проверяет соответствие типа переменной, используемой в
команде, самой команде. Например, команда FIADD ALPHA будет
ошибочна, если тип переменной ALPHA имеет величину, не равную 2
или 4 байтам, так как целочисленное сложение определено только дл
данных типа слово или короткое целое (двойное слово). Тип
операнда также сообщает ассемблеру какую машинную команду
выполнять: хотя для программиста существует только одна команда
FIADD, но для операндов различного типа требуются различные
машинные команды.
Иногда разумно использовать команду с операндом, тип которого не
объявлен. Например, если регистр BX содержит указатель на
переменную типа короткое целое, то программист может пожелать
определить команду FIADD [BX]. Это может быть достигнуто
информированием процессора о типе операнда в команде, то есть
FIADD DWORD PTR [BX]. Соответствующие преобразователи для других
рапределений памяти -  WORD PTR, QWORD PTR и TBYTE PTR.
Однако ассемблер не проверяет типы операндов, используемых в
командах управления процессором. Команда FRSTOR [BP]
подразумевает, что программист поместил в регистр BP указатель
на место (возможно в стеке), в котором заранее была сохранена
запись о состоянии процессора размером 94 байта.
Начальное значение для числовых констант может быть получено
несколькими способами. Двоичные целые константы могут быть
определены как битовые строки, десятичные целые, восьмеричные
целые или шестнадцатиричные строки. Упакованные десятичные
величины обычно записываются как десятичные целые, хотя
ассемблер будет принимать и обрабатывать и другие представления
целых. Вещественные величины могут записываться как обычные
вещественные десятичные числа (с десятичной точкой), как
десятичные числа в научной нотации или как шестнадцатиричные
строки. Использование шестнадцатиричных строк первоначально было
предназначено для определения специальных величин, таких как
бесконечности, NaNs и ненормализованные числа. Большинство
программистов найдут, что обычные и научные десятичные дают
простейший способ инициализации числовых констант. На
рисунке 18-2 дан пример, показывающий несколько способов
пррисвоения данным различных числовых типов одной и той же
начальной величины.
    Таблица 18-2. Директивы распределения памяти ASM386/486.
ЪДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДї
і  Директивы  і    Интерпретация     і       Типы данных        і
ГДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і    DW       і  Определить слово    і Целое слово              і
і    DD       і  Определить двойное  і Короткое целое, короткое і
і             і     слово            і вещественное             і
і    DQ       і  Определить слово    і Длинное целое, длинное   і
і             і   длиной 4 байта     і вещественное             і
і    DT       і  Определить 10 байтові Упакованное десятичное,  і
і             і                      і временное вещественное   і
АДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і  ; ПРИМЕР ОПРЕДЕЛЕНИЯ КОНСТАНТЫ -126                          і
і  ;                                                            і
і  ;EVEN           ; выравнение слов в памяти                   і
і  WORD-INTEGER     DW   111111111000010B ; битовая строка      і
і  SHORT_INTEGER    DD   0FFFFFF82H       ; шестнадцатиричная   і
і                                         ; константа должна    і
і                                         ; начинаться с цифры  і
і  LONG_INTEGER     DQ   -126             ; обычное десятичное  і
і  SINGLE_REAL      DD   -126.0           ; "научное"           і
і  DOUBLE_REAL      DD   -1.26E2          ; представление       і
і  PACKED_DECIMAL   DT   -126             ; обычное десятичное  і
і                                         ; целое               і
і  ;                                                            і
і  ; в следующем определении 'C005' означает знак и порядок,    і
і  ; '7E00..00' - мантисса, 'R' информирует ассемблер, что      і
і  ;   представленная строка вещественного типа                 і
і  ;                                                            і
і  EXTENDED_REAL     DT    0C0057E00000000000000R               і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
       Рисунок 18-2. Пример числовых констант.
Следует заметить, что числовые переменные и константы, следующие
за директивой EVEN, дают уверенность, что операнды будут
представлены выравненными словами. Наилучшее представление
получается, когда данные преобразуются к двойным словам,
расположенным линейно. Все числовые типы данных занимают целое
число слов, так что если блоки переменных объявляются вместе и
перед декларативной частью указано слово EVEN, то память не
растрачивается попусту.
18.1.4.2 Структуры и записи
----------------------------------------------------------------
При программировании вычислений на языке ассемблера ASM386/486
записи RECORD и структуры STRUC могут быть очень полезны. Записи
могут использоваться для определения битовых полей
управляющеющих слов, состояния, признака. На рисунке 18-3
показано одно определение слова состояния и как можно его
использовать в программе, которая опрашивает устройство
обработки операций с плавающей точкой до тех пор, пока не
завершилось выполнение команды.
Так как структуры объединяют различные, но связанные типы данных,
они позволяют получать данные, имитирующие  "реальный мир". То
что структура временно может быть передвинута в памяти,
добавляет ей гибкости. На Рисунке 18-4 дан пример простой
структуры, которая должна быть использована для представления
данных. По необходимости этот пример структуры может быть
реорганизован в целях безопасности и более эффективного
выполнения. Если два двойных вещественных поля были определены
до целочисленных полей, тогда (поддерживая тот факт, что
структура заменяется только адресами, делящимися на 8) все поля
будут оптимально выравнены в памяти для обеспечения
эффективного доступа и кеширования. Структуры также могут
использоваться для определения информации, сохраняемой и
получаемой с помощью команд FSTENV и FLDENV.
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і      ; резервирование памяти для слова состояния              і
і      ; STATUS-WORD                                            і
і      ; расположение полей слова состояния                     і
і      STATUS RECORD                                            і
і      &     BUSY :              1,                             і
і      &     COND_CODE3 :        1,                             і
і      &     STACK_TOP :         3,                             і
і      &     COND_CODE2 :        1,                             і
і      &     COND_CODE1 :        1,                             і
і      &     COND_CODE0 :        1,                             і
і      &     INT_REG :           1,                             і
і      &     S_FLAG  :           1,                             і
і      &     P_FLAG  :           1,                             і
і      &     U_FLAG  :           1,                             і
і      &     O_FLAG  :           1,                             і
і      &     Z_FLAG  :           1,                             і
і      &     D_FLAG  :           1,                             і
і      &     I_FLAG  :           1                              і
і      ;                                                        і
і      REDUCE :  FPREM1                                         і
і                FNSTSW   STATUS_WORD                           і
і                TEST     STATUS_WORD, MASK_COND_CODE2          і
і                JNZ      REDUCE                                і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
        Рисунок 18-3.Определение записи слова состояния.
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і       SAMPLE       STRUC                                      і
і           N_OBS     DD    ?     ;                             і
і           MEAN      DQ    ?     ;                             і
і           MODE      DW    ?     ;                             і
і           STD_DEV   DQ    ?     ;                             і
і           ;                                                   і
і           TEST_SCORES    DW   1000  DUP (?)                   і
і        SAMPLE       ENDS                                      і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
              Рисунок 18-4. Определение структуры
18.1.4.3 Методы адресации
----------------------------------------------------------------
Доступ к числовым данным в памяти может быть получен с помощью
методов адресации через байты ModR/M и SIB (необязательно). Это
означает, что числовые типы данных могут быть объединены в
совокупности данных, изменяющиеся от простых к сложным в
соответствии с необходимостью применения. Методы адресации и
нотация ассемблера ASM386/486, используемая для определения
методов в командах, обеспечивают прямой и последовательный
доступ к структурам, массивам, массивам структур и другим
организациям данных. В таблице 18-3 даны несколько примеров
числовых команд вместе с операндами, иллюстрирующие различные
методы адресации.
            Таблица 18-3. Примеры методов адресации
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і         Код                і         Интерпретация             
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
і  FIADD ALPHA               і ALPHA - простой скаляр (прямой    
і                            і доступ)                           
і  FDIVR ALPHA, BETA         і BETA - поле в структуре, которое  
і                            і перекрывается с ALPHA ( прямой    
і                            і доступ )                          
і  FMUL QWORD PTR [BX]       і BX содержит адреса длинных вещест-
і                            і венных переменных (косвенная адре-
і                            і сация по регистру)                
і  FSUB ALPHA [SI]           і ALPHA - массив, SI содержит смеще-
і                            і ние относительно начала массива   
і                            і (индексный метод доступа)         
і  FILD [BP], BETA           і BP содержит адрес структуры в сте-
і                            і ке ЦПУ, BETA - поле в структуре   
і                            і (базированный метод доступа)      
і  FBLD TBYTE PTR [BX] [DI]  і BX содержит адрес упакованного де-
і                            і сятичного массива, DI - смещение  
і                            і элемента массива (индексный метод 
і                            і доступа)                          
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
18.1.5 Пример сравнительного программирования
----------------------------------------------------------------
На рисунках 18-5 и 18-6 даны примеры простой числовой программы
ARRSUM на языках ассемблера ASM386/486 и PL/M386/486. В программе
рассматривается массив X$ARRAY, содержащий простые вещественные
величины от 0 до 100; целая переменная N$OF$X указывает
размерность массива. Вычисляются три суммы:
- SUM$X, сумма элементов массива
- SUM$INDEXES, сумма каждого элемента, умноженного на его
  индекс, где первый элемент массива имеет индекс 1, второй - 2 и
  так далее
- SUM$SQUARES, сумма квадратов элементов массива
(Настоящая программа, конечно, кроме этих шагов должна сохранять
и использовать результаты вычислений.) Управляющеему слову
присваивается одна из величин: округление до ближайшего целого,
64-разрядная точность, запрещение прерываний и блокировка всех
исключений, кроме недопустимых операций. Предполагается, что
обработчик исключений был написан с учетом недопустимой
операции, и в случае их обнаружения они обрабатывается по
прерыванию 16.
Версия ARRSUM на языке PL/M-386/486 очень последовательна и
иллюстрирует насколько легко в языке могут быть использованы
числовые возможности процессора i486. После объявления
переменных программа вызывает встроенные процедуры для
инициализации модуля обработки операций с плавающей точкой и
загрузки управляющего слова. Программа "очищает" пременные суммы
и затем выполняет шаги цикла DO. Управление циклом принимает в
расчет, что обычно в языке PL/M-386/486 индекс первого элемента
массива имеет величину 0. При вычислении SUM$INDEXES встроенная
процедура FLOAT преобразует величину I+1 от целого типа к
вещественному, так как язык не поддерживает "смешанного"
арифметического режима. Один из недостатков модуля обработки
операций с плавающей точкой процессора i486, что он не
поддерживает вычисления над смешанными типами данных (все
величины преобразуются к 80-битовому вещественному формату
расширенной точности)
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і       /**************************************************     і
і        *                                                *     і
і        *         МОДУЛЬ СУММА_МАССИВА                   *     і
і        *                                                *     і
і        **************************************************/    і
і                                                               і
і        array$sum:       do;                                   і
і                                                               і
і            declare (sum$x, sum$indexes, sum$squares) real;    і
і            declare x$array(100) real;                         і
і            declare (n$of$x, i) integer;                       і
і            declare control $ FPU literally '033eh';           і
і                                                               і
і            /* Инициализация массива x$array и n$of$x */       і
і            call init$real$math$unit;                          і
і            call set$real$mode(control $ FPU);                 і
і                                                               і
і            /* Очистить суммы */                               і
і            sum$x, sum$indexes, sum$squares = 0.0;             і
і                                                               і
і            /* Цикл по массиву с подсчетом сумм */             і
і            do i = 0 to n$of$x - 1;                            і
і                 sum$x = sum$x + x$array(i);                   і
і                 sum$indexes = sum$indexes + (x$array(i)*      і
і                 float(i+1));                                  і
і                 sum$squares = sum$squares + (x$array(i)*      і
і                 x$array(i));                                  і
і            end;                                               і
і                                                               і
і            /* и так далее */                                  і
і                                                               і
і      end array$sum;                                           і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
      Рисунок 18-5. Пример программы на языке PL/M-386/486
Версия программы на ассемблере ASM386/486 (Рисунок 18-6)
определяет внешнюю процедуру INITFPU, которая производит
инициализацию процессора и его эмулятора независимо от текста
исходной программы. После определения данных, настройки
сегментных регистров и указателя стека программа вызывает
процедуру INITFPU и загружает управляющее слово. Вычисления
начинаются со следующих трех команд, которые очищают три
регистра загрузкой 0 в стек. Как показано на Р1исунке 18-7 эти
регистры сохраняют значение вершины стека во время вычислений,
когда временные величины помещаются и удаляются из стека.
Для управления итерацией по массиву XARRAY программа использует
цикл LOOP; в регистр EСX, содержимое которого LOOP автоматически
уменьшает, помещается переменная N_OF_X, число суммируемых
элементов массива. Регистр ESI используется для выборки
(индексирования) элементов массива. Программа выполняется по
массиву с конца к началу, так что регистр ESI инициализируется
указателем на элемент, который должен обрабатываться. Оператор
TYPE используется для определения числа байтов в каждом элементе
массива. Такое представление позволяет изменить тип массива на
вещественный двойной точности простым измененим определения (DD
на DQ) и еще одним проходом ассемблера.
   Рисунок 18-6 Пример программы на языке ассемблер ASM386/486
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і           name         arraysum                               і
і                                                               і
і           ; Определить процедуру инициализации                і
і                                                               і
і           extrn        initFPU:far                            і
і                                                               і
і           ; Выделить память под данные                        і
і                                                               і
і           data         segment  rw  public                    і
і           control_FPU           dw  033eh                     і
і           n_of_x                dd  ?                         і
і           x_array               dd  100 dup (?)               і
і                                                               і
і           sum_squares           dd  ?                         і
і           sum_indexes           dd  ?                         і
і           sum_x                 dd  ?                         і
і           data         ends                                   і
і                                                               і
і           ; Выделить память под стек ЦПУ                      і
і                                                               і
і           stack        stackseg     400                       і
і                                                               і
і           ; Начало тела программы                             і
і                                                               і
і           code         segment  er  public                    і
і                                                               і
і           assume  ds:data, ss:stack                           і
і                                                               і
і           start:                                              і
і               mov      ax, data                               і
і               mov      ds, ax                                 і
і               mov      ax, stack                              і
і               mov      eax, ax                                і
і               mov      esp, stackstart stack                  і
і                                                               і
і           ; Проинициализироавали массив x_array и             і
і           ; переменную n_of_x                                 і
і                                                               і
і           ; Подготовить модуль обработки операций             і
і           ; с плавающей точкой или его эмулятор               і
і                                                               і
і               call     initFPU                                і
і               fldsw    control_FPU                            і
і                                                               і
і           ; Очистить три регистра для хранения                і
і           ; результатов суммирования                          і
і                                                               і
і               fldz                                            і
і               fldz                                            і
і               fldz                                            і
і                                                               і
і                                                               і
і           ; Установить ECX как счетчик цикла и                і
і           ; ES как индекс массива x_array                     і
і                                                               і
і               mov      ecx, n_of_x                            і
і               imul     ecx                                    і
і               mov      esi, eax                               і
і                                                               і
і           ; ESI содержит индекс последнего элемента           і
і           ; массива плюс 1                                    і
і           ; Цикл по массиву с подсчетом суммы                 і
і                                                               і
і           sum_next:                                           і
і           ; возвращение на один элемент назад                 і
і           ; и помещение в стек                                і
і                                                               і
і               sub      esi, type x_array                      і
і               fld      x_array[esi]                           і
і                                                               і
і           ; прибавление к сумме и копирование x               і
і           ; в стек                                            і
і                                                               і
і               fadd     st(3), st                              і
і               fld      st                                     і
і                                                               і
і           ; возведение в квадрат и сложение с суммой          і
і           ; (index+1)                                         і
і                                                               і
і               fmul     st, st                                 і
і               faddp    st(2), st                              і
і                                                               і
і           ; уменьшение индекса для следующей итерации         і
і                                                               і
і               dec      n_of_x                                 і
і               loop     sum_next                               і
і                                                               і
і           ; Перемещение x в память                            і
і                                                               і
і           pop_results:                                        і
і                fstp    sum_squares                            і
і                fstp    sum_indexes                            і
і                fstp    sum_x                                  і
і                fwait                                          і
і                                                               і
і           ;                                                   і
і           ; И так далее.                                      і
і           ;                                                   і
і           code         ends                                   і
і           end    start, ds:data, ss:stack                     і
і                                                               і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і                                                               і
і FLDZ, FLDZ,FLDZ                   FLD X_ARRAY[SI]             і
і       ЪДДДДДДДДї----------------------ЪДДДДДДДДї             і
і ST(0) і  0.0   і SUM_SQUARES     ST(0) і  2.5   і X_ARRAY     і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(1) і  0.0   і SUM_INDEXES     ST(1) і        і SUM_SQUARES і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(2) і  0.0   і SUM_X           ST(2) і  0.0   і SUM_INDEXES і
і       АДДДДДДДДЩ                       ГДДДДДДДДґ             і
і                                  ST(3) і  0.0   і SUM_X       і
і                                        АДДДДДДДДЩ             і
і           _________________________________|                  і
і                                                              і
і  FIADD ST(3), ST                             FLD ST           і
і       ЪДДДДДДДДї----------------------ЪДДДДДДДДї             і
і ST(0) і  2.5   і X_ARRAY(19)     ST(0) і  2.5   і X_ARRAY(19) і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(1) і  0.0   і SUM_SQUARES     ST(1) і  2.5   і X_ARRAY(19) і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(2) і  0.0   і SUM_INDEXES     ST(2) і  0.0   і SUM_SQUARES і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(3) і  2.5   і SUM_X           ST(3) і  0.0   і SUM_INDEXES і
і       АДДДДДДДДЩ                       ГДДДДДДДДґ             і
і                                  ST(4) і  2.5   і SUM_X       і
і                                        АДДДДДДДДЩ             і
і           _________________________________|                  і
і                                                              і
і      FMUL ST, ST                  FADDP ST(2), ST             і
і       ЪДДДДДДДДї----------------------ЪДДДДДДДДї             і
і ST(0) і  6.25  і X_ARRAY(19)(2)  ST(0) і  2.5   і X_ARRAY(19) і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(1) і  2.5   і X_ARRAY(19)     ST(1) і  6.25  і SUM_SQUARES і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(2) і  0.0   і SUM_SQUARES     ST(2) і  0.0   і SUM_INDEXES і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(3) і  0.0   і SUM_INDEXES     ST(3) і  2.5   і SUM_X       і
і       ГДДДДДДДДґ                       АДДДДДДДДЩ             і
і ST(4) і  2.5   і SUM_X                     |                  і
і       АДДДДДДДДЩ                           |                  і
і           _________________________________|                  і
і                                                              і
і     FIMUL N_of_X                  FADDP ST(2), ST             і
і       ЪДДДДДДДДї----------------------ЪДДДДДДДДї             і
і ST(0) і  50.0  і X_ARRAY(19)     ST(0) і  6.25  і SUM_SQUARES і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(1) і  6.25  і SUM_SQUARES     ST(1) і  50.0  і SUM_INDEXES і
і       ГДДДДДДДДґ                       ГДДДДДДДДґ             і
і ST(2) і  0.0   і SUM_INDEXES     ST(2) і  2.5   і SUM_X       і
і       ГДДДДДДДДґ                       АДДДДДДДДЩ             і
і ST(3) і  2.5   і SUM_X                                        і
і       АДДДДДДДДЩ                                              і
і                                                               і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
            Рисунок 18-7 Команды и регистровый стек
На Рисунке 18-7 показано содержимое регистрового стека
модуля обработки операций с плавающей точкой во время выполнения
команд в цикле программы. Предполагается, что программа
находится в ее первой итерации, величина переменной N_OF_X равна
20, и 20-й элемент массива XARRAY(19) имеет величину 2.5. По
окончании цикла суммы извлекаются из вершины стека, и программа
заканчивается простым перемещением сумм в переменные памяти.
18.2 Параллельная обработка
----------------------------------------------------------------
Так как модуль обработки целочисленных операций и модуль
обработки операций с плавающей точкой являются независимыми
устройствами, то возможно выполнение математических команд
модулем обработки операций с плавающей точкой параллельно с
работой модуля обработки целочисленных операций. Такое
одновременное выполнение различных команд называется
параллельностью.
Нет специальных приемов программирования, необходимых для
параллельного выполнения: команды модулю обработки операций с
плавающей точкой просто размещаются в той же строке, что и
команды модулю обработки целочисленных операций. Целочисленные и
вещественные команды инициализируются в том же порядке, как они
встречаются в потоке команд. Однако в силу того, что
вещественные операции, выполняемые модулем обработки операций с
плавающей точкой, в общем требуют больше времени, чем
целочисленные операции, то модуль обработки целочисленных
операций часто может выполнить несколько своих команд до того,
как модуль обработки операций с плавающей точкой завершит
начатую вещественную команду.
Параллельность часто предполагает очевидные преимущества во
время выполнения, однако также налагает определенные правила,
которые должны быть соблюдены для достижения синхронизации работы
модуля обработки операций с плавающей точкой и модуля обработки
целочисленных операций.
Все языки высокого уровня, ориентируемые на процессоры фирмы
Intel, автоматически имеют и управляют параллельностью модуля
обработки операций с плавающей точкой. Программисты, работающие
на ассемблере, однако должны понимать и управлять некоторыми
областями параллельности для достижение гибкости и эффективности
программ. Эта глава для программистов, работающих на ассемблере,
или программистов-профессионалов, пишущих программы на языках
высокого уровня.
18.2.1 Управление параллельностью
----------------------------------------------------------------
Обработка вычислительных программ может быть разбита на две
части: управление программой и арифметика. Часть по управлению
программой выполняет такие действия как решение - какие функции
выполнять, вычисление адресов числовых операндов и управление
циклом. Арифметическая часть просто выполняет сложение,
вычитание, умножение и другие операции над числовыми операндами.
Процессор i486 предназначен для обработки этих частей раздельно
и эффективно.
Управление параллельностью требует проверки на исключение перед
разрешением процессору изменить значение, только что
используемое модулем обработки операций с плавающей точкой.
Почти все числовые команды могут в случае запрещенной операции
создать числовое исключение. Для программистов, работающих на
языках высокого уровня, вся требуемая синхронизация
автоматически выполняется соответствующим компилятором. Для
работающих на ассемблере синхронизация исключений остается на
совести программиста.
Сложность в том, что программист может не ожидать, что его
вычислительная программа может вызывать исключения, но в
некоторых системах они могут регулярно случаться. Для лучшего
понимания таких недоразумений рассмотрим, что может случиться,
когда модуль обработки операций с плавающей точкой обнаружит
исключение.
В зависимости от операций, определенных проектировщиком
программного обеспечения, в случае исключения процессор i486
может выполнить одну из следующих совокупностей действий:
* Модуль обработки операций с плавающей точкой по умолчанию
  может обрабатывать определенные исключения. Программисты могут
  наложить маску на некоторые типы исключений для указания
  модулю обработки операций с плавающей точкой, что нужно
  делать, чтобы в случае исключительной ситуации получить
  разумный результат. Обработка исключения по умолчанию
  выполняется модулем обработки операций с плавающей точкой как
  часть команды, вызвавшей исключение; никаких внешних указаний
  для исключения не дается. При обнаружении исключительной
  ситуации значение флага заносится в регистр состояния, но
  информация о том, где и когда она произошла, является
  доступной. Если модуль обработки операций с плавающей точкой
  обрабатывает все исключения по умолчанию, тогда необходимость
  синхронизации исключительных ситуации не является явной.
  Однако, как будет показано позднее, это не существенная
  причина, чтобы избегать синхронизации при разработке программ,
  использующих модуль обработки операций с плавающей точкой.
* Альтернативой обработке исключений по умолчанию является
  информирование модуля обработки целочисленных операций о
  случившейся исключительной ситуации. Если имело место
  немаскированное исключение, то модуль обработки операций с
  плавающей точкой приостанавливает дальнейшее выполнение
  числовых команд и сигнализирует о случившемся. При обнаружении
  команды ESC или WAIT управление передается обработчику
  исключений. Обработчик исключений сам выбирает процедуру
  обработки любого исключения, обнаруженного модулем обработки
  операций с плавающей точкой. Некоторые команды ESC не
  осуществляют проверки на исключения. Это FNINIT, FNSTENV,
  FNSAVE, FNSTCW и FNCLEX.
Когда модуль обработки операций с плавающей точкой сигнализирует
о немаскированном исключении, то это означает, что ему требуется
помощь. Тот факт, что исключение не было маскировано, указывает,
что дальнейшее выполнение программы модулем обработки операций с
плавающей точкой неразумно.
Если разрешается параллельное вычисление, то состояние
процессора при обнаружении исключения неопределено. Во
время исключения могли быть изменены некоторые внутренние
регистры и выполнены совершенно различные программы. Для
обработки такой ситуации модуль обработки операций с плавающей
точкой имеет специальные регистры, обновляемые в начале каждой
числовой команды, которые позволяют определить состояние
программы, чтобы попытаться повторенить неудачную команду.
При синхронизации исключений надо иметь уверенность, что
модуль обработки операций с плавающей точкой находится в
хорошо определенном состоянии после случившегося
немаскированного исключения. Без такого определенного состояния
программа обработки исключения не могла бы определить причину
исключительной ситуации и успешно восстановить работу.
В следующих двух главах иллюстрируется необходимость
рассмотрения синхронизации исключений при написании числовых
программ, даже если первоначально предполагалось выполнение без
маскирования исключений. Если программа будет позднее
помещена, где исключения не маскированы, то она может работать
неправильно. Пример, когда несколько команд , написанных без
синхронизации исключений, будет работать правильно, однако
провалится при перенесении в другую среду, приведен на Рисунке
18-8.
18.2.1.1 Некорректная синхронизация исключений
----------------------------------------------------------------
На Рисунке 18-8 даны три команды загрузки целого, вычисления его
квадратного корня и уменьшение целого на 1. Синхронная
работа модуля обработки операций с плавающей точкой разрешит
этой программе работать правильно до тех пор, пока команда FILD
не сгенерирует исключения.
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і                                                               і
і                 НЕКОРРЕКТНАЯ СИНХРОНИЗАЦИЯ                    і
і                                                               і
і          FIELD     COUNT  ; команда FPU                       і
і          INC       COUNT  ; целочисленная команда изменения   і
і                           ; операнда                          і
і          FSQRT            ; ошибка из предыдущей команды FPU  і
і                           ; обнаружена здесь                  і
і                                                               і
і                 КОРРЕКТНАЯ СИНХРОНИЗАЦИЯ                      і
і                                                               і
і          FIELD     COUNT  ; команда FPU                       і
і          FSQRT            ; ошибка из предыдущей команды FPU  і
і                           ; обнаружена здесь                  і
і          INC       COUNT  ; целочисленная команда изменения   і
і                           ; операнда                          і
і                                                               і
і                                                               і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
         Рисунок 18-8. Примеры синхронизации исключений.
Ситуация изменяется, если расширить регистровый стек в память. В
этом случае недопустимое исключение не маскировано. Попытка
извлечения из пустого стека или помещения в полный вызывет
недопустимое исключение.
Прграмма обработки исключений должна распознать эту ситуацию,
исправить значение стека и выполнить первоначальную операцию. В
примере, показанном на рисунке, программа обработки будет
работать неверно. Проблема в том, что значение переменной COUNT
увеличивается до вызова обработчика исключений, поэтому
программа обработки получит неправильное значение переменной
COUNT, что приведет к непредсказуемому поведению программы.
18.2.1.2 Корректная синхронизация исключений
----------------------------------------------------------------
Команда WAIT отвечает за синхронизацию исключений. В случае
немаскированного исключения модуль обработки операций с
плавающей точкой сигнализирует процессору об ошибке. При
обнаружении команды WAIT (или неуправляющей команды ESC) сигнал
об ошибке подтверждается и вызывается программный обработчик
исключений. (Для более детальной информации о различных
механизмах обнаружения ошибок в операциях с плавающей точкой
смотри главу 16.) Если команда WAIT или ESC расположена
правильно, то информация, необходимая процессору для обработки
исключений, еще не будет нарушена.


Яндекс цитирования