Spec-Zone.ru › GCC 15

6.3 Именованные адресные пространства

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

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

  • Именованные адресные пространства AVR
  • Именованные адресные пространства M32C
  • Именованные адресные пространства PRU
  • Именованные адресные пространства RL78
  • Именованные адресные пространства x86

6.3.1 Именованные адресные пространства AVR

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

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

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

__flash

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

__flash1
__flash2
__flash3
__flash4
__flash5

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

__flashx

Это 24-разрядное адресное пространство флеш-памяти, размещающее данные в секции .progmemx.data. Перед чтением данных с помощью инструкции ELPM компилятор задаёт соответствующее значение регистра сегмента RAMPZ.

__memx

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

Ограничения и предостережения

  • Чтение через границу секции в 64 КиБ для адресных пространств __flash или __flashN не поддерживается. Через границы сегментов флеш-памяти размером 64 КиБ можно читать только в адресных пространствах __memx и __flashx.
  • При использовании одного из адресных пространств __flashN необходимо настроить сценарий компоновщика так, чтобы секции .progmemN.data размещались в соответствии с вашими требованиями. Пример см. в вики avr-gcc.
  • Любые данные или указатели на негenericные адресные пространства должны иметь квалификатор const, то есть обозначать данные только для чтения. Это правило действует и в том случае, если данные в одном из этих адресных пространств, например номер версии программного обеспечения или таблица калибровочных значений, предполагается изменять после загрузки, например с помощью загрузчика. В этом случае следует использовать квалификаторы const volatile, чтобы компилятор не оптимизировал известные значения и не вставлял их в качестве непосредственных операндов инструкций.
  • Следующий код инициализирует переменную pfoo, размещённую в статической памяти и имеющую 24-разрядный адрес:
    extern const __memx char foo;
    const __memx void *pfoo = &foo;
  • На уменьшенных устройствах Tiny, таких как ATtiny40, адресные пространства не поддерживаются. Используйте обычный код C / C++ без дополнительных затрат, как описано выше. Атрибут progmem поддерживается, но работает иначе; см. Атрибуты переменных AVR.

6.3.2 Именованные адресные пространства M32C

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

6.3.3 Именованные адресные пространства PRU

На целевой платформе PRU переменные с квалификатором __regio_symbol являются псевдонимами, используемыми для доступа к специальным регистрам ввода-вывода процессора. Их необходимо объявлять как extern, поскольку такие переменные не размещаются ни в какой памяти данных. Их также необходимо помечать как volatile; они могут иметь только 32-разрядные целочисленные типы. Допустимы только имена __R30 и __R31, обозначающие соответственно специальные регистры ввода-вывода процессора R30 и R31. Поэтому приведённый ниже пример — единственный допустимый способ использования __regio_symbol:

extern volatile __regio_symbol uint32_t __R30;
extern volatile __regio_symbol uint32_t __R31;

6.3.4 Именованные адресные пространства RL78

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

6.3.5 Именованные адресные пространства x86

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

__seg_fs
__seg_gs

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

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

Если эти адресные пространства поддерживаются, определяются символы препроцессора __SEG_FS и __SEG_GS.

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

Spec-Zone.ru

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