Ассемблер и арифметика
Ассемблер позволяет обработать все операционные кнопки, которые имеются на нашем арифмометре.
Единственный нюанс, который придётся учесть - арифмометр будет работать с
целыми,
положительными
числами.
Сделаем небольшое отступление и поговорим о том, с какими числами
должен
был работать наш арифмометр и почему мы от этого (пока) отказались.
Это дробные (кнопка с символом "точка" - которой у нас нет) десятичные числа.
Мы набираем на
дисплее число, предположим, что дробное. Затем, после знака операции, набираем ещё одно.
Что-бы процессор произвёл арифметическую операцию эти числа необходимо представить в двоичном
виде. Как это будет происходить:
1. берём число с дисплея-строку символов
2. определяем целую часть
2.1 преобразуем целую часть в bin
3. определяем дробную часть
3.1 преобразуем дробную часть в bin
4. собираем число: целая часть + дробная часть...вроде-бы - всё верно, но между целой и дробной
частью имеется разделительный символ "."
5. у разделительного символа есть свой код
2Еh или
00101110 в двоичном , но если его вставить
между целой и дробной частью - процессор этого не поймёт
6. что-бы процессор понял, что число дробное, его надо представить в вещественном виде
Обратим внимание на то, что процессор такие числа
не обрабатывает, этим занимается - сопроцессор
(арифметический процессор), у которого свои арифметические команды.
Мы то-же
воспользуемся услугами сопроцессора - математика у него намного проще.
Oдин из операндов располагается в вершине стека сопроцессора - регистре st(0), куда, после выполнения,
записывается и результат. Другой опреанд может располагатся либо в памяти, либо в другом
регистре st(1)...st(7) стека сопроцессора:
передача данных:
fld источник --> загрузка числа из области памяти в вершину стека st(0)
fst приёмник --> сохранение числа из вершины стека st(0) в память
fstр приёмник --> сохранение числа из вершины стека st(0) в память с
выталкиванием его из регистра
fxch st(i) --> st --> st(i)
сложение:
fadd -----------> st + st(1) -----> st
fadd источник --> st + источник --> st, источник - адрес ячейки памяти
fadd st(i),st --> st(i) + st -----> st(i)
вычитание:
fsub -----------> st - st(1) -----> st
fsub источник --> st - источник --> st, источник - адрес ячейки памяти
fsub st(i),st --> st(i) - st -----> st(i)
умножение:
fmul -----------> st * st(1) ----> st
fmul источник --> st(i) * источник -> st
fmul st(i) -----> st(i) * st ----> st
fmul st(i),st --> st(i) * st ----> st(i)
деление:
fdiv -----------> st : st(1) -----> st
fdiv источник --> st : источник --> st
fdiv st(i) -----> st : st(i) -----> st
fdiv st(i),st --> st : st(i) -----> st(i)
извлечение квадратного корня:
fsqrt --> из значения st --> st
выделение порядка и мантисы значения st:
fxtract --> мантиса (вещественное число) -->st,
порядок (без смещения) --> st(1)
Поскольку мы будем использовать компилятор masm32, то вершину стека мы будем обозначать
st а не
st(0).
Это - не все команды, только те, что могут понадобится.
Хочется ещё раз
подчеркнуть - это команды сопроцессора для работы с вещественными числами.
Во всех
арифметических операциях, на мой взгляд, наиболее удобен первый вариант - безоперандный,
легче следить за регистрами. Есть ещё два момента, которые имеют разную трактовку в разных
источниках.
Момент первый:
Сопроцессор необходимо инициировать - перед его кодом
помещают команду
finit. Среди продчего - она
должна "очищать" регистры стека
сопроцессора, работающего по принципу колеса обозрения. Это удобно, если арифметика не очень
длинная, т.к. регистров всего
8. Поэтому - не стоит забывать о варианте
fstр.
Рассмотрим это колесо поближе на примере операции сложения:
; a + b = c
.data
a db 2,2
b db 3,3
.data?
c db ?
... ; st st(1) st(2) ... st(7)
finit ; - - - -
fld a ; 2,2 - - -
fld b ; 3,3 2,2 - -
fadd ; 5,5 2,2 - -
fstp c ; 2,2 - - -
fwait
push offset c
...
Момент второй:
После кода сопроцессора необходимо помещать команду
fwait -
для синхронизации работы процессора и сопроцессора.
Единого мнения по этому поводу нет.
Поэтому мы будем исползовать обе команды. А поскольку мы не знаем - с какой именно операции
начнётся работа арифмометра, то лучше задействовать их в каждой обработке.
Теперь, когда у
нас есть арифмометр и он умеет (мы так предполагаем) выполнять все задействованые арифметические
операции - начинается самое интересное...
дальше...
...назад