Вывод на экран шестнадцатеричных чисел
Форум |
Назад | Оглавление | Дальше
Contents |
Введение
В четвертой теме мы рассмотрели алгоритм вывода на экран двоичных чисел. Потребность в двоичном числовом формате возникает крайне редко. Но метод, используемый для вывода двоичных чисел, можно использовать и с другими числовыми форматами.
Флаги нуля, знака и переполнения
В последней теме был рассмотрен флаг переноса CF. В распечатке регистров он представлен значениями NC или CY. Кроме CF листинг регистров отображает значения еще семи флагов:
NV UP EI PL NZ NA PO NC
В ближайшее время нам потребуются три флага:
ZF SF OF
Эти флаги хранят состояние, или статус последней арифметической операции.
Все флаги однобитовые, и могут находится в двух состояниях:
1 - установлен 0 - сброшен
ZF (Zero Flag) - флаг нуля.
Флаг устанавливается, если результат операции равен нулю, иначе флаг сбрасывается:
┌─> ZR (Zero) - ноль ZF │ └─> NZ (Not Zero) - не ноль 2h - 2h = 0000h (ZR) 2h + 2h = 0004h (NZ) 2h - 3h = FFFFh (NZ)
SF (Sign Flag) - флаг знака.
Флаг устанавливается, если результат операции меньше нуля, иначе флаг сбрасывается:
┌─> NG (Negative) - минус SF │ └─> PL (Plus) - плюс 0003h - 0009h = FFFAh (-6h) (NG) 0003h + 0007h = 000Ah (PL) 7000h + 2000h = 9000h (-7000h) (NG)
OF (Over Flow) - флаг переполнения.
Флаг устанавливается, если в результате операции превышена граница чисел со знаком 8000h, иначе флаг сбрасывается:
┌─> OV (Overflow) - переполнение OF │ └─> NV (Not Overflow) - нет переполнения 7000h + 2000h = 9000h (-7000h) (OV) 6000h + 1000h = 7000h (NV) 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 MOV AH,02 загружаем функцию печати символа 0ABD:0102 B22A MOV DL,2A загружаем код символа "*" 0ABD:0104 B109 MOV CL,09 устанавливаем счетчик повторений 0ABD:0106 CD21 ┌─> INT 21 печатаем символ 0ABD:0108 80E901 │ SUB CL,01 уменьшаем CL на 1 0ABD:010B 75F9 └─ JNZ 0106 если ZF = NZ, то переход на адрес 106 0ABD:010D CD20 INT 20
Программа содержит условный переход на адрес 106. Перед инструкцией JNZ выполняется уменьшение регистра CL на 1. Когда CL достигнет нуля, произойдет установка флага нуля, и инструкция JNZ передаст управление прерыванию INT 20h.
Используя трассировку программы, проанализируйте действия инструкции JNZ.
Задачи:
- В последней программе замените "*" на знак "=", и увеличьте строку до 20 символов.
- В последней программе замените инструкцию JNZ на LOOP.
- В программе вывода двоичных чисел замените LOOP на JNZ.
Вывод на экран шестнадцатеричной цифры
Символ | ASCII код |
---|---|
0 | 30h |
1 | 31h |
2 | 32h |
3 | 33h |
4 | 34h |
5 | 35h |
6 | 36h |
7 | 37h |
8 | 38h |
9 | 39h |
: | |
; | |
< | |
= | |
> | |
? | |
@ | |
A | 41h |
B | 42h |
C | 43h |
D | 44h |
E | 45h |
F | 46h |
Ранее мы рассмотрели алгоритм вывода на экран цифр 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 MOV BL,0E исходное число 0ABD:0102 B402 MOV AH,02 загружаем функцию печати символа 0ABD:0104 88DA MOV DL,BL копируем исходное число в DL 0ABD:0106 80C230 ADD DL,30 формируем код символа 0ABD:0109 80FA3A CMP DL,3A сравниваем число из DL и 3Ah 0ABD:010C 7C03 ┌─ JL 0111 если DL < 3A, то переход на адрес 111 0ABD:010E 80C207 │ ADD DL,07 корректируем код для чисел A ... F 0ABD:0111 CD21 └─> INT 21 печатаем символ 0ABD:0113 CD20 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 не принимает участия в программе, его задача - сохранить копию числа для вывода на экран младшей цифры.
Выполните программу с разными исходными числами. Убедитесь, что на экран выводится старшая цифра шестнадцатеричного числа.
Логическая операция AND
В предыдущем разделе мы освоили печать старшей цифры двузначного шестнадцатеричного числа. Остается освоить печать младшей цифры и объединить две программы в одну.
Для выделения четырех бит младшей цифры двузначного шестнадцатеричного числа, нужно обнулить четыре бита старшей цифры. Для обнуления заданной последовательности бит, мы используем инструкцию AND (логическое умножение двух чисел).
Рассмотрим все варианты логического умножения чисел 1 и 0:
0 AND 0 = 0 0 AND 1 = 0 1 AND 0 = 0 1 AND 1 = 1
Аналогично выглядит логическое умножение восьмиразрядных двоичных чисел:
10110101 10110110 AND 01110110 AND 00100101 00110100 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
Выполните программу с разными исходными числами. Убедитесь, что на экран выводится младшая цифра шестнадцатеричного числа.
Объединив два фрагмента кода, мы получим программу печати шестнадцатеричного байта:
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".
Задачи:
- Измените программу печати шестнадцатеричного байта так, чтобы в конце числа добавлялся символ "h", например: B9h
- Напишите программу печати шестнадцатеричного слова из регистра CS. Формат вывода: CS=0ABD. Запишите программу на диск.
- Напишите программу печати содержимого регистровой пары SS:SP. Формат вывода: 0ABD:FFEE. Запишите программу на диск.
Форум |
Назад | Оглавление | Дальше