6.16 Пространства именованных адресов
В качестве расширения, GNU C поддерживает пространства именованных адресов, как определено в черновике N1275 стандарта ISO/IEC DTR 18037. Поддержка пространств именованных адресов в GCC будет развиваться по мере изменения черновика технического отчета. Конвенции вызова для любого целевого процессора также могут изменяться. В настоящее время только целевые процессоры AVR, SPU, M32C и RL78 поддерживают пространства адресов, отличные от универсального пространства адресов.
Идентификаторы пространств адресов могут быть использованы точно так же, как и любой другой квалификатор типа C (например, const или volatile). Более подробная информация содержится в документе N1275.
6.16.1 Пространства именованных адресов AVR
На целевом процессоре AVR существует несколько пространств адресов, которые могут быть использованы для размещения данных только для чтения в памяти флэш-памяти и доступа к этим данным с помощью специальных инструкций LPM или ELPM, необходимых для чтения из флэш-памяти.
По умолчанию любые данные, включая данные только для чтения, находятся в ОЗУ (универсальное пространство адресов), поэтому для размещения данных только для чтения в памяти флэш-памяти и для генерации правильных инструкций для доступа к этим данным без использования (встраиваемого) ассемблерного кода необходимы пространства адресов, отличные от универсального.
__flash-
Квалификатор
__flashразмещает данные в секции.progmem.data. Данные считываются с помощью инструкцииLPM. Указатели на это пространство адресов имеют ширину 16 бит. __flash1__flash2__flash3__flash4__flash5-
Это 16-битные пространства адресов, размещающие данные в секции
.progmemN.data, где N относится к пространству адресов__flashN. Компилятор устанавливает сегментный регистрRAMPZсоответствующим образом перед чтением данных с помощью инструкцииELPM. __memx-
Это 24-битное пространство адресов, которое линеаризует флэш-память и ОЗУ: Если старший бит адреса установлен, данные считываются из ОЗУ, используя два младших байта в качестве адреса ОЗУ. Если старший бит адреса сброшен, данные считываются из флэш-памяти с установленным
RAMPZв соответствии со старшим байтом адреса. См.__builtin_avr_flash_segment.Объекты в этом пространстве адресов находятся в
.progmemx.data.
Пример
char my_read (const __flash char ** p)
{
/* p is a pointer to RAM that points to a pointer to flash.
The first indirection of p reads that flash pointer
from RAM and the second indirection reads a char from this
flash address. */
return **p;
}
/* Locate array[] in flash memory */
const __flash int array[] = { 3, 5, 7, 11, 13, 17, 19 };
int i = 1;
int main (void)
{
/* Return 17 by reading from flash memory */
return array[array[i]];
}
Для каждого пространства именованных адресов, поддерживаемого avr-gcc, определена одноименная, но заглавная встроенная макрокоманда. Цель состоит в том, чтобы упростить проверку доступности поддержки соответствующего пространства адресов:
#ifdef __FLASH
const __flash int var = 1;
int read_var (void)
{
return var;
}
#else
#include <avr/pgmspace.h> /* From AVR-LibC */
const int var PROGMEM = 1;
int read_var (void)
{
return (int) pgm_read_word (&var);
}
#endif /* __FLASH */
Обратите внимание, что атрибут progmem размещает данные во флэш-памяти, но доступ к этим данным читается из универсального пространства адресов, т.е. из ОЗУ, поэтому вам нужны специальные средства доступа, такие как pgm_read_byte из AVR-LibC вместе с атрибутом progmem.
Ограничения и замечания
- Чтение через границу раздела 64 Кбайт пространств адресов
__flashили__flashNдемонстрирует неопределенное поведение. Единственное пространство адресов, поддерживающее чтение через границы сегментов флэш-памяти 64 Кбайт, — это__memx. - Если вы используете одно из пространств адресов
__flashN, вы должны организовать свою линкерную скрипт для размещения секций.progmemN.dataв соответствии с вашими потребностями. - Любые данные или указатели на пространства адресов, отличные от универсальных, должны быть квалифицированы как
const, т. е. как данные только для чтения. Это все еще относится, если данные в одном из этих пространств адресов, например, номер версии программного обеспечения или справочная таблица калибровки, предназначены для изменения после загрузки, например, загрузочным программным обеспечением. В этом случае правильной квалификацией являетсяconstvolatile, чтобы компилятор не оптимизировал известные значения или не вставлял их в качестве непосредственных операндов инструкций. - Следующий код инициализирует переменную
pfoo, расположенную в статической памяти, с 24-битным адресом:extern const __memx char foo; const __memx void *pfoo = &foo;
Для такого кода требуется как минимум binutils 2.23, см. PR13503.
6.16.2 Пространства именованных адресов M32C
На целевом процессоре M32C, с вариантами процессоров R8C и M16C, переменные, квалифицированные с помощью __far, обращаются к адресам с 32-битным адресом для доступа к памяти за пределами первых 64 Кбайт. Если __far используется с вариантами процессоров M32CM или M32C, он не оказывает никакого влияния.
6.16.3 Пространства именованных адресов RL78
На целевом процессоре RL78 переменные, квалифицированные с помощью __far, обращаются к 32-битным указателям (20-битным адресам) вместо стандартных 16-битных адресов. Переменные, не являющиеся дальними, предполагаются находящимися в самом верхнем 64 Кбайт пространства адресов.
6.16.4 Пространства именованных адресов SPU
На целевом процессоре SPU переменные могут быть объявлены как принадлежащие другому пространству адресов путём квалификации типа с идентификатором пространства адресов __ea:
extern int __ea i;
Компилятор генерирует специальный код для доступа к переменной i. Он может использовать поддержку библиотеки времени выполнения или генерировать специальные машинные инструкции для доступа к этому пространству адресов.
Далее: Длина ноль, Предыдущий: Фиксированная точка, Вверх: Расширения C [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/Named-Address-Spaces.html