Вывод на экран двоичных чисел
Назад | Оглавление | Дальше Новая версия документа | Форум

Циклический сдвиг и флаг переноса
Сложение с использованием флага переноса
Организация цикла

Данная тема раскрывает секреты вывода на экран чисел в двоичном представлении. В ходе работы будет рассмотрено несколько новых понятий, инструкций и алгоритмов.


Циклический сдвиг и флаг переноса

Мы уже знаем, что при сложении некоторых чисел, в пятом разряде результата появляется единица, например: 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:

CFBL
010110111B7h
1011011106Eh
011011101DDh
110111010BAh
10111010175h
011101011EBh
111010110D6h
110101101ADh
1010110115Bh
010110111B7h
  1. Загрузите в регистр BL число B7h
  2. По адресу 100h запишите инструкцию RCL BL,1
  3. Проверьте стартовый адрес IP = 100h
  4. Выполните инструкцию 9 раз (возвращая IP = 100h)
  5. Убедитесь, что число прошло все стадии сдвига,
    и вернулось в исходное состояние.

Инструкцию 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).

Обобщив все идеи, мы получаем алгоритм вывода на экран старшего бита числа:
  1. сдвигаем число влево на один бит;
  2. преобразуем флаг переноса в код символа;
  3. выводим символ на экран.

Если этот алгоритм повторить 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, и выполняет три действия:
  1. проверяет число в регистре CX;
  2. если CX > 0, то LOOP уменьшает CX на 1 и возвращает управление на 107 адрес;
  3. если 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" не надо указывать адрес остановки.

Задачи:
  1. Измените программу так, чтобы она добавляла символ "b" в конец двоичной записи.
  2. Напишите программу для вывода на экран двоичного слова из регистра BX.

Назад | Оглавление | Дальше Новая версия документа | Форум