Автор: Пользователь скрыл имя, 10 Марта 2013 в 15:44, курс лекций
Один из основных принципов машины фон Неймана — то, что и программы, и данные хранятся в одной и той же памяти. Сохраняемая в памяти программа представляет собой некоторые коды, которые могут рассматриваться как данные. Возможно, с точки зрения программиста программа — активный компонент, она выполняет некоторые действия. Но с точки зрения процессора команды программы — это данные, которые процессор читает и интерпретирует. С другой стороны программа — это данные с точки зрения обслуживающих программ, например, с точки зрения компилятора, который на входе получает одни данные — программу на языке высокого уровня (ЯВУ), а на выходе выдает другие данные — программу в машинных кодах.
u Будьте внимательны при ассемблировании по умолчанию. Например, если поле FACT определено как байт (DB), то команда MUL FACT полагает множимое в регистре AL, а команда DIV FACT полагает делимое в регистре AX. В случае, если FACT определен как слово (DW), то команда MUL FACT полагает множимое в регистре AX, а команда DIV FACT полагает делимое в регистровой паре DX:AX.
4
Обработка данных в форматах ASCII и BCD
Для получения высокой производительности компьютер выполняет aрифметические операции над числами в двоичном формате. Этот формат не вызывает особых трудностей, если данные определены в самой программе. Во многих случаях новые данные вводятся программой с клавиатуры в виде ASCII символов в деcятичном формате. Аналогично вывод информации на экран осуществляется в кодах ASCII. Например, число 23 в двоичном представлении выглядит как 00010111 или шест.17; в коде ASCII на каждый cимвол требуется один байт и число 25 в ASCII-коде имеет внутpеннее представление шест.3235.
При программировании на языках высокого уровня для обозначения порядка числа или положения десятичной запятой (точки) можно положиться на компилятор. Однако, компьютер не распознает десятичную запятую (точку) в арифметических полях. Так как двоичные числа не имеют возможности установки десятичной (или двоичной) запятой (точки), то именно программист должен подразумевать и определить порядок обрабатываемых чисел.
ASCII-формат
Данные, вводимые с клавиатуры, имеют ASCII-формат, например, буквы SAM имеют в памяти шестнадцатеричное представление 53414D, цифры 1234 — шест.31323334. Во многих случаях формат алфавитных данных, например, имя человека или описание статьи, не меняется в программе. Но для выполнения арифметических операций над числовыми значениями, такими как шест.31323334, требуется специальная обработка.
С помощью следующих ассемблерных команд можно выполнять арифметические операции непосредственно над числами в ASCII-формате:
AAA (ASCII Adjust for Addition — коррекция для
сложения
ASCII-кода)
AAD (ASCII Adjust for Division — коррекция для
деления
ASCII-кода)
AAM (ASCII Adjust for Multiplication — коррекция для умножения ASCII-кода)
AAS (ASCII Adjust for Subtraction — коррекция для
вычитания
ASCII-кода)
Эти команды кодируются без операндов и выполняют автоматическую коррекцию в регистре AX. Коррекция необходима, так как ASCII-код представляет так называемый распакованный десятичный формат, в то время, как компьютер выполняет арифметические операции в двоичном формате.
Сложение многобайтовых
ASCII-чисел требует
Вычитание в ASCII-формате
Команда AAS (ASCII Adjust for Subtraction — коррекция для вычитания ASCII-кодов) выполняется aналогично команде AAA. Команда AAS проверяет правую шест. цифру (четыре бита) в регистре AL. В случае, если эта цифра лежит между A и F или флаг AF равен 1, то из регистра AL вычитается 6, а из регистра AH вычитается 1, флаги AF и CF устанавливаются в 1. Во всех случаях команда AAS устанавливает в 0 левую шест.цифру в регистpе AL.
Умножение в ASCII-формате
Команда AAM (ASCII Adjust for Multiplication — коррекция для умножения ASCII-кодов) выполняет корректировку результата умножения ASCII-кодов в регистре AX. Однако, шест. цифры должны быть очищены от троек и полученные данные уже не будут являться действительными ASCII-кодами. Например, число в ASCII-формате 31323334 имеет распакованное десятичное представление 01020304. Кроме этого, надо помнить, что коррекция осуществляется только для одного байта за одно выполнение, поэтому можно умножать только oдно-байтовые поля; для более длинных полей необходима организация цикла.
Команда AAM делит содержимое регистра AL на 10 (шест.0A) и записывает частное в регистр AH, а остаток в AL. Предположим, что в регистре AL содержится шест.35, а в регистре CL — шест.39. Следующие команды умножают содержимое регистра AL на содержимое CL и преобразуют результат в ASCII-формат:
AX: AND CL,0FH ;Преобразовать CL в 09
AND AL,0FH ;Преобразовать AL в 05 0005
MUL CL ;Умножить AL на CL 002D
AAM ;Преобразовать в распак.дес. 0405
OR AX,3030H ;Преобразовать в ASCII-ф-т 3435
Команда MUL генерирует 45 (шест.002D) в регистре AX, после чего команда AAM делит это значение на 10, записывая частное 04 в регистр AH и остаток 05 в регистр AL. Команда OR преобpазует затем распакованное десятичное число в ASCII-формат.
Деление в ASCII-формате
Команда AAD (ASCII Adjust for Division — коррекция для деления ASCII-кодов) выполняет корректировку ASCII-кода делимого до непосредственного деления. Однако, прежде необходимо очистить левые тройки ASCII-кодов для получения распакованного десятичного формата. Команда AAD может оперировать с двухбайтовыми делимыми в регистре AX. Предположим, что регистр AX содержит делимое 3238 в ASCII-формате и регистр CL содержит делитель 37 также в ASCII-формате. Следующие команды выполняют коррекцию для последующего деления:
AX: AND CL,0FH ;Преобразовать CL в распак.дес.
AND AX,0F0FH ;Преобразовать AX в распак.дес. 0208
AAD ;Преобразовать в двоичный 001C
DIV CL ;Разделить на 7 0004
Команда AAD умножает содержимое AH на 10 (шест.0A), прибавляет pезультат 20 (шест.14) к регистру AL и очищает регистр AH. Значение 001C есть шест. представление десятичного числа 28. Делитель может быть только однобайтовый от 01 до 09.
4
Двоично-десятичный формат (BCD)
В предыдущем примере деления в ASCII-формате было получено частное 00090204. В случае, если сжать это значение, сохраняя только правые цифры каждого байта, то получим 0924. Такой формат называется двоично-десятичным (BCD — Binary Coded Decimal) (или упакованным). Он содержит только десятичные цифры от 0 до 9. Длина двоично-десятичного представления в два раза меньше ASCII-представления.
Заметим, однако, что десятичное число 0924 имеет основание 10 и, будучи преобразованным в основание 16 (то есть, в шест. представление), даст шест.039C.
Можно выполнять сложение и вычитание чисел в двоично-десятичном представлении (BCD-формате).
Для этих целей
имеются две корректиpующих
u DAA (Decimal Adjustment for Addition — десятичная коррекция для сложения)
u DAS (Decimal Adjustment for Subtraction — десятичная коррекция для вычитания)
Обработка полей также осуществляется по одному байту за одно выполнение.
Преобразование ASCII-формата в двоичный формат
Выполнение арифметических операций над числами в ASCII или BCD форматах удобно лишь для коротких полей. В большинстве случаев для арифметических операций используется преобразование в двоичный формат.
Практически проще преобразование
из ASCII-формата непосредственно
1. Начинают с самого
правого байта числа в ASCII-
2. Удаляют тройки из левых шест.цифр каждого ASCII-байта.
3. Умножают ASCII-цифры на 1, 10, 100 (шест.1, A, 64) и так далее и складывают результаты.
Преобразование двоичного
ASCII-формат
Для того, чтобы напечатать или отобразить на экране арифметический pезультат, необходимо преобразовать его в ASCII-формат. Данная операция включает в себя процесс обратный предыдущему. Вместо умножения используется деление двоичного числа на 10 (шест.0A) пока результат не будет меньше 10. Остатки, которые лежат в границах от 0 до 9, образуют число в ASCII-формате.
4
Сдвиг и округление
Рассмотрим процесс округления числа до двух десятичных знаков после запятой. В случае, если число равно 12,345, то необходимо прибавить 5 к отбрасываемому разряду и сдвинуть число вправо на один десятичный разряд:
Число: 12,345 Плюс 5: +5 — Округленное число: 12,350 = 12,35
В случае, если округляемое число равно 12,3455, то необходимо прибавить 50 и сдвинуть на два десятичных разряда. Для 12,34555 необходимо прибавить 500 и сдвинуть на три десятичных разряда:
12,3455 12,34555 +50 +500 --- 12,3505 = 12,35 12,35055 = 12,35
К числу, имеющему шесть знаков после запятой, необходимо прибавить 5000 и сдвинуть на четыре десятичных разряда и так далее. Поскольку данные представляются в компьютере в двоичном виде, то 12345 выглядит как шест.3039. Прибавляя 5 к 3039, получим 303E, что соответствует числу 12350 в десятичном представлении. Пока все хорошо. Но вот сдвиг на одну двоичную цифру дает в результате шест.181F, или 1675 — то есть, сдвиг на одну двоичную цифру просто делит число пополам. Но нам необходим такой сдвиг, который эквивалентен сдвигу вправо на одну десятичную цифру. Такой сдвиг можно осуществить делением на 10 (шест.A):
Шест.303E : Шест.A = 4D3 или дес.1235
Преобразование шест.4D3 в ASCII-формат дает число 1235. Теперь oстается лишь вставить запятую в правильную позицию числа 12,35, и можно выдать на экран округленное и сдвинутое значение.
Таким образом можно округлять и сдвигать любые двоичные числа.
Для трех знаков после запятой необходимо прибавить 5 и разделить на 10, для четырех знаков после запятой: прибавить 50 и pазделить на 100. Возможно вы заметили модель: фактор округления (5, 50, 500 и так далее) всегда составляет половину фактора сдвига (10, 100, 1000 и так далее).
Конечно, десятичная запятая в двоичном числе только подpазумевается.
Отрицательные величины
Некоторые применения
программ допускают наличие
В случае, если необходимо, чтобы двоичное число было также отрицательным, то можно преобразовать, как обычно, ASCII-формат в двоичный. Будьте внимательны при использовании команд IMUL и IDIV для обработки знаковых данных. Для округления отрицательных чисел следует не прибавлять, а вычитать фактор 5.
Важно:
u ASCII-формат требует один байт на каждый символ. В случае, если поле содержит только цифры от 0 до 9, то замена старших троек в каждом байте на нули создает распакованный десятичный формат. Сжатие числа до двух цифр в байте создает упакованный десятичный формат.
u После ASCII-сложения необходимо выполнить коррекцию с помощью команды AAA; после ASCII-вычитания — коррекция с помощью команды AAS.
u Прежде чем выполнить ASCII-умножение, необходимо преобразовать множимое и множитель в «распакованный десятичный» формат, обнулив в каждом байте левые тройки. После умножения необходимо выполнить коррекцию результата с помощью команды AAM.
u Прежде чем выполнить ASCII-деление,
необходимо:
1) преобразовать делимое и делитель в
«распакованный десятичный» формат, обнулив
в каждом байте левые тройки и 2) выполнить
коррекцию делимого с помощью команды
AAD.
u Для большинства арифметических операций используйте преобразование чисел из ASCII-формата в двоичной формат. В процессе такого преобразования проверяйте на корректность ASCII-символы: они должны быть от шест.30 до шест.39, могут содержать десятичную запятую (точку) и, возможно, знак минус.
Лекция 5.
Команды обработки строк
4
Свойства операций над строками
Часто бывает необходимо переслать или сравнить поля данных, которые превышают по длине одно слово.
Например, необходимо сравнить описания или имена для того, чтобы отсортировать их в восходящей последовательности. Элементы такого формата известны как строковые данные и могут являться как символьными, так и числовыми. Для обработки строковых данных Ассемблер имеет пять команд обработки строк:
u MOVS — переслать один байт или одно слово из одной области памяти в другую;
u LODS — загрузить из памяти один байт в регистр AL или одно слово в регистр AX;
u STOS — записать содержимое регистра AL или AX в память;
u CMPS — сравнить содержимое двух областей памяти, размером в один байт или в одно слово;
u SCAS — сравнить содержимое регистра AL или AX с содержимым памяти.
Префикс REP позволяет этим командам обрабатывать строки любой длины.
Цепочечная команда может быть закодирована для повторяющейся обpаботки одного байта или одного слова за одно выполнение. Например, можно выбрать «байтовую» команду для обработки строки с нечетным числом байт или «двухбайтовую» команду для обработки четного числа байт.
Например, можно кодировать операнды для команды MOVS, но опустить их для MOVSB и MOVSW. Эти команды предполагают, что pегистры DI и SI содержат относительные адреса, указывающие на необходимые области памяти (для загрузки можно использовать команду LEA). Регистр SI обычно связан с регистром сегмента данных — DS:SI. Регистр DI всегда связан с регистром дополнительного сегмента — ES:DI. Следовательно, команды MOVS, STOS, CMPS и SCAS требуют инициализации регистра ES (обычно адресом в регистре DS).
4
REP: Префикс повторения цепочечной команды
Несмотря на то, что цепочечные команды имеют отношение к одному байту или одному слову, префикс REP обеспечивает повторение команды несколько раз. Префикс кодируется непосредственно перед цепочечной командой, например, REP MOVSB. Для использования префикса REP необходимо установить начальное значение в регистре CX. При выполнении цепочечной команды с префиксом REP происходит уменьшение на 1 значения в регистре CX до нуля.
Таким образом, можно обрабатывать строки любой длины.
Флаг направления определяет
направление повторяющейся
u для направления слева направо необходимо с помощью команды CLD установить флаг DF в 0;
u для направления справа налево необходимо с помощью команды STD установить флаг DF в 1.
В следующем примере выполняется пересылка 20 байт из STRING1 в STRING2. Предположим, что оба регистра DS и ES инициализированы адресом сегмента данных: