Friday, June 17, 2011

HW: Realizacia riadiacich struktur a podpora volania podprogramu

Zacnime tym, ako v assembleri (jazyku symbolickych instrukcii ako by basnik riekol :) ) skaceme a potom si povieme, ako tato ficura funguje.

Skoky mozme delit na podmienene a nepodmiene. Skoky musime nejako adresovat a to robime PC-relativne (kratke skoky), absolutne (dlhe skoky a volanie podprogramov), registrovo nepriamo (case a dynamicke volania), co vyuzivaju vacsinou objektove jazyky a dynamicke kniznice (DLL). Vid sposoby adresacie.

Ako su skoky implementovane v ISA? Napriklad instrukciou Compare and Branch.

BGT R1, R2, WhereToGO #skoc ak R2 je vacsia ako R1
BLT R1, #57, label

Ak by toto bola len jedna instrukcia, tak by sme sa lahko dostali do problemov v prudovom spracovani, pretoze toto je na jednu instrukciu proste mnoho prace. Dalsim problemom by bolo, ako zakodovat konstantu pre porovnanie a offset skoku do jedneho kodu instrukcie. Kvoli tymto problemom delime instrukcie na porovnanie a skok. Funguje to na jednoduchom principe. Prva instrukcia vyhodnoti podmienku, niekam ju ulozi a druha podmienka vykona skok na zaklade podmienky. Miesto, kam sa vysledok vyhodnotenia ulozi je 

  • bud implicitne, typicky register priznakov 
  • alebo explicitne miesto, co su typicky dedikovane alebo univerzalne registre 
Explicitne miesto je specifikovane v instrukcii, ktora vyhodnocuje podmienku. Implicitne miesto je dane "natvrdo". Register priznakov ale moze byt nastaveny ako postranny efekt ALU instrukcie. To znamena, ze register sa moze nastavit aj po instrukcii SUB  alebo ADD. Dedikovana instrukcia pre porovnanie je "compare/test"  CMP. Podmieneny skok sa potom rozhoduje na zaklade registra priznakov. Ukazeme si to na priklade 

SUB r7, r4, r3    #r7 <- r4-r3 a zaroven sa nastavi register priznakov
BRP X               #na zaklade registra priznakov sa uskutocni, alebo neuskutocni skok

SUB r7, #1, r5    #register priznakov sa v tomto pripade nenastavi 
CMP r7, #0        #if r7 == 0 set register else don't set :)
BRP X                #skoc podla hodnoty v registri priznakov 

Nastavovanie priznakov ma svoje slabsie stranky. Nie vsetky instrukcie nastavuju register priznakov rovnako. V pripade pipeline by len jeden register priznakov mohol priniest iste problemy :) a teda, register priznakov sa moze stat uzkym hrdlom pre prudove zpracovanie instrukcii. 


Kazda architektura riesi tento problem inak (samozrejme, co by sme sa potom ucili). PowerPC pouziva 8 nezavislych tzv. podmienkovych registrov (Condition Registers). Kazda ALU instrukcia a instrukcia porovnania potom specifikuje jeden z 8 registrov. Zlozitejsie podmienky je mozne vyhodnocovat medzi viacerymi registrami. IA 64 (Itanium) zase pouziva 128 dedikovanych 1-bitovych podmienkovych registrov. Instrukcie potom mozu nastavit az dva predikatove registre, jeden pri splneni a druhy pri nesplneni podmienky. Vykonavanie kazdej instrukcie je potom mozne na zaklade stavu predikatoveho registru. 

Aby toho nebolo uplne malo, tak podmienene skoky je mozne implementovat pomocou general purpose registers. 

BEQZ R5, label    #branch if R5 is equal to 0
BNEZ R5, label    #branch if R5 is not equal to 0

Tak, aby sme to zhrnuli :), tak mame viacero zakladnych implementacii. 
  • predikatove registre (== podmienkove registre)
  • univerzalne registre 
  • priznaky 
  • alebo len jedna podmienka skoku
Instrukcie by boli vyriesene. Mame ale ine problemy. 
  • Kam ulozit navratovu adresu pri navrate z podprogramu?
  • Ako predavat premenne? 
  • Ako vratit navratovu hodnotu? 
  • Kde alokovat miesto pre lokalne premenne a medzivysledky? 
CISC to riesi zasobnikom a RISC tiez zasobnikom, ale s tym rozdielom, ze RISC by sa volaniu zasobnika najradsej uplne vyhol pomocou inliningu. 

Na kopii slajdu je mozne vidiet deklaraciu a volanie procedury. Deklaracia prebehla z rel. adresy 006789AB a volanie prislo o nieco neskor z adresy 00000128. Ich rozdiel dal adresu, kam sa nakoniec po proceduru "saha" a kam bola zavedena. Po ukonceni behu procedury sa znovu vratime na adresu, na ktorej sme skoncili. Ta bola ulozena na zasobniku pocas behu procedury. Pri navrate si ju teda "popneme" a hotovo.  

Taketo riesenie pomocou zasobnika sa nazyva riesenie pomocou aktivacnych zaznamov. 

Pracujeme s frame pointerom a stack pointerom. Pred zavolanim podporgramu je FP == SP. Pri volani podrogramu sa na zasobnik ulozia vsetky potrebne hodnoty, registre, parametre pre podprogram, stray FP a navratova adresa. Zasobnik moze odkazovat na nadriadeny AZ (vnorenie podprogramov). Data su adresovane relativne voci FP alebo SP. Co presne je do AZ ulozene je dane ABI (Application Binary Interface). 

Architektury ako VAX, x86, DOP obsahuju dedikovane registre pre SP a niekedy aj FP. RISC obcas implementuje zasobnik ako SW konvenciu. Dalsou moznostou je pouzit GPR. 

Dalsou moznostou su registrove okna (SPARC). SPARC pouziva GPR a registre deli na globalne, lokalne, vstupne a vystupne. Vystupne registre nadriadeneho programu sa stavaju vstupnymi registrami volaneho podprogramu. Volany podprogram tak ziska nove vystupne a lokalne registre a moze makat. Na vstupne registre sa potom ulozi navratova hodnota a na tieto registre sa ulozi aj navratova adresa. 

Registrove okna su mapovane na registrove pole. Pocet registrov zavisi na implementacii. Ramec na zasobniku je automaticky vytvoreny k pripadnej uschove v pripade overflowu okien a pre dalsie parametre. Registrove okna mozu pretiect a registrove pole s reg. oknami moze viest k znizeniu Tclk. 





Ostava nam este vyjasnit ako si programy predavaju premenne.Predavanie premennych funguje trochu inak, ako u vyssich programovacich jazykov.

  • pomocou registrov
  • prostrednictvom pamate
  • pomocou tabulky parametrov 
  • prostrednictvom zasobniku
Predavanie pomocou registrov funguje tak, ze program nieco hodi na register a volany program si potom z toho registra vezme premennu. Ak sa vyuzije zdielana pamat, tak musim vediet adresu pamate. Parametre sa potom ukladaju do takych casti pamate, ktore su zdielane. 

Predavanie poomcou tabulky parametrov vlastne znamena, ze premenne sa ulozia do bloku pamate a preda sa len zaciatok pamatoveho bloku. Kazde volanie procedury ma pamatovy blok s rovnakou strukturou umiestneny na inom mieste pamate. 

Predavanie parametrov pomocou zasobniku funguje tak, ze pred volanim procedury sa skutocne parametre ulozia na zasobnik a po vstupe do procedury sa tieto parametre pouziju. Po navrate z procedury je zase potreba tieto parametre zo zasobniku odstranit pomocou instrukcie RET vyraz, kde vyraz je pocet odstranenych bitov zo zasobnika. Predavanie pomocou zasobnika je vyhodne u rekurzivnych procedur.