реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> STM32F7XX аналог bit-banding
amiller
сообщение Dec 26 2016, 10:11
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612



В последние годы пришлось достаточно много писать для STM32F1XX и STM32F4XX.
Везде активно пользовался механизмом bit-banding для доступа к битовым переменным.
Сейчас заказал отладку с STM32F746ZG.
Читаю документацию и вижу, что там никаких упоминаний про bit-banding при работе с оперативной памятью...
Ткните носом, что на замену? Может появились неделимые операции "чтение-модификация-запись"?
Go to the top of the page
 
+Quote Post
jcxz
сообщение Dec 26 2016, 21:34
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(amiller @ Dec 26 2016, 13:11) *
Читаю документацию и вижу, что там никаких упоминаний про bit-banding при работе с оперативной памятью...
Ткните носом, что на замену? Может появились неделимые операции "чтение-модификация-запись"?

Механизм LDREX/STREX есть уже в M3.
Go to the top of the page
 
+Quote Post
amiller
сообщение Dec 27 2016, 03:05
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612



Цитата(jcxz @ Dec 27 2016, 01:34) *
Механизм LDREX/STREX есть уже в M3.

Это немного не то.
Команды предназначены для организации эксклюзивного доступа к ячейке памяти.
Причём они не гарантируют эксклюзивности, а позволяют проверить успешность операции по изменению данных.
В какой то мере это танцы с бубном, которые в некоторых случаях ещё сложнее простого запрета прерываний.
Хотелось бы обойтись без всего этого.
Чтобы код на С выглядел как то так:
X &= mask; или X |= mask;
И при этом, разместив переменную в определенной секции памяти или объявив эту переменную особым образом, мы бы получили результат, когда компилятор генерирует непрерываемый код (в идеале из одной команды), который модифицирует переменную прямо в памяти.
Например IAR (всегда?) генерирует код из трёх отдельных этапов - чтение - модификация - запись.
Механизм bit-banding в Cortex-M3 и Cortex-M4 позволял достаточно красиво обойти эту проблему.
А в Cortex-M7 решили отказаться от этого без каких либо альтернатив?
Go to the top of the page
 
+Quote Post
SSerge
сообщение Dec 27 2016, 07:19
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Идея bit-banding в том, что он делается не процессором, а контроллером памяти.
С одной стороны это хорошо, поскольку все операции выполняются "на месте", не загружая шину лишними пересылками.
С другой это приводит к усложнению логики коммутатора шин.
Наиболее вероятная, на мой взгляд, причина - скорострельности ОЗУ стало недостаточно чтобы провести цикл чтение-модификация-запись за один такт, а за два делать - неоправданное усложнение контроллера и всего шинного хозяйства, которое в семёрке и так не маленькое.

Ну и со стороны компиляторов поддержки так и не дождались.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Dec 27 2016, 09:45
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(amiller @ Dec 27 2016, 06:05) *
Это немного не то.
Команды предназначены для организации эксклюзивного доступа к ячейке памяти.
Причём они не гарантируют эксклюзивности, а позволяют проверить успешность операции по изменению данных.

... которая будет успешной только при эксклюзивном доступе.
И в чём разница?
Вы думаете классический битбандинг какие-то специальные операции делал по шине памяти предназначенные только для битов? wink.gif
Нет, процессор так же выполнял чтение-модификацию бита-запись для всей ячейки содержащей данный бит, но скрыто от программиста и в непрерывном режиме.

Вот моя реализация аналога команды CMPXCHG для x86:
CODE
PUBLIC _Z13AtomicCmpSwapPVjjj
;АтомарнаЯ операциЯ "сравнение и обмен" длЯ типа u32.
;u32 AtomicCmpSwap(u32 volatile *ptr, u32 newVal, u32 cmpVal);
_Z13AtomicCmpSwapPVjjj:
aCmpSwap32_01: LDREX R12, [R0]
CMP R12, R2
ITT EQ
STREXEQ R3, R1, [R0]
CMPEQ R3, #1
BEQ aCmpSwap32_01
MOV R0, R12
BX LR

На основе этой процедуры можно сделать и другие операции атомарной модификации памяти (хоть |=, хоть &=, ...).

Цитата(amiller @ Dec 27 2016, 06:05) *
Чтобы код на С выглядел как то так:
X &= mask; или X |= mask;
И при этом, разместив переменную в определенной секции памяти или объявив эту переменную особым образом, мы бы получили результат, когда компилятор генерирует непрерываемый код (в идеале из одной команды), который модифицирует переменную прямо в памяти.
Например IAR (всегда?) генерирует код из трёх отдельных этапов - чтение - модификация - запись.
Механизм bit-banding в Cortex-M3 и Cortex-M4 позволял достаточно красиво обойти эту проблему.

Святая наивность.... biggrin.gif biggrin.gif biggrin.gif biggrin.gif biggrin.gif
Похоже Вы никогда не заглядывали, что генерит IAR при работе с bit-banding-ом. Там команд подчас ещё больше, чем в той процедуре, что я привёл выше.
И это не "IAR генерирует", это архитектура Cortex-M такова - у него нет команд непосредственно модифицирующих данные в памяти. Чтобы получить то, что Вы хотите, Вам нужно поменять процессор.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 27 2016, 11:56
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(SSerge @ Dec 27 2016, 10:19) *
Ну и со стороны компиляторов поддержки так и не дождались.

Да и со стороны пользователей тоже. Я, к примеру, не стал заморачиваться. Смысл какой? Если бы это было общее решение для всех процов, ну тогда да. Или подход.
Да и вообще, надо от головы плясать. Если бы язык С поддерживал бы какую то директиву, которая бы обеспечивала атомарные операции с данными, либо механизм, то тогда производители компиляторов вынуждены были бы реализовывать эти директивы средствами имеющимися в наличии у конкретного CPU. Вот тогда бы всё закрутилось. А так ... Пустое.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Dec 27 2016, 12:37
Сообщение #7


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(SasaVitebsk @ Dec 27 2016, 14:56) *
Если бы язык С поддерживал бы какую то директиву, которая бы обеспечивала атомарные операции с данными, либо механизм, то тогда производители компиляторов вынуждены были бы реализовывать эти директивы средствами имеющимися в наличии у конкретного CPU. Вот тогда бы всё закрутилось. А так ... Пустое.

С как язык и не должен более развиваться, потому что для решения этих проблем есть плюсы
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 27 2016, 12:45
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(amiller @ Dec 27 2016, 05:05) *
А в Cortex-M7 решили отказаться от этого без каких либо альтернатив?

Альтернатива, причем более, чем разумная, Вам была названа. А вот работу с псевдобитами разумной назвать сложно, ввиду затрат на вычисление адреса бита.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
amiller
сообщение Dec 27 2016, 12:57
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612



Цитата(jcxz @ Dec 27 2016, 13:45) *
Вы думаете классический битбандинг какие-то специальные операции делал по шине памяти предназначенные только для битов? wink.gif

Нет, не думаю.

Цитата(jcxz @ Dec 27 2016, 13:45) *
Похоже Вы никогда не заглядывали, что генерит IAR при работе с bit-banding-ом. Там команд подчас ещё больше, чем в той процедуре, что я привёл выше.

Нет, заглядывал.

Я прекрасно знаю, как работать с разделяемыми переменными программными средствами.
И эти механизмы можно реализовать в любой архитектуре.
Чаще всего существует поддержка на уровне системы команд, т.е. есть специальные команды для упрощения реализации, в Cortex M это LDREX/STREX.
Если речь идёт о реализации семафоров, то bit-banding ничем не поможет,так как он не обеспечивает атомарный доступ (теперь уже к биту).

Позвольте уточню, для чего я использовал этот механизм:
Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной.
И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции.



Цитата(zltigo @ Dec 27 2016, 16:45) *
Альтернатива, причем более, чем разумная, Вам была названа. А вот работу с псевдобитами разумной назвать сложно, ввиду затрат на вычисление адреса бита.

Спорить не буду, но я не занимался вычислением адресов.
Я создавал две секции памяти, одна в bit области, другая в band области памяти.
В этих секциях синхронно создавались две переменные, одна - битовая переменная нужного размера, вторая - структура из переменных int32 для доступа к отдельным битам.
Может быть и коряво, но задачу решало, причём с минимумом накладных расходов.


Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 27 2016, 13:25
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(amiller @ Dec 27 2016, 14:57) *
Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной.

При этом если работать с несколькими битами, то все становится сразу неудобным. При этом количество тактов на этот bit-banding это не один такт.
Цитата
И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции.

Разумнее с проверкой доступа к памяти.
Цитата
Спорить не буду, но я не занимался вычислением адресов.
Я создавал две секции памяти, одна в bit области, другая в band области памяти.
В этих секциях синхронно создавались две переменные, одна - битовая переменная нужного размера

битовая НЕ может быть "нужного размера" sad.gif. Она только битовая.
Цитата
вторая - структура из переменных int32 для доступа к отдельным битам.

В свою очередь 32bit обеспечивает доступ сразу ко всем 32 битам, а не отдельным.
Цитата
Может быть и коряво, но задачу решало, причём с минимумом накладных расходов.

Минимума накладных расходов по производительности, увы, не было. Как то то, что решаемую задачу Вы тоже описали шиворот на выворот.



--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
amiller
сообщение Dec 27 2016, 14:06
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612



Цитата(zltigo @ Dec 27 2016, 17:25) *
При этом если работать с несколькими битами, то все становится сразу неудобным. При этом количество тактов на этот bit-banding это не один такт.

Ну так я с этим и не спорю.

Цитата(zltigo @ Dec 27 2016, 17:25) *
битовая НЕ может быть "нужного размера" sad.gif. Она только битовая.

В данном случае имелась в виду переменная, состоящая из нескольких битов (8, 16, 32, 64).

Цитата(zltigo @ Dec 27 2016, 17:25) *
В свою очередь 32bit обеспечивает доступ сразу ко всем 32 битам, а не отдельным.

А разве смысл bit-banding не в том, что доступ к отдельному биту производится через полноразмерную 32-битную переменную из band области? Нет?
А у меня вроде работает именно так, и в документации так написано. Или опять вопрос в терминологии?

Цитата(zltigo @ Dec 27 2016, 17:25) *
Минимума накладных расходов по производительности, увы, не было. Как то то, что решаемую задачу Вы тоже описали шиворот на выворот.

Да я вроде просто в Cortex M7 не обнаружил bit banding. Была мысль, что придумали что-то новое, более продвинутое, что я не увидел в документации.
Именно в это я попросил ткнуть меня носом.
А меня стали наперебой тыкать носом в известные вещи.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Dec 27 2016, 14:58
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(amiller @ Dec 27 2016, 15:57) *
Позвольте уточню, для чего я использовал этот механизм:
Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной.
И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции.

Блин... Похоже Вы ничего не поняли... wacko.gif
Я же написал в первом сообщении: "На основе приведённой мной процедуры можно реализовать многие операции атомарного чтения-модификации-записи".
Пример - хотим "a |= b" атомарно:
Код
u32 volatile a;
u32 i0, i1;
do i1 = (i0 = a) | b;
while (AtomicCmpSwap(&a, i1, i0) != i0);

Всё! Здесь получили то, что Вы хотели - атомарная работа с битовыми структурами. Только функционал ещё по-больше - можно сразу неск. битов установить.
Подобные процедуры у меня есть и для других типов данных: u8, u16.
Так можно реализовать и все прочие логические и арифметические операции атомарные.
А можно, при желании, написать отдельные функции, подобные этой, для каждой такой операции (чтобы уменьшить кол-во команд).

Цитата(amiller @ Dec 27 2016, 17:06) *
Да я вроде просто в Cortex M7 не обнаружил bit banding. Была мысль, что придумали что-то новое, более продвинутое, что я не увидел в документации.

Даже в M3/M4 bit-banding был опционален и в некоторых камнях его могло и не быть.
Так что может и для M7 то же самое? Может в том МК, который Вы смотрите, его решили не реализовывать? Не большая потеря....
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 27 2016, 19:39
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



На AVR это делал. А теперь вообще так не делаю. Как правило этих флагов ну пусть 30 ... Если каждый поместить в 4-ёх байтное слово будет потрачено 120 байт. Это что критично для M7?
Вообще подходы к написанию поменял. Стараюсь флаги выставлять в одной задаче - забирать в другой... Короче стараюсь писать так, чтобы не возникало проблем. И задачи делаю строго асинхронные.
Выделяю задачу одну, следящего типа... Она диагностирует...
Несколько сложнее работать с общими ресурсами. Например флэш память. Записываются сообщения об ошибках с любой задачи. Можно делать конечно её обслуживание лишь в одной задаче, а туда слать лишь сообщения...
Короче лучше всего поменять подходы к самому программированию. Когда нужно выбрать или производительность или стабильность работы, то думаю, стабильность важнее. А производительность всегда можно повысить выбрав другой камень. Сейчас с этим нет вопросов.
Ну это мой взгляд на вещи.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Dec 27 2016, 22:04
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(SasaVitebsk @ Dec 27 2016, 22:39) *
На AVR это делал. А теперь вообще так не делаю. Как правило этих флагов ну пусть 30 ... Если каждый поместить в 4-ёх байтное слово будет потрачено 120 байт. Это что критично для M7?

Я думаю цель - не экономия памяти, а реализация механизма, когда доступ к объекту возможен как по частям (по битам) так и целиком (словом) из разных задач/ISR. В нескольких разных местах флаги ставятся (клиентами), а в одном месте - считываются-обнуляются другой задачей целиком всё слово.

Цитата(SasaVitebsk @ Dec 27 2016, 22:39) *
Вообще подходы к написанию поменял. Стараюсь флаги выставлять в одной задаче - забирать в другой... Короче стараюсь писать так, чтобы не возникало проблем. И задачи делаю строго асинхронные.

Ну да, если бы всегда так можно было бы, то семафоров разных не придумывали бы.
Представьте случай:
Есть задача (сервер), выполняющая запросы нескольких других задач-клиентов. Соответственно она может быть занята. Клиенты когда хотят пнуть задачу, ставят её флажок, который она обработает или сразу или как только освободится.
Я вот так часто реализую блокирующий или неблокирующий доступ к ресурсам, когда есть одна задача, обслуживающая общий ресурс и осуществляющая приоритетный арбитраж доступа клиентов к ресурсу и много клиентов.
Клиенты ставят флажки-биты в переменной запросов (опционально переходя в ожидание обслуживания) и пингуют задачу-сервер, пробуждая её. Задача, как только получает управление или освобождается от обработки предыдущего запроса, считывает сразу всю переменную флагов-запросов, в соответствии со своими правилами выбирает наиболее приоритетный запрос из имеющихся, сбрасывает этот флаг запроса, обрабатывает запрос.
Вот здесь нужен доступ к флагам-запросам как по отдельности и атомарно, так и сразу ко всем.
Go to the top of the page
 
+Quote Post
AVI-crak
сообщение Dec 28 2016, 02:11
Сообщение #15


Частый гость
**

Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894



Цитата(amiller @ Dec 26 2016, 16:11) *
Читаю документацию и вижу, что там никаких упоминаний про bit-banding при работе с оперативной памятью...
Может появились неделимые операции "чтение-модификация-запись"?

Атомарные операции не терялись. Вот только выглядят они как громадный костыль.

Применимы к флагам которых безумно много, или как вариант - обязаны занимать минимальное место (не всегда правило).
В общем у меня получатся так: глобальная структура с флагами ( ingl ) - цель, собрать в кучу мелкие имена флагов, строго 32б, ну и модификация с помощью стандартных команд __LDREXW и __STREXW.
Поместил функции f_ask_с и f_ask_d в разные задачи, они там в цикле просто меняют свой флаг. Смысла в функции нет, потому как я не придумал способ передать указатель члена структуры (оно ниже физического адреса). Возможно можно перечислениями сделать, но как потом не запутаться - не знаю.

Словом, если кто предложит решение - буду рад.

CODE
typedef union
{
struct
{
uint32_t stop:5;
uint32_t start:1;
uint32_t a:1;
uint32_t b:1;
uint32_t c:1;
uint32_t d:2;
uint32_t e:1;
uint32_t f:1;
uint32_t g:1;
uint32_t h:1;
uint32_t i:1;
uint32_t j:1;
uint32_t k:1;
uint32_t l:1;
uint32_t m:1;
uint32_t n:1;
uint32_t o:1;
uint32_t p:1;
uint32_t q:1;
uint32_t r:1;
uint32_t s:1;
uint32_t t:1;
uint32_t u:1;
uint32_t v:1;
uint32_t w:1;
uint32_t x:1;
uint32_t y:1;
uint32_t z:1;
} Flags;
uint32_t Flagi;
} Flag_Type;

Flag_Type ingl;


static void f_ask_c (void);
void f_ask_c (void)
{
Flag_Type tmp;
do
{
tmp.Flagi = __LDREXW(&ingl.Flagi);
tmp.Flags.c ^= 1;
}while ( __STREXW(tmp.Flagi, &ingl.Flagi));
__CLREX();
}

static void f_ask_d (void);
void f_ask_d (void)
{
Flag_Type tmp;
do
{
tmp.Flagi = __LDREXW(&ingl.Flagi);
tmp.Flags.d ^= 1;
}while ( __STREXW(tmp.Flagi, &ingl.Flagi));
__CLREX();
}


Сообщение отредактировал AVI-crak - Dec 28 2016, 02:19
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 13th August 2025 - 21:37
Рейтинг@Mail.ru


Страница сгенерированна за 0.0152 секунд с 7
ELECTRONIX ©2004-2016