|
Klicanje zbirniških funkcij iz programskega jezika C Besedilo vaje: V zbirniku z naborom ukazov arhitekture ARM napišite funkcijo, ki sešteje dve poljubni nepredznačeni celi števili. Funkcija naj prejme štiri argumente. Prvi trije so kazalci na vsoto in oba seštevanca, četrti argument pa podaja število 32-bitnih besed, s katerimi je posamezno celo število zapisano. Funkcija naj vrne končni prenos. Razlaga: Program napišete v razvojnem okolju, ki teče na osebnem računalniku. Pripravljen delovni prostor (angl. workspace) z vsemi pripadajočimi datotekami najdete tukaj. V njem se poleg nastavitev projekta nahajajo tudi datoteke s spremljajočo zbirniško izvorno kodo in izvorno kodo v programskem jeziku C. Datoteka crt0.s vsebuje zagonsko kodo mikrokrmilnika. Po končanem zagonu pristanemo v funkciji start_up(), ki se nahaja v datoteki startup.c. Tukaj s klicem funkcije init() mikrokrmilnik inicializirate. Preizkus delovanja zbirniške funkcije za seštevanje poljubnih nepredznačenih celih števil boste izvedli v funkciji main(), ki se nahaja v datoteki main.c. Zbirniško funkcijo napišete v pripravljeni datoteki sum.s. Vsako izmed nepredznačenih celih števil, tako seštevanca kot vsota, je v našem primeru zapisano z eno ali več 32-bitnimi besedami. Takšno število je s stališča programskega jezika C pravzaprav polje 32-bitnih besed. Tako na primer 256-bitno število number deklariramo kot polje osmih 32-bitnih besed, za kar lahko uporabimo tip int: int number[8]; Besede number[7], number[6], ..., number[0] imajo skupaj 256 bitov in predstavljajo eno 256-bitno število, pri čemer naj ima beseda number[0] najnižjo, number[7] pa najvišjo težo. Zbirniška funkcija, ki jo moramo napisati, zna sešteti nepredznačeni števili zapisani s poljubnim številom 32-bitnih besed. Za primer je podan klic funkcije iz programskega jezika C. Funkcija, imenujmo jo add(), sešteje dve 256-bitni števili:
#define LEN_32 8
Po vrnitvi se vsota nahaja v polju sum, prenos pa v spremenljivki c. Pri pisanju zbirniških funkcij, ki jih lahko kličemo iz programskega jezika C, moramo upoštevati dogovor o podajanju argumentov in vračanju rezultatov, ki določa vlogo posameznih delovnih registrov. Pravila dogovora so enostavna in jih bomo na kratko opisali v naslednjem odstavku. Procesno jedro ARM7 mikrokrmilnika ima 16 32-bitnih delovnih registrov r0 do r15. Ob klicu se argumenti funkcije nahajajo v delovnih registrih r0 do r3, in sicer prvi argument v registru r0, drugi v r1 itd. Če je argumentov več, se preostali argumenti nahajajo na skladu. Na vrhu sklada se nahaja peti argument, po njim šesti itd. Kazalec sklada je register r13. Naslov vrnitve se nahaja v registru r14. Ob vrnitvi naj se vrnjena vrednost nahaja v registru r0. Zbirniška funkcija s svojo kodo ne sme spremeniti registrov r4 do r11, katerih vrednosti ob vrnitvi morajo biti enake vrednostim ob klicu. Prav tako se mora ohraniti vrednost kazalca sklada r13, saj bi v nasprotnem primeru pokvarili sklad. Register r12 je namenjen začasnemu shranjevanju, register r15 pa je programski števec. Naša zbirniška funkcija prejme štiri argumente. Naslov, kjer je prostor za vsoto, naslova obeh seštevancev in število 32-bitnih besed. Opraviti imamo s štirimi 32-bitnimi podatki, ki jih prejmemo v registrih r0 do r3. Noben argument ni shranjen na skladu. Ob vrnitvi se končni prenos nahaja v registru r0. Algoritem funkcije podaja spodnja slika.
Najprej na sklad shranimo vrednosti tistih delovnih registrov, ki se morajo ohraniti, a se bodo med izvajanjem funkcije spremenili. Za pravilno odlaganje podatkov je potrebno poznati zgradbo sklada. Sklad narašča proti nižjim naslovom, kazalec sklada pa kaže na zadnje zasedeno mesto. Seštevamo po 32-bitov naenkrat. Ob vsakem naslednjem seštevanju upoštevamo prenos iz prejšnjega seštevanja. To naredimo tolikokrat, kolikor je 32-bitnih besed. Končni prenos predstavlja vrnjeno vrednost. Pred vrnitvijo iz sklada poberemo vse odložene vrednosti delovnih registrov. | |