Asi jsem něco přehlédl, ale jak se bude řešit situace, kdy zavolaný podprogram bude volat další podprogram? Dojde tak přece k přepisu v registru schované původní návratové adresy....?
To ji musím ručně schovávat někam do RAM?
Starému opelíchanému assembleristovi připadá takový procesor dost primitivní. Naposled jsem podobně bez stacku řešil návraty z podprogramů na ADT4000 :-)
Něco o MMU ARMu bude?
Kdyz mate podprogram ktery bude jeste neco volat, tak proste lr registr ulozite na stack (spolu s ostatnimi registry ktere nechcete prepsat) na zacatku toho podprogramu. Na to jsou specialni instrukce LDM/STM, ktere nekem do pameti (indexovane zadanym registrem, zde stack pointerem pro ktery se tradicne vyuziva r13) ulozi seznam registru (podle bitove masky) a pouzijete variantu ktera navic ten stack pointer inkrementuje. Kod pak vypada takto
stmfd sp!, {r3,r4,r5,lr}
.... telo funkce ... zde muzu volat podprogram
ldmfd sp!, {r3,r4,r5,pc}
Vsimete si ze ldm obnovi stejne registry, s vyjimkou lr. Navratovou adresu vlozi primo do pc, cimz se provede navrat z podprogramu.
Taky se to dobre hodi pro tail recurstion elimination. Pokud volat nejakou funkci tesne pred navratem z podprogramu, prelozi to gcc takto:
stmfd sp!, {r3,r4,r5,lr}
... vnitrek funkce ...
ldmfd sp!, {r3,r4,r5,lr}
b poslednifunkce
cimz se zamezi zbytecnemu plytvani mista na zasobniku (pokud jste zvykli z lispu psat cykly pomoci rekurze tak nedojde ke zbytecnemu pouzivani zasobniku).
On ten procesor skutecne je primitivni, je to by design, neni to chyba :-) [neco jako MIPSy v prvnich verzich]
Jinak ten call se resi ruzne, podle povahy problemu. Bud se pres Rx (vetsinou R13) implementuje zasobnik v RAM, podobne jako na jinych procesorech, nebo se u nekterych subrutin preorganizuji registry tak, ze je navratova adresa ulozena do neceho jineho nez LR. Dtto s predavanim parametru - vetsinou pres registry, ktere se v subrutine pres LDM/STM mohou odlozit, ale dobry prekladac se tomu zuby nehty bude vyhybat.
O MMU ARM, SIMD atd. se jeste urcite zminim.