Должен быть лучший способ!
В любом процессоре имеется одна из разновидностей косвенной адресации, при которой один или более внутренних регистров используются для хранения адреса операнда в памяти данных. Такие адресные или индексные регистры используются в качестве указателя на данные. Основное отличие от прямой адресации заключается в том, что содержимое регистра-указателя может изменяться в процессе выполнения программы. То есть искомый адрес уже не зафиксирован в виде двоичного кода в памяти программ (обычно ПЗУ), а является переменной величиной. Например, для очистки массива данных из Программы 5.1 можно использовать цикл, инкрементируя в каждом проходе цикла регистр, указывающий на очищаемый регистр.
В микроконтроллерах PIC реализован достаточно простой вариант такого типа адресации — в полном соответствии с их философией. В младшем и среднем семействах[82] имеется отдельный элемент ИЛИ-HE, который детектирует обращение по прямому 7-битному адресу Ь’0000000’ и, как показано на Рис. 5.6, просто выставляет на шину адреса памяти данных содержимое регистра h’04’, называемого индексным регистром (FSR). Это происходит, если в качестве адресата команды используется нулевой адрес, по которому располагается регистр косвенной адресации INDF. Этот регистр является виртуальным, т. е. физически не существует. Он используется исключительно для выставления содержимого регистра FSR в качестве адреса операнда. Хотя такая реализация косвенной адресации может показаться довольно ущербной, она использует очень простую дополнительную логику и не требует для работы дополнительных тактов, в отличие от альтернативных способов, реализованных в других процессорах и микроконтроллерах.
Рис. 5.6. Механизм косвенной адресации
В качестве простого примера предположим, что содержимое регистра FSR равно h’86’.Тогда команда clrf 0 (или clrf INDF) очистит регистр, расположенный по адресу h’86’, а не по адресу h’00’! Разумеется, содержимое регистра FSR можно изменить в любой момент времени, например, его можно инкрементировать в каждом проходе цикла, как в Программе 5.2.
Давайте в качестве примера перепишем Программу 5.1, заменив линейную структуру циклом, как показано на Рис. 5.7.
Рис. 5.7. Использование цикла для очистки массива данных
Теперь наша программа будет работать по следующему алгоритму, представляющему собой перечень задач:
1. Установить указатель FSR на начало массива.
2. Очистить адресуемый регистр данных, указав в качестве адресата регистр данных h’00’.
3. Инкрементировать указатель FSR.
4. Проверить, не достигли указатель конца массива, в нашем случае — адреса h’80’. Если нет, то перейти к пункту 2.
5. Продолжить выполнение программы.
Визуально этот процесс представлен на Рис. 5.8.
Рис. 5.8. Проход массива
Код, соответствующий этому алгоритму, приведен в Программе 5.2. Линейная структура предыдущей программы была преобразована в цикл, тело которого выделено серым цветом. Очистку регистров по-прежнему выполняет команда clrf, которая «проходит» по массиву, начинающемуся с адреса h’20’. При каждом проходе цикла указатель в регистре данных h’04’ инкрементируется. В конце концов содержимое регистра FSR выйдет за границу заданного диапазона, в результате чего программа выйдет из цикла и продолжит выполнение следующей секции кода.
Программа 5.2. Очистка группы регистров с использованием косвенной адресации
В Программе 5.2 имеется много других особенностей, так что нам еще придется вернуться к рассмотрению набора команд.
Задача 1
Регистр FSR инициализируется адресом первого очищаемого регистра данных путем записи константы h’20’ в рабочий регистр W (movlw h’20’) с последующим копированием W в регистр h’04’ (movwf FSR). Как видно, в наборе команд отсутствует отдельная команда непосредственного копирования константы в регистр данных. Практически все циклы требуют инициализации перед входом в них.
Задача 2
Основная команда очистки регистра использует косвенную адресацию, указывая в качестве адресата фантомный регистр h’00’ (INDF) — clrf INDF. Эта строка помечена меткой СLOOP. Ассемблер понимает, что это именно метка, а не команда, поскольку она начинается с самой левой позиции строки исходного файла. Строки без меток должны начинаться с отступа хотя бы в один пробел.
82
В старшем семействе косвенная адресация реализована похожим образом, просто там имеется несколько регистров-указателей и вариантов их использования.