Spec-Zone.ru › GCC 8

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

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

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

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

На целевом устройстве AVR есть несколько адресных пространств, которые можно использовать для размещения данных только для чтения в памяти Flash и доступа к этим данным с помощью специальных инструкций LPM или ELPM для чтения из Flash.

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

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

__flash

Квалификатор __flash размещает данные в разделе .progmem.data. Данные считываются с помощью инструкции LPM. Указатели на это адресное пространство имеют ширину 16 бит.

__flash1
__flash2
__flash3
__flash4
__flash5

Это 16-битные адресные пространства, размещающие данные в разделе .progmemN.data, где N относится к адресному пространству __flashN. Компилятор устанавливает регистр сегмента RAMPZ соответствующим образом перед чтением данных с помощью инструкции ELPM.

__memx

Это 24-битное адресное пространство, которое линейно отображает Flash и RAM: Если старший бит адреса установлен, данные считываются из RAM, используя нижние два байта как адрес RAM. Если старший бит адреса сброшен, данные считываются из Flash с установленным значением 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 размещает данные в памяти Flash, но доступ к этим данным происходит из универсального адресного пространства, то есть из RAM, поэтому вам понадобятся специальные средства доступа, такие как pgm_read_byte из AVR-LibC, вместе с атрибутом progmem.

Ограничения и замечания

  • Чтение через границу раздела 64 КБ адресных пространств __flash или __flashN демонстрирует неопределённое поведение. Единственное адресное пространство, поддерживающее чтение через границы сегментов Flash в 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.16.2 Пространства имён адресов M32C

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

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

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

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

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

extern int __ea i;

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

6.16.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-8.5.0/gcc/Named-Address-Spaces.html

Spec-Zone.ru

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