OldComp.cz
https://oldcomp.cz/

programování v C na Amize
https://oldcomp.cz/viewtopic.php?f=12&t=10232
Stránka 22

Autor:  hynek [ 20.08.2021, 20:26 ]
Předmět příspěvku:  Re: programování v C na Amize

RayeR píše:
Panda38 píše:
Tohle se sice asi Amigy netýká, ale k volatile bych doplnil - moderní překladače (jako gcc) jsou "chytřejší než uživatel" (to asi odkoukaly z Windows) a sice zachovají volatile přístup k adrese, ale nezaručují pořadí přístupu k různým adresám, mohou pořadí změnit. Na to pak může být nutné použít bariéru, která funkčně nic nedělá, jen řekne překladači "přeze mě nejede vlak!" Typický příklad je přehození zapnutí hodin periferie STM32 procesoru za inicializaci, kdy se pak člověk diví proč periferie v Release nefunguje když v Debug funguje.


Nemas konkretni priklad kodu (odkaz) pro to STM32, kde se vyskytuje tenhle problem? Ja sem kdysi narazil na nake podivne chovani, kde stacilo zduplikovat zapis hodnoty do jednoho registru a pak to chodilo a myslim, ze ten problem se objevil prave po nake aktualizaci gcc, ktere je (nekdy bohuzel) cimdal chytrejsi. A nejde to resit jinak nez tim hnusnym inline assemblerem ale jen nakym atributem ci pragmou?


Napr. na procesorech ARM jsou tzv. synchronizacni instrukce, ktere zajistuji, ze kod pred touto instrukci bude provedeny drive nez kod za touto instrukci. Od procesoru Cortex-M3 vyse to je nutne, protoze samotne zapisy do periferii neresi jadro, ale radic sbernice, takze se muze stat, ze se dva po sobe provedene zapisy provedou (z ruznych dovodu) ve stejnem instrukcnim cyklu. Kdyz druhy zapis potrebuje aktivni nastaveni z prvniho zapisu, tak to samozrejme nefunguje. Navic se chovani muze menit podle optimalizaci pri prekladu apod., takze pak se muze zdat, ze je ten kod nevyzpytatelny :-) ale pri dukladnem prozkoumani tam vzdy je k nalezeni nejaka pricina...
Naposledy jsem podobny problem resil dnes u obsluhy SPI na Cortex-M4, kde pomohlo spravne umisteni nekolika instrukci DSB - v C knihovne jsou pripravene jako funkce __DSB().

Autor:  Panda38 [ 20.08.2021, 20:48 ]
Předmět příspěvku:  Re: programování v C na Amize

RayeR píše:
Panda38 píše:
Tohle se sice asi Amigy netýká, ale k volatile bych doplnil - moderní překladače (jako gcc) jsou "chytřejší než uživatel" (to asi odkoukaly z Windows) a sice zachovají volatile přístup k adrese, ale nezaručují pořadí přístupu k různým adresám, mohou pořadí změnit. Na to pak může být nutné použít bariéru, která funkčně nic nedělá, jen řekne překladači "přeze mě nejede vlak!" Typický příklad je přehození zapnutí hodin periferie STM32 procesoru za inicializaci, kdy se pak člověk diví proč periferie v Release nefunguje když v Debug funguje.
Nemas konkretni priklad kodu (odkaz) pro to STM32, kde se vyskytuje tenhle problem? Ja sem kdysi narazil na nake podivne chovani, kde stacilo zduplikovat zapis hodnoty do jednoho registru a pak to chodilo a myslim, ze ten problem se objevil prave po nake aktualizaci gcc, ktere je (nekdy bohuzel) cimdal chytrejsi. A nejde to resit jinak nez tim hnusnym inline assemblerem ale jen nakym atributem ci pragmou?
Konkrétní kód už nemám, navíc to nemusí být reprodukovatelné (podle toho jak se kompilátoru bude zrovna zdát vhodné zpřeházet pořadí), ale bylo to na způsob uvedený níže (funkce PortInit). Běžně se při inicializaci zařízení v STM32 procesoru nejdříve zapnutím hodin aktivuje zařízení a pak se inicializuje zařízení. Setkal jsem se s tím problémem když mi port v debug překladu fungoval normálně, ale při optimalizovaném překladu nefungoval, jakoby neproběhla inicializace. Teprve až při porovnání listingů jsem si všiml, že kompilátor nedodržel uvedené pořadí přístupů k portům, tudíž u vypnutého portu nemohla proběhnout inicializace. Většinou pořadí dodržuje, ale není to zaručené, někdy se může rozhodnout to zpřeházet.

Zařazuji tedy bariéry do míst kde je důležité pořadí přístupů a navíc vypínám pro jistotu optimalizaci u inicializačních funkcí zařízení (kdybych zapomněl doplnit bariéru).

Mimochodem, kernel Linuxu používá bariéry velmi intenzivně, bez toho by nefungoval.

Kód:
// optimalizace kritickych funkci
#define OPTIM __attribute__((optimize("O2")))

// vypnuta optimalizace pri pristupu na porty
#define NOOPTIM __attribute__((optimize("O0")))

// vzdy inline
#define INLINE __attribute__((always_inline)) inline

// compiler barrier
INLINE void cb() { __asm volatile ("" ::: "memory"); }

// data memory barrier
INLINE void dmb() { __asm volatile (" dmb 0xF\n" ::: "memory"); }

// instruction synchronization barrier
INLINE void isb() { __asm volatile (" isb 0xF\n" ::: "memory"); }

// data synchronization barrier
INLINE void dsb() { __asm volatile (" dsb 0xF\n" ::: "memory"); }

NOOPTIM void PortInit()
{
   RCC->AHB4ENR |= 0x1F; // clk pro GPIOA - GPIOE
   cb(); // compiler barrier
   GPIOA->MODER = B0;
   ....

Autor:  RayeR [ 22.08.2021, 05:02 ]
Předmět příspěvku:  Re: programování v C na Amize

Aha, no prave s init. SPI sem s tim mel problem na STM32L476.
Zatim sem ty bariaery nak neresil/neznal a ono to vetsinou nejak fungovalo.
Ted sem ale ponekud zmaten, ze panda uvadi celou radu ruznych barier ale ktere kde pouzit? Jedna se me hlavne o ty init.sekvence zapisu do registru. Postaci to __DSB()? To musim dat po kazdem zapisu hodnoty do cfg registru, takze kdyz budu nastavovat treba 10 registru, tak prolozene 10x __DSB() nebo to jde nak uzavrit do bloku? Co vim gcc ma nakou optimize pragmu:
#pragma GCC optimize ("O2")
#pragma GCC optimize ("O0")
pripadne lze ulozit a obnovit aktualni nastaveni na zacatku a konci bloku pomoci
#pragma GCC push_options
#pragma GCC pop_options
A jak vypada pak ASM kod s tim __DSB()? tam teda primo vlozi nejakou instrukci nebo jen zajisti spravne poradi zapisu do registru?

Jo tady sem nasel ten svuj problemovej kod:

void spi_init(...)
{
RCC->APB2ENR|=RCC_APB2ENR_SPI1EN; // enable bus clock for SPI peripheral
(void)RCC->APB2ENR; // wait 1 APB2 cycle (dummy read) for change being valid
(void)RCC->APB2ENR; // wait 1 APB2 cycle (dummy read) for change being valid
SET_PORT_MODE(SPI1_SS_PORT, SPI1_SS_PIN, GPIO_MODE_ALT, GPIO_OTYPE_PP, GPIO_FLOAT, GPIO_SPEED_HIGH);
SET_PORT_AF(SPI1_SS_PORT, SPI1_SS_PIN, SPI1_SS_AF); // configure GPIO pin to alternate function
...

Autor:  hynek [ 22.08.2021, 06:46 ]
Předmět příspěvku:  Re: programování v C na Amize

RayeR píše:
Aha, no prave s init. SPI sem s tim mel problem na STM32L476.
Zatim sem ty bariaery nak neresil/neznal a ono to vetsinou nejak fungovalo.
Ted sem ale ponekud zmaten, ze panda uvadi celou radu ruznych barier ale ktere kde pouzit? Jedna se me hlavne o ty init.sekvence zapisu do registru. Postaci to __DSB()? To musim dat po kazdem zapisu hodnoty do cfg registru, takze kdyz budu nastavovat treba 10 registru, tak prolozene 10x __DSB() nebo to jde nak uzavrit do bloku?

DSB - synchronizace pristupu k datum; ISB - synchronizace provadeni instrukci; DMB - bariera pristupu do pameti.
Z toho, co jsem zjistoval, tak na Cortex-M3/4 staci vetsinou pouzivat instrukce DSB. Inline funkce __DSB() se prelozi jako instrukce DSB.
Ostatni instrukce jsou uzitecne u vyssich typu ARM jader, kde jsou napr. cache a jine vykon zlepsujici techniky.
Jak tomu rozumim, tak DSB je potreba dat tam, kde napr. jeden zapis zapne hodiny pro periferii a hned druhy zapis zapisuje do periferie, coz predpoklada zapnute hodiny. Prvni zapis je u STM32 do periferie RCC, druhy zapis pak do jine periferie, ktera je treba na jine sbernici, tak se klidne muze stat, ze prvni zapis je zpozdeny, protoze se jeste dokoncuje predesly zapis, a druhy zapis se provede ve stejne chvili jako ten prvni...
Pokud se zapisuje nastaveni do jedne periferie, tak jednotlive zapisy jdou po sobe - kazdy dalsi zapis ceka az po dokonceni predchoziho. Tady DSB neni potreba.
Pokud se zapisuje nastaveni do periferii, kde neni potreba dokonceni predchoziho zapisu, tak tam taky DSB neni potreba.
Ve zminovanem kodu je misto DSB provedeno cteni z RCC registru, do ktereho se zapisovalo. To podle me udela stejnou sluzbu, i kdyz o dost pomalejsi... Ale zrovna tady to neni uplne potreba, protoze dalsi zapisy jdou do GPIO registru, coz nema s nastavovanym bitem SPI1EN nic spolecneho...
Snad jsem to svym vysvetlovacim pokusem moc "nezatemnil" ;)

Autor:  Panda38 [ 22.08.2021, 08:17 ]
Předmět příspěvku:  Re: programování v C na Amize

U jednojádra by se mělo vystačit s bariérou kompilátoru, která zajistí aby se nepromíchávaly přístupy na porty. Stačí použít jen tam kde je pořadí důležité a je zapnutá optimalizace - obvykle jen vypnutí/zapnutí periferie. Do kódu nic nevkládá. Datová bariéra je potřebná hlavně i vícejádra, vloží instrukci dmb/dsb a zajistí aby procesor dokončil paměťové operace a uvidělo je druhé jádro, aby se např. nedržel zápis v cache.

Autor:  RayeR [ 23.08.2021, 01:52 ]
Předmět příspěvku:  Re: programování v C na Amize

On tam u me bude problem asi nekde jinde, kdyz sem zkusil to __DSB(), tak sem ho tam musel dat hned 3x aby ten kod fungoval (inicializace a kresleni na graficky displej po SPI). Ani s vyplou optimalizaci -O0 mi to bez tech opicaren nefunguje. Jinak me zajima jen cortex-M4, ten zadne vice jadra/sperskalary nema...

void spi_init(..)
{
__DSB(); // data sync barrier but why need it 3x ?
RCC->APB2ENR|=RCC_APB2ENR_SPI1EN; // enable bus clock for SPI peripheral
// (void)RCC->APB2ENR; // wait 1 APB2 cycle (dummy read) for change being valid
__DSB();
__DSB();

Takze mozna mi to chybi jeste nekde jinde a zrovna se to projevuje na tomto miste kodu, ale nema to primou souvislost. Ale matne si pamatuju, ze s nakym starsim gcc to kdysi fungovalo bez toho zdvojeneho cteni, ze se to posralo az casem...

Autor:  Lisiak4 [ 23.08.2021, 03:02 ]
Předmět příspěvku:  Re: programování v C na Amize

Jednou, ne já v rámci programování, shodou okolností na Amize a v C, nebo v assembleru programátor taky musel uvést 2 krát po sobě stejný příkaz. Bylo to popsáno, že se instrukce nestihla provést.

Autor:  Panda38 [ 23.08.2021, 04:20 ]
Předmět příspěvku:  Re: programování v C na Amize

RayeR nezkusil jsi místo dsb použít jen nop? Možná to není problém bariér, ale že periferie vyžaduje prodlevu na nastartování.

Stránka 22 Všechny časy jsou v UTC + 1 hodina [ Letní čas ]
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/