Spec-Zone.ru › GCC 11

Далее: Массивы длиной ноль, Предыдущее: Типы с фиксированной точкой, Выше: Расширения для семейства языков 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;
  • На уменьшенных устройствах 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 Пространства имён адресов 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-11.4.0/gcc/Named-Address-Spaces.html

Spec-Zone.ru

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