Goto page Previous 1, 2, 3, 4, 5 Next
J.F.
Guest
Sat Jun 13, 2009 11:35 am
On Sat, 13 Jun 2009 12:31:18 +0200, Grzegorz Kurczyk wrote:
[quote:850052c765]Zwroc uwage na slowo volatile. Swoja droga przeczytaj jak volatile
dziala to rozwiaze sie wiele twoich dziwnych klopotow.
W dużym uproszczeniu ogranicza kompilatorowi możliwości optymalizacji. W
stosunku do zmiennej wymusza bezwarunkowe każdorazowe czytanie aktualnej
wartości zmiennej z pamięci przed wykonaniem jakichkolwiek operacji na
zmiennej. Czyli kompilatorowi nie wolno dla uproszczenia/przyśpieszenia
kodu banglać przez cała procedurę na wartości skopiowanej do rejestrów.
Inaczej mówiąc zmienna ma być tak traktowana jakby jej zawartość mogła
się w każdej chwili zmienić (np. przez inny wątek programu). W
kontekście powyższego (chyba, że jest jednak inna definicja volatile)
nadal nie mogę zrozumieć z jakiej paki rozkaz sei() umieszczony na końcu
funkcji znalazł się nagle na jej początku.
[/quote:850052c765]
Nie - to rozkaz = ze srodka funkcji znalazl sie na jej koncu :-)
J.
Grzegorz Kurczyk
Guest
Sat Jun 13, 2009 12:01 pm
Użytkownik J.F. napisał:
[quote:e5baddb327]
Nie - to rozkaz = ze srodka funkcji znalazl sie na jej koncu :-)
[/quote:e5baddb327]
No fakt

Można to też w taki sposób zinterpretować
Co oczywiście nie rozwiązuje kwestii "z jakiej paki".
Pozdrawiam
Grzegorz
J.F.
Guest
Sat Jun 13, 2009 12:24 pm
On Sat, 13 Jun 2009 13:01:50 +0200, Grzegorz Kurczyk wrote:
[quote:6e30855ef8]Użytkownik J.F. napisał:
Nie - to rozkaz = ze srodka funkcji znalazl sie na jej koncu :-)
No fakt

Można to też w taki sposób zinterpretować
Co oczywiście nie rozwiązuje kwestii "z jakiej paki".
[/quote:6e30855ef8]
Jest potrzebny na koncu [do zwrocenia wartosci], to przerzucaja na
koniec .. po co ma wczesniej rejestry zajmowac ?
J.
Grzegorz Kurczyk
Guest
Sat Jun 13, 2009 12:37 pm
Użytkownik J.F. napisał:
[quote:81b712e6b5]Jest potrzebny na koncu [do zwrocenia wartosci], to przerzucaja na
koniec .. po co ma wczesniej rejestry zajmowac ?
[/quote:81b712e6b5]
To dlaczego w przytoczonej funkcji SetEncoder też tak nie zrobił ? Tam
wszystko jest w takiej kolejności jak w źródłówce - sei jest na końcu,
choć z "matematycznego" punktu widzenia sei nie ma wpływu na wartość
obliczeń i może se być wrzuconym gdziekolwiek ;-)
Ufff... kończmy tę dyskusję, bo się mały flejmik robi
Kolega Zbych podał konkretne i skuteczne rozwiązanie problemu, choć
nadal nie mogę zrozumieć czemu akurat tak się dzieje ? Cóż trzeba
przyjąć to na "wiarę", że tak ma być i koniec ;-)
Jeszcze raz dziękuję Kolegom za udział w dyskusji.
Pozdrawiam
Grzegorz
Grzegorz Kurczyk
Guest
Sat Jun 13, 2009 1:17 pm
Użytkownik T.M.F. napisał:
[quote:731268af40]Co
wiecej gdybys dalej cops robil z ta zmienna w swojej procedurze to
kompilator jej pewnie ponownie by nie ladowal, czyli mialbys kolejne
dziwne bledy.
[/quote:731268af40]
Błędów by nie było pod warunkiem, że sei wylądowałoby na końcu tam gdzie
je napisałem. W sekcji między cli, a sei program staje się jednowątkowy
i nie ma powodu dla którego wartość tej zmiennej mogłby ulec zmianie,
ale fakt... Samo volatile też nie załatwiłoby sprawy. Musi być połaczone
z sekcją cli/sei.
[quote:731268af40]Ale to ciagle twoja wina i nie ma co zwalac na gcc.
[/quote:731268af40]
Ale ja nigdzie nie twierdzę, że to nie moja wina

Pewnie, że moja.
Wystarczyło dopisać volatile lub zastosować sekcję ATOMIC_BLOCK i jest
ok. Poprostu kiedyś tam zasugerowałem się tym, że przecież volatile
stosuje się po to aby wymusić każdorazowe czytanie zmiennej z pamięci, a
moim celem było uniemożliwienie aby cokolwiek innego zmieniło wartość
tej zmiennej na czas wykonywania wnętrza funkcji. A zmienna w tej
funkcji czytana jest w sumie tylko raz. Takie małe odwrócenie problemu

I co gorsza/lepsza w starszych wersjach WinAVR kompilowało się to
"po ludzku", co uśpiło moją czujność ;-)
Jeszcze raz dziękuję Kolegom za cenne wskazówki.
Pozdrawiam
Grzegorz
T.M.F.
Guest
Sat Jun 13, 2009 1:40 pm
W dniu 13.06.2009 06:10, Grzegorz Kurczyk pisze:
[quote:82a2a20f7f]Użytkownik Zbych napisał:
Dlatego napisałem, że do takich rzeczy jak sekcje atomowe są makra
zdefiniowane w pliku atomic.h, a ty uparcie chcesz rzeźbić ręcznie
(pomijając przy tym barierę).
Nie, no nie chcę nic robić uparcie. Sugestie Kolegi bardzo mi pomogły,
za co serdecznie dziękuję. Akurat w moim przypadku wystarczyło volatile,
ale gdybym nie spojrzał do .lss to żyłbym w błogiej nieświadomości będąc
pewnym, że zablokowałem przerwania w krytycznej sekcji programu i
zastanawiając się dlaczego program kiksuje raz na ruski miesiąc. Tym
bardziej, że w poprzedniej wersji kompilatora kolejność działań była
taka jak w źródłówce. Z biblioteki atomic.h nie miałem jeszcze okazji
korzystać, ale widzę, że chyba najwyższy czas

Nie narzekam na
WinAVR, bo to niezły kompilator, ale główny problem w tym, że program,
który w danej wersji WinAVR bez problemu się kompilował i co
najważniejsze działał poprawnie, w nowszej wywala błędy kompilacji (co
nie jest problemem), ale co gorsza kompilacja przechodzi bezbłędnie,
tylko program chodzi nie do końca tak jak powinien. Z tego powodu z dużą
rezerwą podchodzę do nowych wersji kompilatora.
Problem w tym skąd mam wiedzieć (poza "brutalnym" zajrzeniem do pliku
.lss), w którym momencie muszę posiłkować się sztuczką typu ATOMIC_BLOCK
lub czymś podobnym, bo kompilator może wygenerować kod, nie do końca
zgodny z założeniami autora kodu źródłowego. W podanym wcześniej
przykładzie w jednej procedurze było źle, a w następnej już dobrze i
nijak nie mogę wydedukować z czego to wynika. W przypadku volatile
sytuacja jest jasna, ale z tym sei to kompilator zrobił mi psikusa, bo
jest to pierwszy taki przypadek. Przecież sekcji cli() {..} sei() używa
się dość często. W większych programach mam ich dużo i to jest jak na
razie jedyna funkcja, w której takie zjawisko mi wystąpiło (choć po tym
kwiatku nie jestem już tego taki pewien i dla pewności skorzystam z rady
Kolegi Zbycha i porobię klamerki ATOMIC_BLOK).
[/quote:82a2a20f7f]
To nie jest tak jak piszesz. W twoim przykladzie kompilator zachowal sie
zupelnie poprawnie. Zauwaz, ze nie podales nigdzie, ze pEncoderValue
jest volatile, w efekcie kompilator slusznie uznal, ze wartosc tej
zmiennej nie moze sie zmienic nigdzie poza aktualnie kompilowana sekcja,
a wiec miejsce gdzie nastapi przypisanie:
int e = *pEncoderValue;
jest zupelnie dowolne. W koncu skoro nic w miedzyczasie nie modyfikuje
pEncoderValue to umieszczanie tego w sekcji krytycznej nie ma sensu i
kompilator sobie zoptymalizowal to tak jak mu pasowalo. Dopiero
okreslenie tej zmiennej jako volatile mowi kompilatorowi, ze z ta
zmienna trzeba uwazac i nie mozna sobie dowolnie jej przekladac.
Z kolei jesli pEncoderValue jest modyfikowane poza procedura, ktora
pokazales np. w jakims przerwaniu to okreslenie tej zmiennej jako
volatile jest obowiazkowe! Inaczej masz efekty takie jak pokazales. Co
wiecej gdybys dalej cops robil z ta zmienna w swojej procedurze to
kompilator jej pewnie ponownie by nie ladowal, czyli mialbys kolejne
dziwne bledy. Ale to ciagle twoja wina i nie ma co zwalac na gcc.
--
Inteligentny dom -
http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
J.F.
Guest
Sat Jun 13, 2009 2:09 pm
On Sat, 13 Jun 2009 13:37:15 +0200, Grzegorz Kurczyk wrote:
[quote:a22e20d40c]Użytkownik J.F. napisał:
Jest potrzebny na koncu [do zwrocenia wartosci], to przerzucaja na
koniec .. po co ma wczesniej rejestry zajmowac ?
To dlaczego w przytoczonej funkcji SetEncoder też tak nie zrobił ?
[/quote:a22e20d40c]
No bo tam nie bylo takiej potrzeby :-)
Jak sam zreszta zauwazyles - dodanie volatile zaowocowalo dluzszym
kodem. No to slusznie bez volatile zoptymalizowal do krotszego :-)
Inna sprawa ze ta kompilacja dziwna jakas i wcale niepotrzebnie
dluzsza.
[quote:a22e20d40c]Ufff... kończmy tę dyskusję, bo się mały flejmik robi
Kolega Zbych podał konkretne i skuteczne rozwiązanie problemu, choć
nadal nie mogę zrozumieć czemu akurat tak się dzieje ? Cóż trzeba
przyjąć to na "wiarę", że tak ma być i koniec
[/quote:a22e20d40c]
No coz - moral z tego taki ze czasem warto w kod wynikowy zajrzec.
Czlowiek sie czegos moze dowiedziec.
Inna sprawa ze w tym miejscu to volatile powinienes z przyzwyczajenia
pisac :-)
J.
Grzegorz Kurczyk
Guest
Sat Jun 13, 2009 11:49 pm
Użytkownik J.F. napisał:
Quote:
Inna sprawa ze w tym miejscu to volatile powinienes z przyzwyczajenia
pisac :-)
W tym sęk, że tak jak pisałem wcześniej co innego było moim pierwotnym
celem i volatile załatwiło problem niejako niechcący

Przy okazji,
jak to Kolega zauważył, nie do końca optymalnie. W zasadzie tak w 100%
sprawę załatwia rozwiązanie zaproponowane przez Kolegę Zbycha. To jest
to o co mi chodziło i optymalnie.
Tak jak wspomniałem moim celem było: nie dopuścić do przerwania
określonego fragmentu procedury przez inny wątek. To, że kompilator
pomiędzy cli/sei skopiuje sobie wartość zmiennej do rejestrów tylko raz
i będzie później banglał na tych rejestrach wcale mi nie przeszkadza,
więc jakoś nie widziałem w tym momencie miejsca na volatile, bo zmienna
w tej sekcji tak naprawdę wcale nie była ulotna.
Pozdrawiam i życzę Miłej Niedzieli.
Grzegorz
--
Że też mnie coś podkusiło powiedzieć jego ten "sęk"...
Staropolszczyznę sie mnie zachciało... sęk, sęk...
Tak samo mogłem powiedzieć:
ja wiem... "tu leży pies pochowany"...
Zbych
Guest
Sun Jun 14, 2009 10:34 am
T.M.F. pisze:
Quote:
Alez byla. Twoja zmienna jest typu int, czyli ma 2 bajty. AVR nie ma
instrukcji ladowania z pamieci 2 bajtow jednoczesnie, a wiec takie
przeslanie nie jest atomowe. Dlatego musisz okreslic ta zmienna jako
volatile i zapewnic atomowosc operacji przez blokowanie przerwan.
Nie wiem czemu twierdzisz, że dla zachowania atomowości potrzebne ci
jest volatile. To volatile jest w tym przypadku zbędne.
--
przeciez moje rozumowanie bylo bez skazy,
no sam bym wskoczyl do tego wulkanu,
ale kto by tak pieknie gwizdal...
T.M.F.
Guest
Sun Jun 14, 2009 10:40 am
Quote:
Tak jak wspomniałem moim celem było: nie dopuścić do przerwania
określonego fragmentu procedury przez inny wątek. To, że kompilator
pomiędzy cli/sei skopiuje sobie wartość zmiennej do rejestrów tylko raz
i będzie później banglał na tych rejestrach wcale mi nie przeszkadza,
więc jakoś nie widziałem w tym momencie miejsca na volatile, bo zmienna
w tej sekcji tak naprawdę wcale nie była ulotna.
Alez byla. Twoja zmienna jest typu int, czyli ma 2 bajty. AVR nie ma
instrukcji ladowania z pamieci 2 bajtow jednoczesnie, a wiec takie
przeslanie nie jest atomowe. Dlatego musisz okreslic ta zmienna jako
volatile i zapewnic atomowosc operacji przez blokowanie przerwan.
Zauwaz, ze gdyby uzyte przeslanie 16-bitowe bylo atomowe to blokowanie
przerwan w ogole nie byloby potrzebne. Tak jak pisalem, jesli tej
zmiennej nie okreslisz jako volatile to kompilator slusznie umieszcza to
przerwanie gdzie mu wygodniej - w koncu nie powiedziales mu, ze cos moze
wartosc tej zmiennej pomiedzy przeslaniami zmienic.
Zobacz tu:
http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html
wraz z wyjasnieniem i przykladami - powinno sie przydac.
--
Inteligentny dom -
http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
Grzegorz Kurczyk
Guest
Sun Jun 14, 2009 11:23 am
Użytkownik T.M.F. napisał:
Quote:
Alez byla. Twoja zmienna jest typu int, czyli ma 2 bajty. AVR nie ma
instrukcji ladowania z pamieci 2 bajtow jednoczesnie, a wiec takie
przeslanie nie jest atomowe. Dlatego musisz okreslic ta zmienna jako
volatile i zapewnic atomowosc operacji przez blokowanie przerwan.
Zauwaz, ze gdyby uzyte przeslanie 16-bitowe bylo atomowe to blokowanie
przerwan w ogole nie byloby potrzebne.
No dokładnie taki był mój tok rozumowania. Ponieważ pobranie zmiennej
int wymaga dwóch rozkazów blokuję możliwość przerwania tej operacji
przez inny wątek poprzedzając je rozkazem cli wstawionym "z palca". W
momencie gry program staje się jednowątkowy trudno mówić o ulotności
zmiennych.
Tak jak pisalem, jesli tej
Quote:
zmiennej nie okreslisz jako volatile to kompilator slusznie umieszcza to
przerwanie gdzie mu wygodniej - w koncu nie powiedziales mu, ze cos moze
wartosc tej zmiennej pomiedzy przeslaniami zmienic.
Ale co miałoby ją zmienić po rozkazie cli ? Po to dałem ten rozkaz aby
nic nie tykało tej zmiennej poza wnętrzem funkcji. Fakt, że gcc nie jest
kompilatorem dedykowanym do AVR-ów. W innych procesorach zablokowanie
przerwań wcale nie musi wykluczać wielowątkowości.
Quote:
I w sumie w moim przypadku volatile wcale nie jest potrzebne.
ATOMIC_BLOCK załatwia sprawę. I dokładnie taki "ATOMIC" próbowałem
zrobić na piechotę przez ręczne wstawienie cli/sei. Volatile niezbędne
byłoby gdybym gdzieś robił while(*pEncoderValue == bleble) {..} aby
uniknąć porównywania kopi wartości w rejestarch. No i w związku z tym,
że to int dodatkowo będzie potrzebny ATOMIC (choć nie w każdym przypadku).
int *pEncoderValue; // bez volatile
int GetEncoder(void) {
int e;
ATOMIC_BLOCK(ATOMIC_FORCEON) {
e = *pEncoderValue;
}
return e;
}
kompiluje się idealnie do:
1516: f8 94 cli
1518: e0 91 3a 01 lds r30, 0x013A
151c: f0 91 3b 01 lds r31, 0x013B
1520: 80 81 ld r24, Z
1522: 91 81 ldd r25, Z+1 ; 0x01
1524: 78 94 sei
1526: 08 95 ret
Niestety w WinAVR_20071221 nie było jeszcze biblioteki atomic.h, ale
można było to uzyskać metodą podaną przez Kolegę Zbycha czyli:
asm volatile ("cli":::"memory");
int e = *pEncoderValue;
asm volatile ("sei":::"memory");
Tym bardziej, że bezpieczniejszą formą funkcji będzie:
int *pEncoderValue; // może być bez volatile
int GetEncoder(void) {
int e;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
e = *pEncoderValue;
}
return e;
}
bo nie zawsze chciałbym aby wywołanie funkcji z automatu włączało mi
przerwania.
Kiedyś robiłem to na piechotę.
// wyrzucenie zawartości portu na stos
#define push_sfr(port) \
__asm__ __volatile__ ( \
"in __tmp_reg__,%0" "\n\t" \
"push __tmp_reg__" "\n\t" \
::"I" (_SFR_IO_ADDR(port)))
// odtworzenie zawartości portu ze stosu
#define pop_sfr(port) \
__asm__ __volatile__ ( \
"pop __tmp_reg__" "\n\t" \
"out %0,__tmp_reg__" "\n\t" \
::"I" (_SFR_IO_ADDR(port)))
int GetEncoder(void) {
push_sfr(SREG); cli();
int e = *pEncoderValue;
pop_sfr(SREG);
return e;
}
i działało bez problemu... do czasu :-)
Oczywiście dla świętego spokoju na przyszłość... dam te volatile ;-)
P.S. Choroba... w WinAVR_20071221 program wynikowy zajmował 15023 bajty,
a po skompilowaniu w WinAVR_20090313 wyszło już 16154. Całe szczęście,
że to nie ATmega16 ;-)
Pozdrawiam
Grzegorz
Grzegorz Kurczyk
Guest
Sun Jun 14, 2009 11:46 am
Użytkownik Grzegorz Kurczyk napisał:
Quote:
Tym bardziej, że bezpieczniejszą formą funkcji będzie:
Errata. Miało być:
Bezpieczniejszą formą funkcji będzie:
Zbych
Guest
Sun Jun 14, 2009 1:35 pm
T.M.F. pisze:
Quote:
Nie wiem czemu twierdzisz, że dla zachowania atomowości potrzebne ci
jest volatile. To volatile jest w tym przypadku zbędne.
Dlatego jest potrzebne, zeby kompilator zdawal sobie sprawe, ze nie jest
to zwykla zmienna i nie robil takich kwiatkow jak na przykladzie.
Ale ty pisałeś, że jest to potrzebne do zachowania atomowości. A to nie
jest prawda.
--
przeciez moje rozumowanie bylo bez skazy,
no sam bym wskoczyl do tego wulkanu,
ale kto by tak pieknie gwizdal...
T.M.F.
Guest
Sun Jun 14, 2009 1:40 pm
Quote:
Alez byla. Twoja zmienna jest typu int, czyli ma 2 bajty. AVR nie ma
instrukcji ladowania z pamieci 2 bajtow jednoczesnie, a wiec takie
przeslanie nie jest atomowe. Dlatego musisz okreslic ta zmienna jako
volatile i zapewnic atomowosc operacji przez blokowanie przerwan.
Zauwaz, ze gdyby uzyte przeslanie 16-bitowe bylo atomowe to blokowanie
przerwan w ogole nie byloby potrzebne.
No dokładnie taki był mój tok rozumowania. Ponieważ pobranie zmiennej
int wymaga dwóch rozkazów blokuję możliwość przerwania tej operacji
przez inny wątek poprzedzając je rozkazem cli wstawionym "z palca". W
momencie gry program staje się jednowątkowy trudno mówić o ulotności
zmiennych.
Teoretycznie tak. Problem w tym, ze skad kompilator ma wiedziec, ze
wartosc zmiennej moze sie zmieniac poza glownym ciagiem instrukcji? Do
tego wlasnie sluzy volatile. Bez tego kompilator nic nie wie, ze cos
moze zmienic twoja zmienna np. w przerwaniu, w efekcie optymalizuje to
sobie jak uwaza za stosowne i z tego punktu widzenia umiejscowienie cli
w stosunu do pobrania zmiennej jest bez znaczenia.
Quote:
P.S. Choroba... w WinAVR_20071221 program wynikowy zajmował 15023 bajty,
a po skompilowaniu w WinAVR_20090313 wyszło już 16154. Całe szczęście,
że to nie ATmega16
Zapewne problem z bardziej agresywnym inlinowaniem funkcji. Mozna to
wylaczyc.
--
Inteligentny dom -
http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
T.M.F.
Guest
Sun Jun 14, 2009 1:40 pm
Quote:
Alez byla. Twoja zmienna jest typu int, czyli ma 2 bajty. AVR nie ma
instrukcji ladowania z pamieci 2 bajtow jednoczesnie, a wiec takie
przeslanie nie jest atomowe. Dlatego musisz okreslic ta zmienna jako
volatile i zapewnic atomowosc operacji przez blokowanie przerwan.
Nie wiem czemu twierdzisz, że dla zachowania atomowości potrzebne ci
jest volatile. To volatile jest w tym przypadku zbędne.
Dlatego jest potrzebne, zeby kompilator zdawal sobie sprawe, ze nie jest
to zwykla zmienna i nie robil takich kwiatkow jak na przykladzie. To
oczywiscie z atomowoscia nie ma nic wspolnego, ale lacznie generuje
poprawny kod. Ogolna zasada mowi, ze kazda zmienna uzywana w przerwaniu
i programie glownym powinna byc volatile. W szczegolnych przypadkach nie
musi byc, ale nalezy sobie zdawac sprawe z konsekwencji.
--
Inteligentny dom -
http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
Goto page Previous 1, 2, 3, 4, 5 Next