Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29251
Скачиваний: 1689
Глава 25. Работа с сопроцессором
249
Во-вторых, наши программы носят сугубо обучающий характер. Пройдя пол-
ный курс программирования на ассемблере, вы сможете написать собственную
программу так, как вам этого хочется.
В-третьих, то, что мы делаем с помощью сопроцессора, сложно реализовать без
него.
8. Как мы используем сопроцессор?
Мы будем выводить целые десятичные числа на экран. Например, размеры
файлов. Это будет гораздо проще, чем использовать только процессор.
9. Сложно ли на ассемблере вывести десятичное число на экран? В Бейсике,
например, достаточно набрать
PRINT 25*4
, и мы увидим результат умно-
жения.
На ассемблере очень просто выводить на экран шестнадцатеричные и двоич-
ные числа, но никак не десятичные. Поэтому только в этой главе мы затраги-
ваем данную тему, т. к. вы должны уже неплохо разбираться в командах ас-
семблера и понимать принцип программирования на этом мощном и очень
простом языке.
10. Сильно ли отличаются ассемблерные команды сопроцессора и принцип
его работы от программирования процессора?
Да, довольно-таки сильно. Сегодня вы сами лично "нащупаете" эту маленькую
микросхему. По крайней мере увидите, как она работает...
11. А если мне ничего не будет понятно?
Не отчаивайтесь! Все станет предельно ясно со временем. Вспомните, у вас, ве-
роятно, были трудности с тем или иным оператором, процедурой. Но в процессе
экспериментов все стало на свои места. Так и здесь. Если вы сразу поймете все,
что написано в данной главе, то можно сказать, что мы достигли той цели, кото-
рую ставили перед собой. Если нет — экспериментируйте, спрашивайте у наших
экспертов на http://RFpro.ru. Эту тему желательно усвоить всем!
25.2. Введение в работу с сопроцессором
Прежде всего стоит отметить, что для того, чтобы использовать инструкции со-
процессора, необходимо включить в начало программы директиву
.8087
(
.287
,
.387
). То есть указать, команды какого сопроцессора мы будем использовать.
Принцип такой же, как и при указании процессора: либо только 8086 (
.8086
), либо
8086 и 80286 (
.286
) и т. д. В листинге 25.1 приведен пример включения директивы,
которая указывает программе-ассемблеру (MASM/TASM), инструкции какого со-
процессора будут использоваться.
Листинг 25.1. Включение директивы сопроцессора
;Не забывайте указывать процессор, если вы собираетесь использовать
;команды не только 8086!
.386
Часть III. Файловая оболочка, вирус, резидент
250
;Будем использовать команды не только 386 процессора, но и 8087,
;а также 80287 сопроцессоров.
.287
...
В некоторых случаях TASM может выдавать сообщение при попытке ассембли-
рования программы, начинающейся с указанных выше строк. Что-то типа: "Внима-
ние: Вы используете команды процессора 386 и сопроцессора 287!" Зачем нужно
было это делать — не совсем понятно! Программист может использовать, напри-
мер, команды процессора 486, а также сопроцессора 8087. Ничего страшного в этом
нет и быть не может! В любом случае просто игнорируйте это сообщение.
В распоряжении программиста имеется набор нескольких инструкций и 8 реги-
стров (или 8 ячеек памяти) сопроцессора. Принцип загрузки числа в тот или иной
регистр похож на принцип работы стека. Далее будем много тренироваться. Пока
только теория.
Регистры сопроцессора имеют следующие названия:
st(0)
,
st(1)
,
st(2)
, ...,
st(7)
. Иногда для краткости
st(0)
называют просто
st
. Загрузить число в любой
из указанных регистров командой
mov
не получится. Для этого существуют специ-
альные команды сопроцессора.
Хорошим тоном перед использованием сопроцессора является его инициализа-
ция командой
finit
(от англ. FPU initialization — инициализация сопроцессора).
Вообще, все команды сопроцессора начинаются с символа
f
, что является их отли-
чительной чертой. Инструкция
finit
инициализирует сопроцессор. При этом сбра-
сываются все регистры, биты, флаги, а также происходит очистка 8 регистров
st
.
Таким образом, после инициализации сопроцессора программист может быть уве-
рен в том, что никакой регистр не занят и не получится путаницы или переполне-
ния стека при попытке выполнить ту или иную операцию.
Сопроцессор может работать с 16—80-разрядными числами. Следовательно,
в регистры
st(0)
—
st(7)
можно загружать число в указанных выше пределах. Со-
процессор сам определит, 16-разрядное ли это число или 64-разрядное.
Все числа из переменных загружаются в регистр сопроцессора
st(0)
и выгру-
жаются из него в обычные переменные. Регистр
st(0)
является, скажем так, глав-
ным, основным, первичным. Только в него можно загружать числа из переменных
и выгружать результат в переменные.
Например, возьмем команду
fild
(от англ. FPU integer load — загрузка целого
числа в регистр сопроцессора
st(0)
), которая загружает в регистр
st(0)
число из
переменной в памяти (листинг 25.2).
Листинг 25.2. Загрузка числа в регистр сопроцессора
...
FILD Number1
...
Number1 dw 10
...
Глава 25. Работа с сопроцессором
251
Как видите, здесь мы указываем только имя переменной, значение которой бу-
дет загружено в регистр
st(0)
и только в него (как уже упоминалось). Допустим,
нам нужно сложить два целых числа, используя сопроцессор. Для этого мы загру-
жаем в
st(0)
число 10. Затем загружаем второе число — 3 (для выполнения опера-
ции сложения нужно как минимум два числа) (листинг 25.3).
Листинг 25.3. Загрузка двух чисел в регистры сопроцессора
...
(1) FILD Number1
(2) FILD Number2
...
Number1 dw 10
Number2 dw 3
...
Теперь внимание! После выполнения строки (1)
st(0)
будет содержать число
10. После выполнения строки (2) число из
st(0)
переместится в регистр
st(1)
,
а его место в
st(0)
займет число 3. То есть работа системы похожа на работу стека!
Далее нужно сложить числа, которые находятся в
st
и
st(1)
, используя команду
сложения
FADD
.
FADD
Команда
fadd
(от англ. FPU addition — сложение с использованием регистров
сопроцессора) без параметров складывает два числа, которые находятся в регист-
рах
st(0)
и
st(1)
, при этом очищая
st(1)
и помещая результат сложения в
st(0)
.
Рассмотрим, что происходит в регистрах в процессе выполнения данных команд
(табл. 25.1). Итак, пока никаких действий мы не выполняли.
Таблица 25.1. Изначальное состояние регистров сопроцессора
Регистр
Значение
st(0)
Пусто
st(1)
Пусто
st(2)
Пусто
...
st(7)
Пусто
Заносим первое число в регистр
st
командой
fild Number1
(табл. 25.2).
Таблица 25.2. Загружено одно число в регистры сопроцессора
Регистр
Значение
st(0)
10
st(1)
Пусто
Часть III. Файловая оболочка, вирус, резидент
252
Таблица 25.2 (окончание)
Регистр
Значение
st(2)
Пусто
...
st(7)
Пусто
Теперь заносим второе число командой
fild Number2
(табл. 25.3).
Таблица 25.3. Загружено второе число в регистры сопроцессора
Регистр
Значение
st(0)
3
st(1)
10
st(2)
Пусто
...
st(7)
Пусто
Обратите внимание, что числа как бы вталкиваются внутрь. Как уже отмеча-
лось, заносить числа в сопроцессор можно только в регистр
st(0)
. Поэтому-то вто-
рой параметр в команде
fild
отсутствует — и так все понятно...
Теперь произведем сложение двух чисел с помощью команды
fadd
(табл. 25.4).
Таблица 25.4. Результат выполнения команды FADD
Регистр
Значение
st(0)
13
st(1)
Пусто
st(2)
Пусто
...
st(7)
Пусто
Как нам теперь получить результат сложения? Существует также команда, про-
тивоположная
fild
:
fist Result
Команда
fist
(от англ. FPU integer store — сохранение целого числа) сохранит
число, которое находится в регистре
st(0)
, в переменную
Result
.
Теперь ассемблируйте, запускайте отладчик и смотрите, что происходит.
Смеем предположить, что многие из вас столкнутся с проблемой: AFD выводит
на экран совсем не то, что мы набрали, а именно:
wait
,
esc
и пр. Здесь ошибки нет.
Глава 25. Работа с сопроцессором
253
Просто одна команда сопроцессора на самом деле преобразуется в выражения
вида:
WAIT
ESC
Именно это и будет отображать на экране отладчик AFD, как показано на
рис. 25.1.
Рис. 25.1. Отладка программы с командами сопроцессора
Однако лучше всего отлаживать программу, которая использует инструкции со-
процессора, в отладчике TurboDebugger. Мы настоятельно рекомендуем произво-
дить отладку и смотреть результаты выполнения операций именно в этом отладчи-
ке, т. к. он очень удобен и наглядно отображает все, что вам нужно. Более того,
TurboDebugger позволяет настроить рабочий стол таким образом, чтобы пользова-
тель видел все необходимое одновременно: регистры основного процессора и со-
процессора, результаты вычислений, код программы, дамп памяти и пр. Если вы
посмотрели работу приведенной выше программы в TurboDebugger, то читайте
дальше...
Вопрос: сложили два числа, получили результат, но ведь в
st(0)
осталось чис-
ло 13! Получается, что нам нужно перед каждой арифметической операцией ини-
циализировать сопроцессор командой
finit
, чтобы очистить регистры от результа-
тов вычислений? Можно ли как-то убрать это число иным способом? Например,
за один раз (одной командой) перенести его в переменную
Result
и освободить
st(0)
?
Ответ: конечно, можно. Существует ряд команд, облегчающих работу с сопро-
цессором. Описать все в одной книге невозможно. В данной главе мы рассмотрим
определенное количество команд, используя которые вы уже сможете выполнять
многие операции.