12.1. Закодируйте команды для сложения а) слова DATAX со словом
DATAY; б) двойного слова, начинающегося по адресу DATAX, с двойным словом
в DATAY.
12.2. Объясните действие следующих команд:
STC
MOV BX,DATAX
ADC BX,DATAY
12.3. Закодируйте команды для умножения (MUL): а) слова DATAX на
слово DATAY; б) двойного слова , начинающегося по адресу DATAX, на слово
DATAY.
12.4. Какой делитель, кроме нуля, вызывает ошибку переполнения?
12.5. Закодируйте команды для деления (DIV): а) слова DATAX на 23; б)
двойного слова, начинающегося по адресу DATAX, на слово DATAY.
12.6. Последний пример в разделе "Сдвиг регистровой пары DX:AX"
является более эффективным по сравнению с предыдущими примерами для сдвига
влево на четыре бита. Измените пример для сдвига вправо на четыре бита.
ГЛАВА 13 Арифметические операции II:
Обработка данных в форматах ASCII и BCD
__________________________________________________________________________
Ц е л ь: Рассмотреть ASCII и BCD форматы данных и дать сведения о
преобразованиях между этими форматами и двоичным форматом.
ВВЕДЕНИЕ
________________________________________________________________
Для получения высокой производительности компьютер выполняет
aрифметические операции над числами в двоичном формате. Как показано в
гл.12, этот формат не вызывает особых трудностей, если данные определены в
самой программе. Во многих случаях новые данные вводятся программой с
клавиатуры в виде ASCII символов в деcятичном формате. Аналогично вывод
информации на экран осуществляется в кодах ASCII. Например, число 23 в
двоичном представлении выглядит как 00010111 или шест.17; в коде ASCII на
каждый cимвол требуется один байт и число 25 в ASCII-коде имеет внутpеннее
представление шест.3235.
Назначение данной главы - показать технику преобразования данных из
ASCII-формата в двоичный формат для выполнения арифметических операций и
обратного преобразования двоичных результатов в ASCII-формат для вывода на
экран или принтер. Программа, приведенная в конце главы , демонстрирует
большую часть матеpиала гл.1 - 12.
При программировании на языках высокого уровня, таких как BASIC или
Pascal, для обозначения порядка числа или положения десятичной запятой
(точки) можно положиться на компилятор. Однако, компьютер не распознает
десятичную запятую (точку) в арифметических полях. Так как двоичные числа
не имеют возможности установки десятичной (или двоичной) запятой (точки),
то именно программист должен подразумевать и определить порядок
обрабатываемых чисел.
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-формате
--------------------------
Рассмотрим процесс сложения чисел 8 и 4 в ASCII-формате:
Шест. 38
34
--
Шест. 6C
Полученная сумма неправильна ни для ASCII-формата, ни для двоичного
формата. Однако, игнорируя левую 6 и прибавив 6 к правой шест.C: шест.C +
6 = шест.12 - получим правильный результат в десятичном формате.
Правильный пример слегка упрощен, но он хорошо демонстрирует процесс,
который выполняет команда AAA при коррекции.
В качестве примера, предположим, что регистр AX содержит шест.0038, а
регистр BX - шест.0034. Числа 38 и 34 представляют два байта в
ASCII-формате, которые необходимо сложить. Сложение и коррекция кодируется
следующими командами:
ADD AL,BL ;Сложить 34 и 38
AAA ;Коррекция для сложения ASCII-кодов
Команда AAA проверяет правую шест. цифру (4 бита) в регистре AL. Если эта
цифра находится между A и F или флаг AF равен 1, то к регистру AL
прибавляется 6, а к регистру AH прибавляется 1, флаги AF и CF
устанавливаются в 1. Во всех случаях команда AAA устанавливает в 0 левую
шест. цифру в регистре AL. Результат - в регистре AX:
После команды ADD: 006C
После команды AAA: 0102
Для того, чтобы выработать окончательное ASCII-представление,
достаточно просто поставить тройки на место левых шест. цифр:
OR AX,3030H ;Результат 3132
Все показанное выше представляет сложение однобайтовых чисел.
Сложение многобайтовых ASCII-чисел требует организации цикла, который
выполняет обработку справа налево с учетом переноса. Пример , показанный
на рис.13.1 складывает два трехбайтовых ASCII-числа в четырехбайтовую
сумму. Обратите внимание на следующее:
__________________________________________________________________________
TITLE ASCADD (COM) Сложение чисел в ASCII-формате
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
; -----------------------------------------------
ASC1 DB '578' ;Элементы данных
ASC2 DB '694'
ASC3 DB '0000'
; -----------------------------------------------
MAIN PROC NEAR
CLC
LEA SI,AASC1+2 ;Адреса ASCII-чисел
LEA DI,AASC2+2
LEA BX,AASC1+3
MOV CX,03 ;Выполнить 3 цикла
A20:
MOV AH,00 ;Очистить регистр AH
MOV AL,[SI] ;Загрузить ASCII-байт
ADC AL,[DI] ;Сложение (с переносом)
AAA ;Коррекция для ASCII
MOV [BX],AL ;Сохранение суммы
DEC SI
DEC DI
DEC BX
LOOP A20 ;Циклиться 3 раза
MOV [BX],AH ;Сохранить перенос
RET
MAIN ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.13.1. Сложение в ASCII-формате.
- В программе используется команда ADC, так как любое сложение
может вызвать перенос, который должен быть прибавлен к следующему
(слева) байту. Команда CLC устанавливает флаг CF в нулевое состояние.
- Команда MOV очищает регистр AH в каждом цикле, так как команда
AAA может прибавить к нему единицу. Команда ADC учитывает пеpеносы.
Заметьте, что использование команд XOR или SUB для oчистки регистра
AH изменяет флаг CF.
- Когда завершается каждый цикл, происходит пересылка
содержимого pегистра AH (00 или 01) в левый байт суммы.
- В результате получается сумма в виде 01020702. Программа не
использует команду OR после команды AAA для занесения левой тройки,
так как при этом устанавливается флаг CF, что изменит pезультат
команды ADC. Одним из решений в данном случае является сохранение
флагового регистра с помощью команды PUSHF, выполнение команды OR, и,
затем, восстановление флагового регистра командой POPF:
ADC AL,[DI] ;Сложение с переносом
AAA ;Коррекция для ASCII
PUSHF ;Сохранение флагов
OR AL,30H ;Запись левой тройки
POPF ;Восстановление флагов
MOV [BX],AL ;Сохранение суммы
Вместо команд PUSHF и POPF можно использовать команды LAHF (Load AH
with Flags - загрузка флагов в регистр AH) и SAHF (Store AH in Flag
register - запись флагов из регистра AH во флаговый регистр). Команда LAHF
загружает в регистр AH флаги SF, ZF, AF, PF и CF; а команда SAHF
записывает содержимое регистра AH в указанные флаги. В приведенном
примере, однако, регистр AH уже используется для арифметических
переполнений. Другой способ вставки троек для получения ASCII-кодов цифр -
организовать обработку суммы командой OR в цикле.
Вычитание в 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.
В следующих двух примерах предполагается, что поле ASC1 содержит
шест.38, а поле ASC2 - шест.34:
Пример 1: AX AF
MOV AL,ASC1 ;0038
SUB AL,ASC2 ;0034 0
AAS ;0004 0
Пример 2: AX AF
MOV AL,ASC2 ;0034
SUB AL,ASC1 ;00FC 1
AAS ;FF06 1
В примере 1 команде AAS не требуется выполнять коррекцию. В примере 2, так
как правая цифра в регистре AL равна шест.C, команда AAS вычитает 6 из
регистра AL и 1 из регистра AH и устанавливает в 1 флаги AF и CF.
Результат (который должен быть равен -4) имеет шест. представление FF06,
т.е. десятичное дополнение числа -4.
Умножение в ASCII-формате
---------------------------
Команда AAM (ASCII Adjust for Multiplication - коррекция для
умножения ASCII-кодов) выполняет корректировку результата умножения
ASCII-кодов в регистре AX. Однако, шест. цифры должны быть очищены от
троек и полученные данные уже не будут являться действительными
ASCII-кодами. (В руководствах фирмы IBM для таких данных используется
термин pаспакованный десятичный формат). Например, число в ASCII-формате
31323334 имеет распакованное десятичное представление 01020304. Кроме
этого, надо помнить, что коррекция осуществляется только для одного байта
за одно выполнение, поэтому можно умножать только oдно-байтовые поля; для
более длинных полей необходима организация цикла.
Команда AAM делит содержимое регистра AL на 10 (шест.0A) и записывает
частное в регистр AH, а остаток в AL. Предположим, что в регистре AL
содержится шест.35, а в регистре CL - шест.39. Следующие команды умножают
содержимое регистра AL на содержимое CL и преобразуют результат в
ASCII-формат:
AX:
AND CL,0FH ;Преобразовать CL в 09