Как организовать атомарные функции в кейл для aduc70xx

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

Доброго времени суток. Подскажите как организовать атомарные функции в кейл контроллер aduc7024 ядро ARM7. Тему штудировал но такие вещи как atomic block не нашел? просто запретить прерывание тоже не совсем то.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение menzoda »

1. Реализуй какое-нибудь средство синхронизации, например, семафоры. Я думаю в интернете найдется много статей как это сделать.

2. Если запрещать все прерывания не охота, то запрещай только то, которое использует эту функцию.

Если функция вызывается только из прерываний, то не имеет смысла что-либо с ней делать, потому что контроллер прерываний не поддерживает вложенные прерывания, то есть прерывание не может прервать другое прерывание. Это конечно можно обойти, но надо реализовывать ручками функцию-обертку для прерываний.
Аватара пользователя
balmer
Это не хвост, это антенна
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение balmer »

В Cortex процессорах это инструкции DMB и DSB

Вот тут довольно подробно все расписанно.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение menzoda »

Так то у него не Cortex, да и судя по описанию они никак не помогут в реализации атомарной операции.

DMB
Data Memory Barrier acts as a memory barrier. It ensures that all explicit memory accesses that appear in program order before the DMB instruction are observed before any explicit memory accesses that appear in program order after the DMB instruction. It does not affect the ordering of any other instructions executing on the processor.

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

DSB
Data Synchronization Barrier acts as a special kind of memory barrier. No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
All explicit memory accesses before this instruction complete.
All Cache, Branch predictor and TLB maintenance operations before this instruction complete.

Как я понял это некий способ удостоверится, что перечисленные операции (explicit memory accesses, Cache, Branch predictor and TLB maintenance operations) полностью завершены к моменту "выхода" из этой инструкции.

Однако, начиная с ARMv6 есть инструкции которые действительно могут помочь (только помочь) в реализации средства синхронизации: LDREX и STREX. Но ARM7 реализует ARMv4 и там этого нету. Так что в любом случае придется делать что-то самому на Си или на Си+Ассемблер.
Аватара пользователя
balmer
Это не хвост, это антенна
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение balmer »

menzoda писал(а):Однако, начиная с ARMv6 есть инструкции которые действительно могут помочь (только помочь) в реализации средства синхронизации: LDREX и STREX. Но ARM7 реализует ARMv4 и там этого нету.

Да, в сортах процессоров не разбираюсь, казалось что Thumb давно уже везде есть :( .
LDREX и STREX хорошие инструкции. Но лично мне достаточно и простого чтения/записи в память. Достаточно того, что 4-x байтовые слова пишутся и читаются атомарно.

Так что ждем от автора темы подробного описания зачем это надо. Таки у него не многопроцессорная система, так что элементарно должно быть все.
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

Нашел такую реализацию в кейле __disable_irq();/__enable_irq(); у себя в коде не проверял

разворачивается так:

Код: Выделить всё


    49: __disable_irq();         
   0x00081844  E10F0000  MRS       R0,CPSR
   0x00081848  E3800080  ORR       R0,R0,#0x00000080
   0x0008184C  E121F000  MSR       CPSR_c,R0
 
   50: __enable_irq();
   0x00081B08  E10F0000  MRS       R0,CPSR
   0x00081B0C  E3C00080  BIC       R0,R0,#0x00000080
   0x00081B10  E121F000  MSR       CPSR_c,R0



я реализовал проверку без запрета прерывания:

Код: Выделить всё

#define FL_PT_CNT         11U // Флаг активации счетчика протопотоков    
void SetFlagsis(byte  flag) // Установить системный флаг
{
    in_FlagS:
    BitMaskSet(g_lFlagsis,(U32)(1 << flag));   
    if(!(g_lFlagsis & ((U32)(1 << flag))))goto in_FlagS;
}

можно было реализовать через do while но на мой взгляд с goto тоже нормально (ни чего против goto не имею если выглядит красиво)

   136:                 BitMaskSet(g_lFlagsis,(U32)(1 << flag));         
   0x00083104  E3A02001  MOV       R2,#0x00000001
   0x00083108  E59F101C  LDR        R1,[PC,#0x001C]
   0x0008310C  E1A00012  MOV       R0,R2,LSL R0
   0x00083110  E5912028  LDR        R2,[R1,#0x0028]
   0x00083114  E1822000  ORR        R2,R2,R0
   0x00083118  E5812028  STR        R2,[R1,#0x0028]
   137:                 if(!(g_lFlagsis & ((U32)(1 << flag))))goto in_FlagS; 
   0x0008311C  E5912028  LDR       R2,[R1,#0x0028]
   0x00083120  E1120000  TST        R2,R0
   0x00083124  0AFFFFF9  BEQ        0x00083110



может кто подскажет более оптимальный вариант.
мне атомарность нужна в связи с тем что модификация может производится и в прерываниях.
Аватара пользователя
balmer
Это не хвост, это антенна
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение balmer »

Код внутри SetFlagsis в общем случае не решает задачи.
Потому как сразу после проверки внутри if может вызваться прерывание, и очистить эту переменную.

Таки тебе надо описать задачу. Подозреваю, что там логическая проблема с управлением этим флагом.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение menzoda »

Действительно, простая дополнительная проверка не решает поставленной задачи.

Код: Выделить всё

136:                 BitMaskSet(g_lFlagsis,(U32)(1 << flag));         
   0x00083104  E3A02001  MOV       R2,#0x00000001
   0x00083108  E59F101C  LDR        R1,[PC,#0x001C]
   0x0008310C  E1A00012  MOV       R0,R2,LSL R0
   0x00083110  E5912028  LDR        R2,[R1,#0x0028]
// Если прерывание произойдет в этот момент...
   0x00083114  E1822000  ORR        R2,R2,R0
// ...или в этот, то изменения внесенные прерыванием потеряются.
   0x00083118  E5812028  STR        R2,[R1,#0x0028]
   137:                 if(!(g_lFlagsis & ((U32)(1 << flag))))goto in_FlagS;
   0x0008311C  E5912028  LDR       R2,[R1,#0x0028]
   0x00083120  E1120000  TST        R2,R0
   0x00083124  0AFFFFF9  BEQ        0x00083110


Если проверка и установка битов в фоне происходит не слишком часто, то не вижу ничего плохого в запрещении прерывании, которое будет длиться (имеется в виду запрещение) всего несколько тактов. На сколько часто они устанавливаются в прерываниях - не важно, потому что как я уже говорил в ARM7 прерывания не могут прерывать друг-друга и от использования __disable_irq()/____enable_irq() им ни тепло ни холодно.

А вообще я нашел документ от ARM, где вроде бы описано как реализовать синхронизацию (семафор или мьютекс), используя специальные инструкции. То что тебе надо находится в конце (appendix), там где про старые архитектуры до версии ARMv6.
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

Спасибо за ссылку :beer: документ сохранил. У меня проблем в коде нет, в данный момент разрабатываю программу от стабильности которой зависит здоровье людей (проект называть не имею права...). В связи с чем хочу избежать глюков связанных "с фазой луны ))" я понимаю, что разрыв модификации переменной может привести к "красивым" глюкам. Система критична ко времени (реалтайм система). От выше перечисленной переменой в принципе стабильность мало зависит но все таки... в программе использую протопотоки по этому процессы друг на друга не накладываются. А спрашиваю для того, что-бы избежать глюков с атомарностью, при этом данные модули не должны задерживать прерывания.
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

По поводу протопотоков, может откажусь от них немного тормознутая вещь... над проектом только начал работу до конца не решил всю структуру программы, ОС однозначно использовать не буду. Смотрю на написание кооперативной многозадачности, но тема для меня новая поэтому пока остановился на протопотоках так как с их помощью получается не сложная диспетчеризация, ну или по крайней мере мне так показалось.
SII
Вымогатель припоя
Сообщения: 635
Зарегистрирован: Пт янв 30, 2009 14:50:35
Откуда: Солнечногорск

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение SII »

В процессорах до версии ARMv6 единственные инструкции для атомарных операций -- это SWP и SWPB. Они считывают из памяти одно значение и заменяют другим, при этом в промежутке между чтением и записью никто вклиниться не может. Но, если система однопроцессорная, то в них нужды нет: достаточно запрещать прерывания на время чтения-сравнения-модификации тех или иных переменных. Но в любом случае это низкоуровневые механизмы, а задачу надо сначала решить на высоком уровне (т.е. понять, что же конкретно нужно).
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

такая реализация __disable_irq();/__enable_irq(); у меня в коде периодически нарушает работу программы, помогает только сброс! :shock:
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

Что делать ? пришел к выводу что необходимо запрещать прерывания на время модификации очереди задач, и флага состояния, эти процедуры модифицируется как в прерывании так и в основной ветке, но как написал выше кейловские функции шлепают мне программу. Проверял без них работает нормально.
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

Нужен рабочий аналог, полагаю наверно загвоздка при переключении режимов User <----> Interrupt :roll:
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

SII писал(а):В процессорах до версии ARMv6 единственные инструкции для атомарных операций -- это SWP и SWPB. Они считывают из памяти одно значение и заменяют другим, при этом в промежутке между чтением и записью никто вклиниться не может. Но, если система однопроцессорная, то в них нужды нет: достаточно запрещать прерывания на время чтения-сравнения-модификации тех или иных переменных. Но в любом случае это низкоуровневые механизмы, а задачу надо сначала решить на высоком уровне (т.е. понять, что же конкретно нужно).


По поводу SWP и SWPB ниже пример кода, чтобы в данном случае сделать атомарность как я понял функцию необходимо написать на АСМ и вклинить между SWP и SWPB? Т.Е. Си функцию туда уже не вклинишь.

Код: Выделить всё

SWP     R0,R1,[R2]    ; Загрузить в R0 слово по адресу в R2, и сохранить R1 в R2.
SWPB    R2,R3,[R4]    ; Загрузить в R2 байт по адресу в R4,
                      ; и сохранить младший байт R3 в R4.
SWPEQ   R0,R0,[R1]    ; По условию обменять слово, определенное по адресу в R1
                      ; и содержимым в регистре R0.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение menzoda »

1. Странно, что они у тебя рушат программу, я их использовал вполне успешно. Что именно работает не так?

2. Функции __enable/__disable запрещают прерывания модифицируя регистр состояния ядра. Если не получается использовать их, то как я уже говорил, можешь запрещать прерывания в контроллере прерываний. Во-первых, можно будет запретить только те прерывания, которые осуществляют доступ к защищаемым данным, оставив остальные прерывания разрешенными, что может повысить "отзывчивость" системы. Во-вторых, при запрещении через контроллер прерываний ломаться просто нечему, все должно работать как надо.

3. Насчет примитивов синхронизации, типа SWP, LDREX и других. Они всего-лишь примитивы, основа для реализации полноценного и удобного средства синхронизации на Си/Си++, которое можно использовать как угодно, оборачивать любые участки кода и т.п. А иначе, действительно придется реализовывать функцию на ассемблере, или использовать какие-нибудь ассемблерные вставки в Си, что по моему мнению является костылем.

Я за запрещение прерываний через VIC. Это не потребует никаких лишних затрат и должно хорошо работать.
SII
Вымогатель припоя
Сообщения: 635
Зарегистрирован: Пт янв 30, 2009 14:50:35
Откуда: Солнечногорск

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение SII »

Если делать спин-блокировку (т.е. поток тупо крутится в цикле захвата блокировки до тех пор, пока не захватит), то последовательность действий примерно такова:

1. Изначальное состояние спин-блокировки (байта или слова в памяти) -- нуль.
2. Когда поток хочет захватить блокировку, он делает SWP или SWPB, запихивая в блокировку любое ненулевое значение. После этого он проверяет, что было из блокировки считано. Если был считан не нуль (т.е. если блокировка уже была захвачена другим потоком), он повторяет п. 2 -- и так до тех пор, пока не будет считан нуль.
3. Блокировка захвачена. Поток выполняет свои чёрные дела, для которых ему требовалась блокировка.
4. Закончив дела, поток записывает в блокировку нуль (не через SWP, а обычным STR -- здесь доступ к памяти однократный, а не дважды подряд, поэтому нужды в SWP нет).

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

А вот насчёт приведённого Вами фрагмента кода я, честно говоря, ничего не понял. Зачем там три команды SWP и как вообще Вы собираетесь вести обработку?
Аватара пользователя
signum
Встал на лапы
Сообщения: 84
Зарегистрирован: Ср июн 22, 2011 20:41:57
Откуда: Харьков

Re: Как организовать атомарные функции в кейл для aduc70xx

Сообщение signum »

menzoda писал(а):1. Странно, что они у тебя рушат программу, я их использовал вполне успешно. Что именно работает не так?

2. Функции __enable/__disable запрещают прерывания модифицируя регистр состояния ядра. Если не получается использовать их, то как я уже говорил, можешь запрещать прерывания в контроллере прерываний. Во-первых, можно будет запретить только те прерывания, которые осуществляют доступ к защищаемым данным, оставив остальные прерывания разрешенными, что может повысить "отзывчивость" системы. Во-вторых, при запрещении через контроллер прерываний ломаться просто нечему, все должно работать как надо.

3. Насчет примитивов синхронизации, типа SWP, LDREX и других. Они всего-лишь примитивы, основа для реализации полноценного и удобного средства синхронизации на Си/Си++, которое можно использовать как угодно, оборачивать любые участки кода и т.п. А иначе, действительно придется реализовывать функцию на ассемблере, или использовать какие-нибудь ассемблерные вставки в Си, что по моему мнению является костылем.

Я за запрещение прерываний через VIC. Это не потребует никаких лишних затрат и должно хорошо работать.


Точно я за VIC не подумал, спасибо за подсказку.

По поводу потоков там все макросы для безопасной работы присутствуют, например, есть мьютексы, PT_END, PT_EXIT и пр. если интересно как строить OC на протопотоках, можно прочитать о них, например, тут [url]sics.se/~adam/pt/[/url]
Ответить

Вернуться в «ARM»