4.1. Числовые системы.
Для того чтобы освоить программирование в машинных кодах (на языке Ассемблера), необходимо знать, как организовано хранение информации в ячейках памяти и в регистрах процессора.
Основной единицей информации является байт, который в свою очередь состоит из восьми битов. Бит может быть включен (равен 1) или выключен (равен 0), т.е. может принимать только два значения, а байт, соответственно, может принимать 256 (два в восьмой степени) значений и имеет диапазон от 0 до 255.
Те числа, с которыми мы имеем дело в повседневной практике, называются десятичными. Они строятся из разрядов (единицы, десятки, сотни и т.д.), каждый из которых может быть выражен степенью числа 10.
Так, 567 = 5*102 + 6*101 + 7*100
Компьютеру работать в десятичной системе очень неудобно. Поскольку информация в нем представлена электрическими зарядами и можно выделить только два устойчивых состояния (есть заряд/нет заряда), то самое удобное - это хранить числа в компьютере в двоичной системе. Например, обычное десятичное число 156 может быть записано в двоичной форме как 1001 1100B. Здесь буква B на конце означает, что число записано в двоичной (binary) системе. Преобразовать его в десятичную форму можно разложением по степеням числа 2 так, как мы это делали для числа 567 выше, раскладывая его по степеням числа 10.
10011100B = 1*27 + 0*26 + 0*25 + 1*24 + 1*23 + 1*22+ 0*21 + 0*20 = 128 + 0*64 + 0*32 + 16 + 8 + 4 +0*2 + 0*1 = 128 + 16 + 8 + 4 = 156
Вы видите очевидные недостатки двоичной формы записи. Во-первых, это очень громоздкая (длинная) запись, а потому и очень утомительная. Во-вторых, она с трудом переводится в десятичную форму. Все это вызывало бы массу ошибок, если бы программисты, разрабатывая программу, применяли бы двоичное представление целых чисел.
Гораздо удобнее в работе шестнадцатеричная система. Она имеет в качестве основания число 16, поэтому уже двумя разрядами можно выразить 256 целых чисел от 0 до 255 (т.к. 162 =256).
Поскольку для шестнадцатеричной системы не хватает арабских цифр, то для выражения шестнадцатеричных цифр 10…15 приходится прибегать к буквенным обозначениям:
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
То же самое число 156 в шестнадцатеричной форме запишется как 9CH. Здесь буква H в конце числа говорит о том, что оно записано в шестнадцатеричной (hexadecimal) системе.
9C = 9*161 + 12*160 = 144 + 12 = 156
Перед начинающим программистом встает вопрос, в какой системе работать - десятичной или шестнадцатеричной? За десятичную есть только один довод - многолетняя привычка. Шестнадцатеричная система удобна той простотой, с которой двоичная форма в нее переводится, а ведь двоичная форма отражает физическую суть операции, что делает шестнадцатеричную систему основной для программистов-профессионалов, а также для специалистов в электронике и схемотехнике. Простота перевода из двоичной системы в шестнадцатеричную и наоборот обеспечивается вследствие того, что число шестнадцать может быть выражено четвертой степенью числа два: 24 = 16. Поэтому, чтобы перевести число из двоичной формы в шестнадцатеричную, можно перевод выполнять по каждому полубайту (по каждым четырем битам отдельно):
1001 1100 B = 9C H [прим.4]
Таблица для связи между системами приведена ниже.
Выбирая, в какой системе Вам в дальнейшем работать, надо также учесть, что большинство прикладных программ, поддерживающих программирование в машинных кодах - Ассемблеров и Дизассемблеров, работают в шестнадцатеричной системе.
Связь между системами счисления.
|
DEC |
BIN |
HEX |
DEC |
BIN |
HEX |
|
0 |
0000 |
0 |
8 |
1000 |
8 |
|
1 |
0001 |
1 |
9 |
1001 |
9 |
|
2 |
0010 |
2 |
10 |
1010 |
A |
|
3 |
0011 |
3 |
11 |
1011 |
B |
|
4 |
0100 |
4 |
12 |
1100 |
C |
|
5 |
0101 |
5 |
13 |
1101 |
D |
|
6 |
0110 |
6 |
14 |
1110 |
E |
|
7 |
0111 |
7 |
15 |
1111 |
F |
4.2 Двоичная дополнительная форма записи.
Приведенная выше двоичная форма позволяет работать с целыми положительными числами от 0 до 255. Такая двоичная форма называется абсолютной, а операции с такими числами – абсолютной двоичной арифметикой. Рассмотрим, например, что происходит с содержимым аккумулятора, если его постоянно увеличивать на единицу.
|
Флаг C регистра F |
Регистр A |
HEX |
DEC |
|
0 |
0000 0000 |
00 |
0 |
|
0 |
0000 0001 |
01 |
1 |
|
… |
… |
… |
… |
|
0 |
1001 1100 |
9C |
156 |
|
… |
… |
… |
… |
|
0 |
1111 1111 |
FF |
255 |
|
1 |
0000 0000 |
00 |
0 |
и т.д.
В то же время, есть операции, в которых необходимо наличие и целых отрицательных чисел. Например, это операции перехода (аналог GO TO). Переход может быть как вперед на n шагов (n - положительное), так и назад (n - отрицательное).
Когда процессор встречает такую команду, он воспринимает следующий за кодом операции операнд n не как записанный в абсолютной двоичной форме, а как записанный в дополнительной двоичной форме. В этой форме могут записываться целые числа от 0 до 127 и от -128 до -1. Таким образом, она может служить для записи целых чисел со знаком.
Рассмотрим наш предыдущий пример с постепенным наращиванием содержимого аккумулятора, но для двоичной дополнительной арифметики.
|
Флаг C регистра F |
Регистр A |
HEX |
DEC |
|
0 |
0000 0000 |
00 |
0 |
|
0 |
0000 0001 |
01 |
1 |
|
… |
… |
… |
… |
|
0 |
0111 1111 |
7F |
127 |
|
0 |
1000 0000 |
80 |
-128 |
|
0 |
1000 0001 |
81 |
-127 |
|
… |
… |
… |
… |
|
0 |
1111 1111 |
FF |
-1 |
|
(1) |
0000 0000 |
00 |
0 |
и т.д.
Запомните простое правило двоичной дополнительной арифметики: чтобы поменять знак числа, надо все его единицы заменить нулями, а все нули - единицами и к результату прибавить 1.
+ 5 - это 0000 0101B (05H)
Тогда -5 - это 1111 1010B + 1 = 1111 1011B (FBH)
Сложение и вычитание в этой системе выполняются как обычно (поразрядно), но перенос при переполнении старшего разряда игнорируется. Так +5 + (-5) = 0.
Флаг переноса 0000 0101
регистра F +1111 1010
(1) 0000 0000
игнорируется
Ниже показаны значения каждого бита восьмиразрядного числа в абсолютной и в дополнительной двоичной форме.
|
|
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
Абсолютная двоичная форма |
128 |
64 |
32 |
16 |
8 |
4 |
2 |
1 |
|
Дополнительная двоичная форма |
-127 |
64 |
32 |
16 |
8 |
4 |
2 |
1 |
4.3 Десятичная арифметика в двоичном выражении.
Это особый вид представления целых чисел в регистрах процессора. Он называется BCD-арифметикой. BCD – binary coded decimal (двоичный код десятичных чисел).
Эта форма основана на том, что каждый разряд десятичного числа можно представить в виде четырех двоичных битов:
0 – 0000 1 – 0001 2 – 0010 3 - 0011
4 – 0100 5 – 0101 6 – 0110 7 - 0111
8 – 1000 9 – 1001
Значения от 1010 до 1111 - не используются.
Четырехбитную группу называют полубайтом и, таким образом, один байт в этой форме может содержать двухразрядное десятичное число от 0 до 99.
На рисунке показано представление в этой форме десятичного числа 74.
|
Левый полубайт |
Правый полубайт |
|
0 1 1 1 |
0 1 0 0 |
|
0+4+2+1 = 7 |
0+4+0+0 = 4 |
Как Вы видите, один полубайт в BCD-арифметике может содержать число от 0 до 9, в то время как в абсолютной двоичной арифметике - от 0 до 15. Очевидно, что BCD-арифметика является довольно расточительной, но у нее есть свои преимущества.
Для двух чисел, записанных в BCD-арифметике, обычные принципы сложения и вычитания неприменимы. Это происходит потому, что в абсолютной двоичной арифметике полубайт является заполненным, когда он равен 1111 и тогда выполняется переход старшему разряду. В BCD-арифметике полубайт заполнен, когда он равен 1001 и уже здесь выполняется переход старшему разряду.
|
Абс. двоичная арифметика |
BCD-арифметика |
|
1111 |
1001 |
|
+ 1 |
+ 1 |
|
---- |
---- |
|
1 0000 |
1 0000 |
В наборе команд процессора есть всего только три команды, которые работают с числами, представленными в этой форме, но они достаточно часто встречаются, поскольку их применение значительно упрощает преобразование чисел перед выдачей их на экран в десятичной форме.
В предыдущей главе мы рассматривали флаги регистра F процессора и указали на то, что флаги N и H программистом не используются. Они участвуют в операциях с BCD-арифметикой.
Флаг N - флаг сложения/вычитания. Он равен 1 для всех операций вычитания и равен 0 для всех операций сложения.
Флаг H - флаг полупереноса. Он включается при переполнении младшего полубайта, когда начинается заполнение старшего полубайта.



