Assembler для начинающих


Степени десяти



Степени десяти


      Первый пример - исходный текст программы на Фиг. 7.23.      Эта
    программа распечатывает короткое действительное представление
    степеней 10 от 103 до 1039.  Как мы уже видели в разделе,
    посвященном представлению данных, Макроассемблер фирмы IBM не имеет
    возможностей непосредственно генерировать действительные числа.
    Наличие такой таблицы чисел облегчит вам представление в виде
    констант степеней 10.  По этой таблице вы сможете определить
    шестнадцатеричное представление числа, которое нужно использовать в
    программе.
 
      Программа вычисляет только каждую третью степень 10, и
    использует короткий действительный формат.  Если вы работаете с


    много большими числами, или вам нужна большая точность, тогда нужно
    выполнить этот пример, используя длинный действительный формат
    чисел, а также построить каждую степень 10.  Выполните это в
    качестве упражнения.
 
      Первоочередная цель этого примера - введение в программирование
    и работу на сопроцессоре 8087.  Это отдельная самостоятельная
    программа, предназначенная для выполнения в виде файла типа .EXE.
    Прежде чем разобраться в самой программе, заметим, что в нее входит
    сегмент STACK, необходимый в файле типа .EXE.  Сначала в сегменте
    CODE записаны поля данных, а выполнение программы начинается с
    метки CALCULATE_POWER.  Заглянув вперед, на оператор END, вы
    увидите, что первой выполняемой командой будет команда, помеченная
    CALCULATE_POWER, так как она указана в операторе END.
 
      Первая часть программы выполняет инициализацию.  Перед
    загрузкой указателя на сегмент CODE в регистр DS программа помещает
    в стек адрес возврата из файла типа .EXE.  Затем с помощью команды
    FINIT инициализируется сопроцессор 8087, что аналогично аппаратному
    сбросу.  Тем самым сопроцессор 8087 оказывается настроенным на
    обработку особых ситуаций по умолчанию, что наилучшим образом
    подходит для примеров этой книги.  Команда FINIT также сбрасывает
    регистровый стек сопроцессора 8087, освобождая все его восемь
    позиций.  Программа должна использовать команду FINIT только в
    момент запуска.  Команда FINIT никогда не должна быть использована
    внутри подпрограммы для сопроцессора 8087.
 
      Следующие команды загружают число 1000 в регистр ST1 и число 1
    в регистр ST0.  Все следующие команды сопроцессора 8087 используют
    эти два регистра стека.  В регистре ST0 находится текущая степень
    десяти, а в регистре ST1 находится значение 103.  Мы будем
    использовать число в регистре ST1 для увеличения числа в регистре
    ST0 после каждой итерации программы.  Целая переменная POWER
    содержит текущую степень 10, находящуюся в регистре ST0.
 
      После метки POWER_LOOP элемент ST0 умножается на элемент ST1,
    (в котором содержится число 1000), чтобы увеличить содержимое
    регистра ST0 в 103 раз.  Команда FST записывает результат в память.
    Оставшаяся часть программы после метки POWER_LOOP печатает
    результаты вычислений.  В подпрограмме TRANSLATE шестнадцатеричный
    байт преобразуется в двухбайтовую строку в коде ASCII так, что
    программа может его распечатать.  Текущее значение POWER (степень
    десяти), а также шестнадцатеричная строка, записанная процессором
    8087, преобразуются в код ASCII.  Затем функция DOS печатает строку
    на дисплее.  Цикл POWER_LOOP продолжается до тех пор, пока
    последнее напечатанное значение не станет больше 1038.  Это
    значение выбрано потому, что 1038 - это максимальное число, которое
    может быть представлено в коротком действительном формате.    Если бы
    использовался длинный действительный формат чисел, это значение
    было бы равно 10308.  Заключительная часть Фиг. 7.23 показывает,
    как выглядит результат работы этой программы на дисплее.
 

           Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:04:33
           Фиг. 7.23 Степени 10                             Page   1-1
 
 
                                         PAGE    ,132
                                         TITLE   Фиг. 7.23 Степени 10
 
            0000                   STACK   SEGMENT STACK
            0000  0040[                  DW      64 DUP (?)
                  ????
                              ]
 
            0080                   STACK   ENDS
 
            0000                   CODE    SEGMENT
                                         ASSUME  CS:CODE
 
            0000  ????????               POWER_OF_TEN    DD      ?                 ; Область данных для 10**x,
                                                                 ;      короткое плавающее
            0004  0002[            OUTPUT_POWER    DB      2 DUP (' ')     ; Текстовый буфер для значения
                  20
                              ]
 
            0006  48 20 20 20 20                     DB      'H    '         ;  степени
            000B  0008[            OUTPUT_STRING   DB      8 DUP ('         ')     ; Текстовый буфер для результата -
                  20 20 20 20 20
                  20 20 20 20
                              ]
            0053  48 0D 0A 24                        DB      'H',13,10,'$'   ; Конец строки
            0057  00                     POWER       DB      0               ; Текущая степень 10
            0058  03E8             THOUSAND          DW      1000      ; Константа
            005A  03BF             CONTROL_87      DW      03BFH
 
            005C                   CALCULATE_POWER PROC    FAR
            005C  1E                           PUSH    DS        ; Занесение в стек адреса возврата
            005D  B8 0000                      MOV     AX, 0
            0060  50                           PUSH    AX
            0061  0E                           PUSH    CS
            0062  1F                           POP     DS
                                         ASSUME  DS:CODE         ; Адресация области данных
            0063  9B DB E3                     FINIT             ; Инициализация сопроцессора 8087
 
                  Фиг. 7.23 (а) (начало)
            0066  9B DF 06 0058 R              FILD    THOUSAND        ; Загрузка 10**3 в стек сопроцессора 8087
            006B  9B D9 E8                     FLD1              ; Загрузка начального значения в стек 8087
            006E                   POWER_LOOP:
            006E  9B DC 8E 0000                FMUL    ST(1)           ; Умножение ST(0) на ST(1)
            0073  9B D9 16 0000 R              FST     POWER_OF_TEN    ; Сохранение в памяти результата
            0078  80 06 0057 R 03              ADD     POWER, 3        ; Увеличение показателя степени
            007D  A0 0057 R                    MOV     AL, POWER       ; Выборка показателя степени
            0080  8D 1E 0004 R                 LEA     BX, OUTPUT_POWER
            0084  E8 00AC R                    CALL    TRANSLATE
            0087  B9 0004                      MOV     CX, 4
            008A  8D 1E 000B R                 LEA     BX, OUTPUT_STRING
            008E  8D 36 0003 R                 LEA     SI, POWER_OF_TEN+3
            0092  FD                           STD               ; Установка пересылки с уменьшением адреса
            0093                   VALUE_OUTPUT:
 
            0093  AC                           LODSB             ; Выборка байта результата
            0094  E8 00AC R                    CALL    TRANSLATE       ; Занесение символа в выводимую строку
            0097  E2 FA                  LOOP    VALUE_OUTPUT    ; Цикл по всем байтам результата
 
            0099  8D 16 0004 R                 LEA     DX, OUTPUT_POWER
            009D  B4 09                  MOV     AH, 9H
            009F  CD 21                  INT     21H
            00A1  80 3E 0057 R 26              CMP     POWER, 38
            00A6  72 C6                  JB      POWER_LOOP
            00A8  9B DE D9                     FCOMPP            ; Удаление из стека двух чисел
            00AB  CB                           RET
            00AC                   CALCULATE_POWER ENDP
 
            00AC                   TRANSLATE         PROC    NEAR
            00AC  50                           PUSH    AX        ; Сохранение исходного значения
            00AD  51                           PUSH    CX
            00AE  B1 04                  MOV     CL, 4           ; Сдвиг старшей цифры выводимого числа
            00B0  D2 E8                  SHR     AL, CL          ;      на место младшей цифры
            00B2  59                           POP     CX
            00B3  E8 00CB R                    CALL    XLAT_OUTPUT     ; Вывод старшей цифры выводимого числа
            00B6  58                           POP     AX        ; Восстановление младшей цифры
            00B7  E8 00CB R                    CALL    XLAT_OUTPUT     ; Вывод младшей цифры выводимого числа
            00BA  C3                           RET
            00BB                   TRANSLATE         ENDP
 
            00BB  30 31 32 33 34 35 36     ASCII_TABLE     DB      '0123456789ABCDEF'
                37 38 39 41 42 43 44
                45 46
            00CB                   XLAT_OUTPUT     PROC    NEAR
            00CB  24 0F                  AND     AL, 0FH         ; Выделение младшей цифры
            00CD  53                           PUSH    BX
            00CE  8D 1E 00BB R                 LEA     BX, ASCII_TABLE ; Адрес таблицы трансляции
            00D2  D7                           XLAT    ASCII_TABLE     ; Преобразование в символьную форму
            00D3  5B                           POP     BX
            00D4  88 07                  MOV     [BX], AL        ; Сохранение очередного символа результата
            00D6  43                           INC     BX        ; Переключение на следующий символ
            00D7  C3                           RET
            00D8                   XLAT_OUTPUT     ENDP
            00D8                   CODE    ENDS
                                         END     CALCULATE_POWER
                  Фиг. 7.23 (а) (продолжение)
            A>PRINT10
            03H   447A0000H
            06H   49742400H
            09H   4E6E6B28H
            0CH   5368D4A5H
            0FH   58635FA9H
            12H   5D5E0B6BH
            15H   6258D727H
            18H   6753C21CH
            1BH   6C4ECB8FH
            1EH   7149F2CAH
            21H   76453719H
            24H   7B4097CEH
            27H   7F800000H
 
                  Фиг. 7.23 (b)
 
          Фиг. 7.23 (a) Степени 10; (b) Вывод процедуры степеней 10
 
      Вам нужно посмотреть часть программы TRANSLATE, несмотря на то,
    что она не использует ни одной команды сопроцессора 8087.  Эта
    часть - пример подготовки чисел к печати.  В частности, команда
    XLAT преобразует для печати шестнадцатеричную тетраду (значение от
    0 до 0FH) в правильный символ кода ASCII (от 0 до F).  Просто
    прибавлять значение тетрады к значению 0 нельзя, так как в коде
    ASCII символы от A до F не следуют непосредственно за символами от
    0 до 9; преобразование прекрасно выполняет команда перекодировки.
    Мы используем аналогичный метод, когда преобразуем число с
    плавающей точкой в пригодную для печати десятичную форму.




Содержание раздела