Математический сопроцессор x87 FPU

Аннотация

Целью четвертой лабораторной работы является получение навыков работы с математическим сопроцессором.

Ход работы

  1. Перейдите в каталог для файлов лабораторных работ по курсу "Архитектура современных ЭВМ".
  2. Создайте каталог для файлов данной лабораторной работы.
  3. Подготовьте файл с кодом программы:
    /**
     * math.S -- вычисляет и печатает число Пи
     *
     * Copyright (c) 2014 Petrozavodsk State University
     *
     * Permission is hereby granted, free of charge, to any person obtaining
     * a copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     */
    
     
    /* Объявляем внешние имена (необязательно) */
     
    .extern printf
    .extern scanf
    
    
    /* Секция данных */
    
    .data
    
        fmt:
            .asciz "%.25lf\n"               # форматная строка для printf
    
        dbl:
            .double .0                      # вещественнозначное число типа double
    
            
    /* Секция команд процессора */        
    .text
    
        .global main                        # имя точки входа для компоновщика 
    
        
    /**
     * main
     *   главная функция языка Си - точка входа в программу
     */
    main: 
        pushl %ebp                          # сохраняем контекст стека
        movl %esp, %ebp
    
        pushl $dbl                          # передаем адрес для размещения результата
        call calc_pi_1                      # вызываем функцию расчета числа Пи
                                            # с помощью инструкции fldpi
        addl $4, %esp                       # восстанавливаем указатель стека
    
        pushl $dbl                          # передаем адрес числа Пи
        call print_double_by_ptr            # вызываем функцию вывода числа на экран
        addl $4, %esp                       # восстанавливаем указатель стека
    
        pushl $dbl                          # передаем адрес для размещения результата
        call calc_pi_2                      # вызываем функцию расчета числа Пи
                                            # с помощью формулы Мэчина
        addl $4, %esp                       # восстанавливаем указатель стека
    
        pushl $dbl                          # передаем адрес числа Пи
        call print_double_by_ptr            # вызываем функцию вывода числа на экран
        addl $4, %esp                       # восстанавливаем указатель стека
    
        movl %ebp, %esp                     # восстанавливаем контекст стека
        popl %ebp
        
        ret                                 # завершаем выполнение программы
    
        
    /** print_double_by_ptr
     *    выводит вещественнозначное число типа double на экран с помощью вызова
     *    функции printf стандартной библиотеки языка Си
     */
    print_double_by_ptr:
        pushl %ebp                          # сохраняем контекст стека
        movl %esp, %ebp
    
        movl 8(%ebp), %eax                  # получаем указатель на число
        pushl 4(%eax)                       # сохраняем старшую половину
        pushl (%eax)                        # сохраняем младшую половину
        pushl $fmt                          # сохраняем адрес форматной строки
        call printf                         # выводим на экран
        addl $12, %esp                      # восстанавливаем указатель стека
    
        movl %ebp, %esp                     # восстанавливаем контекст стека
        popl %ebp
        ret                                 # завершаем подпрограмму
    
        
    /** calc_pi_1
     *    вычисляет значение числа пи с помощью встроенной функции загрузки
     *    числа пи на вершину стека fpu
     */
    calc_pi_1:
        pushl %ebp                          # сохраняем контекст стека
        movl %esp, %ebp
    
        fldpi                               # загружаем число Пи на вершину стека
        
        movl 8(%ebp), %eax                  # извлекаем из параметра адрес
        fstpl (%eax)                        # выталкиваем результат по адресу
    
        movl %ebp, %esp                     # восстанавливаем контекст стека
        popl %ebp
        ret                                 # завершаем подпрограмму
    
        
    /** calc_pi_2
     *    вычисляет значение числа пи с помощью формулы Мэчина
     */
    calc_pi_2:
        pushl %ebp                          # сохраняем контекст стека
        movl %esp, %ebp
        
        subl $4, %esp                       # резервируем память под локальную переменную
        
        
        fld1                                # st(0) <- 1
        movl $239, -4(%ebp)
        fild -4(%ebp)                       # st(0) <- 239, st(1) <- 1
        fpatan                              # st(0) <- arctg(1/239)
            
        fld1                                # st(0) <- 1, st(0) <- arctg(1/239)
        movl $5, -4(%ebp)
        fild -4(%ebp)                       # st(0) <- 5, st(1) <- 1, st(2) <- arctg(1/239)
        fpatan                              # st(0) <- arctg(1/5), st(1) <- arctg(1/239)
        
        movl $4, -4(%ebp)
        fild -4(%ebp)                       # st(0) <- 4, st(1) <- arctg(1/5), st(2) <- arctg(1/239)
        fmulp                               # st(0) <- 4 * arctg(1/5), st(1) <- arctg(1/239)
        
        fsubp                               # st(0) <- 4 * arctg(1/5) - arctg(1/239)
        
        fild -4(%ebp)                       # st(0) <- 4, st(1) <- 4 * arctg(1/5) - arctg(1/239)
        fmulp                               # st(0) <- 4 * (4 * arctg(1/5) - arctg(1/239))
    
        movl 8(%ebp), %eax                  # извлекаем из параметра адрес
        fstpl (%eax)                        # выталкиваем результат по адресу
    
        movl %ebp, %esp                     # восстанавливаем контекст стека
        popl %ebp
        
        ret                                 # завершаем подпрограмму
        
  4. Изучите способ организации подпрограмм в коде на языке ассемблера, передачи значения в подпрограмму.
  5. Изучите механизм организации вычислений и размещения операндов выражений на стеке FPU на примере вычисления числа Пи с помощью инструкции FPU (calc_pi_1) и по формуле Мэчина (calc_pi_2):
  6. Реализуйте функцию вычисления числа Пи по формуле Штёрмера:

  7. Перепишите функцию main на языке C.