VisualDSP++: использование предварительно определенных макросов препроцессора
Добавил(а) microsin
В дополнение к макросам, которые Вы можете определять сами, препроцессор предоставляет набор заранее определенных макросов (predefined macros) и макросы функций (feature macros), которые можно использовать в коде ассемблера (перевод разделов "Using Assembler Feature Macros" и "Using Predefined Preprocessor Macros" из руководства [1]). Препроцессор автоматически заменит каждый встреченный макрос на указанное (предварительно определенное) значение. Инструменты разработки DSP также определяют макросы функций, которые Вы можете использовать в своем коде.
[Использование макросов функций]
Ассемблер имеет команду для вовлечения макросов препроцессора для определения рабочего контекста, такого как используемый язык исходного кода, архитектура процессора и его определенный тип. Это так называемые макросы функций ассемблера (feature macros) и макросы семейства (family macros), позволяющие программистам использовать команды условной компиляции препроцессора, чтобы конфигурировать исходный код ассемблера на основе используемого контекста.
В таблице 1-5 перечислен набор макросов функций feature macros процессоров Blackfin. Таблица 1-6 перечисляет набор макросов семейства (family macros) процессоров Blackfin. Таблица 1-7 и таблица 1-8 документа [1] перечисляют feature macros для процессоров SHARC и TigerSHARC соответственно.
Присутствует, когда запускается ассемблер: easmblkfn -proc ADSP-BF561
-D__ADSPBF592__FAMILY__=1
Присутствует, когда запускается ассемблер: easmblkfn -proc ADSP-BF592-A
[Использование общих предопределенных макросов]
Макросы __DATE__, __FILE__ и __TIME__ вернут строки символов, заключенные в одиночные кавычки, которые подойдут для инициализации символьных буферов. Для дополнительной информации см. врезку ".VAR и поддержка инициализации строк ASCII".
Директива .VAR directive определяет и опционально инициализирует переменные и буферы данных. Переменная использует одну ячейку памяти, а буфер данных использует массив из таких ячеек.
При декларировании или инициализации переменных:
• Директива .VAR может появляться только внутри секции. Ассемблер связывает переменную с типом памяти секции, в которой появляется определение .VAR.
• Одиночная директива .VAR может определять любое количество переменных или буферов, отделенных друг от друга запятыми или одной строкой.
За исключением абсолютной привязки переменной к адресам, заданным командой RESOLVE() (из файла .ldf), линкер размещает переменные в следующих друг за другом ячейках памяти. Например .VAR d,f,k[50]; последовательно размещает друг за другом в памяти процессора символы x, y и 50 элементов буфера k. Таким образом, этот пример делает то же самое, что и следующее определение:
.VAR d;
.VAR f;
.VAR k[50];
• Количество значений инициализатора может не превышать количество декларируемых переменных или ячеек буфера.
• Директива .VAR может задавать размер буфера неявно с помощью указания пустых квадратных скобок [ ]. Количество элементов инициализации неявно определяет размер буфера. Во время выполнения кода (runtime), оператор LENGTH может использоваться для определения размера буфера. Пример:
.SECTION data1;
.VAR buffer [] =1,2,3,4;
.SECTION program;
LO = LENGTH( buffer ); // Будет возвращено 4
[Синтаксис]
Директива .VAR может принимать одну из следующих форм:
varName определенный пользователем символ для обозначения имени переменной.
bufferName то же самое для обозначения буфера.
fileName показывает, что элементы буфера получают свои начальные значения из файла данных fileName. Параметр fileName может содержать имя файла и полный путь до него. Если файл инициализации находится в текущей директории Вашей операционной системы, то внутри двойных кавычек нужно указать только символы имени файла без полного пути до него. Обратите внимание, что когда читается файл данных, ассемблер считывает список десятичных цифр или HEX-строк, отделенных друг от друга пробелами.
Если файл по указанному имени не найден в текущей директории, то ассемблер просматривает директории, обозначенные путями поиска подключаемых заголовков (include path). Вы можете использовать ключ командной строки ассемблера -I, чтобы указать директории поиска этих подключаемых файлов.
Инициализация из файлов полезна при загрузке буферов какими-нибудь данными, такими как например коэффициенты фильтра или таблицы множителей вращения фазы FFT, которые сгенерированы другими программами. Ассемблер определяет, как эти значения сохранены в памяти, когда он читает их из фалов данных.
Многоточие ... обозначает список параметров, где параметры отделены друг от друга запятой.
[length] не обязательный параметр length задает длину (в словах) связанного буфера. Когда length не задана, то размер буфера определяется по количеству инициализаторов.
[ ] квадратные скобки закрывают опциональный параметр length для указания длины буфера, если это необходимо (см. примеры ниже).
initExpressions эти параметры устанавливают начальные значения для переменных или элементов буфера.
Для процессоров Blackfin ассемблер использует квалификатор /R32 (.VAR/R32) для поддержки 32-битной инициализации для использования дробных чисел в формате 1.31 (см. ниже врезку "Поддержка дробного типа").
Следующий код демонстрирует некоторые директивы .VAR:
.VAR buf1=0x1234;
/* Определение одной инициализированной переменной */
.VAR=0x1234, 0x5678;
/* Определение двух инициализированных слов */
.VAR samples[] = {10, 11, 12, 13, 14};
/* Декларация и инициализация буфера неявного размера из 5
значений; тот же самый эффект даст определение samples[5]. *//* Значения для инициализации, когда буфер задается
неявного размера, должны быть заключены в фигурные скобки. */
.VAR Ins, Outs, Remains;
/* Декларация трех не инициализированных переменных */
.VAR samples[100] ="inits.dat";
/* Декларация буфера из 100 ячеек и инициализация его
содержимым файла inits.dat */
.VAR taps=100;
/* Декларация переменной и инициализация её значением 100 */
.VAR twiddles[10] ="phase.dat";
/* Декларация буфера из 10 ячеек и загрузка его содержимым
файла phase.dat */
.VAR Fract_Var_R32[] ="fr32FormatFract.dat";
/* Декларация буфера неявного размера и загрузка его содержимым
файла fr32FormatFract.dat */
Все доступы к памяти процессора Blackfin требуют правильного выравнивания адреса. Таким образом, когда процессором загружается или сохраняется N-байтное значение, требуется его выравнивание по абсолютному адресу в N байт (т. е. байтовый адрес должен нацело делиться на N); если это условие не выполняется, произойдет генерация аппаратного исключения (ошибка hardware exception).
Пример кода Blackfin. В следующем примере 4-байтные переменные y0, y1 и y2 будут неправильно выровнены без директивы .ALIGN 4; эта директива размещена между операторами .VAR y0; и .VAR y2;.
.SECTION data1;
.ALIGN 4;
.VAR X0;
.VAR X1;
.BYTE B0;
.ALIGN 4; /* Выравнивание следующего элемента данных "Y0" по границе
слова */
.VAR Y0;
.VAR Y1;
.BYTE B1;
.ALIGN 4; /* Выравнивание следующего элемента данных "Y2" по границе
слова */
.VAR Y2;
{spoiler title=.VAR и поддержка инициализации строк ASCII opened=0}
Ассемблеры Analog Devices поддерживают инициализацию строки ASCII. Это позволяет использовать полный набор символов ASCII, включая цифры и специальные символы.
На процессорах SHARC и TigerSHARC символы сохраняются в старшем байте 32-битных слов, младшие биты слова (LSB) очищаются.
Когда используются 16-битные процессоры Blackfin, для получения дополнительной информации см. описание директивы .BYTE.
Инициализация строки может быть в одной их следующих форм:
Завершающий 0 указывать не обязательно. Он симулирует представление строк ANSI-C (так называемые строки ASCIIZ, заканчивающиеся нулевым символом как маркер конца строки).
Ассемблеры также принимают символы ASCII в комментариях. Обратите внимание на специальную обработку символов:
.VAR s1[] = {'1st line',13,10,'2nd line',13,10,0};
/* в конце строки применяются символы CR, LF */
.VAR s2[] = {'say:"hello"',13,10,0};
/* можно использовать двойные кавычки */
.VAR s3[] = {'say:',39,'hello',39,13,10,0};
/* пример вставки в строку одиночной кавычки */
Эта директива используется только с процессорами Blackfin.
Директивы .BYTE, .BYTE2 и .BYTE4 декларирую и опционально (по выбору) инициализируют одно-, двух- и четырехбайтные объекты данных соответственно. Обратите внимание, что директива .BYTE4 выполняет ту же самую функцию, что и директива .VAR.
[Синтаксис]
Для декларации и/или инициализации переменных памяти или элементов буфера используйте одну из следующих форм:
varName определенный пользователем символ для обозначения имени переменной.
bufferName то же самое для обозначения буфера.
fileName показывает, что элементы буфера получают свои начальные значения из файла данных fileName. Параметр fileName может содержать имя файла и полный путь до него. Если файл инициализации находится в текущей директории Вашей операционной системы, то внутри двойных кавычек нужно указать только символы имени файла без полного пути до него. Обратите внимание, что когда читается файл данных, ассемблер считывает список десятичных цифр или HEX-строк, отделенных друг от друга пробелами.
Если файл по указанному имени не найден в текущей директории, то ассемблер просматривает директории, обозначенные путями поиска подключаемых заголовков (include path). Вы можете использовать ключ командной строки ассемблера -I, чтобы указать директории поиска этих подключаемых файлов.
Инициализация из файлов полезна при загрузке буферов какими-нибудь данными, такими как например коэффициенты фильтра или таблицы множителей вращения фазы FFT, которые сгенерированы другими программами. Ассемблер определяет, как эти значения сохранены в памяти, когда он читает их из фалов данных.
Многоточие ... обозначает список параметров, где параметры отделены друг от друга запятой.
initExpressions эти параметры устанавливают начальные значения для переменных или элементов буфера.
Не обязательный параметр [length] задает длину связанного буфера в словах. Количество элементов инициализации определяет длину буфера неявного размера. В квадратные скобки заключается опциональный параметр длины буфера [length], если это необходимо. Для дополнительной информации см. ниже примеры использования директивы .BYTE.
Дополнительно используйте квалификатор /R32 (.BYTE4/R32) для поддержки 32-битной инициализации для использования дробных чисел 1.31.
Следующие строки демонстрируют директивы .BYTE:
Buffer1:
.TYPE Buffer1, STT_OBJECT;
.BYTE =5, 6, 7;
// инициализируются три 8-битные ячейки памяти// для метки данных Buffer1
.Buffer1.end:
.BYTE samples[] =123, 124, 125, 126, 127;
// декларируется буфер, длина которого задана неявно, и инициализирует// его пятью однобайтными константами
.BYTE4/R32 points[] =1.01r, 1.02r, 1.03r;
// декларируется буфер, длина которого задана неявно, и инициализирует// его тремя константами 4-байтных дробных чисел
.BYTE2 Ins, Outs, Remains;
// декларируются двухбайтные переменные, по умолчанию инициализированные// нулями
.BYTE4 demo_codes[100] ="inits.dat";
// декларация буфера из 100 ячеек, и инициализирует его содержимым// файла inits.dat
.BYTE2 taps=100;
// декларация 2-байтной переменной и инициализация её значением 100
.BYTE twiddles[10] ="phase.dat";
// декларация буфера из 10-ячеек и загрузка этого буфера содержимым// файла phase.dat
.BYTE4/R32 Fract_Byte4_R32[] ="fr32FormatFract.dat";
// декларируется буфер, длина которого задана неявно, и инициализируется// данными из файла fr32FormatFract.dat
При декларировании или инициализировании переменных директивой .BYTE, учитывайте ограничения, которые накладываются на директиву .VAR. Директива .VAR выделяет и опционально инициализирует 32-битные объекты данных. For information about the .VAR directive, refer to information on page 1-138.
[Поддержка инициализации строк ASCII]
Ассемблер поддерживает инициализацию строк ASCII. Это позволяет использовать полный набор символов ASCII, включая цифры и специальные символы.
На процессорах Blackfin инициализация ASCII может предоставляться директивами .BYTE, .BYTE2 или .VAR directives. Чаще всего используется директива .BYTE, где каждый символ представляет 1 байт. Это отличается от поведения директивы .VAR, которая для каждого символа выделяет 4 байта. Символы сохраняются в старших байтах 32-битных слов, младшие байты очищаются.
Инициализация строки принимает одну из следующих форм:
Дробные (fract) константы специально помечают константы с плавающей точкой, чтобы они были представлены в формате с фиксированной точкой. Дробные константы используют представление с плавающей точкой и суффиксом "r", где r означает fract.
Допустимый диапазон [–1…1). Это означает, что значения должны быть больше или равны –1 и меньше 1. Числа fract представляют значения со знаком. Пример:
.VAR myFracts[] = {0.5r, -0.5e-4r, -0.25e-3r, 0.875r};
/* Корректное представление констант fract */
.VAR OutOfRangeFract =1.5r;
/* [Error …] Fract constant '1.5r' is out of range.
Константы fract должны быть больше или равны -1,
и меньше 1. Значение 1.5 приводит к ошибке. */
На процессорах Blackfin по умолчанию используется формат дробных чисел с фиксированной запятой fract 1.15. Используйте квалификатор /R32 (in .BYTE4/R32 or .VAR/R32) для поддержки 32-битной инициализации дробных чисел в формате 1.31.
Формат дробных чисел 1.31. Дробные числа, поддерживаемые процессорами компании Analog Devices, могут использовать формат 1.31, который означает 1 бит знака и 31 бит на дробную часть. Это дает диапазон чисел от –1 до +1–2**31. Например, 1.31 отображает константу 0.5r 2**31.
Формула преобразования, используемая процессорами для конвертации формата с плавающей точкой в формат с фиксированной точкой использует фактор масштабирования 31. Например:
.VAR/R32 myFract =0.5r;
// Результат fract для 0.5r будет 0x4000 0000// бит знака + 31 бит// 0100 0000 0000 0000 0000 0000 0000 0000// 4 0 0 0 0 0 0 0 = 0x4000 0000 = .5r
.VAR/R32 myFract =-1.0r;
// Результат fract для -1.0r будет 0x8000 0000// бит знака + 31 бит// 1000 0000 0000 0000 0000 0000 0000 0000// 8 0 0 0 0 0 0 0 = 0x8000 0000 = -1.0r
.VAR/R32 myFract =-1.72471041E-03r;
// Результат fract для -1.72471041E-03 будет 0xFFC77C15// бит знака + 31 бит// 1111 1111 1100 0111 0111 1100 0001 0101// F F C 7 7 C 1 5
Специальный случай 1.0r. 1.0r представляет дробное число, выходящее за пределы допустимого диапазона (out-of-the-range fract). Данные 0x7FFF FFFF делают ближайшую аппроксимацию 1.0r в представлении 1.31.
Арифметика дробных чисел. Ассемблер предоставляет поддержку арифметических выражений с помощью операций над дробными константами, не противоречивых с поддержкой других числовых типов в выражениях констант, как это описано в разделе "Assembler Expressions" документа [1].
Внутреннее (промежуточное) представление чисел для вычисления выражения использует формат с плавающей точкой двойного размера (double floating-point value). Проверка допустимого диапазона дробного числа откладывается до результата вычисления выражения. Пример:
#define fromSomewhereElse 0.875r
.SECTION data1;
.VAR localOne = fromSomewhereElse +0.005r;
// результат .88r находится в допустимом диапазоне
.VAR xyz =1.5r -0.9r;
// результат .6r находится в допустимом диапазоне
.VAR abc =1.5r; // ошибка: 1.5r выходит за пределы допустимого диапазона
Арифметика смешанных типов. Ассемблер не поддерживает арифметику между дробными и целыми числами. Например:
.SECTION data1;
.VAR myFract =1-0.5r;
// [Error ea1998] "fract.asm":2 User Error: Illegal// mixing of types in expression.
Таблица 2-1 описывает общие предопределенные макросы, предоставленные препроцессору.
Таблица 2-1. Общие макросы, которые определяет среда разработки.
Макрос
Назначение
ADI
Обозначает инструментарий компании Analog Devices, всегда определен как 1.
__LastSuffix__
Задает последнее значение суффикса, которое использовалось для сборки меток, сгенерированных препроцессором.
__LINE__
Заменяет __LINE__ номером строки в исходном коде, где встретился этот макрос.
__FILE__
Определяет __FILE__ как имя и расширение файла, в котором этот макрос определен, например macro.asm
__TIME__
Определяет __TIME__ как текущее время в 24-часовом формате hh:mm:ss, например 06:54:35
__DATE__
Определяет __DATE__ как текущую дату в формате mm dd yyyy, например Oct 02 2017
_LANGUAGE_ASM
Всегда установлено в 1
_LANGUAGE_C
Равно 1 когда используется для вызовов компилятора C, чтобы указать .IMPORT заголовков. Заменяет _LANGUAGE_ASM.
Макрос -D__VISUALDSPVERSION____. Это предварительно определенный макрос, применимый ко всем процессорам Analog Devices. Он предоставляет информацию о версии среды разработки VisualDSP++, и позволяет разместить в коде соответствующие проверки препроцессором. Макрос может использоваться для дифференцирования релизов и обновлений VisualDSP++. Ассемблеры и линкер предварительно определяют -D__VISUALDSPVERSION__ при вызове препроцессора.
Для дополнительной информации по кодированию версии (включая параметры и примеры), см. "-D__VISUALDSPVERSION__ Predefined Macro" документа [1].