• Седьмой бит кода команды, обозначенный символом «d», определяет адресата результата операции. Например, команда addwf h’30’,w означает «сложить содержимое рабочего регистра с регистром h’30’ и поместить результат обратно в рабочий регистр», тогда как команда addwf h’30’,f означает «сложить содержимое рабочего регистра с регистром данных h’30’ и поместить результат обратно в регистр h’30’». В первом случае адресатом операции является рабочий регистр W и бит d равен 0, а во втором случае адресатом является регистр данных и бит d равен 1. Мы еще вернемся к этой команде в пятой главе. В символической записи команды символы «,w» соответствуют сброшенному биту адресата d, а символы «,f» соответствуют установленному биту d.
• Младшие семь битов (6…0) определяют адрес регистра данных. Так, в нашем примере используется регистр h’25’, поэтому в указанном поле содержится значение Ь’0100101’. Так как размер поля адреса равен семи битам, то посредством прямой адресации можно адресовать только один
Рис. 3.5.
Команды, работающие с константами, кодируются немного иначе, как показано на Рис. 3.6. В старших шести битах по-прежнему содержится код операции, а в младших восьми битах находится собственно значение константы. Результат выполнения таких команд всегда помещается в рабочий регистр, поэтому не требуется ни бит адресата, ни значение адреса в памяти данных.
Рис. 3.6.
Код операции команды из нашего примера (addlw 04) равен Ь’111110’, а константа равна Ь’00000100’. Значение константы должно лежать в диапазоне Ь’00000000’…Ь’11111111’ (h’00’…h’FF’ или, в десятичной системе, 0…255), что вполне логично, поскольку рабочий регистр, как и все внутренние регистры исполнительного блока, является восьмибитным[49].
* * *
Не только команды могут иметь мнемонические обозначения. Как мы видели, символические имена можно присваивать и ячейкам памяти данных. Так, на Рис. 3.4 идентификатор NUM_1 используется для указания содержимого регистра данных h’25’, a NUM_2 — регистра данных h’26’. Таким образом, нашу программу можно символически записать следующим образом:
NUM_2 = NUM_1 + 4;
Возвращаясь к собственно компьютеру, мы видим, что, начиная с адреса h’000’, наша программа имеет вид
00100000100101
11111000000100
00000010100110
Если только вы не киборг, то чтение такой программы — весьма сомнительное удовольствие[50].
Если мы воспользуемся шестнадцатеричной системой[51], то будет уже удобнее:
0825
ЗЕ04
00А6
но ненамного. К тому же ЦПУ все равно понимает только двоичные числа, поэтому нам в любом случае понадобится программа-транслятор для перевода шестнадцатеричных значений в двоичные, запускаемая, скажем, на персональном компьютере.
Раз уж мы все равно собираемся использовать компьютер для перевода нашей программы, называемой также
movf NUM_1,w; Копируем содержимое NUM_1 в W
addlw 4; Прибавляем к нему число 4
movwf NUM_2; Копируем NUM_1 + 4 в NUM_2
Текст после символов «;» называется
Код, записанный таким образом, представляет собой программу на языке ассемблера. Синтаксису этого языка, а также процессу преобразования написанных на нем программ в исполняемый двоичный код полностью посвящена восьмая глава книги.
При написании программ с использованием языка ассемблера необходимо помнить, что каждая инструкция программы один в один соответствует исходной машинной команде и ее двоичному коду. В главе 9 мы увидим, что в языках высокого уровня это соотношение нарушается.
* * *