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

Флаги нуля, знака и переполнения
Инструкции условных переходов
Вывод на экран шестнадцатеричной цифры
Логический сдвиг числа
Логическая операция AND

В четвертой теме мы рассмотрели алгоритм вывода на экран двоичных чисел. Потребность в двоичном числовом формате возникает крайне редко. Но метод, используемый для вывода двоичных чисел, можно использовать и с другими числовыми форматами.


Флаги нуля, знака и переполнения

В последней теме был рассмотрен флаг переноса CF. В распечатке регистров он представлен значениями NC или CY. Кроме CF листинг регистров отображает значения еще семи флагов:

NV UP EI PL NZ NA PO NC

В ближайшее время нам потребуются три флага: ZF, SF, OF. Эти флаги хранят состояние, или статус последней арифметической операции.

Все флаги однобитовые, и могут находится в двух состояниях: "1" - установлен; "0" - сброшен.

  • ZF (Zero Flag - флаг нуля): устанавливается, если результат операции равен нулю, иначе - сбрасывается.
       | ZR (Zero) - ноль		2h - 2h = 0000h (ZR)
    ZF |				2h + 2h = 0004h (NZ)
       | NZ (Not Zero) - не ноль	2h - 3h = FFFFh (NZ)
    
  • SF (Sign Flag - флаг знака): устанавливается, если результат операции меньше нуля, иначе - сбрасывается.
       | NG (Negative) - минус	0003h - 0009h = FFFAh    (-6h) (NG)
    SF |				0003h + 0007h = 000Ah          (PL)
       | PL  (Plus) - плюс		7000h + 2000h = 9000h (-7000h) (NG)
    
  • OF (Over Flow - флаг переполнения): устанавливается, если в результате операции превышена граница чисел со знаком 8000h, иначе - сбрасывается.
       | OV (Overflow)		7000h + 2000h = 9000h (-7000h) (OV)
    OF |				6000h + 1000h = 7000h          (NV)
       | NV (Not Overflow)		7000h - 8000h = F000h (-1000h) (OV)
    
Придумайте несколько примеров для установки и сброса флагов: ZF, SF, OF.


Инструкции условных переходов

Очень часто в программе требуется выполнять переход на несколько инструкций вперед или назад. Например, программа печати двоичных чисел содержит инструкцию LOOP, которая 8 раз возвращает управление на 4 шага назад. Но существуют и другие варианты переходов:

  • Инструкция JZ (Jump if Zero - перейти, если ноль) выполяет переход на заданный адрес, если результат последней арифметической операции был ноль (ZF = ZR).
  • Инструкция JNZ (Jump if Not Zero), выполняет переход на заданный адрес, если флаг нуля сброшен (ZF = NZ).

Например, используем инструкцию JNZ для вывода на экран строки из девяти звездочек:

0ABD:0100 B402      
0ABD:0102 B22A      
0ABD:0104 B109      
0ABD:0106 CD21      
0ABD:0108 80E901    
0ABD:010B 75F9      
0ABD:010D CD20      

MOV     AH,02    загружаем функцию печати символа
MOV     DL,2A    загружаем код символа "*"
MOV     CL,09    устанавливаем счетчик повторений
INT     21       печатаем символ
SUB     CL,01    уменьшаем CL на 1
JNZ     0106     если ZF = NZ, то переход на адрес 106
INT     20
Программа содержит условный переход на адрес 106. Перед инструкцией JNZ выполняется
уменьшение регистра CL на 1. Когда CL достигнет нуля, произойдет установка флага нуля, и
инструкция JNZ передаст управление прерыванию INT 20h.

Используя трассировку программы, проанализируйте действия инструкции JNZ.

Задачи:
  1. В последней программе замените "*" на знак "=", и увеличьте строку до 20 символов.
  2. В последней программе замените инструкцию JNZ на LOOP.
  3. В программе вывода двоичных чисел замените LOOP на JNZ.

Вывод на экран шестнадцатеричной цифры

СимволASCII код
030h
131h
232h
333h
434h
535h
636h
737h
838h
939h
:3Ah
;3Bh
<3Ch
=3Dh
>3Eh
?3Fh
@40h
A41h
B42h
C43h
D44h
E45h
F46h

Ранее мы рассмотрели алгоритм вывода на экран цифр 0 и 1, где код символа формировался сложением соответствующей цифры с числом 30h. Аналогичный метод можно применить для вывода на экран шестнадцатеричных чисел.

Из таблицы ASCII кодов видно, что коды символов "0" ... "9" можно получить сложением 30h с соответствующим числом:
30h + 9h = 39h (код символа "9").

Коды символов "A" ... "F" формируются аналогично,
только вместо числа 30h используется число 37h:
37h + Dh = 44h (код символа "D").

Для вывода на экран шестнадцатеричных чисел, нам потребуются две новые инструкции:

  • CMP A,B (Compare - сравнение) сравнивает числа A и B. Если A = B, то устанавливается флаг нуля (ZF = ZR).


  • JL (Jump if Less Than - перейти если меньше) проверяет результат сравнения чисел в инструкции CMP.
    Если A < B, то выполняется переход на заданный адрес.

Следующая программа выводит на экран одноразрядное шестнадцатеричное число из регистра BL:

0ABD:0100 B30E      
0ABD:0102 B402      
0ABD:0104 88DA      
0ABD:0106 80C230    
0ABD:0109 80FA3A    
0ABD:010C 7C03      
0ABD:010E 80C207    
0ABD:0111 CD21      
0ABD:0113 CD20      




MOV     BL,0E    исходное число
MOV     AH,02    загружаем функцию печати символа
MOV     DL,BL    копируем исходное число в DL
ADD     DL,30    формируем код символа
CMP     DL,3A    сравниваем число из DL и 3Ah
JL      0111     если DL < 3A, то переход на адрес 111
ADD     DL,07    корректируем код для чисел A...F
INT     21       печатаем символ
INT     20
В программе выполняется проверка кода символа:
- если код меньше чем 3Ah (диапазон символов "0" ... "9"), то переходим к печати символа;
- иначе, корректируем код (смещаемся в диапазон "A" ... "F"), и печатаем символ.

Загружая в регистр BL числа от 0 до F, выполните трассировку программы. Посмотрите, как изменяет флаги инструкция CMP. Проанализируйте действия инструкции JL.


Логический сдвиг числа

Последняя программа корректно работает с числами: 0 ... F. Например, загрузите в BL число 3Eh и выполните программу. Вместо ожидаемого результата "3E", вы получите букву "u".

Изменим программу так, чтобы она печатала любые числа от 0 до FFh. Для этого нам надо научиться выделять старшую и младшую цифры двузначного шестнадцатеричного числа.

Каждая цифра шестнадцатеричного числа занимает четыре бита. Для выделения четырех бит старшей цифры мы используем инструкцию SHR:

  • SHR (Shift Right - сдвиг вправо) логический сдвиг числа вправо, через флаг переноса. После прохождения флага переноса, биты не возвращаются в регистр, как в инструкции RCL, а безвозвратно теряются.

Например, необходимо выделить старшую цифру числа B9h:

Исходное число загружаем в регистр DL.
Все восемь бит числа сдвигаем вправо,
через флаг переноса.

Число, после сдвига на четыре бита вправо:
(в освободившиеся ячейки регистра DL загружаются нули)

Программная реализация сдвига состоит из двух строк:

MOV	CL,4     сдвиг на 4 бита
SHR	DL,CL    число в регистре DL сдвигается вправо на 4 бита

К сожалению Debug не позволяет указывать шаг сдвига непосредственно в инструкции, например: SHR DL,4 или RCL DL,4. Этот формат мы используем позже, при написании компилируемых ассемблерных программ.

Добавим логический сдвиг в программу печати шестнадцатеричной цифры:
0ABD:0100 B3B9          MOV     BL,B9    загружаем исходное число
0ABD:0102 88DA          MOV     DL,BL    копируем исходное число в DL
0ABD:0104 B402          MOV     AH,02    загружаем функцию печати символа
0ABD:0106 B104          MOV     CL,04    загружаем шаг сдвига
0ABD:0108 D2EA          SHR     DL,CL    сдвигаем число в DL на CL бит вправо
0ABD:010A 80C230        ADD     DL,30    формируем код символа
0ABD:010D 80FA3A        CMP     DL,3A    определяем диапазон символа
0ABD:0110 7C03          JL      0115     если диапазон "0"..."9", то переход
0ABD:0112 80C207        ADD     DL,07    иначе, корректируем код
0ABD:0115 CD21          INT     21       печатаем символ
0ABD:0117 CD20          INT     20

Регистр BL не принимает участия в программе, его задача - сохранить копию числа для вывода на экран младшей цифры.

Выполните программу c разными исходными числами. Убедитесь, что на экран выводится старшая цифра шестнадцатеричного числа.


Логическая операция AND

В предыдущем разделе мы освоили печать старшей цифры двузначного шестнадцатеричного числа. Остается освоить печать младшей цифры и объединить две программы в одну.

Для выделения четырех бит младшей цифры двузначного шестнадцатеричного числа, нужно обнулить четыре бита старшей цифры. Для обнуления заданной последовательности бит, мы используем инструкцию AND (логическое умножение двух чисел).

Рассмотрим все варианты логического умножения чисел 1 и 0:
0 AND 1 = 0	0 AND 0 = 0	1 AND 0 = 0	1 AND 1 = 1
Аналогично выглядит логическое умножение восьмиразрядных двоичных чисел:
    10110101		    10110110
AND 01110110		AND 00100101
    00110111		    00100100
Логическое умножение байта на маску 0Fh, позволяет обнулить старшую половину байта:
    10111001		    B9h
AND 00001111	<=>	AND 0Fh
    00001001		    09h
Используем это свойство для вывода на экран младшей цифры шестнадцатеричного числа:
0ABD:0100 B3B9          MOV     BL,B9    загружаем исходное число
0ABD:0102 88DA          MOV     DL,BL    копируем исходное число в DL
0ABD:0104 B402          MOV     AH,02    загружаем функцию печати символа
0ABD:0106 80E20F        AND     DL,0F    обнуляем старшую половину байта
0ABD:0109 80C230        ADD     DL,30    формируем код символа
0ABD:010C 80FA3A        CMP     DL,3A    определяем диапазон символа
0ABD:010F 7C03          JL      0114     если диапазон "0"..."9", то переход
0ABD:0111 80C207        ADD     DL,07    иначе, корректируем код
0ABD:0114 CD21          INT     21       печатаем символ
0ABD:0116 CD20          INT     20

Выполните программу c разными исходными числами. Убедитесь, что на экран выводится младшая цифра шестнадцатеричного числа.

Объединив два фрагмента кода, мы получим программу печати шестнадцатеричного байта:
0ABD:0100 B402          MOV     AH,02
0ABD:0102 88DA          MOV     DL,BL
0ABD:0104 B104          MOV     CL,04
0ABD:0106 D2EA          SHR     DL,CL
0ABD:0108 80C230        ADD     DL,30
0ABD:010B 80FA3A        CMP     DL,3A
0ABD:010E 7C03          JL      0113
0ABD:0110 80C207        ADD     DL,07
0ABD:0113 CD21          INT     21
0ABD:0115 88DA          MOV     DL,BL
0ABD:0117 80E20F        AND     DL,0F
0ABD:011A 80C230        ADD     DL,30
0ABD:011D 80FA3A        CMP     DL,3A
0ABD:0120 7C03          JL      0125
0ABD:0122 80C207        ADD     DL,07
0ABD:0125 CD21          INT     21
0ABD:0127 CD20          INT     20

В приведенном листинге нет загрузки исходного числа в регистр BL. Это делает программу более универсальной. Для ввода чисел в регистр используйте команду "R".

Задачи:
  1. Измените программу печати шестнадцатеричного байта так,
    чтобы в конце числа добавлялся символ "h". Например: B9h.
  2. Напишите программу печати шестнадцатеричного слова из регистра CS.
    Формат вывода: CS=0ABD. Запишите программу на диск.
  3. Напишите программу печати содержимого регистровой пары SS:SP.
    Формат вывода: 0ABD:FFEE. Запишите программу на диск.

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