assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 42
Текст из файла (страница 42)
Вычисление простого выражения<1> ;prg_8_7.asm<2> masm<3><4><5><б><7><8><9>modelsmallstack256.dataa db 5bdb 10с db 2у dw 0.codemain:.386хог ах,ахmov al,acbwmovsxbx,badd ax.bx;точка входа в программуАрифметические операции над двоично-десятичными числами<18><19><20><21><22>idivcexit:1 83;в al - частное, в ah - остатокmov ax ,4c00h ; стандартный выходint 21hend main;конец программыВ этой программе делимое для команды IDIV (строка 18) готовится заранее. Таккак делитель имеет размер байта, то делимое должно быть словом. С учетом этогосложение осуществляется параллельно с преобразованием размера результатав слово (строки 14-17).
Например, расширение операндов со знаком производится двумя разными командами — CBW и MOVSX.Другие полезные командыВ системе команд процессора есть две команды — XADD и NEG, которые могут бытьполезны, в частности, для программирования вычислительных действий:ж xadd приемник,источник — обмен местами и сложение. Команда позволяет выполнить последовательно два действия:1) обменять значения приемник и источник;2) поместить на место операнда приемник сумму: приемник = приемник + источник.В neg операнд — отрицание с дополнением до двух. Команда выполняет инвертирование значения операнд. Физически команда выполняет одно действие:операнд = 0 - операнд, то есть вычитает операнд из нуля.
Команду NEG можноприменять для смены знака и вычитания из константы. Дело в том, что команды SUB и SBB не позволяют вычесть что-либо из константы, так как константа неможет служить операндом-приемником в этих операциях. Поэтому даннуюоперацию можно выполнить с помощью двух команд:neg ax;смена з н а к а (ах)add a x , 3 4 0фактически вычитание: (ах)=340-(ах)Арифметические операциинад двоично-десятичными числамиОпределение и формат BCD-чисел были рассмотрены в начале этой главы.
У вассправедливо может возникнуть вопрос: а зачем нужны BCD-числа? Ответ можетбыть следующим: BCD-числа нужны в коммерческих приложениях, то есть там,где числа должны быть большими и точными. Как мы уже убедились, выполнениеопераций с двоичными числами для языка ассемблера довольно проблематично:в Значения величин в формате слова и двойного слова имеют ограниченный диапазон. Если программа предназначена для работы в области финансов, то ограничение суммы в рублях величиной 65 536 (для слова) или даже 4 294 967 296(для двойного слова) существенно сужает сферу ее применения (да еще в наших экономических условиях — тут уж никакая деноминация не поможет).* Двоичные числа дают ошибки округления.
Представляете себе программу, работающую где-нибудь в банке, которая не учитывает величину остатка при дей-184Глава 8. Арифметические командыствиях с целыми двоичными числами и оперирует при этом миллиардами. Нехотелось бы быть автором такой программы. Применение чисел с плавающейточкой не спасет — там существует та же проблема округления.я Большой объем результатов в коммерческих программах требуется представлять в символьном виде (ASCII-коде).
Коммерческие программы не простовыполняют вычисления; одной из целей их применения является оперативнаявыдача информации пользователю. Для этого, естественно, информация должна быть представлена в символьном виде. Перевод чисел из двоичного кодав ASCII-код, как мы уже видели, требует определенных вычислительных затрат. Число с плавающей точкой еще труднее перевести в символьный вид. А вотесли посмотреть на шестнадцатеричное представление неупакованной десятичной цифры (в начале данной главы) и на соответствующий ей символ в таблице ASCII, то видно, что они различаются на величину ЗОН. Таким образом, преобразование в символьный вид и обратно получается намного проще и быстрее.Эти доводы убеждают в важности овладения хотя бы основами действий с десятичными числами. Далее рассмотрим особенности выполнения основных арифметических операций с такими числами.
Для предупреждения возможных вопросовсразу отметим тот факт, что отдельных команд сложения, вычитания, умноженияи деления BCD-чисел нет. Сделано это по вполне понятным причинам — размерность таких чисел может быть сколь угодно большой. Складывать и вычитать можнодвоично-десятичные числа как в упакованном формате, так и в неупакованном,а вот делить и умножать можно только неупакованные BCD-числа.
Почему, будетвидно из дальнейшего обсуждения.Неупакованные BCD-числаСложениеРассмотрим два случая сложения.Результат сложения не больше 9:6 = 00000110+3 = 000000119 = 00001001.Переноса из младшей тетрады в старшую нет. Результат правильный.Результат сложения больше 9:06 = 00000110+07 = 0000011113 = 00001101.То есть мы получили уже не BCD-число. Результат неправильный. Правильный результат в неупакованном BCD-формате в двоичном представлении долженбыть таким: 0000 0001 0000 0011 (или 13 в десятичном). Проанализировав даннуюпроблему при сложении BCD-чисел (и подобные проблемы при выполнении дру-Арифметические операции над двоично-десятичными числами185гих арифметических действий), а также возможные пути ее решения, разработчики системы команд процессора решили не вводить специальные команды для работы с BCD-числами, а ввести несколько корректировочных команд.
Назначениеэтих команд — корректировка результата работы обычных арифметических команддля случаев, когда операнды в них являются BCD-числами. В случае сложения вовтором примере видно, что полученный результат нужно корректировать. Для коррекции операции сложения двух однозначных неупакованных BCD-чисел и представления результата сложения в символьном виде в системе команд процессорасуществует специальная команда ААА (ASCII Adjust for Addition).Команда ААА не имеет операндов.
Онд работает неявно только с регистром ALи анализирует значение его младшей тетрады. Если это значение меньше 9, тофлаг CF сбрасывается в 0 и осуществляется переход к следующей команде. Еслиэто значение больше 9, то выполняются следующие действия.1. К содержимому младшей тетрады AL (но не к содержимому всего регистра!)прибавляется 6, тем самым значение десятичного результата корректируетсяв правильную сторону.2.
Флаг CF устанавливается в 1, тем самым фиксируется перенос в старший разряд для того, чтобы его можно было учесть в последующих действиях.Так, во втором примере сложения, предполагая, что значение суммы 0000 1101находится в AL, после выполнения команды ААА в регистре будет 1101 + 0110 == 0011, то есть двоичное значение 0000 0011 или десятичное значение 3, а флаг CFустановится в 1, то есть перенос запоминается в процессоре. Далее программистунужно использовать команду сложения A DC, которая учтет перенос из предыдущего разряда. Приведем пример программы сложения двух неупакованных BCD-чисел (листинг 8.8).Листинг 8.8. Сложение неупакованных BCD-чисел<1>;prg_8_8.asm<3><4><5><б><7><8><9>.datalen equb dbсdbsum db.codemain:ml:2разрядность числа1,7; неупакованное число 714,5;неупакованное число 543 dup (0);точка входа в программуxor bx.bxmov cx.lenmov al, b[bx]adc al,c[bx]aaamov sum[bx],al<20>inc bxloop mladc sum[bx] ,0exit:В листинге 8.8 есть несколько интересных моментов, над которыми стоит поразмыслить.
Начнем с описания BCD-чисел. Из строк 5 и 6 видно, что порядок их186Глава 8. Арифметические командыввода обратен нормальному, то есть цифры младших разрядов расположены поменьшему адресу. Это вполне логично по нескольким причинам: во-первых, такойпорядок удовлетворяет общему принципу представления данных для процессоров Intel, во-вторых, это очень удобно для поразрядной обработки неупакованныхBCD-чисел, так как каждое из них занимает один байт. Хотя, повторюсь, программист сам волен выбирать способ описания BCD-чисел в сегменте данных. Строки14 и 15 содержат команды, которые складывают цифры в очередных разрядах BCDчисел, при этом учитывается возможный перенос из младшего разряда.
КомандаААА в строке 16 корректирует результат сложения, формируя в AL BCD-цифру и принеобходимости устанавливая в 1 флаг CF. Строка 20 учитывает возможность переноса при сложении цифр из самых старших разрядов чисел. Результат сложенияформируется в поле sum, описанном в строке 7.ВычитаниеСитуация при вычитании вполне аналогична сложению. Рассмотрим те же случаи.Результат вычитания не больше 9:6 = 000001103 = 000000113 = 00000011.Как видим, заема из старшей тетрады нет. Результат верный и корректировкине требует.Результат вычитания больше 9:6 =000001107=00000111-1-11111111.Вычитание проводится по правилам двоичной арифметики. Поэтому результат не является BCD-числом. Правильный результат в неупакованном BCD-формате должен быть 9 (0000 1001 в двоичной системе счисления).
При этом предполагается заем из старшего разряда, как при обычной команде вычитания, то естьв случае с BCD-числами фактически должно быть выполнено вычитание 16 - 7.Таким образом, как и в случае сложения, результат вычитания нужно корректировать. Для этого существует специальная команда AAS (ASCII Adjust for Substraction), выполняющая коррекцию результата вычитания для представления в символьном виде.Команда AAS также не имеет операндов и работает с регистром AL, анализируяего младшую тетраду следующим образом: если ее значение меньше 9, то флаг CFсбрасывается в 0 и управление передается следующей команде.
Если значение тетрады в AL больше 9, то команда AAS выполняет следующие действия.1. Из содержимого младшей тетрады регистра AL (заметьте, не из содержимоговсего регистра) вычитается 6.Арифметические операции над двоично-десятичными числами1872. Старшая тетрада регистра AL обнуляется.3. Флаг CF устанавливается в 1, тем самым фиксируется воображаемый заем изстаршего разряда.Понятно, что команда AAS применяется вместе с основными командами вычитания SUB и SBB.