После общего обзора архитектур памяти я более подробно рассматривал STM8 и PIC
Теперь пришло время рассмотреть более подробно последнюю архитектуру AVR. Пожалуй, это сегодня самая популярная архитектура у любителей благодаря Arduino. Но в ее основе все таки лежат обычные микроконтроллеры, которые выпускает Atmel. Точнее выпускала, так теперь это принадлежит Microchip.
AVR устроены немного проще, чем две уже рассмотренные архитектуры. Но своих хватает и здесь. Да, AVR тоже бывают разные. Как минимум, большинство вспомнят ATtiny и ATmega. Но между ними нет столь принципиальных различий, как между PIC. Если говорить про архитектуру памяти. Поэтому я буду просто упоминать различия в ходе изложения.
Общие замечания по архитектуре AVR
В Atmel очень хотели сделать микроконтроллер достаточно универсальным и при этом простым. И это им удалось. Классическая Гарвардская архитектура сочетается с не столь строгими ограничениями в RISC подходе. Это еще не позволяет отнести микроконтроллер к CISC, но зато делает его "продвинутым RISC" (advanced RISC, как говорит сама Atmel). В общем, популярность AVR заслужена.
Здесь нет единого адресного пространства, как в STM8. И нет многоуровневого конвейера. А команды нельзя выполнять из ОЗУ. Зато здесь процессор имеет гораздо больше регистров, так что их даже можно (хоть и чрезвычайно условно, с большой натяжкой) назвать подобием кэш памяти данных. Хотя это, собственно говоря, просто расширение понятия регистр-аккумулятор.
При этом здесь нет и банков, и страниц, что сильно путают и пугают новичков в PIC. Зато есть нелогичное адресное пространство ввода-вывода. Почему не логичное скажу чуть позже. И есть "двойные стандарты" при распределении регистров внешних устройств. Но давайте со всем разбираться по порядку.
Регистры процессора AVR
Я опять не буду перечислять абсолютно все регистры, которые можно отнести к процессору. Но назову основные, которые важны для нас в контексте рассматриваемого в статье вопроса. Все регистры процессора имеют свои адреса, но говорить об этом я буду немного позже, когда доберемся до адресных пространств.
Регистр адреса команды PC
Как и во всех микроконтроллерах является указателем в адресном пространстве команд и содержит адрес команды, которая будет выбираться в следующем машинном цикле.
Регистр флагов состояния SREG
Как и следует из названия, хранит признаки состояния результата. Такие как перенос, перенос между тетрадами, признаки нулевого и отрицательного результата, переполнения. Прочие биты этого регистра будут обсуждаться в статьях посвященных системе команд и работе с прерываниями.
Указатель стека SP
Сам стек в AVR располагается в памяти данных, обычно, в самом ее конце. А регистр SP является указателем на вершину стека. Собственно говоря, регистр SP является регистровой парой SPH:SPL, причем SPH может отсутствовать в микроконтроллерах с малым объемом ОЗУ. Просто количество бит регистра SP может быть разным, в зависимости от доступного объема памяти данных.
Для работы со стеком существуют команды POP и PUSH.
Регистры общего назначения
Всего доступны 32 8-битных регистра общего назначения, с R0 по R31. Такое количество регистров общего назначения в процессоре, вместе с тем, что в командах можно указывать любой из них (а в некоторых командах сразу два) и позволило мне сказать, что это похоже на регистровый кэш, управляемый вручную. Тем более, что арифметические и логические команды работают с регистрами, а вот что бы поработать с данными из ОЗУ нужно их сначала перенести в один из регистров, а потом вернуть результат обратно в память.
Индексные регистры
Часть регистров общего назначения выполняют и специальные функции - индексных регистров. Всего есть три 16-битных индексных регистра.
Регистры R26 и R27 образуют регистровую пару R27:R26, которая соответствует паре XH:XL соответствующей индексному регистру X.
Регистры R28 и R29 образуют регистровую пару R29:R28, которая соответствует паре YH:YL соответствующей индексному регистру Y.
Регистры R30 и R31 образуют регистровую пару R31:R30, которая соответствует паре ZH:ZL соответствующей индексному регистру Z.
Таким образом, если вы используете индексные регистры для доступа к данным в ОЗУ использование соответствующих регистров общего назначения для других целей становится невозможным.
Адресное пространство ввода-вывода
В микроконтроллерах AVR есть команды IN и OUT, которые работают в адресном пространстве ввода вывода. Всего в этом пространстве может быть до 64 регистров внешних устройств.
При этом здесь же располагаются и уже упомянутые выше регистры процессора (SREG, SP). А это уже не логично. Но и это еще не все. Однако, для этого мы должны посмотреть на адресное пространство данных.
Адресное пространство данных (на самом деле объединенное)
Кроме собственно данных здесь же располагается стек, о чем я уже говорил ранее. Но кроме того, сюда же отображается и адресное пространство регистров общего назначения процессора, и адресное пространство ввода-вывода. Получается вот такая картина
Я не стал здесь показывать область стека. Она обычно располагается в самом конце памяти данных. Однако, стек можно разместить в любом месте памяти данных просто проинициализировав регистр SP соответствующим значением при запуске программы. Сам же микроконтроллер загружает в SP при старте адрес последней ячейки памяти данных.
Обратите внимание, что здесь воедино соединены сразу три сущности! Во первых, регистры общего назначения. Во вторых, адреса ввода-вывода, но со смещением 20h. В третьих, собственно память данных (включая стек) начиная с адреса 60h.
Таким образом, мы можем обратиться к любому регистру общего назначения и просто указав его номер в соответствующей команде, и по его адресу в пространстве данных (например, загрузив его адрес в индексный регистр).
Более того, есть два способа получения доступа и к регистрам оборудования. Так регистр SREG имеет адрес 3Fh в пространстве ввода-вывода. И к нему можно обратиться например так
IN R5,3F
Но одновременно, он же доступен по адресу 3Fh+20h= 5Fh. А значит, возможно и такое
CLR XH
LDI XH,$5F
LD R5,X
Или просто
LDS R5,$5F
Но и это еще не все! Микроконтроллеры получали все новые встроенные модули и адресного пространства ввода-вывода стало не хватать. Поэтому часть регистров оборудования в некоторых моделях микроконтроллеров вынесли в отдельный блок "расширения регистров ввода-вывода". И разместился этот блок с адреса 60h.
Всего может быть до 160 дополнительных регистров оборудования. И доступ к ним командами IN и OUT уже невозможен. А собственно память данных (включая стек) теперь начинается с адреса 100h.
Как определить, есть в микроконтроллере этот дополнительный блок регистров, или нет? Посмотрев в документации, это самый надежный способ. Дело в том, что название начинающееся с ATmega еще ни о чем не говорит, в данном случае. Так у ATmega32A дополнительного блока нет и данные можно размещать с адреса 60h. А вот ATmega328 или ATmega 644 такой блок имеют, а значит и данные могут размещаться только с адреса 100h.
Ничего данная организация памяти не напоминает? Нет, я не про STM8 с его единым адресным пространством и выделенным под регистры оборудования диапазоном. Я про PIC. Если убрать лишнее (по своей сути) пространство ввода-вывода, то мы получим тот же принцип размещения регистров и данных в едином пространстве!
Режимы адресации операндов в памяти данных
Я опущу описания неявной адресации, равно как и непосредственной (константа или литерал). Здесь нет никаких отличий от уже многократно рассмотренных случаев.
Регистровая прямая
Как я уже говорил, номер регистра общего назначения задается прямо в коде команды. Всего у нас 32 регистра, значит нужно 5 бит номера. При этом в некоторых командах нужно указывать два регистра. Сам принцип не будет отличаться от уже показанного на рисунке, просто добавится еще одно поле с номером регистра.
Адресация ввода-вывода
По большому счету, не отличается от прямой регистровой
Разница только в том, что теперь нужно 6 бит адреса регистра ввода-вывода. Обратите внимание, что в данном случае адреса начинаются с 0!
Прямая адресация
В данном случае в коде команды задается полный адрес в пространстве памяти данных, а сама команда становится 4-байтной
Обратите внимание, что в данном случае мы можем обратиться к любой ячейке в адресном пространстве данных, включая регистры общего назначения и регистры ввода-вывода. При обращении к регистрам ввода вывода нужно учитывать, что адресное пространство ввода-вывода размещается в адресном пространстве данным начиная с адреса 20h.
Косвенная (индексная) адресация
Здесь нам тоже все знакомо. Адрес нужной ячейки данных помещается в один из индексных регистров.
Косвенная (индексная) с автоувеличением или автоуменьшением адреса
Отличается от предыдущего случая только тем, что содержимое соответствующего индексного регистра увеличивается или уменьшается на 1. Причем уменьшение производится ДО использования, а увеличение ПОСЛЕ.
Косвенная со смещением
Обратите внимание, здесь нужно использовать индексные регистры Y или Z!
Адресация памяти команд как данных
Да, возможно выполнять чтение памяти команд как памяти данных. Для это используют специальные команды и индексный регистр Z. При этом возможен и автоинкремент. Однако, доступ к памяти команд как к данным будет рассматриваться в отдельной статье.
Адресное пространство программ
Тут все очень просто. Адресное пространство программ линейное и непрерывное. Общий объем памяти программ (и разрядность регистра PC) зависит от конкретного микроконтроллера.
В некоторых микроконтроллерах, например, в семействе ATmega в конце памяти программ располагается область загрузчика (Bootloader). В этом случае память программ делится на два блока. Первый - область приложений, или собственно прикладной программы. Второй - область загрузчика. При этом разбиением памяти программ на зоны можно, в некоторой степени, управлять.
В данной статье я не буду касаться вопросов работы с загрузчиком. Это будет темой отдельных статей. Причем я еще не решил до конца, буду ли в принципе затрагивать этот вопрос (причем это касается всех семейств микроконтроллеров, а не только AVR), так это выходит далеко за рамки "для начинающих". Возможно, будет несколько упрощенное описание и отсылка к фирменной документации. Там посмотрим.
Режимы адресации в памяти команд
В данном случае речь идет об адресации в командах передачи управления (условные и безусловные переходы, вызов подпрограмм).
Прямая и косвенная адресация в командах перехода
Это очень простые режимы адресации и я не буду приводит иллюстрации. В случае прямой адресации адрес перехода просто задается в коде команды, откуда и загружается в регистр PC. В случае косвенного перехода в PC загружается содержимое индексного регистра Z (которое может быть результатом некоторых вычислений, например).
Относительная адресация в командах перехода
Как видите, тут тоже все просто. Содержимое регистра PC увеличивается на 1 и к нему прибаляется (со знаком!) содержимое поля смещения из кода команды. Получившийся результат становится новым сожержимым PC. То есть, адресом команды, которая и будет выполняться.
Обратите внимание, что в коде команды пол смещение отводится 12 бит, но поскольку число со знаком, то оно лежит в диапазоне от +2047 до -2048.
Заключение
Вот так все довольно просто, и при этом довольно гибко, устроено в микроконтроллерах AVR. Теперь вы понимаете, почему они столь популярны и почему именно они тали основой для Arduino.
До новых встреч!