Spec-Zone.ru › GCC 10

Далее: Массивы нулевой длины, Предыдущее: Типы с фиксированной точкой, Выше: Расширения языка семейства C [Содержание][Индекс]

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

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

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

  • Пространства имён адресов AVR
  • Пространства имён адресов M32C
  • Пространства имён адресов RL78
  • Пространства имён адресов x86

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;
  • На уменьшенных устройствах типа 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-битных адресов. Переменные, не являющиеся дальними, предполагаются расположенными в верхней 64 Кбайт адресного пространства.

6.17.4 Пространства имён адресов 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-10.5.0/gcc/Named-Address-Spaces.html

Spec-Zone.ru

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