Организация памяти 8 битных микроконтроллеров
Microchip PIC

21.02.2019

8-битные микроконтроллеры Microchip PIC построены по Гарвардской архитектуре, поэтому имеют разные адресные пространства памяти программ и данных. Кроме того, многие модели имеют EEPROM или HEF для хранения энергонезависимых данных. Я соберу воедино разбросанную по различным документам информацию и представлю общую картину организации памяти и работы с ней для семейств 8-битных микроконтроллеров. При этом я не буду рассматривать случаи работы с памятью как с внешним, по отношению к процессору микроконтроллера, устройством.

Память программ

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

Для микроконтроллеров базового (BaseLine), среднего (Mid-range) и улучшенного среднего (Enhanced Mid-range) семейств память программ организована в виде последовательности слов из 12 (для BaseLine), или 14 (для остальных семейств) разрядов. Счетчик команд (PC - Program Counter) адресует слова и увеличивается на единицу после выборки очередной команды.

Для семейства PIC18 память программ организована в виде последовательности байт. Счетчик команд адресует байты и увеличивается на два или четыре после выборки очередной команды. Обратите внимание на это важное отличие для PIC18.

Счетчик команд, регистр PC, имеет разную разрядность для разных семейств. Более того, даже в пределах одного семейства его разрядность может быть разной для разных моделей микроконтроллеров. Для BaseLine, обычно, счетчик команд 10-разрядный, однако для PIC10F200 он 9-разрядный, а для PIC16F570 11 разрядный. Максимально он может быть 12-разрядным (это уже для Enhanced BaseLine, если так можно назвать). Для Mid-range счетчик команд 13-разрядный, а для Enhanced Mid-range 15-разрядный. Семейство PIC18 обзавелось 21-разрядным счетчиком команд.

Регистр PC напрямую программно не доступен. Младшие 8 разрядов PC, с 7 по 0, хранятся в регистре PCL, доступном программно. И это верно для всех описываемых здесь семейств. А вот выходящие за пределы байта разряды счетчиков команд хранятся и используются немого по разному.

Для BaseLine 8 разряд регистра PC программно не доступен и может быть задан только в коде инструкции GOTO (инструкция перехода). Обратите внимание,что инструкция CALL (вызов подпрограммы) может задать только 8 разрядов адреса, а не 9, как GOTO! При выполнении инструкции CALL, или любой другой инструкции которая изменяет регистр PCL напрямую, 8 разряд регистра PC сбрасывается в ноль. Остальные разряды счетчика команд, для тех микроконтроллеров, где регистр PC имеет более 9 разрядов, хранятся в старших трех разрядах (7-5) регистра STATUS и называются битами выбора страницы памяти программ (PA2-PA0). Таким образом, размер страницы памяти программ для BaseLine составляет 512 слов. Обратите внимание, что не обязательно все три старших разряда регистра STATUS заняты битами выбора страницы! Так для PIC12F510 для выбора страницы используется только бит 5 (PA0) регистра STATUS, а остальные два старших бита имеют совершенного другое назначение. Таким образом, получаем следующую схему организации памяти программ для BaseLine

Для Mid-range старшие 8 разрядов счетчика команд хранятся в регистре PCH, который программно не доступен. Изменение PCH производится через регистр PCLATH, доступный программно. При выполнении инструкций напрямую изменяющих PCL содержимое 5 младших разрядов PCLATH копируется в PCH. При выполнении инструкций GOTO и CALL младшие 11 разрядов (10-0) регистра PC загружаются из кода команды, а два старших (12,11) копируются из разрядов 4 и 3 PCLATH. Так как в коде команд перехода хранятся 11 разрядов адреса, размер страницы для Mid-range составляет 2К слов. В результате, получаем такую схему организации памяти программ для Mid-range

Для Enhanced Mid-range организация памяти программ похожа на Mid-range с той лишь разницей, что в регистре PCH используются не 5, а 7 разрядов, так как счетчик команд стал 15-разрядным. Кроме того, добавились три команды, две условного перехода (BRA и BRW) и одна вызова подпрограммы (CALLW). Поскольку схема становится слишком громоздкой, я разобью ее на несколько логических частей. Сначала общий вид со схемой адресации памяти программ счетчиком команд

А теперь с различными вариантами формирования содержимого PCL и PCH

Для PIC18 память программ не имеет деления на страницы, поэтому все проще. 21-разрядный счетчик команд позволяет напрямую адресовать всю доступную память. Каждая команда занимает 2 байта или 4 (MOVFF, CALL, GOTO, LFSR). Что бы избежать ошибки выравнивания (нечетный адрес команды) младший разряд счетчика команд, нулевой разряд PCL, всегда равен 0. Как я уже говорил, счетчик команд адресует байты, а не слова, и после выборки очередной команды увеличивается на 2, или 4, в зависимости от длины команды в байтах. Счетчик команд PIC18 занимает три регистра. Как и всегда, младшие 8 разрядов (7-0) хранятся в программно доступном регистре PCL. Следующие 8 разрядов (15-8) в регистре PCH, который программно не доступен. Старшие 5 разрядов (20-16) хранятся в регистре PCU, так же недоступном программно. Доступ к PCH и PCU осуществляется через программно доступные регистры PCLATH и PCLATU. При выполнении команды изменяющей PCL содержимое PCLATH и PCLATU копируется в PCH и PCU, соответственно. В отличии от Mid-range и Enhanced Mid-range, где было невозможно прочитать PCH, в PIC18 содержимое PCH и PCU копируется в PCLATH и PCLATU при чтении PCL. Таким образом, программа может получить текущее значение счетчика команд. Инструкции GOTO, CALL, RCALL формируют значение счетчика команд напрямую, поэтому PCLATH и PCLATU не используются. Таким образом, PIC18 использует простую линейную организацию памяти программ. По этой причине нет необходимости приводить графическую иллюстрацию.

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

Стек

В процессорах стек используется для хранения адресов возврата из подпрограмм и прерываний, а так же, для передачи параметров в подпрограммы и возвращаемых значений. Кроме того, стек может использоваться для временного размещения любой необходимой информации. Однако, в Microchip PIC нет полноценного стека. Стек имеет фиксированный размер, в зависимости от семейства, и располагается вне адресного пространства памяти программ и памяти данных.

Микроконтроллеры BaseLine имеют стек глубиной два 12-разрядных слова, не доступный программно, для хранения адресов возврата из подпрограмм. Адрес возврата заносится в стек при выполнении инструкции CALL и извлекается оттуда инструкцией RETLW. Таким образом, глубина вложенных вызовов подпрограмм равна двум. Прерывания в этих микроконтроллерах не реализованы. Некоторые микроконтроллеры, которые можно назвать Enhanced BaseLine, например, PIC16F570 имеют стек глубиной четыре 12-разрядных слова и могут обслуживать прерывания. Адрес возврата из прерывания помещается в стек при возникновении прерывания, а извлекается инструкцией RETFIE. Других отличий нет.

Микроконтроллеры Mid-range отличаются от BaseLine только увеличенной до 8 уровней глубиной стека и длиной хранимого слова 14 разрядов. Кроме того, извлекать адрес возврата из стека может дополнительная инструкция RETURN. Каких либо иных отличий от BaseLine нет.

Микроконтроллеры Enhanced Mid-range получили стек глубиной 16 уровней хранящий 15-разрядные адреса возвратов из подпрограмм и прерываний. Однако, этот стек уже доступен программно. Указатель текущей позиции в стеке хранится в младших 4 разрядах регистра STKPTR, а содержимое указываемого им слова в регистрах TOSL и TOSH. Причем в TOSH используются только младшие 7 бит. Все три регистра доступны для чтения и записи, что позволяет программе использовать стек для хранения своих данных. Специальных инструкция POP и PUSH нет, необходимо вручную изменять регистр STKPTR. Внимание, при доступе к стеку нужно исключить возможность возникновения прерываний, а лучше, запрещать их.

Можно еще отметить своеобразный одноуровневый стек для сохранения регистров STATUS, WREG,BSR, PCLATH, FSR0L, FSR0H, FSR1L и FSR1H. Причем эти сохраненные копии доступны программно, так, например, регистру FSR0L соответствует сохраненная копия FSR0L_SHAD. Поскольку прерывания не могут быть вложенными такого одноуровневого хранилища достаточно.

Микроконтроллеры PIC18 имеют схожую с Enhanced Mid-range организацию работы со стеком. Только глубина стека увеличилась до 31 слова из 21 разряда. Указатель стека занимает 5 младших разрядов регистра STKPTR, там же расположились признаки переполнения и исчерпания стека. Добавился регистр TOSU, по аналогии с PCHATHU. Появились команды POP и PUSH, которые просто передвигают STKPTR. Внимание, при доступе к стеку нужно исключить возможность возникновения прерываний, а лучше, запрещать их. На рисунке ниже не показаны два бита состояния стека в регистре STKPTR.

Так же, имеется одноуровневый стек для сохранения регистров при возникновении прерывания. Однако, сохраняются только регистры STATUS, WREG и BSR. Причем сохраненные копии программно не доступны. Зато появилась возможность использовать это хранилище при вызове подпрограмм и возврате из подпрограмм. Для этого нужно добавить параметр FAST в инструкции вызова и возврата. Обратите внимание, что можно сохранить только одну копию регистров! Причем, если произойдет прерывание между вызовом и возвратом, то содержимое регистров будет утеряно!

Память данных

Память данных в 8-разрядных микроконтроллерах Microchip PIC отделена от памяти программ и передача управления по ее адресам не возможна. Память данных представлена регистровым файлом и разделена на банки, даже для PIC18. При этом для Enhanced Mid-range и PIC18 возможен линейный, без деления на банки, доступ к памяти данных и, даже, памяти программ. Каждый банк памяти может содержать регистры специальных функций (SFR), которые используются для управления микроконтроллером, и регистры общего применения (GPR), которые используются для хранения данных. Несколько SFR иногда выделяются в отдельную группу Core Registers, которая может быть доступна через любой банк памяти данных. Это позволяет получать доступ к регистрам влияющим на базовую функциональность не обращая внимания на выбранный банк памяти. Регистры общего применения могут быть разделенными между несколькими, или всеми, банками памяти. Это позволяет ускорить доступ к наиболее часто используемым переменным. Но большей частью они ограничены тем банком, в котором расположены. Набор SFR и их расположение в банках памяти, наличие и организация разделяемых GPR, сильно зависят от конкретной модели микроконтроллера. Поэтому я смогу дать лишь общее представление о том, как все устроено. За подробностями придется обращаться к документации на конкретный микроконтроллер. Адресация памяти может быть прямой, косвенной, индексной. PIC18 имеет дополнительные режимы адресации. Вообще говоря, организация памяти данных несколько запутана, особенно, для PIC18. Для большей наглядности я разделю описание на отдельные подразделы.

Память данных BaseLine

В самых простых микроконтроллерах и память данных организована довольно просто. Ниже я привел вырезки из документации на два микроконтроллера базового семейства. PIC10F202 имеет всего один банк памяти данных, а PIC12F510 два банка. Причем на его примере я и покажу разницу между банковой памятью (banked) и разделяемой.

Обратите внимание, банки памяти имеют размер 32 байта. Регистры специальных функций (SFR) имеют свои имена. Так TMR0 - регистр данных счетчика таймера 0. Часть регистров нам знакома, это STATUS и PCL. Регистры общего назначения, для PIC10F202, начинаются с адреса 08h и всего их 24. А вот с PIC12F510 уже интереснее. Обратите внимание, что часть адресов банка 1 отображается на адреса банка 0. Это означает, что регистр STATUS, например, доступен и по адресу 03h, и по адресу 23h. То есть, для PIC12F510 мы можем не обращать внимания на выбранный банк памяти для доступа к SFR. Еще раз повторюсь, каждый микроконтроллер имеет свой набор SFR. Причем совершенно не обязательно их адреса будут независимы от банка памяти.

Теперь внимательно посмотрим на область с адреса с 0Ah по 0Fh. Это регистры общего назначения (GPR). Но у них есть интересная особенность, к ним можно получить доступ и через адреса с 2Ah по 2Fh. Это та самая область разделяемых GPR. Всего таких GPR 6 штук, для данного микроконтроллера. А вот GPR с адреса 10h по 1Fh и с адреса 30h по 3Fh образуют две независимых группы адресуемых только по своему адресу. Это банковая память. Всего таких GPR 32 штуки (две группы по 16 штук). Таким образом, мы имеем всего 38 регистров общего назначения для PIC12F510. Причем 6 из них можно адресовать не обращая внимания на выбранный банк памяти. Количество банков памяти данных зависит от конкретной модели микроконтроллера.

Я несколько раз упоминал про выбранный банк памяти, но не объяснил, что это такое. Выбор банка памяти зависит от способа адресации данных. Поэтому сначала разберемся с этим вопросом. Самый простой случай - данные находятся в самой команде. В таком случае говорят от литерале, или константе. Имена инструкций работающих с литералами включают в себя букву L. Например, инструкция MOVLW  0x10, загрузит в регистр WREG константу 10h.

При прямой адресации адрес данных, а не данные, находится в самой команде. Напрмиер, инструкция CLRF  GPIO обнулит регистр данных порта GPIO. При этом в коде команды есть место только для 5 разрядов адреса данных. Получается, мы ограничены банком 0. Значит, где то нужно указывать номер банка памяти. Для BaseLine это делается через регистр FSR. Вообще говоря, этот регистр предназначен для задания адреса данных для косвенной, точнее, индексной адресации. Но в данном случае разработчик решил, что и управление банками будет осуществляться этим регистром.

Отмечу, что не обязательно все три старших бита FSR отвечают за выбор банка памяти. У PIC10F202 выбора банка нет вообще. У PIC12F510 используется только бит 5, так как всего два банка памяти. У PIC12F506 используются биты 6 и 5, так как есть 4 банка памяти.

У PIC16F570, который хоть и BaseLine, но Enhanced, для выбора банка памяти при прямой адресации вместо регистра FSR используется регистр BSR. А FSR используется только для косвенной адресации, как и положено. Отдельную иллюстрацию делать не буду, так как достаточно заменить FSR на BSR и учесть, что номер банка хранится не в трех старших, а в трех младших разрядах этого регистра.

При косвенной адресации в коде команды задается специальный адрес, регистр INDF. А если быть точнее, то просто нулевой адрес, так как INDF физически не существует. При этом адрес памяти берется из того самого регистра FSR.

Эта иллюстрация верна и для PIC16F570. Если посмотреть внимательнее, то будет видно, что FSR, фактически, просто содержит полный адрес нужной ячейки в памяти данных, включая разряды выбора банка. А в PIC12F510 просто не стали вводить дополнительный регистр выбора банка, что привело к тому, что банк выбирается одновременно и для прямой, и для косвенной адресации. Тогда как в PIC16F570 банки можно выбрать раздельно, что бывает полезно.

Память данных Mid-range

В среднем семействе память данных организована почти так же, как в базовом. Отличий не так много. Длина банка памяти 128 байт, а не 32, как у базового семейства. Это связано с увеличением размера поля адреса данных в инструкциях до 7 разрядов. В качестве примера приведу вырезку из документации на PIC16F628A, довольно популярный микроконтроллер.

Обратите внимание на PCL, STATUS, FSR, PCLATH и INTCON. Они доступны независимо от выбранного банка. Не буду останавливаться на SFR, их состав и расположение сильно зависят от модели микроконтроллера. А вот про GPR поговорим подробнее. Обратите внимание, что разделяемая область занимает 16 байт в конце каждого банка. Есть три блока банковой памяти, два по 80 байт и один 48 байт. Получаем, что всего доступно 224 байта, или регистра. А вот пример посложнее

Это PIC16F72. Я не стал показывать области SFR, там нет ничего интересного. Давайте разберемся с GPR. Здесь у нас есть несколько блоков разделяемой памяти. Первый блок это последние 64 байта каждого банка. Такую память еще называют внебанковой. Второй блок это адреса с 020h по 03Fh и с 120h по 13Fh, всего 32 байта в банках 0 и 2. Обратите внимание, что на рисунке показано два блока по 96 байт в нулевом и втором банках, но 64 байта из них на самом деле являются внебанковой памятью и в данном случае мы не должны их учитывать. Третий блок это адреса с 0A0h по 0BFh и с 1A0h по 1BFh, всего 32 байта в банках 1 и 3. Всего получаем 128 байт памяти данных собранных в три блока.

Теперь посмотрим, как осуществляется доступ к памяти данных при прямой адресации

Разряды выбора банка памяти находятся в регистре STATUS (6, 5) и называются RP1 и RP0, а адрес внутри банка берется из кода команды и имеет длину 7 разрядов. А вот случай косвенной адресации несколько сложнее.

Точно так же, как у BaseLine, для использования косвенной адресации в команде указывают регистр INDF (я не стал это показывать), а сам адрес данных помещают в регистр FSR. А вот разряды выбора банка располагаются не в одном, а сразу в двух регистрах. Младший разряд номера банка располагается в старшем бите регистра FSR, а старший разряд в старшем бите регистра STATUS и называется IRP.

Память данных Enhanced Mid-range

В этом семействе сама память данных организована так же, как в Mid-range, только банков памяти может быть до 32. Первые 12 байт каждого банка занимают "основные SFR" (Core Registers), если помните, я уже говорил об этом. В данном случае в эту группу входят INDF0, INDF1, PCL, STATUS, FSR0L, FSR0H, FSR1L, FSR1H, BSR, WREG, PCLATH и INTCON. К этим регистрам можно обращаться не обращая внимания на выбор банка памяти. Следующие 20 байт каждого банка занимают SFR не относящиеся к Core Registers. Их набор и расположение зависят от модели микроконтроллера, поэтому я не буду останавливаться на их описании. Далее идут до 80 регистров общего назначения (GPR). И последние 16 байт занимает разделяемая память к которой можно обращаться не обращая внимания на выбор банка. То есть, в данном семействе формат всех банков памяти данных одинаков.

Каких либо других особенностей нет. Поэтому сразу перейдем к организации доступа к памяти, тут много интересного. Нужно отметить, что тут уже не один регистр INDF, а два, INDF0 и INDF1. Соответственно, есть и два регистра FSR (точнее, две пары, но об этом позже), FSR0 и FSR1. Сначала прямая адресация

В общем и целом, похоже на Mid-range, только разряды выбора банка памяти находятся в регистре BSR, пять младших разрядов. Косвенная адресация стала несколько логичнее

Посмотрите, схема формирования адреса данных очень похожа на формирование адреса команды. Только вместо PCL и PCH используются FSRL и FSRH. На самом деле, есть регистры FSR0H, FSR0L, FSR1H и FSR1L, но на иллюстрации я, для упрощения, не стал это показывать. Обратите внимание, что регистровая пара FSRH:FSRL фактически задает полный адрес байта! А это дает нам линейное адресное пространство данных. Только мешают находящиеся там SFR. Обойти это ограничение позволяет область (регион) линейного доступа. Эта виртуальная область находится с адреса 2000h по 29AFh. Фактически, это просто область трансляции адресов. Выглядит это так, вырезка из документации на PIC16F18323

То есть, в эту виртуальную линейную область памяти данных последовательно собраны все блоки GPR (по 80 байт) из всех банков, кроме последнего. В этой области нет регистров специальных функций и областей разделяемой памяти. Просто линейное пространство ОЗУ начинающееся с адреса 2000h (0x2000). Это очень удобно, так как снимает все ограничения деления памяти на банки. Безусловно, линейная область не добавит физической памяти. Если в выбранном микроконтроллере памяти меньше, чем может адресовать область линейного доступа, то часть адресов окажется незадействованной.

Линейную память можно использовать только при косвенной адресации. При этом доступ к банкам памяти сохраняется. На самом деле, в этом семействе есть не только линейная область доступа к памяти данных. Так память программ отображается начиная с адреса 8000h и может быть прочитана с помощью косвенной адресации. Но прочитаны могут быть только младшие 8 разрядов слова команды. EEPROM, если есть, отображается начиная с адреса F000h и тоже может быть прочитана с помощью косвенной адресации. Запись в память программ и EEPROM таким способом не возможна. Вот как выглядит полное адресное пространство данных микроконтроллера при доступе с использованием косвенной адресации

Нужно отметить, что область EEPROM часто не изображают в описании полного адресного пространства,показывая нижнюю границу памяти программ FFFFh. Однако, в описании работы с EEPROM через косвенную адресацию называют показанный мной на иллюстрации диапазон адресов.

Говоря о косвенной адресации нельзя не упомянуть инструкции MOVIW и MOVWI. Эти инструкции используют косвенную адресацию для сохранения в памяти содержимого WREG, или для чтения содержимого памяти в WREG. Но они позволяют задать дополнительный параметр, который определяет операцию с FSR. Это может быть преинкремент, предекремент, постинкремент и постдекремент. В семействе PIC18 эта возможность реализована специальными регистрами, задаваемыми вместо INDF.

Память данных PIC18

Мы добрались до самого сложного семейства 8-битных микроконтроллеров Microchip PIC. Организация памяти данных и доступ к ней, так же, довольно сложные. Особенно с учетом того, что картина меняется при использовании расширенного набора инструкций (бит конфигурации XINST=1). В PIC18 память данных разбита на 16 банков по 256 байт. Полный адрес байта памяти данных 12-битный. SFR, в отличии от уже описанных семейств, располагаются в самом конце адресуемой памяти. То есть, начиная с адреса FFFh в сторону уменьшения адресов. Так для PIC18F14K50 SFR будут занимать адреса с FFFh по F53h, а для PIC18F46K22 c FFFh по F38h. Остальное пространство занимают регистры общего назначения.

Кроме того, выделяется специальный виртуальный банк - Access Bank, или Access RAM. На его первые 96 байт отображаются первые 96 байт нулевого банка памяти, а на последние 160 байт - последние 160 байт последнего банка.

В коде некоторых инструкций работающих с памятью данных добавлен специальный разряд определяющий, нужно ли использовать выбор банка для доступа к данным. Если этот разряд нулевой, то выбор банка памяти игнорируется и используется Access Bank. Если этот разряд единица, то используется обычный способ выбора банка. Нетрудно заметить, что фактически это способ выделить блок разделяемой, внебанковой, памяти данных длиной, минимум, 96 байт. Вторая часть Access Bank, начиная с адреса 60h, большей частью, состоит из регистров специальных функций. Это удобно, так работа с ними не потребует переключения банков памяти. Стоит заметить, что в Access Bank попадут не все SFR, а только те, адрес которых не меньше F60h. Так для PIC18F14K50, там не будет 13 регистров, а для PIC18F46K22 уже 40.

Теперь немного усложним ситуацию и включим использование расширенного набора инструкций (XINST=1). При этом ситуация с Access Bank несколько изменится.

Теперь адрес начала отображаемой в начало Access Bank памяти будет определяться регистром FSR2, точнее, парой FSR2H:FSR2L. Но длина этого блока останется равной 96 байтам. Например, если FSR2=120h, то диапазону адресов с 00h по 5Fh Access Bank будет соответствовать диапазон адресов памяти данных с 120h по 17Fh. Отображение адресов с 60h по FFh не изменится. Другими словами, мы получаем возможность перемещать по памяти данных окно отображаемых в Access Bank регистров общего применения.

Пора переходить к организации доступа к памяти данных. По традиции, начинаем с прямой адресации.

Видно, что доступ к памяти очень похож на Enhanced Mid-range, только в коде инструкции хранится 8 разрядов адреса. Важно отметить, что существует инструкция MOVFF, которая позволяет задать полные 12-разрядные адреса источника и приемника. Она занимает 4 байта в памяти программ и использует прямую адресацию, но не использует регистр BSR для выбора банка (за ненадобностью). Косвенная адресация похожа на Enhanced Mid-range и нам уже знакома

В данном случае показан доступ к памяти данных с использованием регистра INDF1 в команде. Эту картинку можно интерпретировать и по другому, что регистровая пара FSR1H:FSR1L, в данном случае, задает полный адрес памяти. И так будет правильнее. Просто я показал преемственность косвенной адресации Enhanced Mid-range и PIC18. Обратите внимание, что в этом случае мы, фактически, имеем дело с линейным адресным пространством, но без необходимости дополнительных отображений.

Однако, на этом косвенная адресация не заканчивается. В дополнение к регистрам FSR и INDF существуют виртуальные регистры POSTDEC, POSTINC, PREINC и PLUSW. Так регистр POSTDEC0 дополняет FSR0 и INDF0. Эти дополнительные регистры указывают вместо INDF в командах использующих косвенную адресацию. Вот как это работает

POSTDEC  -  Регистр FSR используется для доступа к памяти, после чего его содержимое уменьшается на 1.
POSTINC  -  Регистр FSR используется для доступа к памяти, после чего его содержимое увеличивается на 1.
PREINC  -  Содержимое регистра FSR увеличивается на 1, после чего он используется для доступа к памяти.
PLUSW  -  К содержимому регистра FSR прибавляется содержимое WREG со знаком, получившееся значение используется для доступа к памяти.

Обратите внимание, что использование PLUSW не приводит к изменению ни WREG, ни соответствующего FSR. Содержимое WREG, фактически, используется как смещение к FSR, что добавляет дополнительный уровень в режим адресации. Она становится косвенной со смещением. Использование POSTDEC, POSTINC и PREINC изменяет содержимое соответствующего FSR, что нужно учитывать. Не смотря на то, что эти дополнительные регистры виртуальные и 8-разрядные, внутри регистровой пары FSRH:FSRL, соответствующей регистру FSR, выполняются переносы и заемы между половинами. То есть, изменяются и FSRL и FSRH. Я не буду приводить иллюстрацию, так как отличие от обычной косвенной адресации лишь в указании одного из дополнительных регистров вместо INDF и дополнительной операции с FSR.

Но и это еще не все. Есть еще один режим адресации, который в Microchip назвали индексной со смещением. Внешне это выглядит как прямая адресация с некоторыми ограничениями. А вот по сути... Давайте вспомним, что при прямой адресации номер банка памяти задается регистром BSR, что можно рассматривать как способ задать базовый адрес, при этом смещение относительно этой базы будет в коде команды. Но регистр BSR позволяет в качестве базы задать лишь адрес равный адресу начала банка. Если мы используем Access Bank, то базовый адрес задать нельзя. Однако, при включенном расширенном наборе инструкций базовый адрес для Access Bank задается регистром FSR2. Причем этим базовым адресом может быть любой адрес. Если мы сейчас обратимся к Access Bank по адресу от 00h до 5Fh, то наш запрос будет переадресован по адресу FSR2 плюс смещение из кода команды. То есть у нас появилась адресация база+смещение. Обратите внимание, что использовать смещения больше 5Fh нельзя, так эта часть Access Bank всегда отображена на последние 160 байт адресного пространства памяти данных. Например, команда CLRF  0x25,0 при включенном расширенном наборе инструкций очистит байт находящийся по адресу FSR2+0x25. Если FSR2=0x121, то будет очищен байт по адресу 0x146.

Еще раз отмечу обязательные условия использования адресации база+смещение. Во первых, включен расширенный набор инструкций (XINST=1). Во вторых, используется прямая адресация в Access Bank по адресу не более 5Fh.

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

Вот теперь все. Мы закончили разбираться с памятью данных. Это был, пожалуй, самый запутанный раздел.