Особенности выполнения арифметических опреаций
Стр 1 из 2Следующая ⇒ ПРЕДСТАВЛЕНИЕ ДАННЫХ. АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ Здесь рассматривается машинное представление целых чисел, строк и адресов. Представление двоично-десятичных чисел, используемых достаточно редко, не рассматривается. Что касается вещественных чисел, то в ПК нет команд вещественной арифметики (операции над этими числами реализуются программным путем или выполняются сопроцессором) и потому нет стандартного представления вещественных чисел. Кроме того, рассматриваются некоторые особенности выполнения арифметических операций. Шестнадцатиричные числа записываются с буквой h на конце, двоичные числа - с буквой b (так принято в MASM). 1.2.1 Представление целых чисел. В общем случае под целое число можно отвести любое число байтов, однако система команд ПК поддерживает только числа размером в байт и слово и частично поддерживает числа размером в двойное слово. Именно эти форматы и будут рассмотрены. В ПК делается различие между целыми числами без знака (неотрицательными) и со знаком. Это объясняется тем, что в ячейках одного и того же размера можно представить больший диапазон беззнаковых чисел, чем неотрицательных знаковых чисел, и если известно заранее, что некоторая числовая величина является неотрицательной, то выгоднее рассматривать ее как беззнаковую, чем как знаковую. Целые числа без знака. Эти числа могут быть представлены в виде байта, слова или двойного слова - в зависимости от их размера. В виде байта представляются целые от 0 до 255 (=2^8-1), в виде слова - целые от 0 до 65535 (=2^16-1), в виде двойного слова - целые от 0 до 4 294 967 295 (=2^32-1). Числа записываются в двоичной системе счисления, занимая все разряды ячейки. Например, число 130 записывается в виде байта 10000010b (82h).
Числа размером в слово хранятся в памяти в "перевернутом" виде: младщие (правые) 8 битов числа размещаются в первом байте слова, а старшие 8 битов - во втором байте (в 16-ричной системе: две правые цифры - в первом байте, две левые цифры - во втором байте). Например, число 130 (=0082h) в виде слова хранится в памяти так:
----------- | 82 | 00 | ----------- (Отметим, однако, что в регистрах числа хранятся в нормальном виде: ----------- AX | 00 | 82 | ----------- AH AL) "Перевернутое" представление используется и при хранении в памяти целых чисел размером в двойное слово: в первом его байте размещаются младшие 8 битов числа, во втором байте - предыдущие 8 битов и т.д. Например, число 12345678h хранится в памяти так: --------------------- | 78 | 56 | 34 | 12 | --------------------- Другими словами, в первом слове двойного слова размещаются младшие (правые) 16 битов числа, а во втором слове - старшие 16 битов, причем в каждом из этих двух слов в свою очередь используется "перевернутое" представление. Такое необычное представление чисел объясняется тем, что в первых моделях ПК за раз можно было считать из памяти только один байт и что все арифметические операции над многозначными числами начинаются с действий над младшими цифрами, поэтому из памяти в первую очередь надо считывать младшие цифры, если сразу нельзя считать все цифры. Учитывая это, в первых ПК и стали размещать младшие цифры числа перед старшими цифрамми, а ради преемственности такое представление чисел сохранили в последующих моделях ПК. Конечно, "перевернутое" представление неудобно для людей, однако при использовании языка ассемблера это неудобство не чувствуется: в MASM все числа записываются в нормальном, неперевернутом виде (см. ниже). Целые числа со знаком.
Эти числа также представляются в виде байта, слова и двойного слова. В виде байта записываются числа от -128 до 127, в виде слова числа от -32768 до 32767, а в виде двойного слова - числа от -2147483648 до 2147483647. При этом числа записываются в дополнительном коде: неотрицательное число записывается так же, как и беззнаковое число (т.е. в прямом коде), а отрицательное число -x (x>0) представляется беззнаковым числом 2^8-x (для байтов), 2^16-x (для слов) или 2^32-x (для двойных слов). Например, дополнительным кодом числа -6 является байт FAh (=256-6), слово FFFAh или двойное слово FFFFFFFAh. При этом байт 10000000b (=80h) трактуется как -128, а не как +128 (слово 8000h понимается как -32678), поэтому левый бит дополнительного кода всегда играет роль знакового: для неотрицательных чисел он равен 0, для отрицательных - 1. Знаковые числа размером в слово и двойное слово записываются в памяти в "перевернутом" виде (при этом знаковый бит оказывается в последнем байте ячейки). Но в MASM эти числа, как и беззнаковые, записываются в нормальной форме. Иногда число-байт необходимо расширить до слова, т.е. нужно получить такое же по величине число, но размером в слово. Существует два способа такого расширения - без знака и со знаком. В любом случае исходное число-байт попадает во второй (до "переворачивания") байт слова, а вот первый байт заполняется по-разному: при расширении без знака в него записываются нулевые биты (12h -> 0012h), а при расширении со знаком в первый байт записываются нули, если число-байт было неотрицательным, и записывается восемь двоичных единиц в противном случае (81h -> FF81h). Другими словами, при расширении со знаком в первом байте слова копируется знаковый разряд числа-байта. Аналогично происходит расширение числа-слова до двойного слова. Особенности выполнения арифметических опреаций В ПК имеются команды сложения и вычитания целых чисел размером в слово и байт. Специальных команд для сложения и вычитания двойных слов нет, эти операции реализуются через команды сложения и вычитания слов. Сложение и вычитание беззнаковаых чисел производится по модулю 2^8 для байтов и 2^16 для слов. Это означает, что если в результате сложения появилась единица переноса, не вмещающаяся в разрядную сетку, то она отбрасывается. Например, при сложении байтов 128 и 130 получается число 258 = 100000010b, поэтому левая двоичная единица отбрасывается и остается число 2 = 10b, которое и объявляется результатом сложения. Ошибка здесь не фиксируется, но в флаг переноса CF записывается 1 (если переноса не было, в CF заносится 0). "Поймать" такое искажение суммы можно только последующим анализом флага CF.
Искажение результата происходит и при вычитание из меньшего числа большего. И здесь не фиксируется ошибка, однако первому числу дается "заем единицы" (в случае байтов это число увеличивается на 256, для слов - на 2^16), после чего и производится вычитание. Например, вычитание байтов 2 и 3 сводится к вычитанию чисел 256+2=258 и 3, в результате чего получается неправильная разность 255 (а не -1). Для того чтобы можно было обнаружить такую ситуацию, в флаг переноса CF заносится 1 (если заема не было, в CF записывается 0). Сложение и вычитание знаковых целых чисел производится по тем же алгоритмам, что и для беззнаковых чисел (в этом одно из достоинств дополнительного кода): знаковые числа рассматриваются как соответствующие беззнаковые числа, произодится операция над этими беззнаковыми числами и полученный результат интерпретируется как знаковое число. Например, сложение байтовых чисел 1 и -2 происходит так: берутся их дополнительные коды 1 и (256-2)=254, вычисляется сумма этих величин 1+254=255 и она трактуется как знаковое число -1 (255=256-1). Если при таком сложении возникла единица переноса, то она, как обычно, отбрасывается, а флаг CF получает значение 1. Однако в данном случае это отсечение не представляет интерес - результат операции будет правильным, например: 3+(-2) => 3+254(mod 256) = 257(mod 256) = 1. Зато здесь возможна иная неприятность: модуль суммы (ее мантисса) может превзойти допустимую границу и "залезть" в знаковый разряд, испортив его. Например, при сложении байтовых чисел 127 и 2 получается величина 129 = = 100001001b, представляющая дополнительный код числа -127 (=256-129). Хотя результат здесь получился и неправильным, процессор не фиксирует ошибку, но зато заносит 1 в флаг переполнения OF (если "переполнения мантиссы" не было, в OF записывается 0). Анализируя затем этот флаг, можно "поймать" такую ошибку.
Таким образом, сложение (вычитание) знаковых и беззнаковых чисел производится по одному и тому же алгоритму. При этом ПК не "знает", какие числа (со знаком или без) он складывает; в любом случае он складывает их как беззнаковые числа и в любом случае формирует флаги CF и OF. А вот как интерпретировать слагаемые и сумму, на какой из этих флагов обращать внимание - это личное дело автора программы. Что касается умножения и деления знаковых и беззнаковых чисел, то они выполняются по разным алгоритмам, разными машинными командами. Однако и у этих операций есть ряд особенностей. При умножении байтов (слов) первый сомножитель обязан находиться в регистре AL (AX), результатом же умножения является слово (двойное слово), которое заносится в регистр AX (регистры DX и AX). Тем самым при умножении сохраняются все цифры произведения. При делении байтов (слов) первый операнд (делимое) должен быть словом (двойным словом) и обязан находиться в регистре AX (регистрах DX и AX). Результатом деления являются две величины размером в байт (слово) - неполное частное (div) и остаток от деления (mod); неполное частное записывается в регистр AL (AX), а остаток - в регистр AH (DX). 1.2.3 Представление символов и строк На символ отводится один байт памяти, в который записывается код символа - целое от 0 до 255. В ПК используется система кодировки ASCII (American Standard Code for Information Interchange). Она, естественно, не содержит кодов русских букв, поэтому в нашей стране применяется некоторый вариант этой системы с русскими буквами (обычно это альтернативная кодировка ГОСТа). Некоторые особенности этих систем кодировки: - код пробела меньше кода любой буквы, цифры и вообще любого графи- чески представимого символа; - коды цифр упорядочены по величине цифр и не содержат пропусков, т.е. из неравенства код('0')<=код(c)<=код('9') следует, что c - цифра; - коды больших латинских букв упорядочены согласно алфавиту и не со- держат пропусков; аналогично с малыми латинскими буквами; - (в альтернативной кодировке ГОСТа) коды русских букв (как больших, так и малых) упорядочены согласно алфавиту, но между ними есть коды других символов. Строка (последовательность символов) размещается в соседних байтах памяти (в неперевернутом виде): код первого символа строки записывается в первом байте, код второго символа - во втором байте и т.п. Адресом строки считается адрес ее первого байта. В ПК строкой считается также и последовательность слов (обычно это
последовательность целых чисел). Элементы таких строк располагаются в последовательных ячейках памяти, но каждый элемент представлен в "перевернутом" виде.
1.2.4 Представление адресов Адрес - это порядковый номер ячейки памяти, т.е. неотрицательное целое число, поэтому в общем случае адреса представляются так же, как и беззнаковые числа. Однако в ПК есть ряд особенностей в представлении адресов. Дело в том, что в ПК термином "адрес" обозначают разные вещи. Часто под адресом понимается 16-битовое смещение (offset) - адрес ячейки, отсчитанный от начала сегмента (области) памяти, которому принадлежит эта ячейка. В этом случае под адрес отводится слово памяти, причем адрес записывается в "перевернутом" виде (как и числа-слова вообще). В другом случае под "адресом" понимается 20-битовый абсолютный адрес некоторой ячейки памяти. В силу ряда причин в ПК такой адрес задается не как 20-битовое число, а как пара "сегмент:смещение", где "сегмент" (segment) - это первые 16 битов начального адреса сегмента памяти, которому принадлежит ячейка, а "смещение" - 16-битовый адрес этой ячейки, отсчитанный от начала данного сегмента памяти (величина 16*сегмент+смещение даетабсолютный адрес ячейки). Такая пара записывается в виде двойного слова, причем (как и для чисел) в "перевернутом" виде: в первом слове размещается смещение, а во втором - сегмент, причем каждое из этих слов в свою очередь представлено в "перевернутом" виде. Например, пара 1234h:5678h будет записана так: --------------------- | 78 | 56 | 34 | 12 | --------------------- смещение сегмент
1.2.5 Директивы определения данных Для того чтобы в программе на MASM зарезервировать ячейки памяти под константы и переменные, необходимо воспользоваться директивами определения данных - с названиями DB (описывает данные размером в байт), DW (размером в слово) и DD (размером в двойное слово). (Директивы, или команды ассемблеру, - это предложения программы, которыми ее автор сообщает какую-то информацию ассемблеру или просит что-то сделать дополнительно, помимо перевода символьных команд на машинный язык.) В простейшем случае в директиве DB, DW или DD описывается одна константа, которой дается имя для последующих ссылок на нее. По этой директиве ассемблер формирует машинное представление константы (в частности, если надо, "переворачивает" ее) и записывает в очередную ячейку памяти. Адрес этой ячейки становится значением имени: все вхождения имени в программу ассемблер будет заменять на этот адрес. Имена, указанные в директивах DB, DW и DD, называются именами переменных (в отличие от меток - имен команд). В MASM числа записываются в нормальном (неперевернутом) виде в cистемах счисления с основанием 10, 16, 8 или 2. Десятичные числа записываются как обычно, за шестнадцатиричным числом ставится буква h (если число начинается с "цифры" A, B,..., F, то вначале обязателен 0), за восьмиричным числом - буква q или o, за двоичным числом - буква b. Примеры: A DB 162;описать константу-байт 162 и дать ей имя A B DB 0A2h;такая же константа, но с именем B С DW -1;константа-слово -1 с именем С D DW 0FFFFh;такая же константа-слово, но с именем D E DD -1;-1 как двойное слово Константы-символы описываются в директиве DB двояко: указывается либо код символа (целое от 0 до 255), либо сам символ в кавычках (одинарных или двойных); в последнем случае ассемблер сам заменит символ на его код. Например, следующие директивы эквивалентны (2A - код звездочки в ASCII): CH DB 02Ah CH DB '*' CH DB "*" Константы-адреса, как правило, задаются именами. Так, по директиве ADR DW CH будет отведено слово памяти, которому дается имя ADR и в которое запишется адрес (смещение), соответствующий имени CH. Если такое же имя описать в директиве DD, то ассемблер автоматически добавит к смещению имени его сегмент и запишет смещение в первую половину двойного слова, а сегмент - во вторую половину. По любой из директив DB, DW и DD можно описать переменную, т.е. отвести ячейку, не дав ей начального значения. В этом случае в правой части директивы указывается вопросительный знак: F DW?;отвести слово и дать ему имя F, ничего в этот байт не;записывать В одной директиве можно описать сразу несколько констант и/или переменных одного и того же размера, для чего их надо перечислить через запятую. Они размещаются в соседних ячейках памяти. Пример: G DB 200, -5, 10h,?, 'F' Имя, указанное в директиве, считается именующим первую из констант. Для ссылок на остальные в MASM используются выражения вида <имя>+<целое>; например, для доступа к байту с числом -5 надо указать выражение G+1, для доступа к байту с 10h - выражение G+2 и т.д. Если в директиве DB перечислены только символы, например: S DB 'a','+','b' тогда эту директиву можно записать короче, заключив все эти символы в одни кавычки: S DB 'a+b' И, наконец, если в директиве описывается несколько одинаковых констант (переменных), то можно воспользоваться конструкцией повторения k DUP(a,b,...,c) которая эквивалентна повторенной k раз последовательности a,b,...,c. Например, директивы V1 DB 0,0,0,0,0 V2 DW?,?,?,?,?,?,?,?,?,'a',1,2,1,2,1,2,1,2 можно записать более коротко таким образом: V1 DB 5 DUP(0) V2 DW 9 DUP(?), 'a', 4 DUP(1,2)
Воспользуйтесь поиском по сайту: ©2015 - 2025 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|