|
STM32F7XX аналог bit-banding |
|
|
|
Dec 27 2016, 03:05
|
Частый гость
 
Группа: Участник
Сообщений: 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 решили отказаться от этого без каких либо альтернатив?
|
|
|
|
|
Dec 27 2016, 09:45
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(amiller @ Dec 27 2016, 06:05)  Это немного не то. Команды предназначены для организации эксклюзивного доступа к ячейке памяти. Причём они не гарантируют эксклюзивности, а позволяют проверить успешность операции по изменению данных. ... которая будет успешной только при эксклюзивном доступе. И в чём разница? Вы думаете классический битбандинг какие-то специальные операции делал по шине памяти предназначенные только для битов?  Нет, процессор так же выполнял чтение-модификацию бита-запись для всей ячейки содержащей данный бит, но скрыто от программиста и в непрерывном режиме. Вот моя реализация аналога команды 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 позволял достаточно красиво обойти эту проблему. Святая наивность.... Похоже Вы никогда не заглядывали, что генерит IAR при работе с bit-banding-ом. Там команд подчас ещё больше, чем в той процедуре, что я привёл выше. И это не "IAR генерирует", это архитектура Cortex-M такова - у него нет команд непосредственно модифицирующих данные в памяти. Чтобы получить то, что Вы хотите, Вам нужно поменять процессор.
|
|
|
|
|
Dec 27 2016, 11:56
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(SSerge @ Dec 27 2016, 10:19)  Ну и со стороны компиляторов поддержки так и не дождались. Да и со стороны пользователей тоже. Я, к примеру, не стал заморачиваться. Смысл какой? Если бы это было общее решение для всех процов, ну тогда да. Или подход. Да и вообще, надо от головы плясать. Если бы язык С поддерживал бы какую то директиву, которая бы обеспечивала атомарные операции с данными, либо механизм, то тогда производители компиляторов вынуждены были бы реализовывать эти директивы средствами имеющимися в наличии у конкретного CPU. Вот тогда бы всё закрутилось. А так ... Пустое.
|
|
|
|
|
Dec 27 2016, 12:57
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(jcxz @ Dec 27 2016, 13:45)  Вы думаете классический битбандинг какие-то специальные операции делал по шине памяти предназначенные только для битов?  Нет, не думаю. Цитата(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 для доступа к отдельным битам. Может быть и коряво, но задачу решало, причём с минимумом накладных расходов.
|
|
|
|
|
Dec 27 2016, 13:25
|

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

|
Цитата(amiller @ Dec 27 2016, 14:57)  Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной. При этом если работать с несколькими битами, то все становится сразу неудобным. При этом количество тактов на этот bit-banding это не один такт. Цитата И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции. Разумнее с проверкой доступа к памяти. Цитата Спорить не буду, но я не занимался вычислением адресов. Я создавал две секции памяти, одна в bit области, другая в band области памяти. В этих секциях синхронно создавались две переменные, одна - битовая переменная нужного размера битовая НЕ может быть "нужного размера"  . Она только битовая. Цитата вторая - структура из переменных int32 для доступа к отдельным битам. В свою очередь 32bit обеспечивает доступ сразу ко всем 32 битам, а не отдельным. Цитата Может быть и коряво, но задачу решало, причём с минимумом накладных расходов. Минимума накладных расходов по производительности, увы, не было. Как то то, что решаемую задачу Вы тоже описали шиворот на выворот.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Dec 27 2016, 14:06
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(zltigo @ Dec 27 2016, 17:25)  При этом если работать с несколькими битами, то все становится сразу неудобным. При этом количество тактов на этот bit-banding это не один такт. Ну так я с этим и не спорю. Цитата(zltigo @ Dec 27 2016, 17:25)  битовая НЕ может быть "нужного размера"  . Она только битовая. В данном случае имелась в виду переменная, состоящая из нескольких битов (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. Была мысль, что придумали что-то новое, более продвинутое, что я не увидел в документации. Именно в это я попросил ткнуть меня носом. А меня стали наперебой тыкать носом в известные вещи.
|
|
|
|
|
Dec 27 2016, 14:58
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(amiller @ Dec 27 2016, 15:57)  Позвольте уточню, для чего я использовал этот механизм: Есть переменная, содержащая набор флагов. С помощью bit-banding я мог спокойно установить или сбросить любой бит в этой переменой, не заботясь о том, что одновременно другие процессы с разными приоритетами могут работать с другими битами этой переменной. И похоже для Cortex M7 можно работать с битовыми структурами только через критические секции. Блин... Похоже Вы ничего не поняли... Я же написал в первом сообщении: "На основе приведённой мной процедуры можно реализовать многие операции атомарного чтения-модификации-записи". Пример - хотим "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 то же самое? Может в том МК, который Вы смотрите, его решили не реализовывать? Не большая потеря....
|
|
|
|
|
Dec 27 2016, 22:04
|
Гуру
     
Группа: Свой
Сообщений: 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)  Вообще подходы к написанию поменял. Стараюсь флаги выставлять в одной задаче - забирать в другой... Короче стараюсь писать так, чтобы не возникало проблем. И задачи делаю строго асинхронные. Ну да, если бы всегда так можно было бы, то семафоров разных не придумывали бы. Представьте случай: Есть задача (сервер), выполняющая запросы нескольких других задач-клиентов. Соответственно она может быть занята. Клиенты когда хотят пнуть задачу, ставят её флажок, который она обработает или сразу или как только освободится. Я вот так часто реализую блокирующий или неблокирующий доступ к ресурсам, когда есть одна задача, обслуживающая общий ресурс и осуществляющая приоритетный арбитраж доступа клиентов к ресурсу и много клиентов. Клиенты ставят флажки-биты в переменной запросов (опционально переходя в ожидание обслуживания) и пингуют задачу-сервер, пробуждая её. Задача, как только получает управление или освобождается от обработки предыдущего запроса, считывает сразу всю переменную флагов-запросов, в соответствии со своими правилами выбирает наиболее приоритетный запрос из имеющихся, сбрасывает этот флаг запроса, обрабатывает запрос. Вот здесь нужен доступ к флагам-запросам как по отдельности и атомарно, так и сразу ко всем.
|
|
|
|
|
Dec 28 2016, 02:11
|
Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|