Problem lekko OT, ale w WinAVR ;-)

Witam Kolegów.

Tak sobie kombinuję. Jest struktura:

typedef struct { uchar x; uchar y; uchar w; uchar h; } tRect;

i przykładowa funkcja: void Rysuj(tRect r) { Prostokat(r.x, r.y, r.x+r.w, r.y+r.h); }

Pojawił mi się problem składni języka C i nie mogę się doszukać jak to obejść. Funkcję z poziomu programu głównego możemy wywołać:

int main (void) { tRect r; r.x = 10; r.y = 20; r.w = 100; r.h = 10; Rysuj(r); }

Czy jakoś można wywołać funkcję rysuj podając jej parametry bezpośrednio bez uprzedniego definiowania zmiennej r ? Coś w stylu: Rysuj({10,20,100,10}); co oczywiście nie działa :-)

Pewnie, że można zrobić funkcję: void Rysuj(char x, char y, char w, char h) { Prostokat(x, y, x+w, y+h); } i po kłopocie, ale chodzi mi o pewną "sztuczkę" związaną z optymalizacją WinAVR w zakresie przekazywania parametrów do funkcji za pośrednictwem rejestrów.

Pozdrawiam Grzegorz

Reply to
Grzegorz Kurczyk
Loading thread data ...

Grzegorz Kurczyk pisze:

można krócej:

tRect r = {1,2,3,4}; Rysuj(r);

Na c++ trzeba się przesiąść.

Reply to
Zbych

Przyszło mi jeszcze do głowy makro:

#define RECT(__a,__b,__c,__d) ({static const tRect __r = {(__a),(__b),(__c),(__d)}; __r;})

Wtedy można napisać tak:

Rysuj(RECT(1,2,3,4));

Powinieneś tylko mieć włączone rozszerzenie standardu do gnu99.

Reply to
Zbych

W C++ moze to byc faktycznie kosztowne.

W pozostalych sytuacjach trzeba by spojrzec w kod wynikowy co lepiej kompilatorowi wyszlo.

A wracajac do meritum .. wychodzi na to ze najlepiej byloby odwrocic sprawe - zrobic funcje z 4 parametrami, a nad nia ewentualnie nadbudowac wersje ze struktura. I nie korzystac z niej bez potrzeby :-)

J.

Reply to
J.F.

Nie musi wiedziec. Ma wrzucic cala na stos, co powinno pojsc dosc szybko.

Sa to pewne zalozenia i wymagaja odpowiedniego procka. W wielu moze wyjsc odwrotnie.

No, Jesli pamietacie Piotra Wyderskiego to on to polecal od dawna, i chyba mamy przyklad ze by sie przydalo.

Choc w sumie .. jedno makro, troche dyscypliny [potrzebnej tez w ++] i mozna w zwyklym C miec trzy wersje do wyboru, dopasowujac sie do procka.

J.

Reply to
J.F.

Dziękuję wszystkim za odzew :-)

Metody opisywane przez Kolegów męczyłem już wcześniej (poza przesiadką na C++), ale nie przynoszą one spodziewanego rezultatu. Może sprecyzuję o co mi chodzi. Sprawa jest czysto "akademicka" i wynika z mojego pewnego rodzaju "zboczenia" w dążeniu do absurdalnej optymalizacji kodu wynikowego ;-) Jest tak. Funkcja zdefiniowana tradycyjnie:

void ProgressBar(char x, char y, char w, char h, char value) { .... }

przy wywołaniu: ProgressBar(0, 90, 128, 5, y);

otrzymujemy w kodzie wynikowym: 37e2: 0b 2d mov r16, r11 37e4: 25 e0 ldi r18, 0x05 ; 5 37e6: 40 e8 ldi r20, 0x80 ; 128 37e8: 6a e5 ldi r22, 0x5A ; 90 37ea: 80 e0 ldi r24, 0x00 ; 0 37ec: 0e 94 b4 17 call 0x2f68 ; 0x2f68 <ProgressBar>

I to co mnie "wkurza", to czemu łachudra przekazuje parametry w rejestrach r16, r18, r20, r22, r24 niejako promując typ char do int ? Jakby nie mógł po kolei r16..r20. Oczywiście w tym przypadku nie ma to większego znaczenia, ale przy większej ilości parametrów przekazywanych do funkcji i/lub większej ilości zmiennych lokalnych funkcji, zaczyna się kombinacja ze stosem lub z dolnymi rejestrami. Kompilator w pewnym sensie "szatkuje" sobie obszar rejestrów doprowadzając do sytuacji, że w pewnym momencie brakuje np czterech kolejnych rejestrów do zapamiętania lokalnej zmiennej typu long choć pojedynczych wolnych rejestrów jest wystarczająca ilość.

Przekazując do funkcji zmienną typu long lub wspomniany wcześniej typ tRect wszystko jest cacy w kolejnych rejestrach r20..r23.

Tak jak wspomniałem dyskusja jest czysto akademicka w stylu: "czemu kompilator robi to akurat tak, choć w assemblerze wygodniej byłoby inaczej ?" ;-)

Chyba, że w kompilatorze jest jakaś przełącznik, coby przy przekazywaniu parametrów char nie był "przekształcany" w int. Pamiętam, że starsze wersje przy poleceniu switch(zmienna_typu_char) wykonywały niepotrzebne dwubajtowe porównania na typie int.

Pozdrawiam Grzegorz

Reply to
Grzegorz Kurczyk

Nie wysilaj sie, wez lepszy procek :-)

Ja juz nie pamietam .. ale czy to gdzies nie jest w standardzie C zapisane ? cos podobnego bylo .. konwersja parametrow, a moze wyrownanie [alignment] .. Moze trzeba opcje kompilatora sprawdzic ?

J.

Reply to
J.F.

Użytkownik J.F. napisał:

Wiieeeeeem :-) ale to takie zboczenie już chyba nieuleczalne :-) z czasów 8080+2716, 8748 itp. na zasadzie czemu procedura ma zajmować 28 bajtów i 35 taktów zegara skoro może 23 bajty i tylko 31 taktów :-):-):-) W sumie to procek, na którym rzeźbię w tej chwili ma zasobów aż nadto, ale czasem tak dla sportu zaglądam do pliku .lss i patrzę co tam kompilator wysmarował. Choć czasem to musiałem do niego zajrzeć, bo niekiedy program zachowywał się nie do końca tak jak wynikałoby to z kodu źródłowego.

Pozdrawiam Grzegorz

Reply to
Grzegorz Kurczyk

Grzegorz Kurczyk pisze:

Moja rada - nie zaglądać. Ja co zajrzę to rzucam mięsem (a bo to brak optymalizacji przy adresowaniu tablic struktur, albo przy pobieraniu wielu stałych z flasha, albo przy alokacji ramki na stosie przy przekazywaniu parametrów itd.)

Reply to
Zbych

W dniu 11.06.2009 06:03, Grzegorz Kurczyk pisze:

Reply to
T.M.F.

W dniu 11.06.2009 06:03, Grzegorz Kurczyk pisze: > Witam Kolegów. >

Poza tym co radzi ci Zbych jesli zalezy ci na efektywnosci to przekazuj strukture tRect przez wskazanie: void Rysuj(tRect &t); Inaczej kompilator musi utworzyc kopie obiektu tRect i ta kopie dopiero przekazac do funkcji.

Reply to
T.M.F.

W C tez powinno byc kosztowne. Bo skad kompilator ma wiedziec, ze Rysuj nie modyfikuje struktury tRect? Mozna go wspomoc poprzez const, ale IMHO wskazanie ma pare zalet o ktorych za chwile.

Niekoniecznie. 4 parametry to w idealnym przypadku 4 8-bitowe rejestry. Zazwyczaj wiaze sie to z ich wczesniejszym odlozeniem na stosie i potem ponownym pobraniem. Przy przekazaniu przez wskazanie mamy tylko dwa

8-bitowe rejestry wskazujace na strukture, co wiaze sie zmniejszym nakladem na przekazanie parametrow. W procedurze czesto jest to optymalizowane jako LD Rx,Z+y, lub podobne. OT: to co chce zrobic autor wydaje sie lepiej zrealizowac w C++. BTW, w moim repozytorium SVN jest przyklad sterownika do S65 z cala biblioteka prymitywow w C++.
Reply to
T.M.F.

Zbych pisze:

A ja ostatnio sporo dziubię na ARMa w gcc i przeglądając listing asemblerowy co chwila dziwię się, jak to optymalizator ładnie wykoncypował, że sam bym lepiej w asemblerze nie napisał. Tak że jedyna rada - zmienić platformę.

Reply to
Adam Dybkowski

Adam Dybkowski pisze:

To pokaż mi jeszcze ARMa, który po zatrzymaniu zegara pobiera < 1uA.

Reply to
Zbych

T.M.F. pisze:

Nie przesadza, wystarczy sprawdzić.

Reply to
Zbych

Zbych pisze:

A cóż to za wymaganie? 1uA to pobiera dobry RTC a nie mikrokontroler.

AVRy mają prąd upływu do 1uA na każdy pin I/O (patrzę w PDFa pierwszej z brzegu ATmegi 128) plus dodatkowo typowo 5uA (max. 10uA) w najgłębszym power-down i to przy wyłączonym watchdogu. Oprócz tego każdy obciążony pull-up zjada nieco prądu (typowa rezystancja to 20-50 kOhm). Daleko stąd raczej do magicznego 1uA.

Jak chcesz oszczędzać prąd to bierz się raczej za rodzinę MSP430 a nie AVRy.

Reply to
Adam Dybkowski

Tak sie nie da. Jesli tRect jest gdzies dalej wykorzystywany to kompilator musi utworzyc jego kopie, zeby zagwarantowac, ze Rysuj jej nie zmodyfikuje - to wynika ze standardu. Oczywiscie optymalizator moze zauwazyc, ze nasze tRect jest dalej niewykorzystywane i z tego etapu zrezygnowac - no ale to juz zaklada, ze optymalizator jest dosc sensowny. W tym przypadku zapewne sobie poradzi. Jesli przekazesz adres struktury bedzie to zawsze dzialac jak nalezy.

Ale mowimy konkretnie o AVR i AVR-gcc.

Reply to
T.M.F.

W dniu 11.06.2009 10:16, Grzegorz Kurczyk pisze:

Jakiej wersji gcc uzywasz? Ja tu nigdzie nie widze promocji do int bo starsze czesci tych rejestrow nie zawieraja zera.

Sprawdz jak to sie zachowa przy wiekszej ilosci parametrow. Zapewne kompilator bedzie oszczedniej gospodarowal rejestrami. Zauwaz, ze w twoim przykladzie nie ma takiej potrzeby, a wygenerowany kod jest tak samo efektywny.

Reply to
T.M.F.

Cos Zbych przesadza. Tak sobie patrze w swoje programy i tez na AVR gcc ladnie optymalizuje. Czasami pobieznie patrzac na kod wydaje sie, ze mozna by cos zrobic lepiej, ale przy dokladniejszym spojrzeniu okazuje sie, ze jednak nie.

Reply to
T.M.F.

Zobacz np. ATMega48PA/88PA/168PA/328PA. W uspieniu prad 0,8 mikroA. Przy normalnym dzialaniu z zegarem 20MHz prad 2-3mA. ARMy sie do tego nawet nie zblizaja.

Reply to
T.M.F.

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.