Циклический сдвиг и флаг переноса
Сложение с использованием флага переноса
Организация цикла
Данная тема раскрывает секреты вывода на экран чисел в двоичном представлении. В ходе работы будет рассмотрено несколько новых понятий, инструкций и алгоритмов.
Циклический сдвиг и флаг переноса
Мы уже знаем, что при сложении некоторых чисел, в пятом разряде результата появляется единица, например: FFFFh + 1 = 10000h. Микропроцессор хранит эту единицу в специальной ячейке, называемой флагом переноса - CF (Carry Flag).
Посмотрим, как Debug отображает значение флага CF. По адресу 100h запишите инструкцию ADD AX,BX, и загрузите регистры AX = FFFFh, BX = 1h:
AX=FFFF BX=0001 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0ABD ES=0ABD SS=0ABD CS=0ABD IP=0100 NV UP EI PL NZ NA PO NC
0ABD:0100 01D8 ADD AX,BX
Жирным шрифтом выделены значения различных флагов микропроцессора. В этой строке нас интересует флаг NC (No Carry - нет переноса). Выполните трассировку инструкции, и вновь просмотрите регистры.
Состояние флага изменилось CY (Carry - перенос). В результате сложения чисел произошел перенос единицы в пятый разряд, при этом CF принял значение CY.
Если операция проходит без переноса в пятый разряд, то флаг переноса принимает значение NC. Например, выполните сложение 2 + 3, и убедитесь, что CF = NC.
Для вывода на экран двоичных чисел, мы используем инструкцию RCL (Rotate Carry Left), которая сдвигает число на один бит влево через флаг переноса.
В исходном состоянии BL = B7h (10110111b). На рисунке показано состояние регистра BL и флага CF после сдвига числа на один бит влево.
После прохождения флага переноса, бит возвращается в младший разряд регистра BL. Через девять циклических сдвигов число полностью вернется в регистр BL:
CF | BL |
0 | 10110111 | B7h |
1 | 01101110 | 6Eh |
0 | 11011101 | DDh |
1 | 10111010 | BAh |
1 | 01110101 | 75h |
0 | 11101011 | EBh |
1 | 11010110 | D6h |
1 | 10101101 | ADh |
1 | 01011011 | 5Bh |
0 | 10110111 | B7h |
- Загрузите в регистр BL число B7h
- По адресу 100h запишите инструкцию RCL BL,1
- Проверьте стартовый адрес IP = 100h
- Выполните инструкцию 9 раз (возвращая IP = 100h)
- Убедитесь, что число прошло все стадии сдвига,
и вернулось в исходное состояние.
Инструкцию RCL можно использовать и с другими регистрами. Например: RCL DL,1 будет сдвигать байт в регистре DL на один бит влево, через флаг переноса.
Далее мы научимся преобразовывать значение флага переноса, в символ "1" или "0" для последующей печати.
Сложение с использованием флага переноса
Для вывода символа на экран мы использовали функцию 02h прерывания INT 21h. При этом, в регистре DL мы указывали ASCII код символа. Вывод на экран двоичного числа сводится к последовательной печати символов "0" и "1". Эти символы имеют коды: "0" - 30h, "1" - 31h.
При циклическом сдвиге RCL все биты числа (от старшего до младшего) проходят через флаг переноса. Выполняя сложение CF + 30h мы получим код символа "0" или "1" (в зависимости от значения CF):
CF = 0: 30h + CF = 30h (код символа "0")
CF = 1: 30h + CF = 31h (код символа "1")
Инструкция ADC (Add with Carry) выполняет сложение двух чисел, и добавляет к сумме бит CF. Например, для суммы DL + 30h + CF, мнемокод инструкции выглядит так:
ADC DL,30 <=> DL + 30h + CF -> DL
Результат сложения попадает в регистр DL. Если до выполнения инструкции регистр DL = 0, то после суммирования в DL появится код символа "0" или "1" (30h или 31h).
Обобщив все идеи, мы получаем алгоритм вывода на экран старшего бита числа:
- сдвигаем число влево на один бит;
- преобразуем флаг переноса в код символа;
- выводим символ на экран.
Если этот алгоритм повторить 8 раз (для байта) или 16 раз (для слова), то на экране появится цепочка нулей и единиц, соответствующая двоичному представлению заданного числа.
Организация цикла
Рассмотрим программу вывода на экран старшего бита числа B7h:
0ABD:0100 B7B7 MOV BH,B7 загружаем исходное число
0ABD:0102 B402 MOV AH,02 загружаем функцию печати символа
0ABD:0104 B200 MOV DL,00 обнуляем регистр DL
0ABD:0106 D0D7 RCL BH,1 сдвигаем число на бит влево
0ABD:0108 80D230 ADC DL,30 выполняем сложение DL + 30h + CF
0ABD:010B CD21 INT 21 выводим на экран символ (код в DL)
0ABD:010D CD20 INT 20 завершаем работу
Перед сложением необходимо обнулять DL, иначе код символа будет сформирован неверно. После RCL сдвига, бит попадает в CF и добавлятеся в сумму: DL + 30h + CF. В результате сложения, регистр DL получает код символа "1" или "0".
Для вывода остальных битов числа B7h, надо повторить выделенный фрагмент еще семь раз. Организацию циклических повторов мы доверим инструкции LOOP:
0ABD:0100 B7B7
0ABD:0102 B402
0ABD:0104 B90800
0ABD:0107 B200
0ABD:0109 D0D7
0ABD:010B 80D230
0ABD:010E CD21
0ABD:0110 E2F5
0ABD:0112 CD20
|
|
MOV BH,B7
MOV AH,02
MOV CX,0008 загружаем число повторений
MOV DL,00 обнуляем регистр DL
RCL BH,1 сдвигаем число на бит влево
ADC DL,30 выполняем сложение DL + 30h + CF
INT 21 выводим на экран символ
LOOP 0107 если CX > 0, то возврат на адрес 107
INT 20
|
Инструкция LOOP работает в паре с регистром CX, и выполняет три действия:
- проверяет число в регистре CX;
- если CX > 0, то LOOP уменьшает CX на 1 и возвращает управление на 107 адрес;
- если CX = 0, то LOOP передает управление следующией инструкции (INT 20h).
Почему в качестве счетчика повторений выбран регистр CX? Буква "C" в названии регистра CX указывает на его функцию: Count (счетчик). Поэтому CX в основном используется при организации циклов.
Введите программу в память. Проверьте IP и выполните комнду "G":
-g
10110111
Program terminated normally
Испытайте программу с другим числом, для этого измените значение регистра BH:
-a 100
0ABD:0100 MOV BH,FE
0ABD:0102 <Enter>
Число FEh можно записать иначе:
-e 101
0ABD:0101 B7.EF
Проверьте действие программы со следующими числами:
AFh, 6Dh, FFh, 7Ch, 8Bh, C6h
Самостоятельно переведите эти числа из шестнадцатеричной формы в двоичную, и сравните свои результаты с результатами программы.
Основная задача Debug - это пошаговая отладка программ. Поэтому, в качестве следующего упражнения выполните трассировку программы, анализируя:
- содержимое регистров BH, DL, CX;
- состояние флага переноса CF;
- текущую мнемоническую инструкцию.
Для выполнения прерываний (INT 21h, INT 20h) используйте команду "P" (Proceed - переход). В отличие от команды "G", в команде "P" не надо указывать адрес остановки.
Задачи:
- Измените программу так, чтобы она добавляла символ "b" в конец двоичной записи.
- Напишите программу для вывода на экран двоичного слова из регистра BX.
|