Spec-Zone.ru › GCC 9

6.17 Пространства имён адресов

В качестве расширения GNU C поддерживает пространства имён адресов, определённые в проекте N1275 черновика ISO/IEC DTR 18037. Поддержка пространств имён адресов в GCC будет развиваться по мере изменения чернового технического отчёта. Вызовы функций для любого целевого устройства также могут измениться. В настоящее время пространства имён, отличные от общего пространства имён, поддерживаются только для целевых устройств AVR, SPU, M32C, RL78 и x86.

Идентификаторы пространства имён можно использовать точно так же, как и любой другой квалификатор типа C (например, const или volatile). Дополнительные сведения см. в документе N1275.

6.17.1 Пространства имён адресов AVR

Для целевого устройства AVR доступно несколько пространств имён адресов, которые можно использовать для размещения данных только для чтения во флеш-памяти и доступа к этим данным с помощью специальных инструкций LPM или ELPM, необходимых для чтения из флеш-памяти.

Устройства, относящиеся к avrtiny и avrxmega3, могут получать доступ к флеш-памяти с помощью инструкций LD*, поскольку флеш-память отображается в адресном пространстве ОЗУ. Нет необходимости в расширениях языка, таких как __flash или атрибут progmem. Файлы описания линковёра по умолчанию для этих устройств обеспечивают эту функцию, и .rodata остаётся во флеш-памяти: компилятор просто генерирует инструкции LD*, а скрипт линковёра добавляет специфичные для ядра смещения ко всем символам .rodata: 0x4000 в случае avrtiny и 0x8000 в случае avrxmega3. Список соответствующих устройств см. в разделе Параметры AVR.

Для устройств, не входящих в avrtiny или avrxmega3, все данные, включая данные только для чтения, размещаются в ОЗУ (общее адресное пространство), так как флеш-память не отображается в адресном пространстве ОЗУ. Для размещения данных только для чтения во флеш-памяти и генерации правильных инструкций доступа к этим данным без использования (встроенного) кода ассемблера требуются специальные адресные пространства.

__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, т.е. как данные только для чтения. Это всё ещё относится к данным в одном из этих адресных пространств, например, номеру версии программного обеспечения или таблице поиска калибровки, которые предполагается изменять после загрузки, скажем, загрузчиком. В этом случае правильная квалификация — это const volatile , чтобы компилятор не оптимизировал известные значения или не вставлял их в качестве непосредственных операндов инструкций.
  • Следующий код инициализирует переменную pfoo, размещённую в статической памяти, 24-битным адресом:
    extern const __memx char foo;
    const __memx void *pfoo = &foo;
  • На уменьшенных устройствах Tiny, таких как ATtiny40, адресные пространства не поддерживаются. Используйте обычный код C/C++ без дополнительных затрат, как указано выше. Атрибут progmem поддерживается, но работает по-другому, см. Атрибуты переменных AVR.

6.17.2 Пространства имён адресов M32C

На целевом устройстве M32C, с вариантами процессора R8C и M16C, переменные, квалифицированные с помощью __far, обрабатываются с использованием 32-битных адресов для доступа к памяти за пределами первых 64 Кбайт. Если __far используется с вариантами процессора M32CM или M32C, он не имеет эффекта.

6.17.3 Пространства имён адресов RL78

На целевом устройстве RL78 переменные, квалифицированные с помощью __far, обрабатываются с помощью 32-битных указателей (20-битных адресов) вместо стандартных 16-битных адресов. Переменные без квалификатора «far» предполагаются в верхних 64 Кбайт адресного пространства.

6.17.4 Пространства имён адресов SPU

На целевом устройстве SPU переменные могут быть объявлены как принадлежащие другому пространству имён адресов путём квалификации типа с помощью идентификатора пространства имён __ea:

extern int __ea i;

Компилятор генерирует специальный код для доступа к переменной i. Он может использовать поддержку библиотеки времени выполнения или генерировать специальные машинные инструкции для доступа к этому пространству имён.

6.17.5 Пространства имён адресов x86

На целевом устройстве x86 переменные могут быть объявлены как относящиеся к сегментам %fs или %gs.

__seg_fs
__seg_gs

К объекту осуществляется доступ с соответствующим префиксом переопределения сегмента.

Соответствующее основание сегмента должно быть установлено с помощью метода, специфичного для операционной системы. Вместо того, чтобы требовать дорогостоящего системного вызова для получения основания сегмента, эти адресные пространства не считаются подпространствами общего (плоского) адресного пространства. Это означает, что для преобразования указателей между этими адресными пространствами и общим адресным пространством требуются явные приведения типов. На практике приложение должно привести указатель к uintptr_t и применить смещение базы сегмента, которое оно установило ранее.

Макросы препроцессора __SEG_FS и __SEG_GS определяются при поддержке этих адресных пространств.

Далее: Длина ноль, Предыдущий: Фиксированная точка, Вверх: Расширения C [Оглавление][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gcc/Named-Address-Spaces.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API