Keil C51 - tablica adresow funkcji

Apr 15, 2004 12 Replies

Jak zrobic w Keilu C tablice adresow funkcji ? Funkcje sa od siebie niezalezne (nie wywoluja siebie). Poniewaz kompilator zaklada, ze funkcje moga sie wywolywac to rezerwuje pamiec oddzielnie dla kazdej funkcji i w ten sposob bardzo szybko konczy sie wewnetrzny ram. Ewentualnie jak napisac jakas oszczedna funkcje, ktora na podstawie parametru wybiera inna funkcje, cos w stylu switch (ale bez niepotrzebnych rozkazow skoku, ktore pozeraja pamiec)



switch(NrFunkcji) { case 1: Funkcja1(); break; case 2: Funkcja2(); break; ... }



Pozd Gissbourne


Witam.

W manualu C do³±czonym doKeila jest do do¶æ dobrze opisane - nie ró¿ni siê to wiele od normalnego C.

Nie rozumiem - w ramie trzymasz przecie¿ tylko ich adresy (o ile korzystasz z tych wska¼ników), same funkcje znajduj± siê przecie¿ w pamiêci programu...

Je¿eli funkcje maj± ró¿ne typy (ilo¶ci) argumentów mo¿esz je przeci±¿yæ - ale to w sytuacji jakby "odwrotnej" - tablic± wska¼ników do funkcji mo¿esz siê pos³u¿yæ maj±c funkcje zwracaj±ce ten sam typ i przyjmuj±ce te same argumenty - przeci±¿anie opiera siê na przeciwnej zasadzie. pzdr, marcin

U¿ytkownik "marcinuh" snipped-for-privacy@wp.pl napisa³ w wiadomo¶ci news:c5lqdq$4b5$ snipped-for-privacy@nemesis.news.tpi.pl...

Ok, juz rozumiem - zamota³em siê ;-) Chodzi Ci o zmienne lokalne a nie o kod przecie¿ :-). pzdr, marcin

U¿ytkownik "marcinuh" snipped-for-privacy@wp.pl napisa³ w wiadomo¶ci news:c5lqdq$4b5$ snipped-for-privacy@nemesis.news.tpi.pl...

W ramie sa zmienne lokalne. Jesli zrobie tablice adresow funkcji to kompilator zaklada, ze moga wzajemnie sie wywolywac czyli wszystkie zmienne umieszcza w roznych komorkach ramu, zeby nie wystapila sytuacja, ze jedna zmienna zamazuje druga. Bez zdefiniowanej tablicy jest normalnie czyli zmienne lokalne roznych funkcji moga wykorzystywac te same komorki.

Mowiac inaczej - powiedzmy, ze mam 100 funkcji (tego samego typu - bez parametrow). Teraz chce napisac funkcje wyboru tych funkcji zaleznie od jakiejs zmiennej. Moge zrobic to za pomoca instrukcji switch i wszystko ok poza rozmiarem. Jesli zrobie wywolywanie za pomoca wskaznika to nie starcza ramu. Pozd Gissbourne

U¿ytkownik "marcinuh" snipped-for-privacy@wp.pl napisa³ w wiadomo¶ci news:c5lqdq$4b5$ snipped-for-privacy@nemesis.news.tpi.pl

S±dzê, ¿e chodzi o "variable overlaying" czyli lokowanie kilku niezale¿nych zmiennych w tym samym obszarze pamiêci danych. Np. je¿eli wiadomo, ¿e dwie funkcje _na pewno_ nie zostan± wywo³ane jednocze¶nie (nie znajduj± siê w tym samym ³añcuchu odwo³añ) to mo¿na segmenty ich zmiennych lokalnych na³o¿yæ na siebie. W przypadku wywo³ywania funkcji przez tablicê wska¼ników wystêpuj± k³opoty z ustaleniem tych zale¿no¶ci.

Proponujê uwa¿n± lekturê "C51 primera":

formatting link
ile pamiêtam, to istnieje jakie¶ rozwi±zanie (na poziomie dyrektyw linkera) ale na tyle upierdliwe, ¿e kiedy¶ w podobnym przypadku podda³em siê i zarz±dzi³em globalne "NO OVERLAY"

Sorry za brak precyzji, ale piszê z marszu a od dosyæ dawna nie mia³em z tym do czynienia

U¿ytkownik "Gissbourne" snipped-for-privacy@poczta.onet.pl> napisa³ w wiadomo¶ci news:c5lrmk$n2j$ snipped-for-privacy@atlantis.news.tpi.pl...

No tu ju¿ siê przyzna³em do zamotania ;-)

Nie wiem, jak wygl±da switch skompilowany na 51, ale ostatnio robi±c do¶æ poka¼ny interpreter poleceñ na PICku doszed³em do wniosku, ¿e nic lepszego mi nie potrzeba. My¶lê, ¿e nie unikniesz kosztów z jednej lub drugiej strony - pewne mechanizmy musz± zaj±æ albo pamiêæ, albo czas - niestety procesor to rodzaj mêski i intuicji nie posiada ;-). pzdr, marcin

Pomijajac wszystko inne to powinno byc mozliwe zadeklarowanie zainicjowanej tablicy adresow w obszarze programu. cos typu

void *(int) PROGMEM tab[]={funcja1, funkcja2,funkcja3}

czy jak to sie tam w keilu zapisuje.

J.

U¿ytkownik "Gissbourne" snipped-for-privacy@poczta.onet.pl> napisa³ w wiadomo¶ci news:c5lmnp$etr$ snipped-for-privacy@nemesis.news.tpi.pl...

Przyk³ad z ¿ycia (zdradzam swój warsztat, niech stracê ... :-) )

Keil.c:

-------- extern void execute(byte); U8 command;

command = 8; execute(command);

Keil.asm

----------------------------------------------------------------------------

---------------------------------- ; ; Adresy funkcji realizuj±cych obs³ugê poleceñ sterownika nadrzêdnego ; EXTRN CODE (SRVC_00,SRVC_01,SRVC_02,SRVC_03,SRVC_04,SRVC_05,SRVC_06,SRVC_07) EXTRN CODE (SRVC_08,SRVC_09,SRVC_10,SRVC_11,SRVC_12,SRVC_13,SRVC_14,SRVC_15) EXTRN CODE (SRVC_16)

?PR?A51_EXECUTOR segment CODE ;Deklaracja relokowalnego segmentu dla execute()

RSEG ?PR?A51_EXECUTOR ;Relokowalny segment funkcji 'execute(command)'

; ; EXECUTE ; Funkcja wyboru obs³ugi polecenia sterownika ; Wej¶cie : numer polecenia w rejestrze R7 ; Wyj¶cie : brak ; Uwagi : zastêpuje bardziej efektywnie funkcjê switch(command) napisan± w C51 ; umieszczona w odrêbnym segmencie kodu, dla u³atwienia linkerowi ; analizy wzajemnych odwo³añ funkcji ; powrót z execute() odbywa siê przy pomocy RET wybranej obs³ugi w C51 ; _execute: mov A,R7 ;Obliczenie adresu funkcji obs³ugi w tabeli add A,R7 ;Dwa bajty na AJMP mov DPTR,#jump_table jmp @A+DPTR

jump_table: ajmp SRVC_00 ajmp SRVC_01 ajmp SRVC_02 itd ... ajmp SRVC_16

----------------------------------------------------------------------------

----

Jest to wariant duuuu¿o optymalniejszy ni¿ switch(), wypróbowany w praktyce.

Pzdr,

Marek

Nice to by³o, a czy mo¿esz przytoczyæ, jak wygl±da switch skompilowany keilem? Kompilacja dla PICa daje ci±g MOVF parametr (tylko na poczatku switcha) i teraz XORLW (kolejny case) BZ (do adresu z poczatkiem kodu dla danego case) i.t.d.

czyli 2 cykle maszyny na rozpatrzenie kazdego case. pzdr, marcin

Przepraszam, 3 cykle - BZ zajmuje dwa cykle, je¿eli w jego wyniku nie jest wykonywany skok... pzdr, marcin

Trochê mi to zajê³o, ale uda³o siê powtórzyæ:

Keil.C

------------------------------------------------------- switch(command) { case 0 : srvc_00(); break; case 1 : srvc_01(); break; case 2 : srvc_02(); break; case 3 : srvc_03(); break; case 4 : srvc_04(); break; case 5 : srvc_05(); break; case 6 : srvc_06(); break; case 7 : srvc_07(); break; case 8 : srvc_08(); break; case 9 : srvc_09(); break; case 10 : srvc_10(); break; case 11 : srvc_11(); break; case 12 : srvc_12(); break; case 13 : srvc_13(); break; case 14 : srvc_14(); break; case 15 : srvc_15(); break; }

Keil.lst

--------------------------------------------------------

MOV A,R7 CJNE A,#010H,?C0219 ?C0219: JC $ + 5H R LJMP ?C0192 R MOV DPTR,#?C0220 MOV R0,A ADD A,R0 ADD A,R0 JMP @A+DPTR ?C0220: R LJMP ?C0196 R LJMP ?C0197 R LJMP ?C0198 R LJMP ?C0199 R LJMP ?C0200 R LJMP ?C0201 R LJMP ?C0202 R LJMP ?C0203 R LJMP ?C0204 R LJMP ?C0205 R LJMP ?C0206 R LJMP ?C0207 R LJMP ?C0208 R LJMP ?C0209 R LJMP ?C0210 R LJMP ?C0211 ; SOURCE LINE # 784 ?C0196: R LCALL srvc_00 SJMP ?C0192 ; SOURCE LINE # 785 ?C0197: R LCALL srvc_01 SJMP ?C0192

--------------------------------------------

Jeszcze tem switch jako tako, ale potem jest LJMP do adresu, spod którego siê dopiero robi lcall ...

Wszystko razem powodowa³o, ¿e ma³ym Atmelku (2051) nie da³o siê ju¿ upchaæ kolejnej funkcji.

Po przej¶ciu na assemblerow± wstawkê dzia³a do dzi¶ efektywnie i niezawodnie ... kto wie, mo¿e nawet ten kod wyprodukowa³ szyneczkê, któr± dzi¶ jad³e¶ na ¶niadanie ? Jest taka mo¿liwo¶æ ;-)

Pzdr,

Marek

Hehe, istotnie - jad³em dzi¶ szyneczkê ;-)). Hmm, co¶ mi tu brzydko pachnie - a je¶li za case'ami nie bêd± sta³y kolejne liczby zaczynaj±c od zera?, np:

case 0x11: bleble case 0x73: bleble case 0xAA: bleble ... To wtedy nie bêdziesz móg³ (ani kompilator) po prostu dodac do adresu pocz±tku skoków warto¶ci prze³±cznika... Dobrze kombinujê? Bo czasem nie da siê ustawiæ rozkazów w kolejno¶ci i z drugiej strony nie zawsze pod adresem (adres_pocz_skoków + prze³±cznik) mo¿na co¶ wcisn±æ... I jak wtedy by wygl±da³ taki switch? Bo ten, który przytoczy³e¶, jest cacy ;-). Sorki, je¶li co¶ krêcê i za bardzo wnikam, ale w³a¶nie zauwa¿y³em, ¿e trochê zd±¿y³ mi asm51 ulecieæ ;-). pzdr, marcin

[...]

W zasadzie musi - przeciez za kazdym razem moglby byc inny zestaw parametrow funkcji. I tak to dosc zgrabnie skompilowal ..

J.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required