Как написать барьер памяти для DSP TMS320F2812?

Я просмотрел руководство пользователя компилятора TI C/C++ v6.1 (spru514e), но ничего не нашел.

Оператор asm, кажется, ничего не дает в этом отношении, руководство даже предостерегает от изменения значений переменных (p132). Расширение GNU для объявления эффектов переменных не реализовано (стр. 115).

Я также не обнаружил каких-либо внутренних барьеров памяти (например, __memory_changed() в armcc Кейла).

Поиск в Интернете или на форумах TI также ничего не дал.

Любые другие подсказки, как действовать?


person starblue    schedule 09.10.2012    source источник
comment
Требование к порядку, по-видимому, просто связано с оптимизацией компилятора и планированием. Я не думаю, что это можно обойти, переместив оператор asm в статическую встроенную функцию, возвращающую значение, которое вы хотите обновить?   -  person unixsmurf    schedule 09.10.2012
comment
В вики говорится, что компилятор не поддерживает Встроенные элементы Atomic. Вероятно, ваша единственная надежда состоит в том, что доступ к volatile не будет изменен. И вам может потребоваться вставить несколько nops, чтобы избежать незащищенных конфликтов конвейера, как описано в главе «Конвейер» справочного руководства по ЦП и набору инструкций. Если у вас несколько процессоров, все может запутаться.   -  person Alexey Frunze    schedule 09.10.2012
comment
@unixsmurf Я не хочу ничего делать на ассемблере. Пустой встроенный ассемблерный оператор, в котором говорится, что он изменяет память, — это просто способ создать барьер памяти в gcc.   -  person starblue    schedule 09.10.2012
comment
@ Алексей Фрунзе Спасибо за ссылку, я не знал, что gcc имеет явный барьер памяти (´__sync_synchronize()´). Что касается компилятора TI, то volatile, кажется, работает, но я хочу его избежать, так как это предотвратит слишком много оптимизаций компилятора.   -  person starblue    schedule 09.10.2012
comment
Во-первых, барьер памяти не может гарантировать, что вы читаете последние данные из памяти. Однако он может принудительно упорядочивать операции чтения. Если вам действительно нужен барьер памяти, почему бы тогда не создать логический барьер? Использование ключевого слова volatile в C допустимо, есть несколько приемов использования volatile, которые могут уменьшить размер вашего кода при достижении того, чего вы хотите. Или я отклонился от вашего вопроса?   -  person askmish    schedule 11.10.2012
comment
В техническом описании указано, что это простой одноядерный процессор. Никаких намеков на неупорядоченный доступ к памяти. Так велика вероятность, что вы ничего не найдете о барьерах памяти просто потому, что они не нужны. Свяжитесь со службой поддержки TI, чтобы убедиться.   -  person Hans Passant    schedule 14.10.2012
comment
@Hans Passant Проблема не столько в аппаратном обеспечении (на самом деле чтение может опережать запись в конвейере, если я правильно понимаю), сколько в компиляторе, я хочу, чтобы он не переупорядочивал доступ к памяти в определенных местах. В настоящее время я могу использовать только очень слабую оптимизацию (-O1), и код перестает работать для более агрессивной оптимизации.   -  person starblue    schedule 15.10.2012
comment
@starblue, можешь поделиться своим кодом? Не все, конечно, только проблемная часть.   -  person qehgt    schedule 17.10.2012
comment
Часто проблема не в компиляторе, а в модели памяти C/C++. Например, компилятор может предположить, что указатели float* и int* не указывают на одну и ту же область памяти. Таким образом, компилятор может сгенерировать двоичный файл с неправильным поведением.   -  person qehgt    schedule 17.10.2012
comment
Кроме того, используете ли вы какие-либо потоки в своем коде? Прерывания?   -  person qehgt    schedule 17.10.2012
comment
@qehgt Нет, я не могу поделиться этим, нет отдельной изолированной части проблемы. Это происходит одновременно с прерываниями доступа к глобальным данным (в основном числам или статическим структурам, содержащим числа, почти нет указателей, ничего в куче), и явно недостаточно синхронизации (ничего не объявлено volatile). Нет, мы не делаем грязных вещей с указателями (в коде нет ни одного указателя void).   -  person starblue    schedule 17.10.2012
comment
А вы пробовали объявить все данные с доступом из разных потоков/прерываний как volatile? Компилятор ничего не знает о ваших обработчиках прерываний, поэтому он может оптимизировать весь доступ к вашим глобальным данным (и у него есть на это права).   -  person qehgt    schedule 17.10.2012
comment
Я сделал несколько быстрых тестов, которые несколько помогли, поэтому я уверен, что смогу заставить его работать, используя volatile. Но, как я писал выше, я хочу избежать этого, потому что это предотвратит слишком много оптимизаций компилятором.   -  person starblue    schedule 17.10.2012
comment
@starblue Вам не нужно объявлять все ваши глобальные структуры как volatile. Только часть struct может быть объявлена ​​как volatile. Кроме того, вы можете выполнять необходимые операции чтения/записи через другой указатель volatile, но в этом случае вы должны быть очень осторожны.   -  person qehgt    schedule 17.10.2012
comment
@starblue Кроме того, я помню, что мы использовали оператор asm("") (с пустой строкой), чтобы заставить компилятор завершить все пост-эффекты. Он использовался давно с очень старой версией компилятора TI. Но можно проверить, может еще работает. Просто поместите это asm(""); до и после необходимых операций чтения и записи.   -  person qehgt    schedule 17.10.2012


Ответы (1)


Барьеры памяти связаны с порядком доступа к памяти, но вы также должны убедиться, что значения не остаются в регистрах, а вообще записываются в память.

Единственный способ добиться этого с помощью компилятора TI — использовать volatile.

Обратите внимание, что volatile, будучи модификатором переменной, в своей реализации касается не самой переменной (т.е. ее памяти), а всех доступов к этой переменной. Поэтому, если вы хотите избежать эффектов слишком малой оптимизации, напишите свою программу так, чтобы только некоторые обращения к переменным были изменчивыми.

Для этого объявите свои переменные как обычно и добавляйте volatile только тогда, когда вы хотите принудительно прочитать или записать переменную. Вы можете использовать вспомогательные функции следующим образом:

inline void force_write(int *ptr, int value)
{
    *(volatile int *)ptr = value;
}

или используйте этот отличный макрос, украденный из Linux, который можно использовать как для чтения/записи, так и для всех типов:

#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
...
if (ACCESS_ONCE(ready) != 0)
    ACCESS_ONCE(new_data) = 42;

(Название имеет исторические причины; лучше назовите его FORCE_ACCESS.)

person CL.    schedule 17.10.2012