Lektsia 11


Лекция 11.
1.Сложение двоичных чисел без знака.
Процессор выполняет сложение операндов по правилам сложения двоичных чисел. Проблем не возникает до тех пор, пока значение результата не превышает размерности поля операнда (см. табл. 8.1). Например, при сложении операндов размером в байт результат не должен превышать 255. Если это происходит, то результат оказывается неверен. Рассмотрим, почему. К примеру, выполним сложение: 254 + 5 = 259 в двоичном виде:
11111110 + 0000101 = 1 00000011.
Результат вышел за пределы восьми битов, и правильное его значение укладывается в 9 битов, а в 8-разрядном поле операнда осталось значение 3, что, конечно, неверно. В процессоре подобный исход сложения прогнозируется, и предусмотрены специальные средства для фиксации подобных ситуаций и их обработки. Так, для фиксации ситуации выхода за разрядную сетку результата, как в данном случае, предназначен флаг переноса CF. Он располагается в бите 0 регистра флагов EFLAGS/FLAGS. Именно установкой этого флага фиксируется факт переноса единицы из старшего разряда операнда. Естественно, что программист должен предусматривать возможность такого исхода операции сложения и средства для корректировки. Это предполагает включение фрагментов кода после операции сложения, в которых анализируется состояние флага CF. Этот анализ можно провести различными способами. Самый простой и доступный — использовать команду условного перехода JC. Эта команда в качестве операнда имеет имя метки в текущем сегменте кода. Переход на метку осуществляется в случае, если в результате работы предыдущей команды флаг CF установился в 1.
В системе команд процессора имеются три команды двоичного сложения:
inc операнд – команда инкремента, то есть увеличения значения операнда на 1:
add операнд_1,операнд_2 – команда сложения с принципом действия: операнд_1 = операнд_1 + операнд_2.
adc операнд_1,операнд_2 – команда сложения с учетом флага переноса CF : операнд_1 = операнд_1 + операнд_2 + значение_СF.
Обратите внимание на последнюю команду – это команда сложения, учитывающая перенос единицы из старшего разряда. Механизм появления такой единицы мы уже рассмотрели. Таким образом, команда ADC является средством процессора для сложения длинных двоичных чисел, размерность которых превосходит поддерживаемые процессором размеры стандартных полей. Пример вычисления суммы чисел (листинг 8.3) мы рассмотрим на лабораторной работе.
2.Сложение двоичных чисел со знаком.
Теперь настала пора раскрыть небольшой секрет. Дело в том, что на самом деле процессор не подозревает о различии между числами со знаком и числами без знака. Вместо этого у него есть средства фиксации возникновения характерных ситуаций, складывающихся в процессе вычислений. Некоторые из них мы рассмотрели ранее при обсуждении команд сложения чисел без знака – это учет флага переноса CF. Установка этого флага в 1 говорит о том, что произошел выход за пределы разрядности операндов. Далее с помощью команды ADC можно учесть возможность такого выхода (переноса из младшего разряда) во время работы программы.
Другое средство фиксации характерных ситуаций в процессе арифметических вычислений – регистрация состояния старшего (знакового) разряда операнда, которое осуществляется с помощью флага переполнения OF в регистре EFLAGS (бит 11).
При рассмотрении представления числа в компьютере мы отмечали, что положительные числа представляются в двоичном коде, а отрицательные – в дополнительном. Рассмотрим различные варианты сложения чисел.
Примеры призваны показать поведение двух старших битов операндов и правильность результата операции сложения.
Первый вариант сложения чисел:
30566 = 01110111 01100110
+
00687 = 00000010 10101111
31253 = 01111010 00010101.
Следим за переносами из 14-го и 15-го разрядов и за правильностью результата: переносов нет, результат правильный.
Второй вариант сложения чисел:
30566 = 01110111 01100110
+
30566 = 01110111 01100110
61132 = 11101110 11001100.
Произошел перенос из 14-го разряда; из 15-го разряда переноса нет. Результат неправильный, так как имеется переполнение – значение числа получилось больше, чем то, которое может иметь 16-разрядное число со знаком (+32 767).
Третий вариант сложения чисел:
-30566 = 10001000 10011010
+
-04875 = 11101100 11110101
-35441 = 01110101 10001111.
Произошел перенос из 15-го разряда, из 14-го разряда нет переноса. Результат неправильный, так как вместо отрицательного числа получилось положительное (в старшем бите находится 0).
Четвертый вариант сложения чисел:
-4875 = 11101100 11110101
+
-4875 = 11101100 11110101
-9750 = 11011001 11101010.
Есть переносы из 14-го и 15-го разрядов. Результат правильный.
Таким образом, мы исследовали все случаи и выяснили, что ситуация переполнения (установка флага OF в 1) происходит при переносе:
из 14-го разряда (для положительных чисел со знаком);
из 15-го разряда (для отрицательных чисел).
И, наоборот, переполнения не происходит (то есть флаг OF сбрасывается в 0), если есть перенос из обоих разрядов или перенос отсутствует в обоих разрядах.
Таким образом, ситуация переполнение регистрируется процессором с помощью флага переполнения OF. Дополнительно к флагу OF при переносе из старшего разряда устанавливается в 1 и флаг переноса CF. Так как процессор не знает о существовании чисел со знаком и без знака, то вся ответственность за правильность действий с получившимися числами ложится на программиста. Теперь, наверное, понятно, почему мы столько внимания уделили тонкостям сложения чисел со знаком. Учтя все это, мы сможем организовать правильный процесс сложения чисел – будем анализировать флаги CF и OF и принимать правильное решение! Проанализировать флаги CF и OF можно командами условного перехода JC\JMС и J0\JNO соответственно.
Что же касается команд сложения чисел со знаком, то из изложенного ранее понятно, что в архитектуре IA-32 сами команды сложения чисел со знаком те же, что и для чисел без знака.
3.Вычитание двоичных чисел без знака.
Аналогично анализу операции сложения, порассуждаем над сутью процессов, происходящих при выполнении вычитания.
Если уменьшаемое больше вычитаемого, то проблем нет, – разность положительна, результат верен.
Если уменьшаемое меньше вычитаемого, возникает проблема: результат меньше 0, а это уже число со знаком. В этом случае результат необходимо завернуть. Что это означает? При обычном вычитании (в столбик) делают заем 1 из старшего разряда. Процессор поступает аналогично, то есть занимает 1 из разряда, следующего за старшим в разрядной сетке операнда. Поясним на примере.
Первый вариант вычитания чисел:
05 = 0000000 000000101
-10 = 0000000 000001010.
Для того чтобы произвести вычитание, произведем воображаемый заем из старшего разряда:
100000000 00000101
- 00000000 00001010
11111111 11111011.
Тем самым, по сути, выполняется действие (65 536 + 5) - 10 = 65 531, 0 здесь как бы эквивалентен числу 65 536. Результат, конечно, неверен, но процессор считает, что все нормально, тем не менее, факт заема единицы он фиксирует, устанавливая флаг переноса CF. Посмотрите еще раз внимательно на результат операции вычитания. Это же число -5 в дополнительном коде! Проведем эксперимент: представим разность в виде суммы 5 + (-10).
Второй вариант вычитания чисел:
5 =00000000 00000101
+
(-10) =11111111 11110110
11111111 11111011.
То есть мы получили тот же результат, что и в предыдущем примере. Таким образом, после команды вычитания чисел без знака нужно анализировать состояние флага CF. Если он установлен в 1, это говорит о том, что произошел заем из старшего разряда и результат получился в дополнительном коде.
Аналогично командам сложения группа команд вычитания состоит из минимально возможного набора. Эти команды выполняют вычитание по алгоритмам, которые мы сейчас рассматриваем, а учет особых ситуаций должен производиться самим программистом.
dec операнд – rоманда декремента выполняет уменьшения значения операнда на 1;
sub операнд_1,операнд_2 – Команда вычитания (операнд_1 = операнд_1 - операнд_2):
sbb операнд_1,операнд_2 – Команда вычитания с учетом заема, то есть флага CF (операнд_1 = операнд_1 - операнд_2 - значение_СР):
Как видите, среди команд вычитания есть команда SBB, учитывающая флаг переноса CF. Эта команда подобна ADC, но теперь уже флаг CF играет роль индикатора заема 1 из старшего разряда при вычитании чисел.
Пример (листинг 8.4) программной обработки ситуации, рассмотренной ранее для второго варианта вычитания чисел рассмотрим на лабораторной работе.
4.Вычитание двоичных чисел со знаком.
Вычитание двоичных чисел со знаком выполнять несколько сложнее. Последний пример показал то, что процессору незачем иметь два устройства – сложения и вычитания. Достаточно наличия только одного — устройства сложения. Но для вычитания способом сложения чисел со знаком оба операнда (и уменьшаемое, и вычитаемое) необходимо представлять в дополнительном коде. Результат тоже нужно рассматривать как значение в дополнительном коде. Но здесь возникают сложности. Прежде всего, они связаны с тем, что старший бит операнда рассматривается как знаковый. Рассмотрим пример вычитания 45 - (-127).
Первый вариант вычитания чисел со знаком:
45 = 0010 1101

-127 = 1000 0001
=
-44 = 1010 1100.
Судя по знаковому разряду, результат получился отрицательный, что, в свою очередь, говорит о том, что число нужно рассматривать как дополнение, равное -44. Правильный результат должен быть равен 172. Здесь мы, как и в случае знакового сложения, встретились с переполнением мантиссы, когда значащий разряд числа изменил знаковый разряд операнда. Отследить такую ситуацию можно по содержимому флага переполнения OF. Его установка в 1 говорит о том, что результат вышел за диапазон представления знаковых чисел (то есть изменился старший бит) для операнда данного размера и программист должен предусмотреть действия по корректировке результата.
Следующее вычитание чисел со знаком выполним способом сложения:
-45 - 45 = -45 + (-45)= -90.
-45 =1101 0011
+
-45 =1101 0011
-90 =1010 0110.
Здесь все нормально, флаг переполнения OF сброшен в 0, а 1 в знаковом разряде говорит о том, что значение результата – число в дополнительном коде.
;prg_8_3.asm вычисление суммы чисел
masmmodelsmall
stack256
.data
adb254
.code;сегмент кодаmain:
movax,@datamovds,ax;...
xorax,axaddal,17
addal,a
jncm1;если нет переноса, то перейти на m1
adcah,0;в ax сумма с учетом переноса
m1: ;...
exit:
movax,4c00h;стандартный выход
int21h
end main;конец программы;prg_8_4.asm проверка при вычитании чисел без знака
masmmodelsmall
stack256
.data.code;сегмент кода
main:;точка входа в программу
movax,@datamovds,ax;...
xorax,axmoval,5
subal,10
jncm1;нет переноса?
neg al;в al модуль результата
m1: ;...
exit:
movax,4c00h;стандартный выход
int21h
end main;конец программы
;prg_8_5.asm умножение
masmmodelsmall
stack256
.data;сегмент данных
rezlabelword
rez_ldb45
rez_hdb0
.code;сегмент кода
main:;точка входа в программу
movax,@datamovds,ax;...
xorax,axmoval,25
mulrez_ljncm1;если нет переполнения, то на м1movrez_h,ah;старшую часть результата в rez_hm1:
movrez_l,al;младшую часть результата в rez_l;...
exit:
movax,4c00h;стандартный выход
int21h
endmain;конец программы
;prg_8.6.asm деление
masmmodelsmall
stack256
.data
del_blabelbyte
deldw29876
deltdb45
.code;сегмент кода
main:;точка входа в программу
movax,@datamovds,ax;...
xorax,ax;последующие две команды можно заменить одной mov ax,delmovah,del_b;старший байт делимого в ahmoval,del_b+1;младший байт делимого в aldivdelt;в al - частное, в ah - остаток
;...
exit:
movax,4c00h;стандартный выход
int21h
endmain;конец программы
;prg_8_7.asm вычисление простого выраженияmasmmodelsmall
stack256
.data
adb?
bdb?
cdb?
ydw0
.codemain:;точка входа в программу
movax,@datamovds,ax;...
xorax,axmoval,acbwmovsxbx,baddax,bxidivc;в al - частное, в ah - остаток
exit:
movax,4c00h;стандартный выход
int21h
end main;конец программы

Приложенные файлы

  • docx 18814225
    Размер файла: 30 kB Загрузок: 0

Добавить комментарий