arm cm3 dsb instrukce
Jiří Nesvacil
nesvacil na posys.eu
Úterý Červen 16 08:27:02 CEST 2020
Zdravim,
ldrex/strex ma M3 implementovan jako jeden priznak pres cely CPU tj.
jakmile dva z jakekoliv adresy ctou pres ldrex nebo pri preruseni, tak
se shodi a musi jit znovu.
Pokud mate jedno vlakno/ci hlavni smycku na nastaveni priznaku a v
preruseni priznak shazujete, jen jako 1/0, tak s volatile vystacite.
Atomicky zapis je doopravdy v mistech, kdy chteji oba delat nejakou akci.
Priklad: v preruseni prirpravuji data, kdyz jsou pripravena reknu vem si
je priznakem. V hlavni smycce/threadu si prevezmy data a shodim priznak,
tak to je ok. Nesmeji byt dve vlakna, ktere by prebiraly data zaroven,
pokud to bude jedno vlakno/hlavni smycka, tak to bude vzdy ok a v tom je
zakopany pes.
Jirka
Dne 15.06.2020 v 18:28 Miroslav Mraz napsal(a):
> Tak mě tahle diskuze vyprovokovala to celé otestovat. Největší problém
> není ani s tím, že by std::atomic nefungovalo, ale přesvědčit se, že
> pouhá volatilní proměnná fungovat nemůže, pokud do ní zapisuji ze dvou
> různých konců.
> To by jeden ani nevěřil, co to dá práce najít způsob jak se s
> přerušením trefit do těch dvou kritických instrukcí, kde se proměnná
> modifikuje a ukázat, že je to špatně. Zdálo by se, že když udělám
> hlavní smyčku dostatečně krátkou a budu přerušovat hodně svižně, musí
> to zhavarovat dost často. Není tomu tak. Obvyklé použití je asi takovéto:
> static volatile int lock;
> static const int step = 4;
> //...
> int main () {
> for (;;) {
> if (lock >= step) {
> lock -= step; // kritická operace
> }
> }
> }
> a přitom lock v přerušení inkrementuji o 1. A právě ten test na
> velikost lock ve většině případů kritickou operaci úplně vyhodí, takže
> chyba se projeví tak zhruba v jednom případě přerušení z několika
> milionů. O to je to záludnější.
>
> Ale proč jsem si s tím vlastně hrál. To primitivum std::atomic
> normálně používám, trochu tuším, že na Cortex-M3,4 používá dvojici
> LDREX/STREX, nikdy mě však nenapadlo se v tom nějak víc šťourat. Proto
> mě dost překvapilo, že v přerušení (a podobně v main) se používá asi
> takováto sekvence
> 200001aa: f3bf 8f5f dmb sy
> 200001ae: e851 0f00 ldrex r0, [r1]
> 200001b2: 3001 adds r0, #1 @ v main bude naopak subs
> 200001b4: e841 0e00 strex lr, r0, [r1]
> 200001b8: f1be 0f00 cmp.w lr, #0
> 200001bc: d1f7 bne.n 200001ae
> 200001be: f3bf 8f5f dmb sy
> Jenže když mám proměnnou v main uzamčenu, takhle na první pohled by to
> mělo skončit v nekonečné smyčce. Není tomu tak - je to docela chytře
> vymyšleno, výjimka exkluzivitu zruší, takže zápis v přerušení je vždy
> úspěšný. V main se samozřejmě zjistí exkluzivní zápis a proměnná se
> znovu načte. Takže to funguje v pohodě a bez velkého přemýšlení i v
> bare-metal programování.
> Metoda se zákazem a opětovným povolením přerušení v kritické sekci
> funguje ovšem také i když malinko a nepodstatně odlišně (při změně v
> main se do přerušení prostě nedostanete), u Cortex-M0 a jiných
> procesorů stejně nic jiného většinou nezbývá.
>
> Mrazík
>
>
> Dne 05. 06. 20 v 10:20 Jan Waclawek napsal(a):
>>> Jinak øeèeno - pokud máte napøíklad globální
>>> promìnnou, kterou sdílíte mezi smyèkou hlavního programu a pøeruením,
>>> nestaèí jí deklarovat jako volatile, musíte pouít nìco jako
>>> std::atomic<type>.
>>
>> U Cortex-M3/M4 toto nie je potrebne riesit (s vynimkou LDM/STM, ktore
>> su z
>> principu problematicke operacie, hojne sa vyskytujuce aj v ARM
>> erratach, a
>> pochybujem, ze by ich nejaky prekladac generoval pre volatile premenne),
>> vid napr. Cortex-M4 TRM, 3.5 Write buffer:
>>
>> If an interrupt
>> comes in while DMB or DSB is waiting for the write buffer to drain,
>> the
>> processor returns to the
>> instruction following the DMB or DSB after the interrupt completes.
>> This
>> is because interrupt
>> processing acts as a memory barrier operation.
>>
>> wek
> _______________________________________________
> HW-list mailing list - sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
Další informace o konferenci Hw-list