Основы программирования на ассемблере
 

 Содержание >>>



Тема 1: Системы счисления

Debug
Перевод шестнадцатеричных чисел в десятичную форму
Сложение и вычитание шестнадцатеричных чисел
Пятизначные шестнадцатеричные числа
Перевод десятичных чисел в шестнадцатеричную форму
Отрицательные числа
Двоичная система счисления
Дополнительный код

В повседневной деятельности мы привыкли к счету с применением цифр 1, 2, 3 и т. д. Вследствие технических особенностей, компьютер применяет другой метод счета, в котором используется всего две цифры 0 и 1. Например, до пяти компьютер считает так: 1, 10, 11, 100, 101. Числа 10, 11, 100 ... являются двоичными, они базируются на системе счисления, состоящей из двух цифр. Десятичная система состоит из десяти цифр 0 ... 9.

Одно и тоже число можно записать в разных системах счисления. Например: двоичное число 10 соответствует десятичному 2.

Компьютер может оперировать только двоичными числами. Но программисту очень неудобно использовать длинные цепочки нулей и единиц, отображающих разные числовые значения. Поэтому, для написания программ был придуман другой, более компактный способ записи чисел – шестнадцатеричная система счисления.

Изучение шестнадцатеричной системы счисления мы начнем в специальной программе - DEBUG.EXE, которая входит в состав операционной системы Windows.

Debug

Название Debug произошло от слова "Bugs" (насекомые) - так программисты именуют ошибки в программе.

Используя Debug можно проверить работу программы в пошаговом режиме. Это позволяет найти и исправить возможные ошибки. Данный процесс называется отладка "debugging", отсюда и произошло название программы.

Термин "debugging" (обезжучивание) имеет глубокие корни - он появился в тот день, когда перестал работать компьютер Гарвардского университета Марк 1. После долгих поисков техники обнаружили небольшую моль, попавшую между контактами реле. Они удалили моль и внесли запись в сменный журнал о процессе под названием "debugging", произведенном над Марком.

Наиболее удобной средой для изучения Debug является файл-менеджер FAR. Для запуска Debug необходимо в командной строке FAR-а набрать команду "debug" и нажать [Enter]:
debug <Enter>
-

Дефис означает, что Debug ждет команды. Чтобы покинуть программу наберите команду "Q" (Quit - выход) и нажмите ввод:
-q <Enter>

Для сложение и вычитание двух шестнадцатеричных чисел используем команду "H" (Hex – шестнадцатеричный), например:
-h 3 2 <Enter>
0005 0001

Debug печатает сумму 3 + 2 = 5 и разность 3 - 2 = 1. С числами от 0 до 9 Debug ведет себя как с десятичными числами. Сходство между шестнадцатеричной и десятичной системами заканчивается при получении результата больше девяти, например 9 + 1:
-h 9 1
000A 0008

A - это шестнадцатеричное число, аналог десятичного числа 10. Выполните вычисления: 9 + 2, 9 + 3, 9 + 4, 9 + 5, 9 + 6. В результате получатся остальные числа: B, C, D, E, F. Такой способ записи чисел является очень компактным и удобным с точки зрения представления информации в компьютере.

Debug работает только с шестнадцатеричными числами. Некоторые операции с такими числами могут давать не совсем обычные результаты. Например, сложите 8 + 8:
-h 8 8
0010 0000

10 - это шестнадцатеричное число, аналог десятичного числа 16. Теперь найдите разность между числами 2 и 3:
-h 2 3
0005 FFFF

Разность чисел FFFF - это шестнадцатеричное число, соответствующее единице со знаком минус "-1". Попробуйте получить -2, -3 и другие отрицательные числа.

Перевод шестнадцатеричных чисел в десятичную форму

Название "шестнадцатеричный" произошло от числа 16. Цифры 0 ... 9 одинаковы и для шестнадцатеричной, и для десятичной систем счисления. Шестнадцатеричные цифры от A до F соответствуют десятичным числам от 10 до 15. Соответствие между десятичными числами (Decimal) и шестнадцатеричными (Hexadecimal) можно представить в виде таблицы:
 
dec hex
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 A
11 B
12 C
13 D
14 E
15 F
16 10
17 11
18 12
19 13
20 14

Обычно шестнадцатеричные числа помечают специальным символом "h": 12h, F8h, 10h и др. Это позволяет избегать путаницы между десятичными и шестнадцатеричными числами, не содержащими букв: 12 - десятичное, 12h - шестнадцатеричное.

Для перевода чисел из hex- в dec- форму используется очень простой алгоритм. Например, переведем A7h в десятичную форму:
 
1 переводим обе цифры в десятичную форму
2 умножаем каждое число на коэффициент, соответствующий разряду числа (весовой коэффициент)
3 складываем полученные числа 160+7=167

 
 
 
 
 
 
 
 

Шестнадцатеричное число A7h соответствует десятичному числу 167.
Данный пример можно записать более компактно:

 

перевод числа A7h в десятичную форму

Примеры перевода чисел из одной системы счисления в другую:
 
Перевод числа 2E8h в десятичную форму:

Перевод числа AF1Ch в десятичную форму:


Весовые коэффициенты:
 
65535
4096
256
16
1

Перевод числа 3B8D2h в десятичную форму:

Переведите следующие шестнадцатеричные числа в десятичную форму:

1. A7h     4. 100h     7. 4F8Ch
2. 45h     5. 5E9h     8. 1000h
3. FFh     6. FFFh     9. FFFFh

Сложение и вычитание шестнадцатеричных чисел

Сложение и вычитание шестнадцатеричных чисел проходит аналогично действиям над десятичными числами. Приведем несколько простых примеров:
A + 1 = B     B - A = 1     F + 1 = 10     A + C = 16
B - 2 = 9     7 + 7 = E     F + F = 1E     10 - 8 = 8
Рассмотрим, как получается 1Eh в результате сложения F + F. Запишем результат операции в десятичном виде: F + F = 15 + 15 = 30.

Проверим, сколько шестнадцатеричных десятков содержится в числе 30: 30 / 16 = 1 (один десяток). Шестнадцатеричный десяток 10h соответствует десятичному числу 16. Проводим вычитание 30 - 16 и получаем остаток 14, откуда: 14 + 16 = Eh + 10h = 1Eh.
Числа с большим числом разрядов можно складывать "столбиком":

1        1      1         1111       1 1
 C      2A7      F451      BCD8      BCD8
+D     +92A     +CB03     +FAE9     +0509
19      BD1     1BF54     1B7C1      C1E1
Вычислите "столбиком" следующие примеры, а результаты проверьте в Debug:
1. 3F8h + AB9h     4. 4E5h + 4F3h     7. DF8h - AB9h
2. FF7h + 8BFh     5. FFFh + FFFh     8. FF7h - 8BFh
3. CD0h + A82h     6. FFFh + 001h     9. CD2h - A82h

Пятизначные шестнадцатеричные числа

Что произойдет, если в сложении использовать пятизначное шестнадцатеричное число? Вычислим сумму следующих чисел:
-h 5C3F0 4BC6
       ^Error
Debug сообщил об ошибке. Команда "h" не может обрабатывать числа, длина которых больше четырех разрядов. Шестнадцатеричное число, состоящее из четырех разрядов называют так: "СЛОВО" или "WORD".

Если сложить два "слова", например C000h и D000h, то вместо действительного результата 19000h получится "урезанный" до четырех разрядов результат 9000h:
-h C000 D000
9000 F000

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

Подумайте, какое значение имеет старший (пятый) разряд при сложении четырехразрядных шестнадцатеричных чисел?

Перевод десятичных чисел в шестнадцатеричную форму

Перевод десятичного числа в шестнадцатеричную форму выполняется делением исходного числа на 16. Например, переведем 300 в шестнадцатеричную форму:
_300 ?16                             То же самое можно записать иначе:
 16  _18 ?16                         300 / 16 = 18 остаток 12 ® C
_140  16  1  1                      18 / 16 = 1  остаток  2 ® 2
 128   2 ???® 2 ? 12Ch         1 / 16 = 0  остаток  1 ® 1
  12 ??????® С               ??????????????????
                                     300 = 12Ch
Примеры перевода чисел 1000 и 60000 в шестнадцатеричную форму:
60000/16 = 3750 остаток  0 ® 0     1000/16 = 62 остаток  8 ® 8
 3750/16 =  234 остаток  6 ® 6       62/16 =  3 остаток 14 ® E
  234/16 =   14 остаток 10 ® A        3/16 =  0 остаток  3 ® 3
   14/16 =    0 остаток 14 ® E     ?????????????????
???????????????????     1000 = 3E8h
60000 = EA60h
Переведите следующие числа в шестнадцатеричную форму:

945, 138, 1100, 885, 230, 256, 1024.

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

Отрицательные числа

Ранее было отмечено, что FFFFh фактически равно -1. Однако если перевести число FFFFh в десятичную форму, то получится 65535. Почему так происходит? Действительно ли FFFFh ведет себя как отрицательное число?

Пусть так, тогда если сложить FFFFh и 5, то должно получиться 4:
-h 5 FFFF
0004 0006

Похоже, Debug действительно обращается с FFFFh, как с -1. Рассмотрим механизм сложения чисел 5 и FFFFh, при суммировании "столбиком":

1111
 0005     5 + (-1) = 4
+FFFF
10004
Если игнорировать единицу в старшем разряде, то получается правильный ответ 5 + (-1) = 4. Debug сохраняет четыре младшие цифры результата. Старший (пятый) разряд запоминается в специальной ячейке памяти и называется - "ПЕРЕПОЛНЕНИЕ".
 
FFFF -1
FFFE -2
FFFD -3
FFFC -4
FFFB -5
FFFA -6
FFF9 -7
FFF8 -8
FFF7 -9
FFF6 -A
FFF5 -B
FFF4 -C
FFF3 -D
FFF2 -E
FFF1 -F
FFF0 -10

Сложение чисел, больших чем 8000h дает переполнение.
Такие числа ведут себя аналогично отрицательным числам:

1111                 1111
 0008                 FFF0
+FFFA                +8FFF
10002   8+(-6)=2     18FEF   -10h+(-7001h)= -7011h
В последнем примере установлено соответствие чисел 8FEFh и -7011h. Как проверить справедливость этого утверждения? Ранее отмечалось, что FFFFh это (-1), значит FFFEh это (-2) и т.д. В приведенной таблице представлен ряд отрицательных чисел. Если ряд продолжить, то при достижении числа 8FEFh мы увидим его отрицательный эквивалент: -7011h.

Любой язык программирования позволяет оперировать двумя типами чисел: знаковыми и беззнаковыми. Представление числа зависит от конкретной ситуации. Например: FFFAh можно рассматривать как число без знака, и как отрицательное число -6. Если в программе нужны отрицательные числа, то диапазон 0 ... FFFFh делится на две части:
[0 ... 7FFFh] - положительные числа и [8000h ... FFFFh] - отрицательные числа.

Отрицательный аналог числа 8FEFh называется его дополнительным кодом, и выражается числом -7011h. Рассмотрим алгоритм нахождения дополнительного кода:

  1. Инвертировать исходное число, т.е. заменить все цифры числа на противоположные:

  2. F ® 0, E ® 1, D ® 2, C ® 3, B ® 4 и т.д. После инверсии 8FEFh выглядит так: 7010h.
     
  3. К инверсному числу добавить единицу: 7010h + 1 = 7011h. Получилось искомое число.
Если в программе используются только положительные числа, то область числовых значений ограничивается диапазоном: 0 ... FFFFh или 0 ... 65535.

Если в вычислениях требуются отрицательные числа, то предыдущий диапазон смещается в отрицательную область: -8000h ... 7FFFh или -32768 ... 32767.

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

FF00h, AD3Fh, 9000h, EDF4h, B348h.
 
 

Двоичная система счисления

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

0 вольт соответствует цифре "0"
1 вольт соответствует цифре "1"
...
9 вольт соответствует цифре "9"

При этом вероятность возникновения ошибки (например, из-за колебаний напряжения) очень велика. Наиболее надежным способом представления чисел в электронном устройстве, является двоичная система счисления:

0...0,5 вольт соответствует цифре "0"
2,5...5 вольт соответствует цифре "1"

Такая разница между уровнями сигналов (соответствующих "0" и "1") практически исключает ошибки связанные с колебаниями напряжения и другими искажениями сигнала. Кроме того, значительно упрощается компонентная база компьютера.

Таким образом, двоичная система счисления стала единым стандартом представления чисел в любом "думающем" электронном устройстве.

Двоичная система оптимальна для разработки микропроцессорных систем, но очень неудобна для написания программ. Чтобы упростить процесс общения с микропроцессором, были разработаны программы, транслирующие шестнадцатеричные числа в двоичный код, и выполняющие обратное преобразование. Одной из таких программ является Debug.

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

Двоичные числа мы будем помечать индексом "b" (binary - двоичный), например: 10010111b.
Номера разрядов 3 2 1 0
Весовые коэффициенты
Число 1 1 0 1
Рассмотрим число 1101b. Все разряды числа характеризуются весовыми коэффициентами, которые получаются возведением основания системы счисления (два) в степень, соответствующую номеру разряда. Нумерация разрядов начинается с нуля.

Для перевода числа из двоичной системы в десятичную, необходимо выбрать весовые коэффициенты тех разрядов, где есть единица (в случае числа 1101b, это:  и ). Далее нужно сложить эти числа:  = 13.
 
1 1 0 1 0 0 1 0
= 210

Перевод числа 11010010b в десятичную форму:

Переведите следующие двоичные числа в десятичный формат:

1. 0110b     3. 0101b     5. 10111001b     7. 10101101b
2. 1011b     4. 1001b     6. 10011001b     8. 11111111b
По размеру двоичные числа делятся на следующие:
- бит                        1
- полубайт                1011
- байт               1101 0011
- слово    1001 0110 0101 1110
Графически это разделение можно показать так:
знаковый бит   бит     байт 
          ?             ?        ?                 ?
          1001 0110 1101 0111
          ?      слово      ?
bin hex dec
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 8 8
1001 9 9
1010 A 10
1011 B 11
1100 C 12
1101 D 13
1110 E 14
1111 F 15

Рассмотрим таблицу, в которой отражено соответствие двоичных, шестнадцатеричных и десятичных чисел.

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

  • двоичный полубайт 1111b = Fh
  • двоичный байт 11111111b = FFh
  • двоичное слово 1111111111111111b = FFFFh
Благодаря кратности, преобразования чисел из двоичной системы в шестнадцатеричную, выполняются очень просто. Двоичное число разбивается на декады (четырехбитные фрагметны):
1001001001011011b ® 1001.0010.0101.1011b

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

1001b =      =  9 ® 9
0010b =                 =  2 ® 2
0101b =      =  5 ® 5
1011b =   = 11 ® B
??????????????????
1001.0010.0101.1011b = 925Bh
Переведите следующие числа в шестнадцатеричную форму:
1. 1111b     4. 1110b     7. 10101001b
2. 1010b     5. 1001b     8. 10001001b
3. 1011b     6. 1101b     9. 11111111b
Арифметические действия с двоичными числами выполняются аналогично действиям с десятичными числами. Например, сложение одноразрядных двоичных чисел выглядит так:
              1
 1      0      1
+0     +1     +1
 1      1     10
Сложение четырехразрядных и восьмиразрядных двоичных чисел:
1111                       111111
 1101     13 + 3 = 16      01101110     110 + 90 = 200
+0011                     +01011010
10000                      11001000
Выполните следующие действия:
1. 0101 + 1100     3. 10100011 + 00110011
2. 1110 + 0011     4. 10110011 + 01011100
(проверку результатов выполните в шестнадцатеричной системе счисления)
 
 

Дополнительный код

0000 0000 0000 0000 0000h
... ...
0111 1111 1111 1111 7FFFh
1000 0000 0000 0000 8000h
... ...
1111 1111 1111 1111 FFFFh

Раннее отмечалось, что в некоторых случаях числа 8000h ... FFFFh ведут себя как отрицательные.
Рассмотрим числа 0 ... FFFFh в двоичной системе счисления. Данный ряд делится на две равные части. Cтарший бит, в двоичном представлении чисел, выделен жирным шрифтом. Начиная с числа 8000h, старший бит устанавливается в единицу.

Старший бит является признаком отрицательного числа. По его состоянию микропроцессор определяет знак числа. Но если в программе используются команды для чисел без знака, то микропроцессор игнорирует знаковый бит, и воспринимает диапазон [0 ... FFFFh] как ряд положительных чисел.

Числа, в которых старший бит используется для хранения знака, известны как двоичное дополнение положительных чисел или дополнительный код.

Ранее мы находили дополнительный код шестнадцатеричных чисел (вспомните инверсию шестнадцатеричного числа с добавлением единицы). Дополнительный код двоичного числа определяется аналогично. Например, найдем дополнительный код числа 1101011010001001:

1. Инвертируем число:              1101.0110.1000.1001 (D689h)
                                            ?
2. Добавляем к результату единицу: 0010.1001.0111.0110
                                  +                  1
                                   0010.1001.0111.0111 (-2977h)
Вычитание двоичных чисел, например A - B, сводится к их сложению A + (-B). При этом: A не меняется, B преобразуется в дополнительный код. Далее числа складываются. Например, надо произвести вычитание 1101b - 1010b:
  1. Преобразуем 1010 в дополнительный код: 1010 ® 0101 ® 0101 + 1 = 0110
  2. Выполняем сложение:
  3. 11
     1101     1101 + (-1010) = 0011 или 13 + (-10) = 3
    +0110
    10011     (единица в старшем разряде игнорируется)
Выполните следующие действия:
1. 1110 - 0011     3. 11110000 - 00110111
2. 1001 - 0110     4. 01110110 - 00111001
 Содержание >>>