Budapesti M˝ uszaki ´ es Gazdas´ agtudom´ anyi Egyetem Villamosm´ern¨oki ´es Informatikai Kar Ir´ any´ıt´ astechnika ´es Informatika Tansz´ek
´ m´ Uj odszer algoritmusok VHDL-be to en˝ o transzform´ aci´ oj´ ara Haskell ¨rt´ funkcion´ alis nyelvb˝ ol kiindulva TDK Dolgozat
K´esz´ıtette
Konzulens
Suba Gergely
dr. Arat´o P´eter
2011. okt´ober 28.
Tartalomjegyz´ ek K¨ osz¨ onetnyilv´ an´ıt´ as
2
Kivonat
3
Bevezet˝ o
4
1. A ford´ıt´ as ki- ´ es bemenete
8
1.1. A Haskell nyelv ´es saj´ atoss´ agai . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.1.1. Lambda-kalkulus . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
1.1.2. T´ıpusrendszer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.2. A Haskell GHC ford´ıt´ o f¨ obb tulajdons´agai . . . . . . . . . . . . . . . . . . . 12 1.2.1. K¨ oztes reprezent´ aci´ o - a Core nyelv . . . . . . . . . . . . . . . . . . . 12 1.2.2. Primit´ıv t´ıpusok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.2.3. F¨ uggv´enybehelyettes´ıt´es . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.3. A VHDL nyelv ´es saj´ atoss´ agai . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2. A ford´ıt´ asi m´ odszer alapelvei ´ es megval´ os´ıt´ asa
19
2.1. Az egyes modulok interf´eszei . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.1.1. Bemeneti forr´ ask´ od . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.1.2. Elemi m˝ uveleti gr´ af . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.1.3. Kimeneti hardverle´ır´ as . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.1.4. M˝ uvelethalmaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.2. Forr´ ask´ od ford´ıt´ asa elemi m˝ uveleti gr´afra . . . . . . . . . . . . . . . . . . . 30 2.2.1. Forr´ ask´ od magasszint˝ u feldolgoz´asa . . . . . . . . . . . . . . . . . . . 32 2.2.2. El´ agaz´ asok ´ atalak´ıt´ asa . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.2.3. Iter´ aci´ ok ´ atalak´ıt´ asa . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.2.4. Alkalmaz´ asok ´ atnevez´ese . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.2.5. H´ıv´ asi f´ ara t¨ ort´en˝ o´ atalak´ıt´as . . . . . . . . . . . . . . . . . . . . . . 37 2.2.6. Faegyszer˝ us´ıt´es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 2.2.7. Elemi m˝ uveleti gr´ afra t¨ort´en˝o ´atalak´ıt´as . . . . . . . . . . . . . . . . 41 2.3. Elemi m˝ uveleti gr´ af ford´ıt´ asa hardverle´ır´o nyelvre . . . . . . . . . . . . . . . 42 2.4. Alap m˝ uvelethalmaz defini´ al´ asa . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.4.1. A m˝ uvelethalmazok k¨otelez˝o elemei . . . . . . . . . . . . . . . . . . 43 2.4.2. Egyszer˝ u alapm˝ uveletek . . . . . . . . . . . . . . . . . . . . . . . . . 45 ii
3. A m´ odszer kiterjeszt´ ese t¨ obbsebess´ eg˝ u (multi-rate) probl´ em´ akra 48 3.1. T¨ obbsebess´eg˝ u adatfolyamok a ford´ıt´as interf´eszein . . . . . . . . . . . . . . 49 3.1.1. T¨ obbsebess´eg˝ u elemi m˝ uveleti gr´af . . . . . . . . . . . . . . . . . . . 49 3.1.2. A bemeneti forr´ ask´od . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.1.3. Kimeneti hardverle´ır´as . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.2. A ford´ıt´ asi algoritmus kiterjeszt´ese . . . . . . . . . . . . . . . . . . . . . . . 55 3.2.1. MapConversion transzform´aci´o . . . . . . . . . . . . . . . . . . . . . 56 3.2.2. A hierarchia automatikus fel´ep´ıt´ese . . . . . . . . . . . . . . . . . . . 56 3.3. A m˝ uvelethalmaz kiv˝ ov´ıt´ese . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.3.1. Stream m˝ uveletek . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.3.2. T¨ omb m˝ uveletek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4. A m´ odszer gyakorlati alkalmaz´ asa mintafeladatokon
61
4.1. PID szab´ alyoz´ o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.1.1. A ford´ıt´ as l´ep´esei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.1.2. Szimul´ aci´ o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 4.2. MP3 dek´ odol´ o algoritmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 4.2.1. VHDL szimul´ aci´ os eredm´enyek . . . . . . . . . . . . . . . . . . . . . 75 5. Tov´ abbfejleszt´ esi lehet˝ os´ egek
76
5.1. Optimaliz´ al´ asi l´ep´esek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.2. Egyebek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 ¨ 6. Osszefoglal´ as
78
Irodalomjegyz´ ek
83
Fu ek ¨ ggel´
84
F.1. Stream m˝ uveletek VHDL k´odja . . . . . . . . . . . . . . . . . . . . . . . . . 84 F.2. T¨ omb m˝ uveletek VHDL k´odja . . . . . . . . . . . . . . . . . . . . . . . . . . 86 F.3. Az Haskell nyelven implement´alt szint´ezis program ford´ıt´oi napl´oja . . . . . 88
iii
´ NYILATKOZAT HALLGATOI Alul´ırott Suba Gergely, hallgat´o kijelentem, hogy ezt a TDK dolgozatot meg nem engedett seg´ıts´eg n´elk¨ ul, saj´ at magam k´esz´ıtettem, csak a megadott forr´asokat (szakirodalom, eszk¨oz¨ ok stb.) haszn´ altam fel. Minden olyan r´eszt, melyet sz´o szerint, vagy azonos ´ertelemben, de ´ atfogalmazva m´ as forr´asb´ol ´atvettem, egy´ertelm˝ uen, a forr´as megad´as´aval megjel¨ oltem. Hozz´ aj´ arulok, hogy a jelen munk´am alapadatait (szerz˝o(k), c´ım, angol ´es magyar nyelv˝ u tartalmi kivonat, k´esz´ıt´es ´eve, konzulens(ek) neve) a BME VIK nyilv´anosan hozz´af´erhet˝ o elektronikus form´ aban, a munka teljes sz¨oveg´et pedig az egyetem bels˝o h´al´ozat´an kereszt¨ ul (vagy autentik´ alt felhaszn´ al´ ok sz´ am´ara) k¨ozz´etegye. Kijelentem, hogy a beny´ ujtott munka ´es annak elektronikus verzi´ oja megegyezik.
Budapest, 2011. okt´ ober 28.
Suba Gergely hallgat´o
K¨ osz¨ onetnyilv´ an´ıt´ as Szeretn´ek k¨ osz¨ onetet mondani konzulensemnek, Dr. Arat´o P´eternek a TDK dolgozat k´esz´ıt´ese sor´an ny´ ujtott tan´ acsok´ert ´es az´ert, hogy k´erd´eseimmel b´armikor fordulhattam hozz´a.
A jelen dolgozatot t´ amogatta a 72611 sz. Feladatf¨ ugg˝o t¨obbprocesszoros rendszerek ” tervez´ese” c´ım˝ u OTKA kutat´ asi t´ema az Ir´any´ıt´astechnika ´es Informatika Tansz´eken.
2
Kivonat B´ar egyre nagyobb a hagyom´ anyos, processzoros rendszerek m˝ uk¨od´esi sebess´ege, kifejezetten id˝ oig´enyes feladatok, bonyolult biol´ogiai, fizikai sz´am´ıt´asok sz¨ uks´egess´e teszik, hogy az ´altal´ anos c´el´ u processzorokn´ al hat´ekonyabb hardverstrukt´ ur´akat, esetenk´ent c´elhardvereket fejlessz¨ unk a probl´ema megold´as´ara. Ezeket a hardverstrukt´ ur´akat ´altal´aban hardverle´ır´ o nyelveken (HDL) implement´alj´ak. A matematikusok, informatikusok el˝ott ezek a nyelvek ´ altal´ aban kev´esb´e ismertek, ˝ok az algoritmusokat ´altal´anos programnyelveken fogalmazz´ ak meg. A hardverle´ır´ o ´es ´altal´anos programnyelvek nagyon elt´er˝o m´odon haszn´alhat´ oak (a k´et m´ odszert szinte szakad´ek v´alasztja el egym´ast´ol), ´es k¨oz¨ott¨ uk az ´atj´ar´ as lehet˝os´ege csek´ely. Az ´ atj´ ar´ as megold´as´ara jelenleg is sz´amos kutat´as folyik, ezek a m´odszerek rendk´ıv¨ ul l´enyeges r´esz´et k´epezik az u ´n. rendszerszint˝ u szint´ezisnek. Egy funkcion´ alis nyelvb˝ ol kiindul´o hardverszint´ezisnek t¨obb el˝onye is van a hardverle´ır´o nyelven t¨ ort´en˝ o implement´ al´ashoz k´epest. A fejleszt´es gyorsabb a magasabb szint˝ u absztrakci´ onak k¨ osz¨ onhet˝ oen, az algoritmus v´altoztat´asa eset´en a hardverm´odos´ıt´as pedig k¨onnyebben kivitelezhet˝ o, mert egy funkcion´alis nyelvi program az algoritmusb´ol k¨ozvetlen¨ ul ´es j´ oval egyszer˝ ubben k´epezhet˝o, mind egy HDL le´ır´as. A HDL-re val´o ford´ıt´as pedig a jelen dolgozatban kifejlesztett ford´ıt´oprogrammal el˝ony¨osen automatiz´alhat´o. A funkcion´alis nyelvi programk´ od futtathat´o PC-n, ez´altal k¨onnyen tesztelhet˝o, ezzel szemben a hardverle´ır´ o nyelvek bonyolult szimul´aci´oval ´erik el ezt a funkci´ot, ahol r´aad´asul a be- ´es kimeneteket digit´ alis jelszintekk´ent kezelik, tov´abb bonyol´ıtva ezzel a tesztel´est. Fentiek alapj´ an a TDK dolgozatomban egy olyan elj´ar´as (ford´ıt´oprogram) kidolgoz´asa, implement´ al´ asa ´es tesztel´ese a c´elom, amelyek kiindul´opontja a funkcion´alis nyelven le´ırt k´od. A funkcion´ alis nyelvek k¨ oz¨ ul a Haskell nyelvre koncentr´alok, ami egy igen lend¨ uletesen fejl˝od˝o, a kutat´ omunk´ at el˝ ony¨ osen t´amogat´o nyelv. Az elj´ ar´ as f˝ o el˝ onye, hogy automatikusan gener´alja a bizonyos megk¨ot´esekkel rendelkez˝ o Haskell nyelvi k´ odb´ ol az FPGA-ba szintetiz´alhat´o VHDL le´ır´ast. A ford´ıt´asi folyamatba beilleszthet¨ unk ak´ ar egy olyan pipeline optimaliz´al´o fokozatot, mint pl. az Ir´any´ıt´astechnika ´es Informatika Tansz´eken fejlesztett PIPE tervez˝o programrendszert. Az elj´ ar´ as hat´ekonys´ ag´ at az MP3 dek´odol´o algoritmus r´eszlet´en szeml´eltetem.
3
Bevezet˝ o TDK dolgozatom sor´ an olyan m´ odszert dolgoztam ki, amely egy bizonyos megk¨ot´esekkel rendelkez˝ o funkcion´ alis nyelven le´ırt algoritmust hardverle´ır´o nyelvre ford´ıt, ez´altal egy kereskedelmi forgalomban kaphat´ o FPGA-s fejleszt˝ok¨ornyezetet seg´ıts´eg¨ ul v´eve a magasszint˝ u le´ır´ asb´ ol konkr´et hardvermegval´os´ıt´ast kaphatunk. Mindezt ford´ıt´oprogramk´ent implement´altam, amellyel a m´ odszer gyakorlati alkalmazhat´os´ag´at demonstr´alom. Sokszor el˝ ofordul´ o ig´eny, hogy egy adott alkalmaz´ast hardverk´ent implement´aljunk. Bizonyos probl´em´ ak eset´en ´ıgy sokkal hat´ekonyabb ´es nagyobb sebess´eg˝ u feladatv´egrehajt´ast ´erhet¨ unk el, egy PC fogyaszt´ as´ anak t¨ ored´eke ´ar´an. M´askor konkr´et c´el lehet a hardverben t¨ort´en˝o futtat´ as, mert az algoritmus egy nagyobb hardverrendszer r´esze, ´es nem szeretn´enk PC-t csatlakoztatni a rendszerhez. A rendszerszint˝ u szint´ezis ´es a hardver-szoftver egy¨ uttes szint´ezis sor´an sz¨ uks´eges, hogy legal´ abb r´eszfeladatokat hardverben implement´aljunk. Egy algoritmust ´ altal´ aban sokkal k¨ onnyebb magasabb szint˝ u, szoftveres nyelveken megfogalmazni, mint hardverle´ır´ ask´ent. A matematikusok ´es informatikusok vil´agk´ep´ehez is k¨ozelebb ´allnak a magasabb szint˝ u nyelvek. A dolgozatom a szoftveres ´es hardveres n´ez˝opont k¨ ul¨onbs´egeinek ´ athidal´ as´ ara ad seg´ıts´eget; az elj´ar´as magasszint˝ u nyelvi le´ır´asb´ol automatikusan gener´ alja a hardverhez k¨ozeli VHDL k´odot. A magasszint˝ u nyelveken bel¨ ul a funkcion´alis megk¨ozel´ıt´esre koncentr´alok. Ezek a nyelvek (pl. Erlang, SML, Haskell) a deklarat´ıv nyelvcsal´adba tartoznak, ´es legf˝ok´eppen abban k¨ ul¨onb¨oznek az imperat´ıv nyelvekt˝ ol (ilyen pl. a C, Java), hogy explicit vez´erl´esfolyamot nem defini´alnak. Ez azt jelenti, hogy egy deklarat´ıv nyelv azt ´ırja le, mit kell v´egrehajtania az algoritmus adott l´ep´es´enek, nem azt, hogy ezeket pontosan hogyan, milyen sorrendben kell tennie. Ez a tulajdons´ aga k´enyelmess´e teszi ezeket a nyelveket arra, hogy hardvergener´al´as bemenetek´ent haszn´ aljuk, mert explicit vez´erl´es´araml´as n´elk¨ ul a p´arhuzamosan futtathat´o r´eszek a le´ır´ asb´ ol egyszer˝ uen ad´odnak. A funkcion´ alis nyelvek a hardverben t¨ort´en˝o implement´al´as szempontj´ab´ol rendelkeznek egy´eb fontos el˝ ony¨ okkel is. Kiz´ arj´ak pl. a glob´alis v´altoz´ok defini´al´as´at, teh´at nem hozhatunk l´etre olyan v´ altoz´ ot, aminek az ´ert´ek´et t¨obb f¨ uggv´eny t¨orzs´eb˝ol is megv´altoztathatjuk. M´eg enn´el is nagyobb el˝ ony, hogy minden v´altoz´o csak egyszer kaphat ´ert´eket, amit ´eletciklusa v´eg´eig meg˝ oriz. Az ilyen t´ıpus´ u v´altoz´o k¨onnyen reprezent´alhat´o bitenk´ent egy flip-floppal, vagy nagyon egyszer˝ u esetben bitenk´ent egy vezet´ekkel. Ezeket a nyelveket nagyon sokszor haszn´alj´ak ´altal´anos, szoftveres k¨ornyezetben. Az el˝onyei szembet˝ un˝ oek gr´ afok fel´ep´ıt´esekor ´as bej´ar´asakor, l´ancolt list´ak kezel´esekor, de m´as algoritmusok eset´eben is van l´etjogosults´aguk. A tiszta funkcion´alis programoz´ast k¨ovetve
4
nagyon j´ ol u ´jrahaszn´ alhat´ o, kevesebb hibalehet˝os´eget mag´aban foglal´o programokat ´es modulokat fejleszthet¨ unk. A funkcion´ alis nyelv ´es hardverle´ır´as k¨oz¨otti ford´ıt´as kutat´as´anak manaps´ag megvan a kell˝o l´etjogosults´ aga. M´ıg imperat´ıv nyelvr˝ol, pontosabban C-r˝ol ford´ıt´o HLS (magasszint˝ u logikai szint´ezis) programok kereskedelemi forgalomban is kaphat´oak ([1],[2],[3]), ugyanez nem mondhat´ o el a funkcion´ alis nyelvek ter´en. Matematikusoknak kifejezetten el˝ony¨ os lehet funkcion´ alis nyelvet haszn´ alni, mert a vil´agk´ep¨ ukh¨oz sokkal k¨ozelebb van ez a fajta programoz´ asi paradigma. Amennyiben hat´ekonys´agi okokb´ol egy funkcion´alis nyelven meg´ırt algoritmust hardverben szeretn´enek futtatni, manaps´ag erre kev´es lehet˝os´eg ad´ odik, ´es azok is k´ıs´erleti, kiforratlan st´adiumban vannak. A dolgozatom c´elkit˝ uz´ese teh´ at egy funkcion´ alis bemenetr˝ ol t¨ ort´en˝o automatiz´alt hardverle´ır´as-gener´al´as, aminek sor´ an figyelembe kell venni a jelenleg alapkutat´asi szakaszban l´etez˝o megold´asokat. Dolgozatom k´esz´ıt´ese sor´ an bemeneti funkcion´alis nyelvk´ent a Haskell egy megszor´ıtott v´altozata mellett d¨ ont¨ ottem, az indokaim a k¨ovetkez˝ok: • ez egy nagyon dinamikusan fejl˝od˝o nyelv • a Haskell-hez rendelkez´esre ´all egy, az elm´ ult k´et ´evtizedben folyamatosan fejlesztett, viszonylag j´ ol dokument´ alt ford´ıt´oprogram (GHC) • a GHC ford´ıt´ o k¨ oztes reprezent´aci´oit k¨onyvt´ari f¨ uggv´enyekkel k´ezben lehet tartani, teh´ at saj´ at ford´ıt´ o ´ır´ asakor felhaszn´alhat´oak a GHC m´ar megl´ev˝o algoritmusai is • el˝ otanulm´ anyaim sor´ an megismerkedtem, ill. egy tansz´eki kutat´as keret´eben m´ ar foglalkoztam a nyelvvel, ´es ez alatt megptapasztaltam az el˝onyeit m´as nyelvekhez (pl. Erlang ´es SML, ezeket el˝otanulm´anyaimb´ol szint´en ismerem) k´epest Hab´ ar a konkr´et megold´ asom a Haskell nyelvhez k¨ot˝odik, nem lenne neh´ez ´att´erni m´ as funkcion´ alis nyelvekre, hiszen a t¨obbi funkcion´alis nyelvnek is a k´es˝obbiek sor´an ismertetett lambda-kalkulus az alapja. Ahogy azt m´eg r´eszletesen taglalni fogom, egy ´altal´anos Haskell k´od nem k´epzelhet˝ o el hardverszint´ezis bemenetek´ent, ez´ert ´esszer˝ u megk¨ot´esek ut´an a 2. fejezetben defini´alni fogok egy ford´ıtand´ o r´eszhalmazt. A k¨ ovetkez˝ okben ´ attekintem azokat a megl´ev˝o, szakirodalomb´ol ismerhet˝o ford´ıt´okat, amelyek funkcion´ alis nyelv˝ u forr´ ask´odb´ol hardvert vagy hardverle´ır´o nyelvet gener´alnak. Lava: A Lava [16] egy Haskell alapokon nyugv´o hardverle´ır´o nyelv. Defini´al k¨ ul¨onf´ele hardverben k¨ ozvetlen¨ ul alkalmazhat´ o t´ıpusokat ´es kombin´atorokat, viszont egy ´altal´anosabb (lehet ak´ ar rekurzi´ omentes) Haskell forr´ask´odot nem tud leford´ıtani. A Lava hardverk¨ozeli nyelv, teh´ at a dolgozatom egyik f˝o c´elkit˝ uz´es´et nem teljes´ıti, m´egpedig, hogy a hardveres vil´agt´ol elszakadt, szoftveres fogalmakkal fel´ep´ıthet˝o forr´ask´odot haszn´alhassunk a szint´ezis bemenetek´ent. (a Lava-ban pl. az el´agaz´ast is a hardveres vil´agb´ol ismert multiplexerrel kell megoldanunk, nem pedig a Haskell-ben megszokott if ´es case szerkezetekkel) A Lava 5
nyelvet a µF P [32] ´es a Ruby [20] nyelvek alapjain fejlesztett´ek, az el˝obbi hardverspecifikus kombin´atorokra ´ep¨ ul, az ut´ obbi pedig egy rel´aci´os hardverle´ır´o nyelv, ahol az ´aramk¨or¨oket ´es komponenseiket a ki- ´es bemenetek k¨oz¨otti rel´aci´okkal adj´ak meg. [4] SASL: A Cambridge egyetemen egy SASL (Statically-Allocated Stream Language) nev˝ u funkcion´alis nyelvet ´es egy ahhoz tartoz´ o hardverszint´ezist fejlesztettek ki, ami t¨obbek k¨oz¨ott egy PhD disszert´ aci´ o [19] form´ aj´ aban l´ atott napvil´agot 2004-ben. A statikus itt arra utal, hogy fix, hardverben is megval´ os´ıthat´ o strukt´ ur´akb´ol ´all a nyelv, a stream pedig a modulok ki- ´es bemeneti interf´esz´ere vonatkozik. Az itt bemutatott szint´ezer k´epes CSP-t [21] ´es adatfolyamgr´afot el˝o´all´ıtani. Az adatfolyamgr´af k´er´es ´es nyugt´ az´ as jeleket is mag´aban foglal, teh´at a dolgozatomban haszn´alt adatfolyamgr´ aft´ ol (EOG) ebben a l´enyeges k´erd´esben elt´er. CλasH: A hollandiai Twente egyetemen 2009-ben k´et diplomaterv [12, 24] keret´eben elindult egy projekt CλasH n´even, amely az els˝ o nagyobb nyilv´anoss´agot 2010 nyar´an kapta a Haskell hackageDB adatb´ azis´ aban val´ o megjelen´essel. A CλasH a CAES Language for Synchronous Hardware elnevez´esb˝ ol sz¨ uletett mozaiksz´o. A fejleszt˝oknek itt is egy funkcion´alis nyelv˝ u hardverle´ır´as megalkot´ asa volt a c´eljuk, amihez alapnak a Haskell nyelvet v´alasztott´ak. (nekem hardverle´ır´ as megalkot´ asa nem volt c´elom, s˝ot mi t¨obb, egy hardveres fogalmakt´ol mentes forr´ask´ od defini´ al´ as´ at t˝ uztem ki) A CλasH a ford´ıt´ as els˝ o l´ep´esek´ent a GHC frontendet haszn´alja, m´egpedig a szintaktikai ´edes´ıt˝oszerek elt´ avol´ıt´ as´ aig. Ezen a ponton a CλasH-ben megval´os´ıtott normaliz´aci´os elj´ar´asok kapj´ ak bemenetk´ent az itt kialakult Core reprezent´aci´ot, ´es hajtj´ak v´egre a normaliz´aci´os l´ep´eseket, eg´eszen az elv´ art norm´alform´ara val´o ´atalak´ıt´asig. A ford´ıt´as v´egs˝o l´ep´ese az el´ert norm´ alforma hardverle´ır´ass´a alak´ıt´asa, a szerz˝ok szerint ehhez a l´ep´eshez m´ar egyenes u ´t vezet. A CλasH alapjainak megismer´ese ut´ an nyilv´anval´ov´a v´alt, hogy a feladatki´ır´asom szempontj´ab´ol ez a legink´ abb relev´ ans, dokument´alt ford´ıt´o, ´ıgy a m˝ uk¨od´es´et r´eszletesebben megismertem. Ezek alapj´ an n´eh´ any szempont, amiben a dolgozatom sor´an le´ırt ford´ıt´o el˝onyre tesz szert a CλasH-sel szemben: • explicit adatfolyamgr´ afot (EOG) haszn´al k¨oztes reprezent´aci´ok´ent, ´ıgy a pipeline optimaliz´ al´ as a szakirodalomban [10] ismertetett m´odon elv´egezhet˝o • a modularit´ ast jobban el˝ ot´erbe helyezi, ´ıgy a ford´ıt´as egyes l´ep´esei (Haskell-EOG, ill. EOG-VHDL ´ atalak´ıt´ o ´es ezek almoduljai) u ´jrahasznos´ıthat´oak • a forr´ask´ odban haszn´ alhat´ o m˝ uvelethalmaz a ford´ıt´oprogram ´at´ır´asa n´elk¨ ul b˝ov´ıthet˝o, csup´ an a m˝ uvelethez tartoz´ o VHDL modult kell defini´alnunk • a Core reprezent´ aci´ ot ki´ert´ekel˝ o algoritmus determinisztikus (a CλasH normaliz´aci´os l´ep´esek nem konfluensek, a determinisztikuss´ag pedig a dokument´aci´o alapj´an nem eld¨onthet˝ o) 6
• haszn´ alja a GHC simplifier mechanizmus´at, ´ıgy annak nagyfok´ u optimaliz´al´o tulajdons´ ag´ at az eg´esz ford´ıt´ as el˝ony´ere tudjuk haszn´alni (pl. lefutnak a magasszint˝ u ´at´ır´ asi szab´ alyok, a rewrite rule-ok is) Az eg´esz ford´ıt´ orendszert modul´arisan ´ep´ıtem fel annak ´erdek´eben, hogy az egyes r´eszfeladatok j´ ol elk¨ ul¨ on´ıthet˝ oek, a modulok k¨ozti interf´eszek egyszer˝ uek ´es teljes m´ert´ekben defini´altak legyenek. Ezek alapj´ an cser´elhet˝o modulokat kapunk, ´ıgy a rendszer az egyes r´eszfeladatok u ´jrahasznos´ıt´ as´ at messzemen˝oen t´amogatja.
A 1. fejezetben a be- ´es kimeneti nyelvek, azaz a Haskell ´es a VHDL saj´atoss´agait taglalom. A 2. fejezetben ismertetem az ´altalam kidolgozott, egysebess´eg˝ u (single-rate) adatfolyamokra alkalmazhat´ o ford´ıt´oi m´odszert ´es ford´ıt´oprogramot, kit´erve a CλasH-sel val´o k¨ ul¨ onbs´egekre ´es hasonl´ os´ agokra. A 3. fejezetben a m´odszert kiterjesztem t¨obbsebess´eg˝ u (multi-rate) adatfolyamokra, ´es ehhez kapcsol´od´oan elk´esz´ıtem a szakirodalomb´ol [10] ismert EOG modell t¨ obbsebess´eg˝ u k¨ornyezetben is alkalmazhat´o v´altozat´at, az MREOG-t. A 4. fejezetben konkr´et p´eld´ akon ismertetem a m´odszer m˝ uk¨od´es´et, amit az elk´esz¨ ult ford´ıt´oprogram k¨ oztes reprezent´ aci´ oival ´es VHDL szimul´aci´oval illusztr´alok. Az 5. fejezetben kit´erek a tov´ abbfejleszt´esi lehet˝ os´egekre, v´eg¨ ul a 6. fejezetben ¨osszefoglalom a dolgozatomban el´ert eredm´enyeket.
7
1. fejezet
A ford´ıt´ as ki- ´ es bemenete 1.1. A Haskell nyelv ´ es saj´ atoss´ agai A Haskell nyelv egy szabv´ anyos´ıtott, a´ltal´anos felhaszn´al´as´ u, tiszt´an funkcion´alis, lusta ki´ert´ekel´es˝ u, er˝ osen t´ıpusos, polimorf t´ıpusokat t´amogat´o nyelv. Ebben a fejezetben a nyelvi saj´atoss´agokat taglalom, amelyeket figyelembe kellett vennem a Haskell nyelvr˝ol t¨ort´en˝o ford´ıt´as sor´an. Az im´ent felsorolt fogalmak kicsit r´eszletesebben kifejtve a k¨ovetkez˝oket takarj´ak: • szabv´anyos´ıtott: a nyelvnek k´et szabv´anya l´etezik, Haskell 98 [30] ´es Haskell 2010 [28] n´even • ´altal´anos felhaszn´ al´ as´ u: a nyelvet nem konkr´et c´elfeladatra fejlesztett´ek, sz´elesk¨or˝ uen haszn´alhat´ o, legyen sz´ o tiszt´ an algoritmikus feladatokr´ol vagy grafikus interf´esszel rendelkez˝ o programr´ ol • tiszt´ an funkcion´ alis (pure functional): egy f¨ uggv´eny kimenete csak a bemeneteit˝ol f¨ ugghet, teh´ at a f¨ uggv´enyek mell´ekhat´asmentesek, aminek el˝onye a k´odol´askor t¨ort´en˝o hib´ az´ asok cs¨ okken´ese ´es a modularit´as nagy fok´ u t´amogat´asa, ugyanis a k´odr´eszek egym´ ast´ ol teljesen f¨ uggetlen¨ ul tesztelhet˝oek ill. felhaszn´alhat´oak • lusta ki´ ert´ ekel´ es˝ u (lazy evaluation): egy adott kifejez´es csak akkor ´ert´ekel˝odik ki, amikor a teljes program ki´ert´ekel´ese sor´an erre mindenk´eppen sz¨ uks´eg van (ez a call-by-need strat´egia, l´ asd k´es˝ obb) • er˝ osen t´ıpusos: egy v´ altoz´ o t´ıpusa a fut´asi id˝oben nem v´altozhat, vagyis k¨ ul¨onb¨oz˝o t´ıpus´ u v´ altoz´ ok k¨ oz¨ ott explicit konverzi´o sz¨ uks´eges (ellent´etben pl. a php nyelvvel, ahol a v´ altoz´ ok t´ıpusa fut´ asid˝ oben v´altozhat) • polimorf t´ıpusok: param´eteres t´ıpusok, ahol a param´eterek szint´en t´ıpusokat jelentenek (egy t´ıpus ez´ altal specializ´ altabb t´ıpusok egy halmaz´at jelentheti - ez nagyban n¨oveli a k´ od u ´jrafelhaszn´ alhat´ os´ ag´at) A funkcion´ alis nyelvek a lambda-kalkulus-ra ´ep¨ ulnek, ez´ert a k¨ovetkez˝okben a lambdakalkulus alapjainak r¨ ovid le´ır´ asa k¨ ovetkezik. 8
1.1.1. Lambda-kalkulus A lambda-kalkulus meg´ert´es´enek j´o kiindul´opontja Henk Barendregt ´es Erik Barendsen Introduction to Lambda Calculus c´ım˝ u m˝ uve [13]. A lambda-kalkulust lambda-kifejez´esek alkotj´ak. Egy lambda-kifejez´ es lehet • egy egyszer˝ u v´ altoz´ o • egy lambda-absztrakci´ o, aminek a jel¨ol´ese: λv.E, ahol v egy v´altoz´o ´es E egy lambda-kifejez´es • egy alkalmaz´ as, aminek a jel¨ol´ese: F E, ahol F egy lambda-absztrakci´o ´es E egy tetsz˝ oleges lambda-kifejez´es A lambda-absztrakci´ ora gondolhatunk u ´gy, mint egy f¨ uggv´eny megtestes´ıt˝oj´ere, az alkalmaz´ asra pedig u ´gy, mint egy f¨ uggv´eny megh´ıv´as´ara. (k´es˝obb l´atni fogjuk, hogy ez a felfog´as s´ ant´ıt, de most egyszer˝ ubb csak ´ıgy gondolni r´a) Tekints¨ uk pl. a k¨ovetkez˝o intuit´ıv kifejez´est: (λx.2 ∗ x + 1)3. Ez egy alkalmaz´as, amely v´egrehajtja a benne szerepl˝ o lambda-absztrakci´ ot a 3 bemeneti ´ert´ekkel. Ha az absztrakci´o x v´altoz´oj´ara behelyettes´ıtj¨ uk a 3-at, akkor m´ ar egyszer˝ uen l´atszik, hogy ennek a kifejez´esnek (2 ∗ 3 + 1) = 7 az ´ert´eke. A k¨ovetkez˝ okben a lambda-kalkulus u ´jabb fogalmait vezetj¨ uk be: • k¨ ot¨ ott/szabad v´ altoz´ o: Egy lambda-absztrakci´o kifejez´es´eben azok a v´altoz´ok k¨ ot¨ ottek, amelyek szerepelnek az absztrakci´o defin´ıci´oj´aban, a t¨obbi v´altoz´ot szabadnak mondjuk. Teh´ at λx.x + y eset´eben x egy k¨ot¨ott, y egy szabad v´altoz´o. • fu eny: Azok a lambda-absztrakci´ok tekinthet˝ok f¨ uggv´enynek, amelyben nincs ¨ ggv´ szabad v´ altoz´ o. (teh´ at kimeneti” ´ert´eke csak a bemenett˝ol” f¨ ugg) ” ” • α-konverzi´ o: Alpha-konverzi´onak nevezz¨ uk a k¨ot¨ott v´altoz´ok ´atnevez´es´et. Pl. λx.x alpha konverzi´ o ut´ an kin´ezhet ´ıgy is: λy.y. • β-redukci´ o: A beta redukci´o a lambda-kalkulus legfontosabb konverzi´oja, ez tulajdonk´eppen az alkalmaz´ as v´egrehajt´as´at jelenti. A fenti p´eld´an´al maradva (λx.2 ∗ x + 1)3 a beta redukci´ o ut´ an (2 ∗ 3 + 1) alakot vesz fel. • η-konverzi´ o: Az eta-konverzi´ot a k¨ovetkez˝o egyszer˝ u egyenl˝os´eggel illusztr´aljuk: λx.F x = F , ahol x v´ altoz´ o ´es F egy lambda-absztrakci´o. Ez azt jelenti, hogy egy lambda-absztrakci´ o, ami egy F x alkalmaz´asb´ol ´all, egyszer˝ uen helyettes´ıthet˝o az alkalmaz´ as lambda-absztrakci´oj´aval, azaz F -fel. • lambda lifting: Olyan m´ odszer, amely elt´avol´ıtja a lambda-absztrakci´okon bel¨ uli szabad v´ altoz´ okat. Ezt oly m´odon hajtja v´egre, hogy a szabad v´altoz´okat k¨ot¨ott´e teszi egy u ´jabb lambda-absztrakci´o bevezet´es´evel, amin kereszt¨ ul az addigi szabad v´ altoz´ o ´ert´ek´enek ´ atad´ asa biztos´ıthat´o. Funkcion´alis nyelv˝ u f¨ uggv´enyekre ez a k¨ ovetkez˝ ok´epp ´ertelmezhet˝ o. Minden szabad v´altoz´o eset´eben l´etrehozunk egy u ´jabb 9
param´etert, majd a kiz´ ar´ olag k¨ ot¨ott v´altoz´okat tartalmaz´o lambda kifejez´eseket f¨ uggv´enyk´ent a glob´ alis n´evt´erbe helyezz¨ uk. (a f¨ uggv´enyeknek persze egyedi n´evvel kell rendelkezni¨ uk) Ki´ ert´ ekel´ esi strat´ egi´ ak A ki´ert´ekel´esi strat´egi´ ak szab´ alyok sorozatai, amelyeket v´egrehajtva egy programoz´asi nyelv kifejez´ese ki´ert´ekelhet˝ o, vagyis a kifejez´es ´ert´eke meghat´arozhat´o. Lambdakalkulusban ezeket ´ altal´ aban redukci´ os strat´egi´aknak nevezik. A k¨ovetkez˝o r´eszben a leggyakrabban alkalmazott ki´ert´ekel´esi strat´egi´akat mutatom be: • call-by-value: A moh´ o (m´ as n´even szigor´ u) ki´ert´ekel´es csal´adj´aba tartoz´o strat´egia. A f¨ uggv´enyh´ıv´ as el˝ ott ki´ert´ekelj¨ uk az o¨sszes argumentum-kifejez´est, ´ıgy a f¨ uggv´eny h´ıv´asakor a m´ ar kisz´ am´ıtott ´ert´ekeket adjuk ´at. Nagyon sok programoz´asi nyelv haszn´alja ezt a m´ odszert, nem is kell messzire menn¨ unk, az egyik leg´altal´anosabban haszn´alt imperat´ıv nyelv, a C pontosan ´ıgy m˝ uk¨odik. • call-by-reference: Szint´en a moh´o ki´ert´ekel´es csal´adj´aba tartozik. Az argumentumok ki´ert´ekel´ese itt is megt¨ ort´enik a f¨ uggv´enyh´ıv´as el˝ott, de a param´eter´atad´as a v´altoz´ora mutat´ o referenci´ an kereszt¨ ul bonyol´odik, amely nagyobb m´eret˝ u v´altoz´o eset´en j´ oval k¨ olts´eghat´ekonyabb lehet. A m´asik k¨ ul¨onbs´eg, hogy az indirekci´o miatt a f¨ uggv´enyen bel¨ ul a k¨ uls˝ o v´ altoz´ o ´ert´eke is megv´altoztathat´o. A C++ alap´ertelmezetten call-by-value ´ atad´ ast val´ os´ıt meg, de referenci´at haszn´alva a call-by-reference strat´egi´ at is t´ amogatja. • call-by-name: Lusta (nem szigor´ u) ki´ert´ekel´es˝ u. A f¨ uggv´enyargumentum kifejez´es´et nem ´ert´ekeli ki a f¨ uggv´eny h´ıv´ asa el˝ott, hanem csak egy hivatkoz´ast (thunk) ad ´at a teljes argumentum-kifejez´esre. Akkor ´ert´ekel˝odik ki az argumentum, ha a f¨ uggv´enyen bel¨ uli ki´ert´ekel´es m´ ar mindenk´eppen sz¨ uks´egess´e teszi ezt. Ez adja a megold´as legnagyobb el˝ ony´et, hiszen addig nem kell foglalkoznunk egy kifejez´essel, am´ıg biztoss´a nem v´alik annak t´enyleges felhaszn´al´asa. Ez el˝ony lehet akkor is, ha az argumentum ki´ert´ekel´ese o aban v´egtelen ciklushoz vezetne, hiszen ha az argumentumot a ¨nmag´ f¨ uggv´enyen bel¨ ul nem haszn´ aljuk, akkor nem ´allhat el˝o v´egtelen ciklus. • call-by-need [11]: Lusta ki´ert´ekel´es˝ u szint´en, a call-by-name strat´egi´at´ol csak abban t´er el, hogy az argumentumkifejez´est legfeljebb egyszer ´ert´ekeli ki, majd az ´ert´eket elt´arolja egy v´ altoz´ oban. Amikor a k¨ovetkez˝okben sz¨ uks´eg van r´a, az ´ert´eket a v´altoz´ob´ol veszi ki, teh´ at t´enyleges ki´ert´ekel´es nem t¨ort´enik. A lusta ki´ert´ekel´es legink´abb haszn´alatos m´ odja ez a strat´egia, t¨obbek k¨oz¨ott a dolgozatom szempontj´ab´ol fontos Haskell nyelv is ezen alapszik.
1.1.2. T´ıpusrendszer A funkcion´alis nyelvek t´ıpusrendszer´enek alapja az algebrai adatt´ıpus (algebraic data type, ADT), amely Haskell eset´eben a k¨ ovetkez˝o defin´ıci´ot jelenti ([30], 4.2.1 fejezet):
10
data T t1 t2 ... tn = | | |
A a1 a2 ... ak B b1 b2 ... bl ... X x1 x2 ... xm
T a t´ıpuskonstruktor, t1..tn a param´eterei, A,B..X az adatkonstruktorok, az a1..xm k¨oz¨otti szimb´ olumok pedig az adott konstruktorhoz tartoz´o t´ıpusokat jelentik. Ez halmazelm´eleti nyelven megfogalmazva adatok Descartes-szorzat´anak o¨sszeg´et, vagyis megk¨ ul¨onb¨ oztetett uni´ oj´ at jelenti. Az ¨osszeg tagjait, vagyis a t´ıpusalternat´ıv´ akat a | (pipe) jel¨ol´essel kell elv´ alasztanunk. Egy T t1 ...tn t´ıpus´ u v´altoz´o b´armelyik t´ıpusalternat´ıva szerinti ´ert´eket felvehet. Az n-esek (h´etk¨ oznapi nyelven a rekord t´ıpusok) a Descartes szorzatnak felelnek meg. Az n-eseket tekinthetj¨ uk az ´ altal´ anos defin´ıci´o egyik speci´alis eset´enek, amikor az o¨sszegnek csak egyetlen tagja van, ´es az adatkonstruktor (,) (b´armennyi vessz˝o szerepelhet) alakban adott. A nyelvben a szokv´anyos n-es jel¨ol´es, pl. (a,b,c,d) csak egy szintaktikai ´edes´ıt˝oszer, teh´ at egy jobban olvashat´o le´ır´asa a (,,,) a b strukt´ ur´anak. N´eh´any p´elda algebrai adatt´ıpusok megad´ as´ ara [5]:
data Bool = False | True data Maybe a = Nothing | Just a data Either a b = Left a | Right b
A Bool a szok´ asos boolean t´ıpusnak felel meg, k´et egyszer˝ u konstruktora van, False ´es True n´even, az ilyen t´ıpus´ u kifejez´es csak ezt a k´et ´ert´eket veheti fel. A Maybe a ett˝ ol annyiban t´er el, hogy amikor a Just konstruktort haszn´aljuk, akkor meg kell adnunk egy tetsz˝oleges t´ıpus´ u kifejez´est is. (pl. Just "szoveg" ). Az Either a b enn´el is tov´abb megy, ez arra j´ o, hogy egy t´ıpusba foglaljon o¨ssze k´et egym´assal nem kompatibilis kifejez´est. Pl. egy ilyen t´ıpus´ u kifejez´es lehet Left "szoveg" , vagy Right 67 . A Haskell szabv´ any bevezeti a t´ıpusoszt´ aly fogalm´at. Egy t´ıpusoszt´aly f¨ uggv´enyeket deklar´ al, amelyeket csak a t´ıpusoszt´alyba tartoz´o t´ıpusokra lehet alkalmazni. Egy t´ıpusoszt´alyt p´eld´ anyos´ıtva konkr´et t´ıpusok eset´ere megadhatjuk a f¨ uggv´enyek defin´ıci´oj´at, ´ıgy a k¨ ul¨ onb¨ oz˝ o t´ıpusokra k¨ ul¨ onb¨ oz˝ o f¨ uggv´enyimplement´aci´o adhat´o. Egy egyszer˝ u p´elda a Num t´ıpusoszt´ aly, amely algebrai f¨ uggv´enyeket deklar´al (pl. (+) , (-) , (*) ). Az Int t´ıpus t¨obbek k¨ oz¨ ott a Num t´ıpusoszt´ alynak is tagja, mert l´etezik egy Num Int p´eld´anyos´ıt´as. Ebben a p´eld´ anyos´ıt´ asban az algebrai m˝ uveleteket az Int t´ıpus szerint implement´alt´ak, ´ıgy pl. k´et Int t´ıpus ¨ osszead´ asa eset´en az itt defini´alt k´od hajt´odik v´egre. 11
1.2. A Haskell GHC ford´ıt´ o f¨ obb tulajdons´ agai Jelenleg a GHC sz´ am´ıt de facto standard” Haskell ford´ıt´onak, versenyt´arsai funkcionali” t´asban csak messze lemaradva k¨ ovetik. A dolgozatom szempontj´ab´ol nagyon fontos volt megismernem a GHC ford´ıt´ o m˝ uk¨ od´es´et, ez´ert jelen fejezetben kit´erek azokra a megismert tulajdons´agokra, amelyekre a fejleszt´es sor´an nagy sz¨ uks´eg volt.
1.2.1. K¨ oztes reprezent´ aci´ o - a Core nyelv A GHC egy k¨ oztes nyelvet, a Core [35] strukt´ ur´at haszn´alja az ´eppen ford´ıtott k´od egyszer˝ us´ıtett reprezent´ al´ as´ ara, ami tulajdonk´eppen egy lambdakalkulus elveit k¨ovet˝o AST (absztrakt szintaxisfa) reprezent´ aci´ o. Az optimaliz´aci´os l´ep´esek nagy r´esze ezen a nyelven t¨ort´enik, ezekre a transzform´ aci´ okra ´eppen ez´ert szoktak Core2Core n´even is hivatkozni. A Core l´enyegret¨ or˝ o defin´ıci´ oja: data Expr b = | | | | | | | |
Var Id Lit Literal App (Expr b) (Arg b) Lam b (Expr b) Let (Bind b) (Expr b) Case (Expr b) b Type [Alt b] Cast (Expr b) Coercion Note Note (Expr b) Type Type
type Alt b = (AltCon, [b], Expr b) data Bind b = NonRec b (Expr b) | Rec [(b, Expr b)]
Az egyes kifejez´esek jelent´ese: • Var Id : Egy v´ altoz´ o haszn´ alat´ at jelenti. Ez tulajdonk´eppen egy hivatkoz´as a legfels˝o szinten megadott glob´ alis, vagy a Let kifejez´essel le´ırt lok´alis v´altoz´ok¨ot´esre (m´as n´even ¨ osszerendel´esre). • Lit Literal : Konstanst jel¨ ol. A konstansoknak egy sz˝ uk halmaz´at adhatjuk meg, az obbi konstans ezekb˝ ol sz´ armazhat. (pl. az App kifejez´essel, adatkonstruktort ¨osszes t¨ alkalmazva) N´eh´ any jellemz˝ o t´ıpus: Int# , Int64# , Float , Double , FastString • App (Expr b) (Arg b) : Egy lambda-kalkulus szerinti alkalmaz´ast jel¨ol, ezek alapj´an csak egyetlen argumentuma lehet. T¨obb argumentum´ u f¨ uggv´enyeket egym´asba ´agyazott alkalmaz´ asokkal ´ırhatunk le, ´ıgy pl. az 1 ´es 2 sz´amok ¨osszead´asa a k¨ovetkez˝ok´epp n´ez ki: App (App (Var (+)) (Lit 1)) (Lit 2) . A p´eld´ab´ol az is kider¨ ul, hogy a (+) f¨ uggv´eny itt egy v´ altoz´on kereszt¨ ul jelenik meg, teh´at egy el˝oz˝oleg defini´alt f¨ uggv´eny alkalmaz´ as´ ara v´ altoz´oval hivatkozunk. A GHC az adatkonstrukci´okat is alkalmaz´ ask´ent kezeli, teh´ at algebrai t´ıpus´ u konstansokat is csak az App seg´ıts´eg´evel ´ırhatunk le. 12
• Lam b (Expr b) : Egy lambda-absztrakci´ot defini´al. A lambda-absztrakci´o tulajdonk´eppen nem m´ as, mint egy kifejez´es burkolva, aminek egyetlen k¨ot¨ott param´etere van (a kifejez´es els˝ o, itt b -vel jel¨olt param´etere). Minden f¨ uggv´enydefin´ıci´o Coreban t¨ ort´en˝ o ´ abr´ azol´ asa lambda-absztrakci´oval t¨ort´enik. T¨obb argumentum eset´en az App -hoz hasonl´ oan egym´asba ´agyazott Lam kifejez´esek szerepelnek, ´ıgy pl. az osszead´ asn´ al: Lam(a)(Lam(b)(...)) ¨ • Let (Bind b) (Expr b) : V´altoz´o-kifejez´es o¨sszerendel´est (Bind , l´asd k´es˝obb) ´es egy tov´ abbi kifejez´est (Expr ) defini´al. A v´altoz´o haszn´alata minden esetben a m´ ar bemutatott Var kifejez´essel ´ırhat´o le. A call-by-need ki´ert´ekel´es miatt egy Let csom´ oponthoz ´erve csak az Expr kifejez´essel kell ´erdemben t¨or˝odni, az ¨osszerendel´esben tal´ alhat´ o kifejez´essel annak haszn´alat´aig nem kell foglalkoznunk. • Case (Expr b) b Type [Alt b] : A Core nyelv k´ets´egk´ıv¨ ul legbonyolultabb szerkezete egy el´ agaz´ ast (case ) reprezent´al. A Haskell forr´ask´od case ´es if kifejez´esei biztosan erre fordulnak, de emellett a v´altoz´ok illeszt´es´ere is ezt a form´at haszn´ alj´ ak. Az Expr itt az a kifejez´es, ami alapj´an kiv´alaszt´asra ker¨ ul az alternat´ıv´ak k¨oz¨ ul egyetlen ´ ag. (a szakirodalomban erre a kifejez´esre scrutinee n´even hivatkoznak) A b egy v´ altoz´ o k¨ ot´es (hasonl´oan a Lam b -j´ehez), ez a teljes scrutinee-t k¨oti az itt megadott v´ altoz´ ora, ez az´ert fontos, hogy a tov´abbiakban hivatkozni lehessen a teljes kifejez´esre. A Type a Case visszat´er´esi ´ert´ek´enek t´ıpusa, az [Alt b] t¨omb pedig az alternat´ıv´ ak le´ır´ asa, amir˝ol m´eg sz´o lesz. • Cast (Expr b) Coercion : Explicit t´ıpuskonverzi´o. • Note Note (Expr b) : A Core f´aban lehet˝os´eg van megjegyz´est elhelyezni, ezt a Note kifejez´essel tehetj¨ uk meg. • Type Type : T´ıpusdefin´ıci´ o, a Core legfels˝o szintj´en lehet megtal´alni. • (AltCon, [b], Expr b) : A case alternat´ıv´ak ebben a form´aban jelennek meg. AltCon az alternat´ıva konstruktora, ami adatkonstruktor vagy liter´al lehet. A [b] t¨ omb azokat a v´ altoz´ okat tartalmazza, amiket az AltCon szerinti param´eterekhez k¨ ot¨ unk, az Expr b pedig az adott alternat´ıva eset´en ki´ert´ekelend˝o kifejez´es. • NonRec b (Expr b) : Nemrekurz´ıv o¨sszerendel´est defini´al. A b v´altoz´ot ´es az Expr kifejez´est rendeli ¨ ossze, a kifejez´esre ezek ut´an a Core Var bejegyz´es´evel hivatkozhatunk, megadva a k¨ ot¨ ott v´ altoz´o, azaz a b nev´et. Az Expr kifejez´esben csak a f´aban ezt a pontot megel˝ oz˝ o¨ osszerendel´esre hivatkozhatunk. • Rec [(b, Expr b)] : Rekurz´ıv o¨sszerendel´eseket defini´al. Egy-egy ¨osszerendel´es a b param´eterben adott v´ altoz´ot ´es az Expr param´eterben adott kifejez´est rendeli ossze. Az Expr kifejez´esben a f´aban ezt a pontot megel˝oz˝o ¨osszerendel´esre, vagy a ¨ saj´ at Rec kifejez´esben felsorolt t¨obbi ¨osszerendel´es´ere hivatkozhatunk. (ez a l´enyegi k¨ ul¨ onbs´eg a rekurz´ıv ´es nemrekurz´ıv o¨sszerendel´es k¨oz¨ott) A k¨olcs¨on¨os hivatkoz´ as kiz´ ar´ olag rekurz´ıv ¨ osszerendel´essel val´os´ıthat´o meg. 13
1.2.2. Primit´ıv t´ıpusok Primit´ıv t´ıpusnak nevezz¨ uk a GHC be´ep´ıtett t´ıpusait, vagyis azokat a t´ıpusokat, amelyek alap´ertelmezetten nem szerepelhetnek a ford´ıtand´o k´odban. A primit´ıv t´ıpusok k¨oz¨ott megtal´aljuk t¨ obbek k¨ oz¨ ott a nat´ıv k¨ornyezet t´ıpusait, a mai szokv´anyos sz´am´ıt´og´epes k¨ornyezetben 32 vagy 64 bites integert (Int# ), a float (Float# ) ´es a double (Double# ) lebeg˝opontos t´ıpusokat. (a z´ ar´ ojeles nevek a t´ıpusok GHC szerinti nevei) A primit´ıv t´ıpusok azonos´ıt´oja konvencion´ alisan a kett˝ oskereszt karakterrel z´arul. Egy primit´ıv t´ıpus lehet csomagolt (boxed) vagy csupasz (unboxed) att´ol f¨ ugg˝oen, hogy megval´ os´ıt´ asa pointerrel (indirekt) vagy ´ert´ek alapj´an t¨ort´enik. Az el˝obb felsorolt t´ıpusok mind csupasz t´ıpusok, de a ByteArray# pl. m´ar csomagolt. A primit´ıv t´ıpusokat saj´ at programjainkban is haszn´alhatjuk, ha a GHC.Prim modult import´aljuk, ´es a kett˝ oskereszt karakterek haszn´alat´at ford´ıt´oi opci´oval enged´elyezz¨ uk. ([34], 7.3.2 fejezet) A primit´ıv t´ıpusok az´ert fontosak sz´ amunkra, mert a GHC t´ıpusrendszer alapj´at k´epezik, teh´at ezeket mindenk´eppen tudnunk kell ´abr´azolni hardverben. A legegyszer˝ ubb t´ıpusok, ´ıgy az Int , Integer , Float ´es Double is ezeknek a t´ıpusoknak a csomagolt v´altozatai, ahogy az a GHC forr´ asf´ ajljaib´ ol ki is der¨ ul:
-- GHC.Types data Int data Float data Double
modul: = I# Int# = F# Float# = D# Double#
-- GHC.Integer.Type modul: data Integer = S# Int# | J# Int# ByteArray#
-- small integers -- large integers
L´athat´o, hogy ezek az egyszer˝ u, leggyakrabban haszn´alt t´ıpusok is ADT-k. Az Int p´eld´aul egy I# adatkonstruktorral ´es az Int# primit´ıv t´ıpussal k´epzett t´ıpus. Az Integer korl´atlan m´eret˝ u eg´esz sz´ amot t´ arolhat, ´ıgy a megval´os´ıt´asa is k¨or¨ ulm´enyesebb. Att´ol f¨ ugg˝oen, hogy ´epp milyen nagys´ agrend˝ u ´ert´eket tartalmaz, lehet az Int -hez hasonl´o (erre szolg´al a S# konstruktor) ´es lehet egy kell˝oen nagy t¨omb ´altal megval´os´ıtott (erre szolg´al a J# konstruktor). A nyilv´anval´ o aritmetikai m˝ uveleteknek is mind-mind megvan a primit´ıv megfelel˝oje, ´ıgy az ¨osszead´ as a (+#) , a szorz´ as pedig a (*#) primit´ıv m˝ uveletekkel val´os´ıthat´o meg. A GHC.Prim modulban tal´ alhat´ o ezeknek a m˝ uveleteknek a virtu´alis” defin´ıci´oja, vagyis egy ” let x = x in x kifejez´es, ami t´enyleges funkci´oval nem rendelkezik, ugyanis a primit´ıv m˝ uveleteknek m´ ar k¨ ozvetlen¨ ul nat´ıv k´ odra kell fordulnia. A Num t´ıpusoszt´ alyt megval´ os´ıtja t¨obbek k¨oz¨ott az Int ´es az Integer t´ıpus is, emiatt mindk´et t´ıpushoz defini´ alni kellett a megfelel˝o aritmetikai m˝ uveleteket. Ez Int -ek ¨osszead´as´an´al annyit jelent, hogy a GHC kicsomagolja (unboxing) a bemeneteket Int# primit´ıv t´ıpusra, majd ezeken v´egrehajtja a (+#) primit´ıv m˝ uveletet, v´eg¨ ul az eredm´enyt u ´jra becsomagolja (boxing). Pontosan ezen az elven m˝ uk¨odik a GHC.Base.plusInt 14
f¨ uggv´eny, amit a Num Int p´eld´ anyos´ıt´as o¨sszead´as f¨ uggv´enye h´ıv a GHC.Num modulban. Az Integer eset´eben enn´el sokkal bonyolultabb a helyzet, hiszen b´armilyen nagys´ag´ u sz´amokat is tartalmazhat (persze a sz´am´ıt´og´ep mem´ori´aj´anak f¨ uggv´eny´eben), amiket a v´eges, Int# t´ıpus´ u (+#) m˝ uvelet – rosszabb esetben - egym´as ut´ani v´egrehajt´as´ara kell lek´epeznie. Eset¨ unkben nagyon fontos k´erd´es, hogy az eg´esz t´ıpus´ u liter´alok hogyan szerepelnek a Core reprezent´ aci´ oban. A Literal adatt´ıpus MachInt konstruktora Int# ´ert´eket szolg´ altat, ´ıgy a Core f´ aban megjelenik a csomagol´ashoz sz¨ uks´eges adatkonstruktor is:
app GHC.Types.I\# lit 2
Egy 32 bitn´el nagyobb Integer , t¨ort´enetesen a 7 ∗ 109 eset´eben a Core a k¨ovetkez˝ o, k¨or¨ ulm´enyes form´ at veszi fel:
app GHC.Integer.plusInteger app GHC.Integer.smallInteger lit 557549059 app GHC.Integer.timesInteger app GHC.Integer.smallInteger lit 3 app GHC.Integer.smallInteger lit 2147483647
Ha belegondolunk, hogy a 32 bites architekt´ ur´an ez a sz´am egyetlen nat´ıv konstanssal nem lenne reprezent´ alhat´ o, akkor teljesen logikus, hogy m´ar a Core reprezent´aci´oban is csak 32 biten ´ abr´ azolhat´ o konstansok ´es m˝ uveletek lehetnek. Ez a tov´abbiakat annyiban ´erinti, hogy egy nagyobb sz´ am eset´eben az aritmetikai m˝ uveletek ´es a konstansok t¨obb primit´ıv m˝ uveletet eredm´enyeznek, holott egy hardverben tetsz˝oleges bitsz´am´ u aritmetika kialak´ıthat´ o, ´ıgy erre a bonyol´ıt´ asra” nem lenne sz¨ uks´eg. ”
1.2.3. Fu enybehelyettes´ıt´ es ¨ ggv´ A behelyettes´ıt´ es az a k´ odtranszform´aci´o, ami egy f¨ uggv´eny h´ıv´asi pontj´ara a f¨ uggv´eny t¨orzs´et bem´ asolja. (a szakirodalom az inline mellett unfold n´even is hivatkozik erre a transzform´ aci´ ora, l´ asd pl. a GHC k´ezik¨onyv´et [34]) Megjegyzend˝o, hogy a behelyettes´ıt´es lambda-kalkulus szerinti megfelel˝oje a β-redukci´o. A ford´ıt´ as egyik kulcsfontoss´ ag´ u k´erd´es´ehez ´ert¨ unk, ami mind processzoros, mind hardveres rendszer eset´en nagyban kihat a futtat´as hat´ekonys´ag´ara. Processzoron t¨ort´en˝o futtat´as eset´eben a behelyettes´ıt´es gyorsabb fut´ast eredm´enyezhet (hisz a f¨ uggv´enyh´ıv´asb´ ol ered˝o overhead elt˝ unik), viszont j´o es´ely van arra, hogy a program b´ajtk´odja ez´altal n¨ ovekszik, mert adott esetben t¨ obb helyre is bem´asoljuk ugyanazt a k´odot. Ezek alapj´ an 15
az egyik alapvet˝ o szab´ aly, hogy a kiz´ ar´olag egyszer megh´ıvott f¨ uggv´enyekre mindenk´eppen v´egre kell hajtani az inlining-ot, ez ugyanis b´ajtk´od n¨oveked´est nem okoz, ellenben gyorsabb fut´ ast eredm´enyez(het). A GHC egy o ar´ assal d¨ onti el, hogy egy f¨ uggv´enyt behelyettes´ıt-e vagy sem ¨sszetett elj´ [31]. Az ¨osszetetts´eg ellen´ere vannak alapelvek [6], amik k¨onnyen meg´erthet˝oek ´es ezeket ismerve egyszer˝ ubben tudjuk befoly´ asolni a GHC behelyettes´ıt´esi mechanizmus´at, ez´ert most ezekre t´erek ki. A GHC simplifier programr´esze akkor hajt v´egre automatikus behelyettes´ıt´est, • ha a f¨ uggv´eny m´erete nagyon kicsi, vagy • ha a modul export list´ aj´ aban nem szerepeltetj¨ uk a f¨ uggv´enyt ´es a modulon bel¨ ul csak egyszer h´ıvjuk (´ altal´ anosabban: ha a f¨ uggv´enyt biztosan csak egyszer h´ıvjuk meg) Tov´abbi megjegyz´esek: • Ha a modul export list´ aj´ aban szerepel a f¨ uggv´eny, akkor a modul ford´ıt´as´an´al m´eg nem garant´ alhat´ o, hogy azt csak egy helyr˝ol fogjuk megh´ıvni, mert h´ıvhatjuk pl. m´asik modulb´ ol. • Ha a modul fejl´ec´et megadjuk, de az exportlist´at elhagyjuk, az azt jelenti, hogy minden f¨ uggv´enyt export´ alunk. • Ha modul fejl´ecet nem ´ırunk, az eredm´eny a module Main where fejl´eccel ekvivalens lesz, teh´ at itt is minden f¨ uggv´enyt export´alunk Hardveres k¨ ornyezetben sokkal egyszer˝ ubb´e v´alhat a megval´os´ıt´as a behelyettes´ıt˝o transzform´aci´ok elv´egz´ese ut´ an. Ilyen esetben az adatfolyam egyszer˝ u marad, egy adott feldolgoz´oegys´eg az adatfolyamban csak egyszer fog szerepelni, ´ıgy k¨olts´eges multiplexerekre sincs sz¨ uks´eg. Kiz´ ar´ olag nagyon k¨ olts´eges f¨ uggv´eny eset´en van ´ertelme behelyettes´ıt´es n´elk¨ uli megold´asban gondolkodni, teh´ at amikor a multiplexer beilleszt´es´evel jobban j´arunk, mint a m˝ uveletek megfelel˝ o sz´ am´ u sokszoros´ıt´as´aval. (ez persze a fut´asi id˝ot is megn¨ovelheti, mert egy feldolgoz´ oegys´eg p´ arhuzamosan t¨obb feladatot nem tud ell´atni) A behelyettes´ıt´esnek van m´eg egy ´ arnyoldala, ez pedig az inform´aci´oveszt´es. Behelyettes´ıt´es eset´en az inline f¨ uggv´eny neve elt˝ unik, ´es az az inform´aci´o is elv´esz, hogy az adatfolyamgr´afban mely csom´ opontok halmaza alkotta az eredeti f¨ uggv´enyt. Ezzel az inform´aci´oveszt´essel a teljes f¨ uggv´enyt m´ ar nem tudjuk egy feldolgoz´oegys´egk´ent kezelni, amivel esetleg k´es˝obbi optimaliz´ al´ asi lehet˝ os´egeket vesz´ıthet¨ unk. Polimorf f¨ uggv´eny implement´ al´ asa hardverben t´ uls´agosan k¨olts´eges ´es ´esszer˝ utlen lenne, mivel akkor a v´ altoz´ o t´ıpus´ at, egy metaadatot is nyilv´an kellene tartanunk. Ennek az a k¨ovetkezm´enye, hogy egy polimorf f¨ uggv´eny m´as-m´as t´ıpusparam´eterrel t¨ort´en˝o h´ıv´asa m´as-m´as t´enyleges f¨ uggv´eny h´ıv´ as´ anak (nem ugyanazon f¨ uggv´eny t¨obb helyr˝ol t¨ort´en˝o h´ıv´as´anak) sz´am´ıt, teh´ at ez nem z´ arhatja ki a behelyettes´ıt´est. A gyakorlatban ezt a speci´alis esetet u ´gy tudjuk megoldani, hogy els˝ o l´ep´esben specializ´aljuk a f¨ uggv´enyt (behelyettes´ıtj¨ uk a t´ıpusparam´etereket), majd csak egy m´asodik l´ep´esben hajtjuk v´egre a behelyettes´ıt´esi algoritmust. 16
1.3. A VHDL nyelv ´ es saj´ atoss´ agai A VHDL az egyik legelterjedtebben haszn´alt hardverle´ır´o nyelv, amely FPGA ´es ASIC ´aramk¨ or¨ ok implement´ al´ as´ ara, szimul´al´as´ara ´es dokument´al´as´ara szolg´al. A VHDL nyelvet az IEEE 1076-os szabv´ anya r¨ogz´ıti, amelynek legels˝o verzi´oj´at 1987-ban, legfrissebb verzi´oj´ at [23] pedig 2008-ban adt´ak ki. A jelenlegi szabv´ any nagyon terjedelmes (640 oldal), ebben nagyon sok nyelvi kifejez´est ´es lehet˝ os´eget defini´ altak, ´ am a kereskedelmi szint´ezer programok ezeknek csak egy r´esz´et t´amogatj´ ak. Ahhoz, hogy a dolgozatom sor´an le´ırt ford´ıt´oprogram a lehet˝o legt¨obb szint´ezerrel egy¨ uttm˝ uk¨ odj¨ on, a tov´ abbiakban csak az itt bemutatott egyszer˝ u ´es ´altal´anosan haszn´alt kifejez´eseket fogom haszn´alni. Egy hardverle´ır´ as ´es egy szoftveres programnyelv k¨oz¨ott a legnagyobb k¨ ul¨onbs´eg, hogy a szoftver egy processzorban fut, ez´ert egym´as ut´an v´egrehajtand´o utas´ıt´asokra kell ford´ıtani, m´ıg a hardverle´ır´ as vezet´ekeket, logikai kapukat, regisztereket, stb. ´ır le statikus m´odon. ´ Eppen ez´ert a deklarat´ıv nyelvekhez hasonl´oan a VHDL kifejez´esek sorrendje ugyancsak nem sz´ am´ıt. Egy VHDL modul az 1.1. ´ abr´ an v´azolt fel´ep´ıt´essel rendelkezik. Minden modul k´et fontos r´eszb˝ol ´ all. Az egyik az entity deklar´aci´oja, ami a modul interf´esze, teh´at a portokat ´es a generikus param´etereket ´ırja le. A m´asik az architecture , ami a modul t¨orzse, teh´at a bels˝o struktur´ at ´es viselked´est ´ırja le az 1.2. ´abr´an l´athat´o form´aban. (a -- jelek a VHDL k´odban megjegyz´esek ´ır´ as´ ara szolg´alnak) Ha haszn´ alni szeretn´enk egy m´asik modult, akkor azt p´eld´anyos´ıtani kell. Ehhez az architecture-ben deklar´ aljuk a modult a component kulcssz´oval ill. a t¨orzsben el kell v´egezn¨ unk a konkr´et p´eld´ anyos´ıt´ ast. Az architecture viselked´ esi ´es struktur´ alis model szerint ´ırhat´o le, vagy ak´ar ezeket vegyesen is haszn´ alhatjuk. A struktur´alis le´ır´as (1.3. ´abra) azt jelenti, hogy modulokat p´eld´anyos´ıtunk, ´es csup´ an az azok k¨ozti o¨sszek¨ottet´eseket, azaz csak a struktur´at ´ırjuk le. A viselked´esi model szerint (1.4. ´abra) konkr´et logik´at, ´aramk¨ori elemeket haszn´alunk m˝ uveletek form´ aj´ aban. A megval´ os´ıtott ford´ıt´ oprogramban csak a legsz¨ uks´egesebb t´ıpusokat haszn´alom. Az std_logic az egy bites vezet´ek, az std_logic_vector pedig t¨obb bites vezet´ekek deklar´al´as´ara szolg´ al, ´es a legfels˝ obb szint˝ u modulban ezeken k´ıv¨ ul nincs sz¨ uks´eg m´as t´ıpusokra.
17
1.1. ´ abra. VHDL modulok fel´ep´ıt´ese [9] entity NAME OF ENTITY i s [ generic g e n e r i c d e c l a r a t i o n s ) ; ] port ( s i g n a l n a m e s : mode type ; −− s i g n a l n a m e s : mode type ) ; end [ NAME OF ENTITY ] ; architecture a r c h i t e c t u r e n a m e of NAME OF ENTITY i s −− D e c l a r a t i o n s −− components , s i g n a l s , c o n s t a n t s , −− functions , procedures , types begin −− S t a t e m e n t s end a r c h i t e c t u r e n a m e ; 1.2. ´ abra. VHDL modulok sz¨oveges v´aza architecture s t r u c t u r a l of BUZZER i s component AND2 port ( in1 , i n 2 : in s t d l o g i c ; out1 : out s t d l o g i c ) ; end component ; −− d e c l a r a t i o n o f s i g n a l s used t o i n t e r c o n n e c t g a t e s s i g n a l DOOR NOT, SBELT NOT, B1 , B2 : s t d l o g i c ; begin −− Component i n s t a n t i a t i o n s s t a t e m e n t s U2 : AND2 port map (IGNITION , DOOR NOT, B1 ) ; end s t r u c t u r a l ; 1.3. ´ abra. VHDL struktur´alis le´ır´as p´elda [9] architecture b e h a v i o r a l of AND2 i s begin out1 <= i n 1 and i n 2 ; end b e h a v i o r a l ; 1.4. ´ abra. VHDL viselked´esi le´ır´as p´elda [9]
18
2. fejezet
A ford´ıt´ asi m´ odszer alapelvei ´ es megval´ os´ıt´ asa A most k¨ ovetkez˝ o fejezetben az ´ altalam fejlesztett ford´ıt´asi m´odszert mutatom be, amelyet Haskell nyelven implement´ altam is a m´odszer tesztelhet˝os´eg´et el˝oseg´ıtve. A m´odszer, vagyis a ford´ıt´ oprogram k¨ ovetelm´enyeinek elemz´es´et, architekt´ ur´aj´at, a k¨oztes adatstrukt´ ur´akat ´es az egyes modulok algoritmusait r´eszletezem a most k¨ovetkez˝o oldalakon. Ahogy a bevezet˝ oben le´ırtam ´es indokoltam, az ´altalam v´alasztott funkcion´alis nyelv a Haskell, ennek ´ertelm´eben az elk´esz´ıtend˝o elj´ar´as ill. szoftver egy Haskell ´es VHDL nyelv k¨oz¨otti ford´ıt´ oprogram. A fejleszt´es ezen t´ ulmen˝oen tov´abbi d¨ont´eseket ig´enyel, ´ıgy k¨ovetkez˝o l´ep´esk´ent meghat´ aroztam a ford´ıt´oprogrammal szemben t´amasztott k¨ovetelm´enyeket: 1. a Haskell forr´ ask´ od ´es VHDL le´ır´as k¨oz¨otti ford´ıt´as legyen teljesen automatikus 2. ford´ıt´ as sor´ an a felhaszn´ al´ o kapjon hiba¨ uzenetet, ha a forr´ask´od szintaxisa nem megfelel˝ o, vagy ha egy Haskell kifejez´es a megk¨ot´esek miatt nem haszn´alhat´o 3. a program modul´ aris fel´ep´ıt´es˝ u legyen, hogy az egyes r´eszek a j¨ov˝oben minden tov´ abbi n´elk¨ ul u ´jrahaszn´ alhat´oak legyenek 4. a j¨ ov˝ oben k¨ onnyen, teh´ at a f˝obb modulok legfeljebb minim´alis m´odos´ıt´asa ut´an implement´ alhat´ oak legyenek optimaliz´aci´os algoritmusok 5. a forr´ ask´ od megk¨ ot´eseit ne kelljen teljes eg´esz´eben a fejleszt´esi peri´odus elej´en meghat´ arozni, vagyis a haszn´ alhat´o Haskell kifejez´esek lehet˝oleg a ford´ıt´oprogram ut´olagos fejleszt´ese n´elk¨ ul, dinamikusan b˝ov´ıthet˝oek legyenek A modul´ aris fel´ep´ıt´es akkor el˝ony¨os, ha a modulok k¨oz¨otti interf´eszek egyszer˝ uek ´es j´ol meghat´ arozottak. Ennek szellem´eben interf´eszk´ent adatfolyamgr´afot vezetek be, ami ´ıgy a Haskell ´es VHDL nyelvek k¨oz¨otti ford´ıt´asn´al k¨oztes reprezent´aci´ok´ent fog szolg´alni. A v´alaszt´ ast az indokolja, hogy egy adatfolyamgr´afb´ol viszonylag egyszer˝ uen gener´alhat´ o hardverle´ır´ as. R¨ oviden o ´gy, hogy a gr´af csom´opontjait a hardverle´ır´as ope¨sszefoglalva u r´atoraira vagy moduljaira k´epezz¨ uk le, a gr´af ´elei pedig egyszer˝ uen vezet´ekek lesznek. A Haskell nyev˝ u forr´ ask´ odb´ ol teh´ at ebben az esetben adatfolyamgr´afot kell k´esz´ıten¨ unk, ami 19
az al˝obbin´el komplik´ altabb feladat, de erre a jelen fejezetben kidolgozott m´odszer megold´ast ad. Mivel a ford´ıt´ as v´egs˝ o kimenete ´ orajelvez´erl´est mag´aban foglal´o hardverle´ır´as lesz, az adatfolyamgr´ afot ´erdemes SDF-k´ent (szinkron adatfolyamgr´af) [26] felfogni. Els˝o k¨ozel´ıt´esben az SDF egyszer˝ us´ıtett, homog´en v´altozat (HSDF) vizsg´alom, ami csak olyan m˝ uveleteket enged meg, amelyek a bemenetr˝ol egyetlen adatot (tokent) mintav´etelezve egyetlen adatot (tokent) szolg´ altatnak kimenet¨ uk¨on. Az ilyen adatfolyamokat egysebess´ eg˝ u (single-rate) [15] adatfolyamoknak nevezz¨ uk. K´es˝obb l´atni fogjuk, hogy az egysebess´eg˝ u adatfolyamok kiz´ ar´ olagoss´ aga nagyban korl´atozza a ford´ıt´o bemenet´ere adhat´o algoritmusokat. Erre a probl´em´ ara a m´ odszer a 3. fejezetben le´ırt kiterjeszt´ese fog megold´ask´ent szolg´alni. HSDF-b˝ol t¨ obb f´ele konkr´et modell [33] is l´etezik, de mivel ezek k¨oz¨ott sz´amottev˝o k¨ ul¨onbs´eg nincs, a v´ alaszt´ asom az EOG (elemi m˝ uveleti gr´af) [10] megold´asra esett. Ehhez a modellhez PIPE n´even rendelkez´esre ´ all egy, az Ir´any´ıt´astechnika ´es Informatika Tansz´eken fejlesztett pipeline optimaliz´ aci´ os m´ odszer ´es programcsal´ad is, ez´altal a 4. k¨ovetelm´eny szint´en teljes¨ ul. Az EOG teh´ at k´et r´eszre, egy Haskell-EOG ´es egy EOG-VHDL ford´ıt´ora osztja a teljes probl´em´at, ´es ezzel tk. az ´ altal´ anos ford´ıt´oprogramokb´ol m´ar ismert frontend-backend strukt´ ur´at kapjuk. A forr´ask´ odi megk¨ ot´esek dinamikus v´altoztathat´os´ag´at (5. k¨ovetelm´eny) a m˝ uvelethalmaz fogalm´ anak bevezet´es´evel val´ os´ıtottam meg. A m˝ uvelethalmaz k¨or¨ ulhat´arolja azokat a m˝ uveleteket (f¨ uggv´enyeket), amelyeket a forr´ask´odban felhaszn´alhatunk, ´es amelyeket haszn´ alva a ford´ıt´ oprogram helyes kimenetet gener´al. Ett˝ol elt´er˝o m˝ uveleteket haszn´alva a programnak hibajelz´est kell adnia, mert az ´ıgy le´ırt forr´ask´od az adott m˝ uvelethalmaz szerint nem ford´ıthat´ o. Ha a dinamikus v´altoztat´as c´elj´at el szeretn´enk ´erni, akkor a m˝ uvelethalmazt a ford´ıt´ oprogram fut´asi idej´eben sz¨ uks´eges ki´ert´ekelni. Ezen megfontol´ asokat alapul v´eve kialak´ıtottam a 2.11. ´abr´an l´athat´o, DFD (adatfolyam diagram) jel¨ ol´essel ´ abr´ azolt architekt´ ur´at. A bemeneti adat tulajdonk´eppen a felhaszn´al´ot´ol ´erkez˝o algoritmus Haskell nyelv˝ u forr´ask´od form´aj´ aban, amit a ford´ıt´ o Haskell-EOG modulja dolgoz fel els˝o l´ep´esk´ent. A modul felhaszn´alja a m˝ uvelethalmaz f¨ uggv´eny-m˝ uvelet lek´epz´es´et (FOpMap) mint m´asik fontos bemen˝o adatot, ´es a transzform´ aci´ okat elv´egezve kimenetk´ent szolg´altat egy EOG-ben reprezent´alt algoritmusle´ır´ ast. Az EOG-VHDL ford´ıt´ o az EOG reprezent´aci´ob´ol automatikusan gener´al egy VHDL modult, amely az algoritmus konkr´et m˝ uveleteket nem tartalmaz´o hardveres v´aza, azaz struktur´alis le´ır´ asa lesz. A kimeneten megjelen˝o VHDL modul p´eld´anyos´ıthat egy´eb, a m˝ uvelethalmazban defini´ alt VHDL modulokat, ezek tartalmazz´ak a m˝ uveletek hi´anyz´o implement´aci´ oit. Az ´ıgy ad´ od´ o VHDL f´ajlok egy¨ uttesen adj´ak az algoritmus hardveres le´ır´as´at, amit ´ atadva egy kereskedelemben kaphat´o FPGA vagy ASIC szint´ezernek, a k´ıv´ant hardvermegval´ os´ıt´ ast kaphatjuk. 20
Algoritmus Haskell nyelven
Felhasználó Művelethalmaz
Fordítás paramétere
Fordítóprogram Haskell-EOG fordító
FOpMap
EOG
EOG-VHDL fordító
OpVhdlMap
VhdlModules
VHDL leírás
Külső szoftver FPGA szintézer eszköz
Hardver FPGA konfiguráció
2.1. ´ abra. A ford´ıt´o architekt´ur´aja
2.1. Az egyes modulok interf´ eszei Ebben a fejezetben sor ker¨ ul az im´ent felv´azolt modulok ki- ´es bemeneti interf´eszeinek r´eszletes ismertet´es´ere, teh´ at a forr´ask´od, az elemi m˝ uveleti gr´af, a VHDL kimenet ´es a m˝ uvelethalmaz csatol´ asi fel¨ uleteinek bemutat´asa k¨ovetkezik.
2.1.1. Bemeneti forr´ ask´ od A m˝ uvelethalmaz bevezet´ese miatt a konkr´et, ford´ıtand´o f¨ uggv´enyeket nem kellett a fejleszt´es kezdet´en meghat´ aroznom, mert azokat csak az aktu´alisan haszn´alt m˝ uvelethalmaz fogja korl´ atozni. Ennek ellen´ere fontos kiz´arni a ford´ıt´oprogram ´altal nem ´ertelmezhet˝ o forr´ask´ odi kifejez´eseket, ´es ezzel k¨or¨ ulhat´arolni a Haskell nyelv bemenetk´ent haszn´alhat´ o r´eszhalmaz´ at. Egy megk¨ ot´esek n´elk¨ uli Haskell k´od hardverk´ent sajnos aligha lenne implement´alhat´ o, gondoljunk pl. az adatrekurzi´ ot vagy f¨ uggv´enyt´ıpust tartalmaz´o ADT-re. Az adatrekurzi´o egyik egyszer˝ u esete a lista, ami elm´eletben ak´ar v´egtelen hossz´ u is lehet, ´ıgy vil´agos, hogy megfelel˝ oen alacsonyan tartott korl´at n´elk¨ ul hardverben nem implement´alhat´o. Ennek megfelel˝ oen minden adatrekurzi´ot vagy param´eterk´ent f¨ uggv´enyt tartalmaz´o ADT-t ki kell z´ arnunk a ford´ıthat´ o t´ıpusok k¨oz¨ ul. Ezeket a t´ıpusokat m´as, hardverkompatibilis 21
t´ıpusokkal kell a j¨ ov˝ oben helyettes´ıten¨ unk. Az ´altal´anos korl´ atoz´ asok ut´ an t´erj¨ unk ´at a haszn´alhat´o f¨ uggv´enyek k´erd´esk¨or´ere. A tov´abbiakban elemi fu eny n´even hivatkozom minden, a m˝ uvelethalmazban le´ırt, k¨oz¨ ggv´ vetlen¨ ul hardverre ford´ıthat´ o f¨ uggv´enyre. A forr´ask´odban haszn´ alhat´ o elemi f¨ uggv´enyeket a gyakorlatban u ´gy tudjuk a m˝ uvelethalmaz elemeire korl´ atozni, hogy elker¨ ulj¨ uk a Haskell szabv´anyt implement´al´o GHC modul, vagyis a Prelude import´ al´ as´ at. Ezt a k¨ovetkez˝o nyelvi pragma seg´ıts´eg´evel ´erhetj¨ uk el:
{-# LANGUAGE NoImplicitPrelude #-}
A megold´ as l´enyege az, hogy a m˝ uvelethalmazban defini´alt elemi f¨ uggv´enyeket a Prelude helyett az InstructionSet.hs import´al´as´an kereszt¨ ul ´erhetj¨ uk csak el, ´es ennek marad´ektalanul teljes¨ ulnie kell minden ford´ıtand´o modulra. Az elemi f¨ uggv´enyeken k´ıv¨ ul csak olyan f¨ uggv´enyeket haszn´alhatunk a forr´ask´odban, amiket mi magunk defini´ altunk, ´es ´ıgy igaz r´ajuk a fenti szab´aly, vagyis, hogy a Prelude helyett az InstructionSet modul m˝ uveleteit haszn´alj´ak. Az ilyen, ´altalunk megadott f¨ uggv´enyekre a tov´ abbiakban ¨ osszetett fu eny n´even fogok hivatkozni. Egyetlen ¨ossze¨ ggv´ tett f¨ uggv´enyt minden forr´ ask´ odnak konvencion´alisan tartalmaznia kell, ez pedig a hwmain , ami a szoftveres main -hez anal´ og m´ odon hardveres topmodulk´ent fog szolg´alni. A forr´ask´od egy lehets´eges p´eld´ aja:
{-# LANGUAGE NoImplicitPrelude #-} module Adder(hwmain) where import InstructionSet hwmain :: Int -> Int -> Int hwmain a b = a+b
Ez a p´elda egy nagyon egyszer˝ u¨ osszead´o ´aramk¨ort val´os´ıt meg. L´athat´o, hogy a Prelude helyett itt az InstructionSet modult import´aljuk, ´es a k´od egy ¨osszead´ot val´os´ıt meg.
2.1.2. Elemi m˝ uveleti gr´ af Az EOG a jelen rendszer egy nagyon fontos k¨oztes reprezent´aci´oja, amelyet interf´eszk´ent haszn´alva a teljes feladatot k´et j´ ol elk¨ ul¨on¨ ul˝o r´eszfeladatra osztjuk. Az EOG r´eszletes le´ır´asa [10] helyett itt csak egy gyors ´ attekint´es k¨ovetkezik a l´enyegi k´erd´esekr˝ol. Az EOG egy adatfolyam h´ al´ ozatok le´ır´ as´ ara szolg´al´o gr´af, amelynek csom´opontjai az adatfolyam h´al´ozat m˝ uveletei, ´elei pedig a m˝ uveletek k¨oz¨otti adatfolyamok. Egy egyszer˝ u o¨sszead´o EOG reprezent´ aci´ oja l´ athat´ o a 2.2. ´ abr´an. A csom´opontokon a m˝ uvelet azonos´ıt´oj´at, ill. als´o sorban annak t´ıpus´at lehet l´atni. Az ´abr´an egyetlen val´ odi, add t´ıpus´ u m˝ uvelet mellett szerepelnek m´eg a ki- ´es bemenetek jelz´es´ere szolg´ al´ o csom´ opontok, SYSTEM t´ıpusn´evvel. 22
IN_1 SYSTEM
IN_2 SYSTEM
add_1 Add
OUT SYSTEM
2.2. ´ abra. Egy ¨osszead´o elemi m˝uveleti gr´afja
A gr´ afot egy nagyon egyszer˝ u form´atum´ u f´ajl ([10], 13. fejezet) seg´ıts´eg´evel ´ırhatjuk le. A f´ ajl h´ arom f´ele sort tartalmazhat, defini´alhatunk m˝ uvelett´ıpusokat, megadhatunk m˝ uveleti csom´ opontokat ´es besz´ urhatunk megjegyz´eseket. A 2.2. ´ abra szerinti ¨ osszead´ o sz¨oveges le´ır´asa pl. a k¨ovetkez˝o:
## a m˝ uvelettípusok következnek (ez egy megjegyzés) # type add 1 # type SYSTEM 0 ## a m˝ uveleti csomópontok leírása követezik (ez is megjegyzés) IN_A SYSTEM IN_B SYSTEM add_1 add IN_A IN_B OUT SYSTEM add_1
A # type kulcssz´ o seg´ıts´eg´evel defini´aljuk az add ´es a SYSTEM m˝ uvelett´ıpusokat, ´es megadjuk azoknak ´ orajelben kifejezett adatfeldolgoz´asi idej´et, vagyis azt az id˝ot, ami a bemenet mintev´etelez´ese ´es az eredm´eny kimenetre val´o kiad´asa k¨oz¨otti ´orajelek sz´ama, azaz latency-j´et (lappang´ asi id˝ o). (a k¨ovetkez˝o p´eld´akban helytakar´ekoss´ag miatt a t´ıpust csak akkor fogom szerepeltetni, amikor a latency is fontos szempont) A csom´ opontok megad´ asakor el˝osz¨or az azonos´ıt´o szerepel, ezt k¨oveti a t´ıpus, majd azoknak a m˝ uveleteknek az azonos´ıt´oi k¨ovetkeznek, amelyek az adott m˝ uvelet bemeneteire csatlakoznak. Az egyes adatok k¨oz¨ott whitespace karaktereknek kell szerepelni¨ uk. A t´ıpusokat az eredeti le´ır´ ast´ ol elt´er˝oen a k´es˝obbiekben karakterf¨ uz´erk´ent, id´ez˝ojelek k¨oz¨ ott fogom szerepeltetni. Az EOG sz¨ oveges le´ır´ as´ ab´ ol l´ athat´o, hogy egy m˝ uveletnek csak egyetlen kimenete lehet, viszont az az egy kimenet b´ armennyi m˝ uvelet bemenet´ere csatlakozhat. Ebb˝ol az k¨ovetkezik, hogyha minden m˝ uvelethez hozz´arendelj¨ uk a kimenet´enek adatt´ıpus´at, akkor ezzel l´enyeg´eben meghat´ aroztuk az ¨ osszes adat´ ut t´ıpus´at is. 23
2.1.3. Kimeneti hardverle´ır´ as A kimeneti VHDL le´ır´ as az EOG-VHDL r´eszegys´eg ´altal gener´alt topmodulb´ol ´es a m˝ uvelethalmazban defini´ alt, az elemi f¨ uggv´enyek viselked´es´evel megegyez˝o VHDL modulokb´ol ´all. Ezek a VHDL modulok f´ ajlok form´aj´aban jelennek meg, amelyek egy¨ uttesen ´atadhat´oak pl. egy FPGA szint´ezer programnak. A most k¨ ovetkez˝ o r´eszben a megold´asomban alkalmazott kimeneti VHDL form´atum bemutat´asa k¨ ovetkezik.
Algebrai adatt´ıpus k´ odol´ asa A forr´ask´od t´ıpusrendszer´enek alapja az ADT, ´ıgy ennek hardveres ´abr´azol´as´ar´ol sz´ot kell ejteni. Egy ADT-vel megadott v´ altoz´o egyszer˝ uen ´abr´azolhat´o bitvektork´ent, aminek fels˝o k bitje a konstruktornak fenntartott szakasz, ami abban az esetben haszn´alatos, ha az adott t´ıpus´ u v´ altoz´ o egyn´el t¨ obb konstruktor haszn´alat´at teszi lehet˝ov´e, vagyis egyn´el t¨obb t´ıpusalternat´ıv´ aval rendelkezik). Egyetlen lehets´eges konstruktor eset´eben k = 0, azaz a konstruktornak sz´ ant biteket nem haszn´aljuk. A fels˝o k bit alatti bitek a konstruktort k¨ovet˝o ´ert´ekek k´ odol´ as´ ara szolg´ alnak. Az, hogy a fels˝ o k bit alatti bitvektorr´eszlet milyen eloszt´asban tartalmazza az egyes ´ert´ekeket, a konstruktort´ ol f¨ ugg. Az ADT-nek megfelel˝o teljes bitvektor hossza a legt¨obb bitet ig´enyl˝o t´ıpusalternat´ıva hossz´ aval egyenl˝o. Ha egy adott t´ıpusalternat´ıva eset´eben az ´abr´azol´as kevesebb bitet ig´enyel, mint a teljes bitvektor sz´eless´ege, akkor a fennmarad´o bitek ´ert´eke konvencion´ alisan 0 . Az im´ent le´ırt reprezent´ aci´ ot egy p´eld´an fogom demonstr´alni. A Maybe Int ADT-hez a k¨ovetkez˝o bitvektort kell l´etrehoznunk:
32. bit
31-0. bitek
Konstruktor
Int
A konstruktor elf´er egy biten, hiszen a Maybe a t´ıpus eset´en ´ert´eke Nothing ill. Just lehet csak. Ezek alapj´ an n´eh´ any konkr´et konstans ´abr´azol´asa:
Nothing => 100000000000000000000000000000000 Just 64 => 000000000000000000000000001000000 Just 31 => 000000000000000000000000000011111
Ebben a p´eld´ aban a Nothing konstruktor k´odja 1 , a Just konstruktor k´odja 0 (ezek l´athat´oak az MSB-n), a fennmarad´ o 32 bit pedig az Int trivi´alis ´abr´azol´asa.
Vez´ erl´ esi szerkezet lek´ epz´ ese A szakirodalomban [10] k´et, alapj´ aban k¨ ul¨onb¨oz˝o vez´erl´esi szerkezetet k¨ ul¨onb¨oztetnek meg, az egyik egy k¨ ozpontos´ıtott vez´erl˝o´aramk¨ort felt´etelez, a m´asik pedig elosztottan, 24
minden m˝ uvelethez saj´ at sorrendi h´al´ozatot t´ars´ıtva oldja meg a vez´erl´es probl´em´aj´at. V´alaszt´ asom az elosztott vez´erl´esre esett, ez ugyanis teljes m´ert´ekben sk´al´azhat´o ´es az adatfolyam-szeml´elettel sokkal ink´abb o¨sszeegyeztethet˝o elj´ar´as. Ezek alapj´ an minden egyes m˝ uvelethez csatolunk egy DCC-t (elosztott vez´erl˝o cella). Az egyszer˝ u m˝ uveletek eset´eben ez egy nagyon egyszer˝ u kapcsol´as, tulajdonk´eppen csak annyi a feladata, hogy amint az o¨sszes bemenet´en vez´erl˝ojel ´erkezett, a kimeneti vez´erl˝obitet akt´ıvra ´ all´ıtja, ez´ altal az adatfolyamban k¨ovetkez˝o m˝ uveletet ´ertes´ıti a m˝ uvelet ´ befejezt´er˝ ol. Ez a funkcionalit´ as egy egyszer˝ u ES kapuval megval´os´ıthat´o. A vez´erl˝ obitek tulajdonk´eppen azt jelzik, hogy a hozz´a tartoz´o adat´ uton ´eppen ´erv´enyes adat van-e. A konkr´et megval´ os´ıt´ as a DCC-hez tartoz´o csom´opont t lefut´asi idej´et˝ol f¨ ugg. Ha egy olyan csom´ opontr´ ol van sz´ o, amely csak egy kombin´aci´os h´al´ozatot tartalmaz (t = 0), ´ kapur´ ´ kapu kimenet´ere egy akkor egyszer˝ u ES ol besz´el¨ unk, ha viszont t > 0, akkor az ES t hossz´ u k´esleltet´est is implement´alnunk kell.
M˝ uveletek kombin´ aci´ os h´ al´ ozatk´ ent Legegyszer˝ ubb esetben az elemi f¨ uggv´eny funkcionalit´as´anak megfelel˝o EOG m˝ uvelet egy egyszer˝ u kombin´ aci´ os h´ al´ ozattal megval´os´ıthat´o. A kombin´aci´os h´al´ozat t´ıpus´ u m˝ uveletek VHDL nyelven t¨ ort´en˝ o le´ır´ as´at az eddig is haszn´alt p´eld´an, az o¨sszead´as m˝ uveleten mutatom be. A 2.3. ´ abr´ an l´ athat´o a m˝ uvelet VHDL k´odja ´es az ebb˝ol Xilinx ISE ´altal gener´alt RTL kapcsol´ asi rajz. Az entity r´esz meghat´ arozza a VHDL modul interf´esz´et, az architecture pedig a bels˝o viselked´est ´ırja le. L´ athat´ o, hogy bitvektork´ent k´et bemenet¨ unk ´es egy kimenet¨ unk van, a kimeneti ´ert´ek pedig a k´et bemenet ¨osszege. Ugyancsak k´et bemenet ´es egy kimenet szolg´al a vez´erl´es lebonyol´ıt´ as´ ara, de ezek m´ar egy bites portok. Mivel a modul egy egyszer˝ u kombin´ aci´ os h´ al´ ozat, megjegyz´esben fel kell t˝ untetn¨ unk a 0 ´atfut´asi id˝ot, erre szolg´al a latency = 0 sor. Minden egyes aszinkron m˝ uvelethez egy-egy ehhez hasonl´o VHDL modul tartozik, ´es ezeket egy-egy k¨ ul¨ on f´ ajlban t´ aroljuk. A modulok rendelkezhetnek generikus param´eterekkel, ami azt jelenti, hogy a VHDL k´od egy r´esz´et a p´eld´ anyos´ıt´ as hely´en megadott adatokkal cser´eli ki a szint´ezer. Ez egy fontos tulajdons´ ag, ugyanis ezt a lehet˝os´eget kihaszn´alva el´eg pl. egy ´altal´anos o¨sszead´ ot defini´alnunk, aminek a bitsz´ am param´eter´et p´eld´anyos´ıt´askor adjuk meg, ´ıgy nem kell a k¨ ul¨onb¨ oz˝ o bitsz´ am´ u m˝ uveletekhez k¨ ul¨onb¨oz˝o VHDL modult l´etrehoznunk a m˝ uvelethalmazban. A CλasH egyik h´ atr´ anya, hogy a VHDL k´odban nem haszn´al generikus param´etereket.
M˝ uveletek szinkron h´ al´ ozatk´ ent L´eteznek olyan m˝ uveletek, amelyek csak szinkron h´al´ozatk´ent val´os´ıthat´oak meg, ilyen pl. egy ´ allapotg´ep, vagy egy blokk-RAM olvas´o ´es ´ır´o m˝ uvelete. Ezen k´ıv¨ ul minden kombin´aci´os h´ al´ ozattal megadott m˝ uvelet le´ırhat´o szinkron h´al´ozattal is. Egy aszinkron h´al´ ozat helyett bevezetett szinkron h´al´ozatnak t¨obbek k¨oz¨ott akkor van l´etjogosults´aga, ha a
25
l i b r a r y IEEE ; use IEEE . STD LOGIC 1164 .ALL; use IEEE . STD LOGIC ARITH .ALL; use IEEE . STD LOGIC UNSIGNED .ALL; −− l a t e n c y = 0 entity add i s generic ( p1 : i n t e g e r ) ; port ( a : in s t d l o g i c b : in s t d l o g i c q : out s t d l o g i c ca : in s t d l o g i c cb : in s t d l o g i c cq : out s t d l o g i c ); end add ;
v e c t o r ( ( p1 −1) downto 0 ) ; v e c t o r ( ( p1 −1) downto 0 ) ; v e c t o r ( ( p1 −1) downto 0 ) ; ; ;
architecture B e h a v i o r a l of add i s begin q <= a+b ; cq <= ca and cb ; end B e h a v i o r a l ; 2.3. ´ abra. Aszinkron ¨osszead´o
kombin´aci´os h´ al´ ozatk´ent megval´ os´ıtott m˝ uveletek nagy sz´ama miatt a flip-flopok k¨oz¨otti vezet´ekek nagyon hossz´ uak lenn´enek. Ekkor ugyanis a szint´ezernek az eg´esz alkalmaz´as ´orajel´et alacsonyan kellene tartania, ami negat´ıv hat´assal lehet egy m´asik r´eszegys´eg teljes´ıtm´eny´ere. Ebben az esetben az szinkron h´al´ozatra val´o ´att´er´es jav´ıthat a maxim´alis ´orajelsebess´egen, ´ıgy a teljes rendszer teljes´ıtm´eny´en. Az el˝obbi ¨ osszead´ o szinkronh´ al´ ozatt´ a alak´ıtott v´altozata a 2.4. ´abr´an k¨ovethet˝o nyomon. Az el˝oz˝oekhez k´epest az RTL ´ abr´ an egyetlen szembet˝ un˝o v´altoz´as tal´alhat´o, ez pedig a vez´erl´es kimenet´en´el megjelen˝ o D flip-flop a vez´erl˝o ´ag kimenet´en. A k´odban megjelenik a clk ´orajel port, ´es a process szekci´ o az ´orajelre t¨ort´en˝o vez´erl´eshez. A latency itt 1, mivel a m˝ uvelet egy ´ orajel alatt hajt´ odik v´egre. Id˝oig´enyesebb m˝ uveletekn´el (pl. oszt´as) sokszor el˝ofordul, hogy a fut´asi id˝o t > 1, ilyen 26
−− l a t e n c y = 1 entity add i s generic ( p1 : i n t e g e r ) ; port ( a : in s t d l o g i c b : in s t d l o g i c q : out s t d l o g i c ca : in s t d l o g i c cb : in s t d l o g i c cq : out s t d l o g i c c l k : in s t d l o g i c ); end add ;
v e c t o r ( ( p1 −1) downto 0 ) ; v e c t o r ( ( p1 −1) downto 0 ) ; v e c t o r ( ( p1 −1) downto 0 ) ; ; ; ;
architecture B e h a v i o r a l of add i s begin q <= a+b ; p r o c e s s 1 : process ( c l k ) begin i f ( c l k ’ e v e n t and c l k = ’ 1 ’ ) then cq <= ca and cb ; end i f ; end process ; end B e h a v i o r a l ; 2.4. ´ abra. Szinkron o¨sszead´o
esetben a flip-flop helyett t¨ obb o´rajel hossz´ u id˝oz´ıt˝o egys´eget kell be´ep´ıten¨ unk, vagy a vez´erl´es kimenet´et k¨ ozvetlen¨ ul a bels˝o ´allapotg´epre kell k¨otn¨ unk.
Legfels˝ o szint˝ u modul A legfels˝ o szint˝ u modul az egyetlen, ford´ıt´as sor´an gener´alt VHDL modul. Ez tulajdonk´eppen az EOG gr´ afnak megfeleltethet˝o hardverle´ır´as, ami kiz´ar´olag modul p´eld´anyos´ıt´asokat ´es a modulok k¨ ozt fut´ o vezet´ekeket (bitvektorokat) tartalmaz. A topmodulban minden EOG m˝ uvelet p´eld´ anyos´ıt´ask´ent, ´es minden EOG adatfolyam bitvektork´ent jelenik meg. 27
entity main i s port ( i n 1 in2 in3 out1 ); end main ;
: : : :
in in in out
std std std std
logic logic logic logic
vector vector vector vector
(39 (39 (39 (39
downto downto downto downto
0); 0); 0); 0)
architecture B e h a v i o r a l of main i s component add i s generic ( p1 : i n t e g e r ) ; port ( a : in s t d l o g i c v e c t o r ( ( p1 −1) downto 0 ) ; b : in s t d l o g i c v e c t o r ( ( p1 −1) downto 0 ) ; q : out s t d l o g i c v e c t o r ( ( p1 −1) downto 0 ) ); end component ; s i g n a l x : s t d l o g i c v e c t o r ( 3 9 downto 0 ) ; s i g n a l cx : b o o l e a n ; −− o s s z e s t o b b i k o z t e s a d a t f o l y a m d e k l a r a c i o j a begin −− add p e l d a n y o s i t a s a add1 neven add1 : add generic map ( p1 => 4 0 ) port map( in1 , in2 , x ) ; −− add p e l d a n y o s i t a s a add2 neven add2 : add generic map ( p1 => 4 0 ) port map( x , in3 , out1 ) ; −− o s s z e s t o b b i p e l d a n y o s i t a s end B e h a v i o r a l ; 2.5. ´ abra. VHDL topmodul p´elda
A topmodul egy lehets´eges p´eld´ aj´ at a 2.5. ´abra mutatja. Az entity r´esz a teljes alkalmaz´as ki- ´es bemeneteit sorolja fel. Az architecture szakaszban el˝osz¨or deklar´alnunk kell minden k´es˝ obb haszn´ alt modult (component kifejez´es), majd az adatfolyamoknak megfelel˝o vezet´ekeket deklar´ aljuk. Minden adatfolyamhoz k´et deklar´aci´o tartozik, egyik az adatvezet´ekeket, m´ asik pedig a vez´erl˝ o vezet´eket hozza l´etre. Az architecture t¨ orzs´eben a m˝ uveleteknek megfelel˝o modulp´eld´anyos´ıt´asok szerepelnek. A modulok portjaik´ent egyr´eszt az im´ent deklar´alt vezet´ekek, m´asr´eszt az alkalmaz´as ki- ´es bemenetei szerepelhetnek.
2.1.4. M˝ uvelethalmaz A m˝ uvelethalmaz egy olyan interf´esz, ami felsorolja a forr´ask´odban leg´alisan felhaszn´alhat´o f¨ uggv´enyeket ´es t´ıpusokat, ill. ezekhez konkr´et hardveres megval´os´ıt´ast t´ars´ıt VHDL le´ır´as 28
form´aj´ aban. A m˝ uvelethalmazt egyar´ ant felhaszn´alja a Haskell-EOG ´es az EOG-VHDL ford´ıt´omodul is. Az el˝ obbinek ez alapj´ an kell eld¨ontenie, hogy a haszn´alt m˝ uveletek defini´altak-e, vagyis a megadott hib´ atlan szintaktik´ aj´ u forr´ask´od t´enylegesen ford´ıthat´o-e. A VHDL-t gener´al´ o ford´ıt´o a m˝ uvelethalmazban defini´alt VHDL modulokat p´eld´anyos´ıtja a kimeneti le´ır´asban. A m˝ uvelethalmaz el˝ osz¨ or is mag´aban foglalja a m´ar bevezetett, m˝ uvelethalmazra jellemz˝o f¨ uggv´enyeket export´ al´ o modult (InstructionSet.hs ), amit a felhaszn´al´onak a Prelude helyett import´ alnia kell saj´ at forr´ask´odj´aban. A haszn´alhat´o elemi f¨ uggv´enyek list´aj´at, vagyis a FOpMap-ot ezen k´ıv¨ ul a Haskell-EOG ford´ıt´o is megkapja a k¨ovetkez˝o p´eld´aval szeml´eltetett f´ ajlform´ atumban:
GHC.Num.(+) GHC.Classes.(||) GHC.Num.abs
Add Or Abs
Ez a lek´epz´es kett˝ os c´elt szolg´al. Egyr´eszt a Haskell-EOG ford´ıt´o ennek seg´ıts´eg´evel el tudja d¨ onteni, hogy egy adott elemi f¨ uggv´eny haszn´alata jogos-e, m´asr´eszt az EOG le´ır´asban nem enged´elyezett karaktersorozatok helyett helyettes´ıt˝o neveket vezet be. (a p´eld´aban a (+) nev˝ u helyett bevezet´esre ker¨ ult az Add f¨ uggv´eny) Egy m´ asik fontos lek´epez´es az OpVhdlMap, ami az adott esetben polimorf m´odon le´ırt elemi f¨ uggv´enyeket EOG m˝ uveleti nevekre k´epezi le. (ezek a nevek m´ar megegyeznek a m˝ uveletnek megfelel˝ o VHDL modul nev´evel) A polimorf le´ır´as azt jelenti, hogy a f¨ uggv´eny neve ut´ an generikus param´eterk´ent (<> ) szerepelnek a f¨ uggv´eny t´ıpusargumentumai is. A lek´epz´es egy lehets´eges p´eld´ aja:
Add
Add Add Or Abs
add<32> add<8> add_float or abs<32>
Ebb˝ ol a p´eld´ ab´ ol az l´ athat´ o, hogy a 8 ´es 32 bites Int -re vonatkoz´o ¨osszead´as egyar´ant elv´egezhet˝ o az add nev˝ u VHDL modullal, egy esetleges Float t´ıpusargumentummal megh´ıvott o¨sszead´ ast viszont m´ ar egy m´asik VHDL modulnak kell hardveresen implement´alnia, mert a lebeg˝ opontos ´ert´ekek ¨ osszead´asa az eg´esz t´ıpusok´ehoz k´epest t´ uls´agosan elt´er. A m˝ uvelethalmaz az im´enti lek´epz´eseken k´ıv¨ ul defini´alja az egyes elemi f¨ uggv´enyek viselked´es´et le´ır´ o VHDL modulokat a 2.3. ´es a 2.4. ´abr´akon m´ar bemutatott form´aban. A modulok interf´esze (entity) k¨ot¨ott sorrendben tartalmazza a portokat, egy k´et bemenet˝ u EOG m˝ uvelet eset´eben pl. az ´abr´akon l´athat´o form´aban kell azokat megadni. A modul portjainak els˝ o fele az adatokat, a m´asodik fele a vez´erl´est szolg´alja. Az a ´es a b a modul bemeneti param´eterei, a q a kimenet, a c prefixszel ell´atott v´altozatok pedig az ugyanezen jelekhez tartoz´ o vez´erl˝obitek. Ahogy az EOG interf´esz le´ır´as´an´al m´ar ´ırtam, a 29
m˝ uveletek csak egyetlen kimenettel rendelkezhetnek, ez azt jelenti, hogy a modul portjai k¨oz¨ ul pontosan kett˝ o, egy adat ´es egy vez´erl˝o port lesz kimeneti ir´any´ u. Az eddigiek ¨ osszefoglal´ asak´eppen n´egy pontban felsoroltam a m˝ uvelethalmaz elemeit: • InstructionSet.hs - az egyed¨ uli, haszn´alhat´o, be´ep´ıtett” k¨onyvt´ar ” • fop.map - FOpMap lek´epz´es • opvhdl.map - OpVhdl lek´epz´es • m˝ uveletenk´ent egy-egy .vhdl f´ ajl - a m˝ uvelet hardverle´ır´as´ara
2.2. Forr´ ask´ od ford´ıt´ asa elemi m˝ uveleti gr´ afra A 2.1.2 fejezetben bemutatott elemi m˝ uveleti gr´af a ford´ıt´as sor´an egy k¨ozb¨ uls˝o, egyszer˝ u absztrakt le´ır´ as´ at adja a funkcion´ alis nyelven megfogalmazott algoritmusnak. A most k¨ovetkez˝o fejezetben ismertetem a Haskell forr´ask´od ´es az elemi m˝ uveleti gr´af k¨oz¨otti ´atalak´ıt´asi l´ep´eseket, ´es az ezekhez sz¨ uks´eges algoritmusokat. A forr´ask´ odok feldolgoz´ as´ at szerencs´ere nem kell a legels˝o l´ep´essel, vagyis a lexik´alis elemz´essel kezdeni, ugyanis ehhez a forr´asnyelvhez l´etezik m´ar szabad forr´ask´od´ u ford´ıt´oprogram. A Haskell forr´ ask´ odok PC-s t´ argyk´odra ford´ıt´as´ara a jelenleg legink´abb elterjedt szoftver a Glasgow Haskell Compiler (GHC) [7]. Ez a ford´ıt´o is, mint ´altal´aban a ford´ıt´ok t¨obbs´ege k´et j´ ol elk¨ ul¨ on´ıthet˝ o ford´ıt´ asi f´azist k¨ ul¨onb¨oztet meg, egyik a forr´ask´odot egy k¨oztes, leegyszer˝ us´ıtett nyelvre ford´ıtja (frontend fokozat), a m´asik pedig a k¨oztes nyelvi le´ır´asb´ol v´eg¨ ul t´ argyk´ odot gener´ al (backend fokozat). A GHC frontend v´egzi a lexik´ alis ´es szintaktikai elemz´est, a szintaktikai ´edes´ıt˝oszereket feloldja, elk´esz´ıti az absztrakt szintaxis f´at (AST) ´es alapvet˝o k´odoptimaliz´al´ast v´egez. Ezek a funkci´ ok a jelen rendszer sz´ am´ ara is n´elk¨ ul¨ozhetetlenek, ez´ert c´elszer˝ u ezt a – m´ar megl´ev˝o – programr´eszt felhaszn´ alni, elker¨ ulve ezzel ugyanilyen funkci´ok saj´at k´oddal t¨ort´en˝o u ´jb´oli implement´ al´ as´ at. A CλasH a legels˝o, optimaliz´aci´o el˝otti Core reprezent´aci´ot veszi alapul, az ´en megold´ asom pedig az egyszer˝ us´ıt´esek ut´anit. Ez a megold´as az´ert el˝ony¨os, mert kihaszn´ alja a GHC nagyfok´ u optimaliz´al´as´at, ´ıgy t¨obbek k¨oz¨ott a magasszint˝ u ´at´ır´asi szab´alyok (rewrite rules) is lefutnak. A GHC backendje u ´gy k´esz¨ ult, hogy a ford´ıt´as v´eg´en processzoros t´argyk´odot kapjunk, ´ıgy ez a r´esz sz´ amunkra nem u ´jrafelhaszn´alhat´o. A frontend ´es backend k¨ oz¨ ott az 1.2.1. fejezetben m´ar ismertetett Core nyelv szolg´al k¨oztes interf´eszk´ent. A Haskell forr´ ask´ od helyett az EOG ford´ıt´ashoz ezt a reprezent´aci´ot tekintem kiindul´ asi alapnak. Ha j¨ ov˝ oben Haskell helyett m´as funkcion´alis nyelvet k´ıv´anunk hardveres k¨ornyezetre ford´ıtani, akkor egy j´o megold´as lehet Core alakra hozni azt; ´ıgy a dolgozatom sor´ an elk´esz¨ ult modulok teljes eg´esz´eben felhaszn´alhat´oak lesznek, csup´an a GHC frontend r´esz helyett kell egy adott nyelvre specializ´alt frontendet implement´alni. A GHC alapj´ aban egy t¨ obb platformra is leford´ıtott parancssori program, de emellett a konkr´et ford´ıt´ ast v´egz˝ o r´eszeket kiexport´alt´ak k¨onyvt´ari f¨ uggv´enyekk´ent is, vagyis egy Haskell nyelven ´ırt programmal k¨ onnyed´en tudunk Haskell k´odot ford´ıtani, s˝ot, a ford´ıt´as l´ep´eseit ´es azok param´eter´et m´elyrehat´oan tudjuk szab´alyozni. 30
A k¨ ovetkez˝ o alfejezetekben bemutatom az egyes l´ep´esek algoritmusait, amik alapj´ an implement´ altam az elk´esz¨ ult Haskell-EOG modult. Ebben a r´eszben szerepelni fognak Core nyelvi r´eszletek, ´ıgy a haszn´alt szintaktik´ar´ol sz´ot kell ejtenem. A Core faszerkezet sz¨ ul˝o-gyermek viszony´ at beh´ uz´ assal fogom jel¨olni, ahol minden azonos sz¨ ul˝oh¨oz tartoz´ o gyermek azonos oszlopban kezd˝ odik. P´eld´ an szeml´eltetve:
a = lam t u app (+) var t var u
Az app teh´ at a lam egyed¨ uli gyereke, a k´et var sz¨ ul˝oje pedig az app . Az a = egy azonos´ıt´ o-kifejez´es o ¨sszerendel´est (a Core szerint ez a Bind ) jelent, ahol a kifejez´est gyerekk´ent ´ abr´ azoljuk (ez lesz a lam ). A var -nak ´es a lit -nek nincs gyereke, a lam -nak ´es a let -nek egy gyereke van. Az app nak annyi gyermeke van, amennyi param´eterrel rendelkezik, ami elt´er´es az eredeti Core reprezent´ aci´ ohoz k´epest, hiszen a lambda-kalkulusban csak egy param´eter˝ u alkalmaz´asok tal´alhat´ oak. Ezt a reprezent´ aci´ ot az egyszer˝ us´eg kedv´e´ert vezetem be, de a gyakorlati megval´ os´ıt´ asn´ al ugyancsak el˝ oker¨ ul ez az ´atalak´ıt´as. Szerencs´ere a b˝obesz´ed˝ u Core App csom´opontjait f¨ uggv´enyn´evre ´es param´eterlist´ara ´atalak´ıt´o m˝ uveletet egy GHC k¨onyvt´ari f¨ uggv´eny (collectArgs ) megh´ıv´as´aval k¨onnyed´en el tudjuk v´egezni. A case csom´ opont sorrendben els˝o gyermekek´ent a saj´at kifejez´es´et, t¨obbi gyermekk´ent pedig az el´ agaz´ o alternat´ıv´ akat tartalmazza. A 2.6. ´ abr´ an a Haskell-EOG ford´ıt´o architekt´ ur´aja l´athat´o, ahol az egyes algoritmusok c´ımszavakban:
1. GHC frontend: forr´ ask´ od magasszint˝ u feldolgoz´asa 2. CaseReduction: el´ agaz´ asok ´atalak´ıt´asa 3. IterateConversion: iter´ aci´ ok ´atalak´ıt´asa 4. AppRename: alkalmaz´ asok ´atnevez´ese 5. CoreToTree: h´ıv´ asi f´ ara t¨ ort´en˝o ´atalak´ıt´as 6. TreeSimplifier: faegyszer˝ us´ıt´es 7. ConvertToEOG: elemi m˝ uveleti gr´afra t¨ort´en˝o ´atalak´ıt´as A k¨ ovetkez˝ o alfejezetekben r´eszletesen ismertetem a ford´ıt´as egym´as-ut´ani f´azisait. 31
Algoritmus Haskell nyelven
Művelethalmaz
GHC frontend
FOpMap OpVhdlMap
CaseReduction
IterateConversion
AppRename
ConvertToEOG
TreeSimplifier
CoreToTree
Elemi műveleti gráf
2.6. ´ abra. A Haskell-EOG modul architekt´ur´aja
2.2.1. Forr´ ask´ od magasszint˝ u feldolgoz´ asa Ahogy m´ar sz´ o volt r´ ola, a Haskell forr´ ask´od Core reprezent´aci´ora alak´ıt´as´at a GHC k¨onyvt´ari f¨ uggv´enyeivel el lehet v´egezni. A CλasH megold´as´aval ellent´etben nem a kezdeti Core kimenetet haszn´ alom fel, hanem kihaszn´alom a GHC optimaliz´aci´os algoritmusait, ´es az algoritmusok lefut´ asa ut´ an keletkez˝ o Core ´allapotot haszn´alom a k¨ovetkez˝o ´atalak´ıt´asi l´ep´es bemenetek´ent. A GHC h´ arom optimaliz´ aci´ os szintet k¨ ul¨onb¨oztet meg, 0 a nem optimaliz´alt, 1 a j´o min˝os´eg˝ u, de nem t´ ul hossz´ u ford´ıt´ assal el´erhet˝o, a 2 pedig a maxim´alisan optimaliz´alt k´od. Mivel a hardver szempontj´ ab´ ol nagyon fontos az er˝oforr´asig´eny minim´alisra szor´ıt´asa, ez´ert a ford´ıt´ oprogramban a maxim´ alisan optimaliz´alt k´odot haszn´alom.
2.2.2. El´ agaz´ asok ´ atalak´ıt´ asa A Core reprezent´ aci´ o k´ets´egk´ıv¨ ul legnagyobb bonyolults´ag´ u elemei a Case csom´opontok, amik egyar´ant haszn´ alatosak el´ agaz´ asok ´es mintailleszt´ esek le´ır´as´ara. A ford´ıt´as sor´an el˝obb vagy ut´ obb a Core ezen r´eszeit is EOG elemekre (m˝ uveletekre ´es adatfolyamokra) kell ford´ıtanunk. Azt a megold´ ast v´ alasztottam, hogy a Case csom´opontokat m´ar a ford´ıt´as elej´en Let ´es App csom´ opontokra alak´ıtom, ugyanis ezek EOG-ra ford´ıt´asa trivi´alisabb, ´es a k´es˝obb sorra ker¨ ul˝ o CoreToTree algoritmus ezt minden tov´abbi er˝ofesz´ıt´es n´elk¨ ul meg is fogja tenni. Ennek a l´ep´esnek a miel˝ obbi elv´egz´ese az´ert fontos, mert ez´altal a bonyolult Case szerkezettel a tov´ abbiakban nem kell foglalkoznom. A [24] 4.3.5 fejezet´eben ismertetett Case normalization elj´ar´asok nagyon hasonl´o feladatot l´atnak el, mint az itt le´ırt CaseReduction transzform´aci´o. A k¨ ul¨onbs´eg az, hogy az 32
´en megold´ asomban minden Case csom´opontot azonnal megsz¨ untetek, ezzel egyszer˝ us´ıtve a tov´abbi ´ atalak´ıt´ asi l´ep´eseket.
01: case of b 02: E 03: . 04: . 05: alt C1 c11 c12 06: . 07: . 08: . 09: . 10: . 11: E1 12: alt C2 c21 c22 13: . 14: . 15: . 16: . 17: . 18: E2
01: 02: let scrutinee_1 = E 03: b = scrutinee_1 04: app mux 05: let c11 = app select 06: var scrutinee_1 07: c12 = app select 08: var scrutinee_1 09: app ifcon 10: var scrutinee_1 11: E1 12: let c21 = app select 13: var scrutinee_1 14: c22 = app select 15: var scrutinee_1 16: app ifcon 17: var scrutinee_1 18: E2
2.7. ´ abra. CaseReduction a´ltal´anos k´eplet (a pont-ok csak az ´atl´athat´os´agot seg´ıtik)
Az itt ismertetett algoritmus az, amely bemenetk´ent kapja a k¨ozvetlen¨ ul a GHC k¨onyvt´arakb´ ol sz´ armaz´ o Core k´ odot, majd a 2.7. ´abr´an ´altal´anoss´agban ismertetett ´atalak´ıt´ast elv´egzi. Els˝o l´ep´esben bevezet¨ unk egy u ´j v´altoz´ot, scrutinee_1 n´even, amihez a fenti k´odban E -nek jel¨ olt scrutinee -t k¨ otj¨ uk. (ez anal´og a CλasH Scrutinee simplification normaliz´ aci´oj´aval) A Case szintaktik´ aja megengedi egy u ´j v´altoz´o bevezet´es´et (a fenti k´odban ezt b -vel jel¨ oltem), ilyen esetben ehhez hozz´arendelj¨ uk a scrutinee_1 -et, teh´at v´egeredm´enyben mindk´et v´ altoz´ o a scrutinee kifejez´esre fog mutatni. A CλasH ezt az ut´obbi v´altoz´ o bevezet´est elimin´ alja az´ altal, hogy a k´odban az o¨sszes ilyen v´altoz´ot lecser´eli az u ´j scrutinee_1 v´ altoz´ ora. Ezt a megold´ ast nem tartottam szerencs´esnek, ugyanis az alkifejez´esek u ´jabb bej´ ar´ asa miatt plusz k¨ olts´eggel j´ar. Az el˝ oz˝ o elj´ ar´ assal l´etrehozott Let t¨orzs´ebe a mux nev˝ u, ebben a f´azisban l´etrehozott alkalmaz´ as ker¨ ul. A mux egy olyan f¨ uggv´eny, amely t¨obb Maybe a t´ıpus´ u bemenetb˝ ol egyetlen Maybe a t´ıpus´ u adattal t´er vissza. Azzal a bemenettel t´er¨ unk vissza v´altoztat´ as n´elk¨ ul, amelyik Just konstruktorral rendelkezik. (ha t¨obb ilyen is van, akkor a param´eterek sorrendj´eben legels˝ ovel t´er¨ unk vissza)
33
Egy h´arom bemenet˝ u mux viselked´es´et tekintve a k¨ovetkez˝o, gyakorlatban nem realiz´alt Haskell k´oddal lenne ekvivalens: mux3 a b c = i f ( isJust ( a ) ) then a else i f ( isJust ( b ) ) then b else c
Fontos megjegyezni, hogy ez a Haskell k´od nem ker¨ ul leford´ıt´asra, mert ha ez megt¨ort´enne, azzal az eg´esz ´ atalak´ıt´ as ´ertelm´et veszten´e, ugyanis ez a k´od szint´en tartalmaz Case szerkezetet (if form´ aj´ aban), teh´ at ezzel a Case teljes elimin´al´asa nem val´osult volna meg. A megold´as az lesz, hogy ezt a speci´ alis f¨ uggv´enyt elemi f¨ uggv´enyk´ent haszn´alom, teh´at k¨ozvetlen¨ ul hardverben fogom implement´alni. T´erj¨ unk ´at a Case alternat´ıv´ aira, az alt csom´opontokra. Minden ilyen bejegyz´es egyegy Let csom´ opontra fordul, amiben az alt -ban bevezetett o¨sszes v´altoz´ot k¨otni fogjuk. (hasonl´oan a CλasH Case Normalization megold´as´ahoz) A k¨ot´es v´altoz´oja az alt -ban megjelen˝o v´altoz´ o, az ahhoz k¨ ot¨ ott kifejez´es pedig a select alkalmaz´as lesz. P´eldak´ent tekints¨ uk meg, hogy a select milyen k´epzeletbeli viselked´est takar (a v´altoz´o megnevez´esek a 2.7. ´ abr´ ab´ ol sz´armaznak): s e l e c t C 1 0 x = case x of { C1 c11 −> c11 }
Ezzel tulajdonk´eppen az illeszt´est val´os´ıtottuk meg oly m´odon, hogy a select f¨ uggv´eny egy adott ADT kifejez´esb˝ ol az adott konstruktorhoz tartoz´o egyik argumentum´ert´eket adja vissza. Az im´enti p´eldak´ od a C1 konstruktor ut´ani legels˝o param´etert, azaz a c11 -et adja vissza. A mux -hoz hasonl´ oan ez a k´ od is kiz´ar´olag hardverben ker¨ ul implement´al´asra. A Let kifejez´es t¨ orzs´er˝ ol m´eg nem esett sz´o. A t¨orzs egy ifcon nev˝ u f¨ uggv´eny lesz, ami az´ert felel, hogy csak a megfelel˝ o konstruktor eset´eben ´ert´ekelj¨ uk ki az adott kifejez´est, ´es adjuk vissza annak eredm´eny´et. Az el˝obbiekhez hasonl´ oan az ifcon is le´ırhat´o k´epzeletbeli Haskell k´oddal: i f c o n C 1 x e = case x of { C1 −> Just e ; −> Nothing }
Ebben az esetben teh´ at akkor adjuk vissza az e kifejez´est (ami az e ki´ert´ekel´es´et fogja maga ut´an vonni), ha az x argumentum a C1 konstruktorral kapott ´ert´eket. A bevezetett mux , select ´es ifcon alkalmaz´ asok teh´at az im´ent ismertetett szemantik´akkal helyettes´ıteni tudnak egy Case csom´ opontot, ´ıgy ez ut´obbira a tov´abbiakban nem lesz sz¨ uks´eg. P´eldak´ent tekints¨ unk meg egy illeszt´est (2.8. ´abra), ´es egy el´agaz´ast (2.9. ´abra) megval´os´ıt´o Core f´at, ´es azoknak CaseReduction ´ atalak´ıt´as ut´ani v´altozatait!
34
01: case (bind wild) 02: app foo 03: lit 3 04: 05: alt (,,) a b c 06: 07: 08: 09: 10: 11: app bar 12: var a 13: var b
01: 02: let scrutinee_1 = app foo 03: lit 3 04: app mux 05: let a = app select<(,,),0> 06: var scrutinee_1 07: b = app select<(,,),1> 08: var scrutinee_1 09: c = app select<(,,),2> 10: var scrutinee_1 11: app bar 12: var a 13: var b 2.8. ´ abra. CaseReduction illeszt´es p´elda
01: case 02: app foo 03: lit 3 04: 05: alt Left a 06: 07: 08: 09: app bar1 10: var a 11: alt Right a 12: 13: 14: 15: app bar2 16: var a
01: 02: let scrutinee_2 = app foo 03: lit 3 04: app mux 05: let a = app select 06: var scrutinee_2 07: app ifcon 08: var scrutinee_2 09: app bar1 10: var a 11: let a = app select 12: var scrutinee_2 13: app ifcon 14: var scrutinee_2 15: app bar2 16: var a 2.9. ´ abra. CaseReduction el´agaz´as p´elda
35
2.2.3. Iter´ aci´ ok ´ atalak´ıt´ asa A Core Rec {} kifejez´eseit a ford´ıt´ oprogram nem dolgozza fel, ez ugyanis rekurz´ıv f¨ uggv´enyeket vagy v´ altoz´ ohivatkoz´ asokat eredm´enyezne. Rekurzi´o n´elk¨ ul viszont algoritmusok nagy sz´am´at z´ arn´ ank ki a ford´ıt´ as al´ ol, ami nem engedhet˝o meg. A probl´ema megold´as´ara az iterate Haskell f¨ uggv´eny haszn´alat´at vezetem be, amelynek eredeti defin´ıci´oja a GHC.List modulban tal´ alhat´ o: i t e r a t e : : ( a −> a ) −> a −> [ a ] iterate f x = x : iterate f ( f x)
Az iterate els˝ o param´etere egy egyparam´eteres f f¨ uggv´eny, ami minden iter´aci´oban megh´ıv´odik. Az f az els˝ o iter´ aci´ os l´ep´esn´el az iterate m´asodik param´eterek´ent megadott kezdeti ´ert´eket, a k¨ ovetkez˝ o iter´ aci´ ok sor´an pedig az azt megel˝oz˝o iter´aci´os l´ep´es kimenet´et kapja. Az iterate k¨ ozvetlen¨ ul nem ford´ıthat´o EOG-ra, mivel f¨ uggv´enyparam´etert tartalmaz. A megold´as az IterateConversion Core2Core transzform´aci´o bevezet´ese, amely a ford´ıt´o k¨ovetkez˝o l´ep´esei sz´ am´ ara feldolgozhat´ o form´aba alak´ıtja az iter´aci´ot. A CaseReduction l´ep´esn´el megismert szintaktika szerint elk´esz´ıtettem az IterateConversion transzform´ aci´ o´ altal´ anos k´eplet´et, amit a 2.10. ´abr´an ismertetek.
01: app iterate_old 02: lam x 03: E 04: E2 05: 06: 07:
01: let x = 02: app iterate_new 03: var it_out 04: E2 05: let it_out = 06: E 07: var it_out
2.10. ´ abra. IterateConversion a´ltal´anos k´eplet
A lam csom´ opont helyett egy let csom´opontot vezetek be, ami a lam -ban szerepl˝o x param´eterhez egy u ´jonnan l´etrehozott kifejez´est rendel. Egy u ´jabb let csom´opont szint´en bevezet´esre ker¨ ul, ami az it_out azonos´ıt´ohoz az eredeti bels˝o f¨ uggv´eny lam n´elk¨ uli t¨orzs´et, azaz az E -t rendeli. Ez ut´obbira az´ert van sz¨ uks´eg, hogy az E kifejez´esre a tov´abbiakban k´et helyr˝ ol is hivatkozhassunk. Az x -hez rendelt u ´j kifejez´es a f¨ uggv´enyparam´etert˝ol mentes iterate_new alkalmaz´as, aminek els˝o param´etere az im´ent bevezetett it_out -ra mutat´o v´altoz´o, m´asodik param´etere pedig az E2 , vagyis a kezdeti ´ert´ek kifejez´ese. Az ´atalak´ıt´ ast megvizsg´ alva ´eszrevehet˝o, hogy a var it_out bevezet´ese rekurzi´ot eredm´enyez, ugyanis az egy k´es˝ obb bevezetett azonos´ıt´ora hivatkozik. (ehhez m´eg azt kell l´atni, hogy az E kifejez´esgr´ af valahol tartalmaz egy var x csom´opontot). Ahhoz, hogy a k´es˝obbi CoreToTree algoritmus a behelyettes´ıt´esekkel ne ker¨ ulj¨on v´egtelenciklusba, a var it_out -ot egy olyan megjegyz´essel kell ell´atnunk, ami az inline -t ezen a ponton 36
megakad´ alyozza.
2.2.4. Alkalmaz´ asok ´ atnevez´ ese Minden elemi f¨ uggv´eny alkalmaz´ as´ab´ol EOG m˝ uvelet lesz, ez´ert ezeknek az alkalmaz´asoknak egyedi n´evvel kell rendelkezni¨ uk. Az itt ismertetett, alkalmaz´asoknak egyedi nevet ad´ o algoritmus a tov´ abbiakban AppRename n´even fog szerepelni. A v´ altoz´ ok egyedi nev´enek t´ arol´as´ara a GHC egyszer˝ u lehet˝os´eget biztos´ıt a v´altoz´ ok unique mez˝ oivel. A ford´ıt´ o implement´al´asa k¨ozbeni saj´at tapasztalatom, hogy a GHC ´altal biztos´ıtott unique mez˝ ok nem mindig egyediek, pl. a Case csom´opont egyes alternat´ıv´ ai tartalmaznak azonos unique ´ert´eket. (a Case csom´opontokat az el˝oz˝oekben elimin´altuk, de az ´atalak´ıt´ as ut´ an a nevek az u ´j t´ıpus´ u csom´opontokban tov´abb l´eteznek) Megold´ asomban az alkalmaz´ asok v´altoz´oinak unique mez˝oi oi form´aj´ u ´ert´eket kapnak, ahol i az alkalmaz´ as egyedi sorsz´ ama. A sorsz´amot a Core fa inorder bej´ar´asa adja, ami azt jelenti, hogy ebben a sorrendben ker¨ ulnek az egyes indexek az alkalmaz´asok v´altoz´oinak unique mez˝ oibe.
2.2.5. H´ıv´ asi f´ ara t¨ ort´ en˝ o´ atalak´ıt´ as A Core reprezent´ aci´ o ki´ert´ekel´es´ere ´es egy u ´j, oper´aci´okat ´es hivatkoz´asokat tartalmaz´ o ´ faszerkezet faszerkezet, az OpTree l´etrehoz´ as´ara a CoreToTree algoritmus szolg´al. Uj l´etrehoz´ asa az´ert volt sz¨ uks´eges, mert a Core reprezent´aci´o t´ uls´agosan lambda-kalkulus k¨ozeli, ´ıgy pl. a t¨ obb bemenet˝ u m˝ uveletek le´ır´asa nagyon k¨or¨ ulm´enyes. A CλasH megold´ asban normaliz´aci´os elj´ar´asok sokas´ag´at alkalmazz´ak, hogy v´eg¨ ul egy hardverk¨ ozeli Core sz¨ ulessen. A megold´as h´atr´anya, hogy az egyes normaliz´aci´os elj´ar´ asok futtat´ asi sorrendje nem k¨ ot¨ ott, egy adott ´allapotban az az ´at´ır´asi szab´aly ind´ıthat´ o, amelynek az el˝ ofelt´etelei teljes¨ ulnek. Egy adott ´allapotban t¨obb normaliz´aci´os l´ep´es is v´egrehajthat´ o, ´es a l´ep´esek sorrendj´et˝ol f¨ ugg˝oen m´as-´es-m´as v´egeredm´eny sz¨ ulethet, teh´at az algoritmus nem konfluens. (a szerz˝o, v´elem´enyem szerint hib´asan, a nem-determinisztikus” ” sz´ot haszn´ alja ennek kifejez´es´ere ([24] 4.4.2. fejezet)) Az ´en megold´ asomban normaliz´al´as helyett supercompiling k¨ozeli technik´at alkalmazok. A supercompiling-ot el˝ osz¨ or Turchin mutatta be 1986-ban [36], ´es az´ota is nagy sz´am´ u cikk foglalkozott a t´em´ aval, az egyik legfrissebb pl. Neil Mitchell 2010-es publik´aci´oja [29]. A supercompiling tulajdonk´eppen a program ford´ıt´asidej˝ u v´egrehajt´asa, teh´at pontosan olyan sorrendben j´ arjuk be a Core szerkezetet, ahogyan azt a processzor a programunk fut´asa k¨ ozben tenn´e. Mivel a Haskell a lusta ki´ert´ekel´esen alapul, ez´ert a bej´ar´asnak is eszerint, vagyis call-by-need strat´egi´aval kell t¨ort´ennie. Ahhoz, hogy a bej´ ar´ as minden pontj´an a ford´ıt´oprogram tiszt´aban legyen az ott haszn´ alhat´o azonos´ıt´ ok halmaz´ aval, bevezetek egy k¨ornyezetet reprezent´al´o t´ıpust. A k¨ornyezet tulajdonk´eppen egy sor azonos´ıt´o-kifejez´es p´art foglal mag´aban, aminek az ´ertelme az, hogy a k´es˝ obbiekben az azonos´ıt´ oval hivatkozhatunk az adott kifejez´esre. Fontos ´eszrevenni, hogy a k¨ ornyezetet csup´an k´et t´ıpus´ u Core csom´opont k´epes b˝ov´ıteni, a Let , ami u ´j lok´ alis v´ altoz´ ot hoz l´etre ´es a Lam , ami u ´j param´eterv´altoz´ot hoz l´etre. (a 37
Case szint´en b˝ ov´ıtene a k¨ ornyezetet, de az el˝oz˝o algoritmusok ut´an ez a t´ıpus´ u csom´opont m´ar nem jelenlhet meg) A bej´ar´as legbonyolultabb pontja az, amikor egy v´altoz´o ki´ert´ekel´esekor a v´altoz´o ´altal hivatkozott kifejez´est kell behelyettes´ıten¨ unk. Ez a f´azis nagyban hasonl´ıt az 1.2.3. fejezetben ismertetett GHC ´ altal megval´os´ıtott inlining-ra. Az algoritmus bej´ arja a teljes Core f´at, m´egpedig u ´gy, hogy els˝o k¨orben kiz´ar´olag a hwmain glob´ alis o uk, hogy az egyes cso¨sszerendel´eshez tartoz´o kifejez´est ´ert´ekeli ki. N´ezz¨ m´opontokhoz ´erve milyen l´ep´eseket kell v´egrehajtanunk: • Lit literal : A legegyszer˝ ubb eset, egyetlen liter´alt defini´al. A Lit a Core f´aban egy lev´el, ez´ert csak annyi a dolgunk, hogy az OpTree fa adott pontj´ahoz ezt a levelet hozz´aadjuk. • Let bind expr : A call-by-need strat´egia ´ertelm´eben a f´ahoz nem adunk hozz´a egyetlen elemet sem, viszonyt a k¨ ornyezetet a bind -ben megadott k¨ot´essel b˝ov´ıtj¨ uk. (azaz l´etrehozunk egy thunk-¨ ot [22]) A b˝ov´ıt´es ut´an a t¨orzset (expr ) az u ´j k¨ornyezetet ´atadva ki´ert´ekelj¨ uk, ´ıgy biztos´ıtva, hogy a tov´abbiakban az itt defini´alt azonos´ıt´ora hivatkozhassunk. • App var [params] : Ez az alkalmaz´asok azon form´aja, amely m´ar t¨obb param´etert is tartalmazhat, mert a lambda-kalkulus egyparam´eter˝ u alkalmaz´asait m´ar egyszer˝ uen ´atalak´ıtottuk t¨ obbparam´eter˝ u f¨ uggv´enyh´ıv´asra. Itt k´et eset lehets´eges: – Elemi f¨ uggv´eny eset´en a f´ aban u ´j gyereket hozunk l´etre, ezeket ugyanis EOG m˝ uveletk´ent kell megval´ os´ıtani. ¨ – Osszetett f¨ uggv´eny eset´en behelyettes´ıt´est kell v´egezn¨ unk. A ki´ert´ekel´es k¨ovetkez˝ o l´ep´ese teh´ at a f¨ uggv´eny defin´ıci´oja lesz, amit a teljes eddigi, g¨orgetett k¨ ornyezettel kell v´egrehajtanunk. Az´ert sz¨ uks´egesek a k¨ornyezet legut´obb felvett elemei is (teh´ at a lok´ alis vagy argumentum azonos´ıt´ok), mert a bej´arand´o lambda-absztrakci´ o a param´eterein kereszt¨ ul ezeket el´erheti. A f¨ uggv´eny defin´ıci´ oj´ anak ki´ert´ekel´esekor sz¨ uks´egesek az argumentumok is, ez´ert a [params] t¨ omb elemeit ´ atadjuk, m´egpedig a lusta ki´ert´ekel´es miatt feldolgoz´as n´elk¨ ul. • Lam b expr : Egy f¨ uggv´eny defin´ıci´oj´anak ki´ert´ekel´ese ezzel a csom´oponttal kezd˝odik. Egy kiv´etellel minden esetben egy App csom´opont el˝ozte meg k¨ozvetlen¨ ul ennek a ki´ert´ekel´es´et, ez a kiv´etel pedig a legfels˝o szint˝ u Lam , amely param´eterein kereszt¨ ul kommunik´ al a k¨ ulvil´ aggal. A csom´opont ki´ert´ekel´es´en´el els˝o l´ep´esk´ent a param´eterill. argumentumlist´ ab´ ol k´epzett azonos´ıt´o-kifejez´es p´arokat a k¨ornyezethez hozz´a kell adnunk, arra az esetre, ha a f¨ uggv´enyen bel¨ uli csom´opontokban hivatkozunk a param´eterekre. Ezt a k¨ ornyezetb˝ ov´ıt´est az´ert ilyen k´es˝on tessz¨ uk, mert a lok´alis n´evt´erben szerepl˝ o param´etereket a Lam hozza l´etre, teh´at a k¨ornyezethez sz¨ uks´eges azonos´ıt´onevek csak ett˝ ol kezdve ´ allnak rendelkez´esre. • Var id : a csom´ opontn´ al az ´ altala hivatkozott kifejez´es ´ert´ek´et kell m¨og¨ottes jelent´esk´ent elk´epzeln¨ unk. Ha a hivatkozott kifejez´est m´eg nem ´ert´ekelt¨ uk ki (teh´at az csak 38
egy thunk), akkor erre a pontra ´erve ezt meg kell tenn¨ unk, teh´at az adott kifejez´est¨ orzset ide kell m´ asolnunk (behelyettes´ıt´es). Ha a ki´ert´ekel´es m´ar megt¨ort´ent, akkor az OpTree f´ at csak egy referenci´aval kell kib˝ov´ıten¨ unk, ami a m´ar ki´ert´ekelt kifejez´esre (az OpTree m´ ar l´etez˝ o algr´afj´ara) mutat. H´aromfajta azonos´ıt´ot k¨ ul¨onb¨oztet¨ unk meg: – glob´ alis azonos´ıt´ o: Amit b´armelyik f¨ uggv´eny t¨orzse el´erhet. – lok´ alis azonos´ıt´ o: Egy Let hozta l´etre az azonos´ıt´ot, amit a fa ez alatti elemei ´ernek el. Ha ilyen v´ altoz´ohoz ´er¨ unk, akkor az azonos´ıt´ohoz rendelt kifejez´es ki´ert´ekel´es´en´el a k¨ ornyezet nem v´altozik, hiszen egy lok´alis o¨sszerendel´es nem mutat ki a lambda-absztrakci´ob´ol. – argumentum azonos´ıt´ o: Egy Lam hozta l´etre, szint´en a fa ez alatti elemei ´erik el. Ha ilyen t´ıpus´ u v´altoz´o ker¨ ul ki´ert´ekel´esre, akkor a k¨ornyezet legutols´ o szintj´et elt´ avol´ıtjuk (hiszen a Lam -on k´ıv¨ ulr˝ol a Lam ´altal hozz´aadott azonos´ıt´ ok nem el´erhet˝ oek) ´es ´ıgy folytatjuk a fabej´ar´ast. Az algoritmus m˝ uk¨ od´es´et a 2.1. t´abl´azattal demonstr´alom.
a = lam t u app (+) var t var u
01. 02. 03. 04. 05.
node:(lam ...) node:(op +) node:(var t) go:09 node:(var u) go:10
+ [u=10,t=09] [yy..] [y..] [c..] atad: ([yy..] [y..] [c..]) ´ atad: ([yy..] [y..] [c..]) ´
lam aa xx yy app aa var xx var yy
06. 07. 08. 09. 10.
node:(lam node:(app node:(var node:(var
+ [yy=20,xx=19,aa=18] [y..] [c..] atad: ([yy..] [y..] [c..]) ´ atad: ([y,i,x] [c,b,a]) ´ atad: ([y,i,x] [c,b,a]) ´
lam x let i= lit 1 let y= var i app b var a var x var y
11. 12. 13. 14. 15. 16. 17. 18. 19. 20.
node:(lam node:(lit node:(var node:(app node:(var node:(lnk node:(var
b =
c =
...) aa) go:18 xx) go:19 yy) go:20
x) go:15 finish go:17 i) go:14 b) go:07 a) go:02 IN) back:05 y) go:16 1)
+ [c=12,b=07,a=02] + [x=IN] [c,b,a] + [i=14,x] [c,b,a] + [y=16,i,x] [c,b,a] atad: ([i] [c,b,a]) ´ atad: ([yy..] [y..] [c..]) ´ atad: ([i,x] [c,b,a]) ´
2.1. t´ abl´ azat. CoreToTree algoritmus p´eld´an kereszt¨ul
Az els˝ o oszlopban az algoritmus bemenetek´ent kapott Core reprezent´aci´o l´athat´o. A m´ asodik oszlop az egyes Core elemekhez sorsz´amot rendel ´es a Core elemhez k¨ot˝od˝o cselekv´est tartalmazza. A go:n azt jelenti, hogy k¨ovetkez˝o l´ep´esben az n. sort kell ki´ert´ekeln¨ unk, a node:(nodeexpr) pedig azt, hogy a kimeneti OpTree f´aban egy nodeexpr gyereket kell l´etrehoznunk. A harmadik oszlop a k¨ornyezet mindenkori ´allapot´at t¨ ukr¨ozi. 39
A hwmain f¨ uggv´eny szerep´et helytakar´ekoss´agi okokb´ol itt a c nev˝ u f¨ uggv´eny t¨olti be. Ezek alapj´an kiindul´ opontunk a c -hez k¨ot¨ott kifejez´es, vagyis a 12. sorsz´ammal jel¨olt Core elem. A kezdeti k¨ ornyezetben a glob´ alis v´altoz´ok ([c,b,a] ) tal´alhat´oak, a program pedig soronk´ent halad, kiv´eve, ha a go utas´ıt´as m´ask´epp nem rendelkezik. A 14. ´es 16. sort ´ atugorjuk, hiszen a call-by-need miatt ezeket nem ´ert´ekelhetj¨ uk ki addig, am´ıg a v´egs˝ o ´ert´ek meghat´ aroz´ asa miatt ez elker¨ ulhetetlenn´e nem v´alik. A 17. sorban az alkalmaz´ as ki´ert´ekel´ese app b k¨ovetkezik. Ez azt jelenti, hogy a k¨ovetkez˝o OpTree bejegyz´esek a f¨ uggv´eny t¨ orzs´eb˝ ol (7. sor) fognak sz´armazni. L´athatjuk, hogy a 7. sorban a k¨ornyezet az yy , xx ´es aa argumentumv´altoz´okkal b˝ov¨ ul. Az egyes azonos´ıt´okhoz rendelt ´ert´ekek a jobb ´ atl´ athat´ os´ ag v´egett a hivatkozott kifejez´es sorsz´am´at mutatj´ak. A 8. sorban az aa nev˝ u param´eterben kapott f¨ uggv´eny alkalmaz´asa k¨ovethet˝o l´atszik. A param´eter a 18. sorban kap ´ert´eket, de ez is csak egy hivatkoz´as a 2. sorban tal´alhat´o a nev˝ u f¨ uggv´eny t¨orzs´ere. A 3. sorban egy elemi f¨ uggv´enyt tal´alunk, ´ıgy abb´ol egy t´enyleges m˝ uveleti bejegyz´es (op + ) keletlekzik az OpTree f´aban. A (+) f¨ uggv´eny els˝ o bemeneti param´etere t¨obbsz¨or¨os indirekci´on (4. ´es 9. sorok) kereszt¨ ul el´er a 19. sorban tal´ alhat´ o lnk IN csom´opontig, ami v´eg¨ ul egy lev´el elem lesz az OpTree f´aban. Ezt k¨ ovet˝ oen a (+) f¨ uggv´eny m´asodik bemenete ker¨ ul ki´ert´ekel´esre, ami szint´en t¨obbsz¨ or¨ os indirekci´ on (5., 10., 20., 16. sorok) kereszt¨ ul a 14. sor lit 1 kifejez´es´en´el ´er v´eget (ebb˝ ol szint´en OpTree lev´el lesz), ´es ezzel a teljes Core bemenetet bej´arta az algoritmus. A ki´ert´ekel´es eredm´enye, azaz a kimeneti OpTree fa v´eg¨ ul a k¨ovetkez˝o form´at veszi fel:
lam x app b lam aa xx yy app aa var a lam t u op add var t var xx var x lnk IN var u var yy var y var i lit 1
Az OpTree fa a Core ki´ert´ekelt v´ altozata. Szerepel benne a Core Let kifejez´esein k´ıv¨ ul az o¨sszes t¨ obbi, ´ıgy l´ athatjuk pl., hogy az ¨osszead´as m˝ uvelet operandusai h´arom ill. n´egy indirekci´ on kereszt¨ ul jutnak el az o¨sszead´ashoz (t -xx -x ´es u -yy -y -i ). Az op + csom´opont a CoreToTree kimenet´en op add form´aban jelenik meg, mert a m˝ uvelethalmaz FOpMap lek´epz´ese a + jelet add -ra m´odos´ıtja. Az azonos´ıt´ok egyszer˝ us´eg kedv´e´ert nem tartalmazz´ak a unique mez˝ ot, ´ıgy pl. az add_o8_i4 helyett csak add , az IN_1_a0 helyett pedig csak IN szerepel. 40
A lam , app ´es var elemek az EOG gr´afban nem jelennek meg, ennek ellen´ere a hibakeres´esn´el nagyon fontos, hogy ezen a szinten m´eg megmaradjanak.
2.2.6. Faegyszer˝ us´ıt´ es Az el˝oz˝ o pontban kialakult fa t¨obb olyan csom´opontot is tartalmaz, amelyeket a k´es˝obbiekben nem haszn´ alunk, ´ıgy ezeket meg kell sz˝ untetn¨ unk, ezt az egyszer˝ us´ıt´est a TreeSimplifier algoritmus v´egzi el. Az algoritmus els˝ o l´ep´ese, hogy minden App , Lam ´es Var csom´opontot elt¨ untet¨ unk oly m´odon, hogy ezeket a gyerek¨ ukkel helyettes´ıtj¨ uk. Ezt mindig meg tudjuk tenni, mert ezeknek a csom´ opontoknak k¨ otelez˝oen egyetlen gyereke kell, hogy legyen. Az algoritmus m´asodik l´ep´ese az, hogy minden egyes Lit csom´opontot const t´ıpus´ u Op csom´opontt´ a, azaz konstans m˝ uvelett´e alak´ıt. Elk´epzelhet˝ o, hogy egy konstans t¨obbsz¨or is felhaszn´al´asra ker¨ ul, pl. a lit 0 adott esetben sok helyen szerepel. Lehet˝os´eg lenne arra, hogy a konstans csom´opont csak egyszer szerepeljen, ´es minden azt felhaszn´al´o m˝ uveletnek ide huzalozzuk be a bemenet´et, de ez f¨ol¨osleges ´es adott esetben a hardver vezet´ekeinek sz´am´at n¨oveli. Emiatt minden konstanst csak egy m˝ uvelet haszn´ al, ez´ert a TreeSimplifier az o¨sszes konstansb´ol egyedi nev˝ u Op csom´opontot gener´ al. A k¨ ovetkez˝ o k´ odr´eszleten j´ ol l´ atszik, hogy a CoreToTree algoritmusn´al bemutatott bonyolult, magasabbrend˝ u f¨ uggv´enyeket is tartalmaz´o Core le´ır´asunk a TreeSimplifier lefut´asa ut´ an j´ oval egyszer˝ ubb form´ at vesz fel:
lam x add_o8_i4 lnk IN_1_a0 op const_1_i4
2.2.7. Elemi m˝ uveleti gr´ afra t¨ ort´ en˝ o´ atalak´ıt´ as A kialakult OpTree f´ at egy inorder bej´ar´assal k¨onnyed´en EOG f´ajlform´atumra hozhatjuk. Az el˝obbi p´eld´ anak megfelel˝ o gr´ af a 2.11. ´abr´an l´athat´o. OUT
add_o8_i4
IN_1_a0
const_1_i4
2.11. ´ abra. OpTree
Az EOG els˝ o soraiban felsoroljuk az ¨osszes bemeneti, az utols´oban pedig a kimeneti 41
m˝ uveletet. A gr´ af inorder bej´ ar´ asa adja a be- ´es kimenetek k¨ozt az adatfolyamban tal´alhat´o m˝ uveletek list´ aj´ at. Az inorder bej´ ar´ as szerinti els˝ o pont az IN_1_a0 , viszont ez csak egy link a bemenetre (ezt jelzi a piros sz´ın), ez´ert ezzel nem kell semmit tenni. K¨ovetkez˝o l´ep´es a const_1_i4 lev´el, ´ıgy ez ker¨ ul a bemenet ut´ ani els˝ o sorba. Ezt k¨oveti az add_o8_i4 cs´ ucs, ami ´ıgy a 2. sorba ker¨ ul, a sor v´eg´en pedig fel kell t˝ untetni bemenetk´ent az IN_1_a0 ´es const_1_i4 gr´afcs´ ucsokat. Ezeket k¨ovetve a Haskell-EOG modul kimenetek´ent a k¨ovetkez˝o EOG le´ır´ast kapjuk:
IN_1_a0 const_1_i4 add_o8_i4 OUT
"SYSTEM" "const<1>" "add" IN_1_a0 const_1_i4 "SYSTEM" add_o8_i4
2.3. Elemi m˝ uveleti gr´ af ford´ıt´ asa hardverle´ır´ o nyelvre A fejezet sor´ an olyan m´ odszer ker¨ ul bemutat´asra, amely a Haskell-EOG modul kimenet´eb˝ol, azaz az EOG form´ atum´ u adatfolyam le´ır´asb´ol ´es a m˝ uvelethalmazb´ol el˝o´all´ıtja a VHDL le´ır´ast. Ezt a le´ır´ ast a piacon kaphat´o FPGA tervez˝o szoftverek fel tudj´ak haszn´alni konkr´et FPGA szintetiz´ al´ as´ ara, aminek eredm´enyek´epp a magas szinten megfogalmazott alkalmaz´ast v´eg¨ ul t´enylegesen hardverk´ent implement´alhatjuk. A ford´ıt´o egyetlen VHDL modult szolg´altat kimenetk´ent, ami a m˝ uvelethalmazban defini´alt ´es a konkr´et algoritmusban felhaszn´alt m˝ uveleteket p´eld´anyos´ıtja, a k¨oz¨ott¨ uk sz¨ uks´eges adatutakat pedig kialak´ıtja. Az EOG-VHDL ford´ıt´ omodul bels˝ o architekt´ ur´aj´at a 2.12. ´abr´an v´azoltam. Az egyes almodulok jelent´ese: • ParseEOG: feldolgozza az elemi m˝ uveleti gr´afot, ´es egy bels˝o strukt´ ur´aban (Operations ) elt´arolja. • MakeModuleList: o ujti az ¨osszes, EOG-ben megjelen˝o m˝ uveletet, ´es a hoz¨sszegy˝ z´ajuk tartoz´ o VHDL modulokat feldolgozza. A feldolgoz´as eredm´enyek´epp l´etrehozza a ModuleList struktur´ at, ami az egyes m˝ uveletekhez tartoz´o legfontosabb param´etereket t´ arolja. (latency, port ´es generic deklar´aci´ok) • ProduceComponents: a ModuleList-b˝ol VHDL component szekci´okat gener´al. Ezek a szekci´ ok a topmodulban deklar´alj´ak a felhaszn´alni k´ıv´ant modulokat, hogy azokat a f˝ omodul t¨ orzs´eben p´eld´ anyos´ıtani lehessen. • ProduceSignals: minden m˝ uvelethez l´etrehozza a hozz´a tartoz´o kimeneti vezet´ekeket, egy adatvezet´eket ´es egy vez´erl˝o vezet´eket. Az el˝obbi a m˝ uvelet kimeneti adatcsatorn´aj´at, az ut´ obbi pedig az adott csom´oponthoz tartoz´o kimeneti vez´erl˝obitet fogja reprezent´ alni. Az adatvezet´ek bitsz´am´at a m˝ uvelethez tartoz´o, ModuleList-ben elt´arolt deklar´ aci´ ok (port ´es generic) ´es a p´eld´anyos´ıt´asn´al megadott sablonparam´eterek hat´arozz´ ak meg. 42
Elemi műveleti gráf
Művelethalmaz
ParseEOG
MakeModuleList
Operations
ModulList
ProduceOperations
ProduceSignals
OpVhdlMap VhdlModules
ProduceComponents Topmodul sablon
GenerateVHDL
VHDL topmodul
2.12. ´ abra. Az EOG-VHDL modul architekt´ur´aja
• ProduceOperations: minden m˝ uvelethez l´etrehozza az adott t´ıpusnak megfelel˝ o modulp´eld´ anyos´ıt´ ast. P´eld´ anyos´ıt´askor az EOG t´ıpusnevekben szerepl˝o sablonparam´etereket haszn´ alja a generic map -ben, ill. a ProduceComponents ´altal l´etrehozott k¨ oztes vezet´ekeket ´es a ki- bemeneti portokat haszn´alja a port map-ben. • GenerateVHDL: a 2.13. a´br´an bemutatott topmodul sablonf´ajl alapj´an l´etrehozza a v´egs˝ o, kimeneti topmodult, azaz a sablonba beilleszti a hi´anyz´o VHDL szekci´okat. (a k´ odban a hi´ anyz´ o szekci´ okat %input% , %output% , %components% , %signals% ´es %operations% sablonparam´eterk´ent jelzem).
2.4. Alap m˝ uvelethalmaz defini´ al´ asa A Haskell-VHDL ford´ıt´ oprogram az el˝oz˝o fejezetekben le´ırt algoritmusok alapj´an elk´esz¨ ult. A megengedett forr´ asnyelvi f¨ uggv´enyek ´es t´ıpusok list´aj´at eddig a pontig nem defini´altam, tettem ezt az´ert, mert a v´ altoztathat´o m˝ uvelethalmaz bevezet´es´evel a ford´ıt´oprogram ´es a ford´ıthat´ o elemi f¨ uggv´enyek list´aja sz´etv´alik egym´ast´ol. A most k¨ovetkez˝o fejezetben bep´otolom a hi´ anyoss´ agot, ´es teljesk¨or˝ uen defini´alok egy alap m˝ uvelethalmazt.
2.4.1. A m˝ uvelethalmazok k¨ otelez˝ o elemei A Haskell-EOG ford´ıt´ o algoritmusai bevezetnek olyan m˝ uveleteket, amelyek nem a forr´ask´odban megadott elemi f¨ uggv´enyek megfelel˝oi, hanem a Haskell forr´ask´od bizonyos kifejez´esei miatt ker¨ ulnek az EOG interf´eszre. Ilyen kifejez´es a case szerkezet, amelyet a CaseReduction algoritmus h´ arom k¨ ul¨onb¨oz˝o m˝ uveletre alak´ıt (select , ifcon , mux ), 43
l i b r a r y IEEE ; use IEEE . STD LOGIC 1164 .ALL; use IEEE . STD LOGIC ARITH .ALL; use IEEE . STD LOGIC UNSIGNED .ALL; use work . d e f s . a l l ; entity benchmark i s port ( r e s t a r t , c l k : in s t d l o g i c ; %i n p u t% : in s t d l o g i c v e c t o r ( 3 1 downto 0 ) ; Output : out s t d l o g i c v e c t o r ( 9 5 downto 0 ) ; c%i n p u t% : in s t d l o g i c ; cOutput : out s t d l o g i c ); end benchmark ; architecture B e h a v i o r a l of benchmark i s %components% %s i g n a l s% begin %o p e r a t i o n s% Output <= %output %; cOutput <= c%output %; end B e h a v i o r a l ; 2.13. ´ abra. VHDL topmodul sablon
ezenk´ıv¨ ul a konstansok (const ) ´es a Core alkalmaz´ask´ent megval´osul´o adatkonstruktorok (dcon ). Az IterationConversion algoritmus az iterate f¨ uggv´ennyel oper´al, ´ıgy ez is r´esze a k¨ otelez˝ o elemeknek. Ezeknek a m˝ uveleteknek sz¨ uks´egk´eppen minden m˝ uvelethalmaznak elemei kell, hogy legyenek, hiszen b´armelyik Haskell forr´ask´od tartalmazhatja ezeket a kifejez´eseket. A Haskell-EOG ford´ıt´o ¨ot k¨ ul¨onb¨oz˝o m˝ uveletet vezet be, ezek list´aj´at a 2.2. ´abr´an soroltam fel, az egyes m˝ uveletek ´es param´etereik jelent´ese pedig a k¨ovetkez˝o: • const : olyan m˝ uvelet, amelynek nincs bemeneti param´etere, ´ıgy a kimenet´en mindig egy konstans ´ert´eket k¨ ozvet´ıt – width : a konstans bitsz´eless´ege const dcon1 dcon2 dcon3 select ifcon mux2 mux3 iterate
Const<width,value> DCon1 DCon2 DCon3 Select Ifcon<width,cw,c> Mux2<width> Mux3<width> Iterate<width>
konstans 1 param. ADT konstru´al´as 2 param. ADT konstru´al´as 3 param. ADT konstru´al´as ADT adatlev´alaszt´as case alternat´ıva case multiplex (2 ir´any) case multiplex (3 ir´any) iter´aci´o
2.2. t´ abl´ azat. K¨otelez˝o m˝uvelethalmaz elemek (az oszlopok rendre: bevezetett f¨uggv´enyn´ev, VHDL moduln´ev sablonparam´eterekkel ´es a m˝ uvelet le´ır´ asa)
44
– value : a konstans ´ert´eke • dcon1 ..dcon3 : l´etrehoz egy ADT adatot megadott konstruktorral ´es param´eterekkel (data constructor) – cw : a konstruktor bitsz´eless´ege – c : a konstruktor ´ert´eke – v1 ..v3 : a konstruktor ut´ani param´eterek (sz´amuk att´ol f¨ ugg, hogy az adott konstruktornak h´ any param´etere van) • select : egy ADT adat´ utr´ ol lev´alasztja az egyik konstruktor ut´ani ´ert´eket – inw : a bemeneti bitsz´eless´eg – from : az els˝ o olyan bit sorsz´ama, amely szerepelni fog a kimeneten – outw : a kimeneti bitsz´eless´eg • ifcon : megvizsg´ alja, hogy egy ADT adat´ uton a megfelel˝o konstruktorral ´erkezik-e az adat, ha a v´ alasz igen, adattov´abb´ıt´as t¨ort´enik – width : a bemeneti bitsz´eless´eg – cw : a konstruktor bitsz´eless´ege – c : a konstruktor ´ert´eke • mux2 ..mux3 : az el´ agaz´ asok ut´ani egyes´ıt´es´ert felel (az el´agaz´asok sz´ama szerint k¨ ul¨ onb¨ oz˝ o megval´ os´ıt´ as sz¨ uks´eges) – width : a ki- ´es bemeneti bitsz´eless´eg • iterate : iter´ aci´ ot megval´ os´ıt´o m˝ uvelet, ami a Haskell iterate f¨ uggv´enyb˝ol, ´atalak´ıt´ assal j¨ on l´etre. – width : a ki- ´es bemeneti bitsz´eless´eg
2.4.2. Egyszer˝ u alapm˝ uveletek Megvizsg´ altam a GHC 6.12.2 verzi´oj´anak Prelude alapk¨onyvt´ar´at [5], ´es ezt alapul v´eve meghat´ aroztam azokat a m˝ uveleteket, amelyek a sz´amt´ıpusokon ´ertelmesek ´es seg´ıts´eg¨ ukkel matematikai f¨ uggv´enyek sz´eles k¨ore ´ırhat´o le. A sz´ amt´ıpusok k¨ oz¨ ul kiz´ arom a Rational ´es az Integer haszn´alat´at, ezek ugyanis rekurz´ıv strukt´ ur´ ak, ´ıgy azok implement´al´asa a v´egtelen sz´amok ´abr´azol´as´anak elker¨ ul´ese ´erdek´eben nem val´ osulhat meg. A lebeg˝opontos t´ıpusok implement´al´asa megval´os´ıthat´ o lenne l´etez˝ o, VHDL form´ aban adott hardveres IP-kkel. Ezek er˝oforr´asig´enye kifejezetten nagy, viszont l´enyeg´eben nem v´ altoztatj´ak a nyelv kifejez˝oerej´et, ugyanis kisebb pontoss´agot megengedve a m˝ uveletek fixpontos ´abr´azol´assal (´ıgy teh´at eg´esz t´ıpusokkal) is megval´os´ıthat´ oak. Az alap m˝ uvelethalmazban ez´ert lebeg˝opontos m˝ uveleteket nem implement´altam. 45
A m˝ uvelethalmazban a 32 bites Int sz´amt´ıpust fogom defini´alni, ennek anal´ogi´aj´ara b´armilyen m´ as fixpontos t´ıpus megval´os´ıthat´o. A sz´amt´ıpus mellett n´elk¨ ul¨ozhetetlen a logikai t´ıpus, ´ıgy a Bool ugyancsak beker¨ ul a m˝ uvelethalmaz t´ıpusai k¨oz´e. Azok az ADT t´ıpusok, amelyek csak ezeket a t´ıpusokat tartalmazz´ak param´eterk´ent, minden tov´abbi n´elk¨ ul haszn´ alhat´ oak. (ilyenek pl. a Maybe a ´es Either a b param´eteres t´ıpusok) A t´ıpusok meghat´ aroz´ asa ut´ an fontos k¨or¨ ulhat´arolni az azokkal v´egezhet˝o m˝ uveleteket. Fontos, hogy egy olyan m˝ uveletalmazt adjunk meg, amellyel minden ´ertelmes m˝ uvelet megval´os´ıthat´ o. A Bool t´ıpus szok´ asos m˝ uveletei a logikai ´es, vagy, nem, az Int t´ıpus aritmetikai m˝ uveleteit pedig az Eq , Ord , Num ´es Integral t´ıpusoszt´alyok defini´alj´ak. A m˝ uvelethalmaz o otelez˝ o m˝ uveleteken (2.4.1. fejezet) k´ıv¨ uli elemeit ¨osszefog¨sszes, k¨ laltam a 2.3. t´ abl´ azatban. A m˝ uvelethalmaz egyes elemeinek megval´os´ıt´asa a k¨ovetkez˝ok´eppen alakul. A Num t´ıpusoszt´aly o uvelete a 2.1.3. fejezetben implement´alt (+) m˝ uvelethez hasonl´oan ¨sszes m˝ egyszer˝ u kombin´ aci´ os h´ al´ ozattal trivi´ alisan megval´os´ıthat´o. Az Eq ´es Ord t´ıpusoszt´ alyok m˝ uveletei sem okoznak probl´em´at, ezek annyiban k¨ ul¨onb¨oznek az el˝ oz˝ o csoportt´ ol, hogy a kimenet¨ uk (Min ´es Max kiv´etel´evel) Bool t´ıpus´ u lesz. (Az Eq t´ıpusoszt´ alyn´ al a compare m˝ uveletet nem szerepeltetem, mert ez a t¨obbi m˝ uvelettel kiv´althat´ o) A Bool t´ıpushoz tartoz´ o && , || ´es not m˝ uveletek k´et-k´et ill. egy db. bitb˝ol ´all´ıtanak el˝o ugyancsak egybites adatkimenetet, ez szint´en megval´os´ıthat´o kombin´aci´os h´al´ozatk´ent. K¨ ul¨on b´an´ asm´ odot ´erdemelnek az Integral t´ıpusoszt´aly quot , rem , div ´es mod m˝ uveletei, ezeket ugyanis algoritmikus k¨ olts´eg¨ ukn´el fogva nem ´eri meg kombin´aci´os h´al´ozattal megval´os´ıtani, ezeket ez´ert t¨ obb ´ orajelciklust ig´enyl˝o VHDL modulokkal val´os´ıtom meg.
46
Bool m˝ uveletek: (££) :: Bool -> Bool -> Bool (||) :: Bool -> Bool -> Bool not :: Bool -> Bool -> Bool
logikai ´es logikai vagy logikai nem
And Or Not
GHC.Classes.Eq oszt´ aly m˝ uveletei: (==) :: a -> a -> Bool (/=) :: a -> a -> Bool
Eq<width> Ne<width>
egyenl˝o nem egyenl˝o
GHC.Classes.Ord oszt´ aly m˝ uveletei: (<) :: a -> a -> Bool (<=) :: a -> a -> Bool (>) :: a -> a -> Bool (>=) :: a -> a -> Bool min :: a -> a -> a max :: a -> a -> a
Lt<width> Le<width> Gt<width> Ge<width> Min<width> Max<width>
kisebb kisebb v. egyenl˝o nagyobb nagyobb v. egyenl˝o minimum maximum
GHC.Classes.Num oszt´ aly m˝ uveletei: (+) :: (*) :: (-) :: negate abs :: signum
a -> a -> a -> :: a a -> :: a
a -> a a -> a a -> a -> a a -> a
Add<width> Mul<width> Sub<width> Neg<width> Abs<width> Signum<width>
o¨sszead´as szorz´as kivon´as neg´aci´o abszol´ ut ´ert´ek szignum
GHC.Real.Integral oszt´ aly m˝ uveletei: quot :: a -> a -> a rem :: a -> a -> a div :: a -> a -> a mod :: a -> a -> a
Quot<width> Rem<width> Div<width> Mod<width>
oszt´as marad´ek oszt´as marad´ek
2.3. t´ abl´ azat. A m˝uvelethalmaz ¨osszes eleme (az oszlopok rendre: Haskell f¨uggv´enyfejl´ec, VHDL moduln´ev sablonparam´eterrel, ill. a m˝ uvelet sz¨ ovegesen)
47
3. fejezet
A m´ odszer kiterjeszt´ ese to eg˝ u (multi-rate) ¨bbsebess´ probl´ em´ akra A 2. fejezetben bemutatott m´ odszer egyszer˝ u, kiz´ar´olag egysebess´eg˝ u adatfolyamok Haskell nyelv˝ u implement´ al´ as´ ara, ´es annak VHDL-be t¨ort´en˝o konvert´al´as´ara j´ol haszn´alhat´o, azonban t¨ obbsebess´ eg˝ u (multi-rate) [27, 17, 15] adatfolyamokat is tartalmaz´o Haskell forr´ask´odokra nem alkalmazhat´ o. A k¨ovetkez˝ o szakaszban egy egyszer˝ u sz´am´ıt´asi k´eplet p´eld´aj´an kereszt¨ ul megvil´ag´ıtom, mi´ert nem hagyhatjuk figyelmen k´ıv¨ ul a t¨obbsebess´eg˝ u adatfolyamokat is tartalmaz´o pr´obl´em´akat. Ezt k¨ ovet˝ oen a haszn´ alt adatfolyam modellt (EOG) ´es a ford´ıt´oi m´odszert olyan kiterjeszt´esekkel l´ atom el, amelyekkel a rendszer alkalmas lesz t¨obbsebess´eg˝ u adatfolyamgr´afok kezel´es´ere is. Adott a k¨ ovetkez˝ o egyszer˝ u feladat, miszerint ki kell sz´amolnunk a bemenetk´ent kapott x ´ert´ekre a k¨ ovetkez˝ o k´epletet:
g(x) +
k X
f (x + i)
(3.1)
i=0
Itt f ´es g egy-egy ´ altal´ anos, a 2.4. fejezetben defini´alt alapm˝ uveletekkel le´ırhat´o f¨ uggv´eny. (fontos megjegyezni, hogy ezek b´armilyen f¨ uggv´enyek lehetnek, ´ıgy pl. nem csak as, amely esetben a fenti k´epletb˝ol elt˝ untethet˝o lenne a szumma) ¨osszead´as vagy szorz´ Tekints¨ uk u ´gy, hogy f ´es g egy-egy olyan m˝ uvelet, amit az EOG reprezent´aci´oban a gr´af csom´opontjak´ent felhaszn´ alhatunk, ´es legyen k = 1023. A probl´ema f˝o forr´asa az, hogy a g f¨ uggv´enyt egy adott x bemenetre egyszer kell ki´ert´ekeln¨ unk, m´ıg az f f¨ uggv´enyt adott x bemenetre 1024-szer alkalmaznunk kell. Ez a k´eplet az eddig ismertetett EOG le´ır´assal csak u ´gy realiz´ alhat´ o, ha az egyetlen g csom´opont mellett l´etrehozunk 1024 db. f , ´es a hozz´ajuk tartoz´ o 1023 db. ¨ osszead´ o csom´opontot. Egy´ertelm˝ uen l´atszik, hogy ez az elj´ar´as megfelel˝oen nagy k eset´en er˝ oforr´ asprobl´em´ak miatt hardverben kivitelezhetetlen, m´eg ha a k¨oztes reprezent´ aci´ ok´ent szolg´ al´ o elemi m˝ uveleti gr´af esetleg kezelhetetlen (de legal´abbis
48
´atl´athatatlan) nagys´ ag´ ar´ ol nem is ejt¨ unk sz´ot. A megold´ as az, hogy az f f¨ uggv´eny fizikailag egyszer (esetleg kis sz´am´ u eg´eszszer, ezzel az esettel tov´ abbfejleszt´esi lehet˝ os´egk´ent foglalkozom) ker¨ ul megval´os´ıt´asra, ´es egy x bemenet be´erkez´ese eset´en egym´ as ut´an t¨obbsz¨or (k-szor) ker¨ ul alkalmaz´asra. Ezt az eddig haszn´alt EOG modell nem tudja reprezent´alni, mert a gr´af k¨ ul¨onb¨oz˝o m˝ uveleteire k¨ ul¨onb¨oz˝ ou ´jraind´ıt´ asi id˝ okkel kellene sz´amolnunk, ´ıgy az alapfeltev´esek ´es az algoritmusok [10] nem haszn´ alhat´ oak. A megold´as az EOG modell kiterjeszt´ese olyan form´ara, ami m´ ar k´epes a t¨ obbsebess´eg˝ u adatfolyamokat is kezelni. A k¨ ovetkez˝ okben megvizsg´ alom a 2. fejezetben ismertetett interf´eszeket a t¨obbsebess´eg˝ u adatfolyamok megjelen´ese szempontj´ab´ol, majd az interf´eszeket u ´gy m´odos´ıtom, hogy az u ´j felt´etelek is kiel´eg´ıthet˝ oek legyenek.
3.1. T¨ obbsebess´ eg˝ u adatfolyamok a ford´ıt´ as interf´ eszein A t¨obbsebess´eg˝ u adatfolyamok probl´em´aja a ford´ıt´asi m´odszer mindh´arom interf´esz´en, a Haskell nyelv˝ u forr´ ask´ odban, a k¨oztes adatfolyam reprezent´aci´on ´es a VHDL hardverle´ır´ ason is megjelennek. A 3.1.1. fejezetben kiterjesztem az EOG modellt olyan form´ara, hogy az alkalmas legyen t¨ obbsebess´eg˝ u adatfolyamgr´afok le´ır´as´ara, a 3.1.2. fejezetben azt vizsg´alom, hogy a Haskell nyelv˝ u forr´ask´odb´ol mik´ent k¨ovetkeztethet˝o ki minden m˝ uveletre vonatkoz´ oan a kimeneti adatfolyamok frekvenci´ainak elt´er´ese, majd a 3.1.3. fejezetben a kimeneti VHDL le´ır´ as sz¨ uks´eges v´altoztat´asait taglalom.
3.1.1. T¨ obbsebess´ eg˝ u elemi m˝ uveleti gr´ af A 2.1.2. fejezetben r¨ oviden ismertetett EOG reprezent´aci´o egy egysebess´eg˝ u adatfolyamgr´af, ´es a modell t¨ obbsebess´eg˝ u adatfolyamok eset´en nem alkalmazhat´o. A most k¨ovetkez˝ o fejezetben kiterjesztem az EOG modellt, ami ennek k¨osz¨onhet˝oen alkalmas lesz t¨obbsebess´eg˝ u adatfolyamok le´ır´ as´ ara is. A kitereszt´esre a tov´abbiakban MREOG (multi-rate EOG, azaz t¨ obbsebess´eg˝ u elemi m˝ uveleti gr´af) n´even fogok hivatkozni. Ahol az egy´ertelm˝ us´eg miatt fontos, ott az egysebess´eg˝ u EOG-t SREOG n´even fogom haszn´alni. Fontos c´el, hogy az EOG modellhez kapcsol´od´o szab´alyok az MREOG-n is fenn´aljanak, ´ıgy a hozz´ a kapcsol´ od´ o nagy sz´ am´ u algoritmusok az u ´j modellen is alkalmazhat´oak lesznek. Az MREOG egy olyan adatfolyamgr´af, amelyb˝ol egy´ertelm˝ uen megtudhat´o, hogy melyek az azonos frekvenci´ aj´ u jeleket tov´abb´ıt´o adatfolyamok. (a frekvencia itt a megszokott ´ertelm˝ u, azaz az adatfolyamon ´erkez˝o ´ert´ekek egy m´asodpercre vet´ıtett darabsz´ama) Az MREOG blokk egy olyan rekurz´ıv strukt´ ura, amely tov´abbi blokkokat ´es m˝ uveleteket tartalmaz, az ut´ obbiakra a blokk saj´ at m˝ uveletei n´even hivatkozunk. Egy blokk saj´at m˝ uveletei k¨ oz¨ ul b´ armelyik kett˝o k¨oz¨ott kiz´ar´olag azonos frekvenci´aj´ u jeleket tov´abb´ıt´o adatfolyamok szerepelhetnek ´es erre az azonos frekvenci´ara a blokk saj´ atfrekvenci´ aja n´even is hivatkozhatunk. Az MREOG az el˝ obbi defin´ıci´ ot haszn´alva egy egyetlen blokkb´ol ´all´o rekurz´ıv strukt´ ura, amely ´ıgy az ¨ osszes m˝ uveletet tartalmazza a k¨ozt¨ uk fel´ep´ıtett adatfolyamokkal egy¨ utt. (az egyetlen blokk persze tartalmazhat u ´jabb blokkokat, ahogy az a defin´ıci´ob´ol kider¨ ul) 49
Az ´ıgy defini´ alt blokkok hierarchi´ at alkotnak, ez pedig le´ırhat´o egy f´aval, aminek gy¨ok´ereleme a legk¨ uls˝ o blokk, azaz amit m´ar egyik blokk sem tartalmaz. (ez tulajdonk´eppen az az egyetlen blokk, ami a teljes MREOG-t jelenti) A fa levelei a m˝ uveletek, k¨oztes csom´opontjai pedig az egyes blokkok. Blokk nem lehet lev´el, hiszen ez azt jelenten´e, hogy a blokk nem tartalmaz saj´ at m˝ uveletet ´es tov´abbi blokkokat sem. A fa csom´opontjai teh´at az MREOG blokkjai ´es m˝ uveletei, a k¨ozt¨ uk fut´o ´eleket pedig a k¨ovetkez˝o szab´alyokkal hat´arozhatjuk meg. A f´aban a Bi blokknak megfelel˝ o csom´opont a Bj blokknak megfelel˝o csom´opont gyereke lesz, ha Bj k¨ ozvetlen¨ ul tartalmazza Bi -t, azaz a felt´etel halmazm˝ uveletekkel le´ırva (a halmaz elemei maguk a m˝ uveletek): Bi ⊂ Bj ∧ @k, k 6= i, k 6= j, Bi ⊂ Bk ⊂ Bj A f´aban az oi m˝ uveletnek megfelel˝ o csom´opont a Bj blokknak megfelel˝o csom´opont gyereke lesz, ha oi a Bj saj´ at m˝ uvelete, azaz a felt´etel: oi ∈ Bj ∧ @k, k 6= j, Bk ⊂ Bj , oi ∈ Bk Az ´ıgy defini´ alt hierarchia f´ at a tov´abbiakban seg´edgr´afk´ent alkalmazom, ami a m˝ uveletek vagy a blokkok bizonyos param´etereinek sz´am´ıt´as´ara lesz alkalmas. Mivel a fa az eredeti gr´af adatfolyamait nem tartalmazza (´elei nem adatfolyamok, hanem a hierarchia szinteket v´alasztj´ ak el egym´ ast´ ol), ez´ert VHDL gener´al´asra nem is lenne alkalmas. Fentiekb˝ol k¨ ovetkezik, hogy az SREOG egyetlen blokkot tartalmaz, amelynek saj´atfrekvenci´aja megegyezik a bemenet (´es ezzel egy¨ utt a kimenet) frekvenci´aj´aval, azaz minden egyes bemeneti jelre az o uvelet egyszer hajt´odik v´egre. Egy MREOG eset´eben a ¨sszes m˝ modell t¨obb, egym´ asba ´ agyazott blokkot is tartalmaz. A gy¨ok´er blokk saj´atm˝ uveleteire itt is igaz, hogy minden bemenetre egyszer hajt´odnak v´egre, ezzel szemben a gyerek blokkok saj´atm˝ uveletei bemenetenk´ent n-szer hajt´odnak v´egre, ahol n > 1, n ∈ N. Minden blokk egyedi azonos´ıt´ oval rendelkezik, a gy¨ok´er blokk neve defin´ıci´o szerint Root. Egy m˝ uvelet hierarchiaszintje a gy¨ok´erelem ´es a m˝ uvelet k¨oz¨otti u ´ton tal´alhat´o csom´opontok sz´ ama lesz. (a gy¨ ok´erelem ´es a m˝ uvelet csom´opontok nem sz´am´ıtanak, ´ıgy egy k´et ´el hossz´ uu ´t eset´eben a hierarchiaszint 1) Az EOG-hez k´epest a grafikus megjelen´ese u ´gy m´odosul, hogy a hierarchia f´at tekintve minden blokk eset´eben keretez´essel l´ atjuk el a blokk gyerekeit, ´ıgy elv´alasztva azokat a t¨obbi m˝ uvelett˝ ol ´es blokkt´ ol. Az EOG sz¨ oveges le´ır´ asa u ´gy m´ odosul, hogy a t´ıpusmegad´as ut´ani oszlopban listaalakban felsoroljuk a gy¨ ok´ert˝ ol az adott m˝ uvelethez vezet˝o u ´ton tal´alhat´o blokkok azonos´ıt´oj´at. A t´ıpus template param´eter´enek els˝ o ´ert´eke a hierarchiaszint lesz (ami nem m´as, mint az el˝obbi lista elemsz´ ama egyel cs¨ okkentve). Egy egyszer˝ u MREOG sz¨oveges ´es grafikus ´abr´azol´asa ´es a hozz´ a tartoz´ o hierarchia fa az a 3.1. ´abr´an k¨ovethet˝o nyomon. Az MREOG defini´ al´ asa ut´ an r´ at´erek az EOG k´et fontos param´eter´enek sz´am´ıt´as´ara a t¨obbsebess´eg˝ u esetre vonatkoz´ oan.
50
a b c d e f g h i j k
"a<0,32>" "b<1,32>" "c<2,32>" "d<2,32>" "e<1,32>" "f<1,32>" "g<1,32>" "h<1,32>" "i<0,32>" "j<0,32>" "k<0,32>"
["Root"] ["Root","B"] ["Root","B","C"] ["Root","B","C"] ["Root","B"] ["Root","B"] ["Root","A"] ["Root","A"] ["Root"] ["Root"] ["Root"]
a b c b d e a g a i h j f
i
a
g
h
j k
b
e
c
f
d
Root
A
g
a
B
h
b
C
c
i
e
j
k
f
d
3.1. ´ abra. Egyszer˝u MREOG sz¨oveges ´es grafikus le´ır´asa, ´es a hozz´a tartoz´o hierarchia gr´ af (az MREOG-ban ´es a hierarchia gr´ afban egym´ asnak megfeleltethet˝ o blokkokat azonos sz´ınnel ´es szaggatott vonallal jel¨ oltem)
´ Ujraind´ ıt´ asi- ´ es lappang´ asi id˝ o sz´ am´ıt´ asa SREOG eset´eben alapvet˝ o fontoss´ag´ u az u ´jraind´ıt´asi- ´es lappang´asi id˝ok sz´am´ıt´asa [10]. Az u ´ jraind´ıt´ asi id˝ o (R) azt adja meg, hogy az adatfolyamgr´af bemenet´ere milyen id˝ ok¨oz¨onk´ent ´erkezhet u ´jabb feldolgozand´o adat. A lappang´ asi id˝ o (L) azt adja meg, hogy a bemeneti mintav´etelez´eshez k´epest mennyi id˝o m´ ulva jelenik meg a kisz´am´ıtott eredm´eny az adatfolyamgr´ af kimenet´en. Fontos teh´at, hogy ezek sz´am´ıt´asa MREOG eset´ere is megoldhat´ o legyen. 51
Egy MREOG csup´ an a hierarchia elt˝ untet´es´evel ( lap´ıt´as”) nem lesz alkalmas az R ´es ” L meghat´aroz´ as´ ara, mert az elt´er˝ o adatfolyam-frekvenci´ak miatt a m˝ uveletek egyenk´ent vett fut´asi ideje (ti ) nem o o. ¨sszem´erhet˝ Az MREOG azon Bi blokkja, amely csak leveleket (vagyis csak m˝ uveleteket) tartalmaz, az R ´es L sz´ am´ıt´ as a szok´ asos m´ odon [10] elv´egezhet˝o, hiszen ez csak egysebess´eg˝ u adatfolyamokat tartalmaz. A Bi blokkra megkapott Ri ´es Li ´ert´ekekb˝ol kisz´am´ıthat´o a Bi blokkra, mint virtu´ alis m˝ uveletre vett fut´asi id˝o, azaz a ti : ti = (ni − 1) ∗ Ri + Li
(3.2)
A k´epletben szerepl˝ o ni azt jelenti, hogy az Bi m˝ uveleteit ni -szer futtatjuk le minden olyan bemenetre, ami a Bi -n k´ıv¨ ulr˝ ol j¨on, azaz k¨ozvetlen sz¨ ul˝oj´et˝ol. Az ni -t a Bi blokk r´at´aj´anak nevezz¨ uk, ami azt mondja meg, hogy mialatt Bi sz¨ ul˝oj´eben egyszer alkalmazzuk a saj´atm˝ uveleteket, az alatt mennyiszer alkalmazzuk Bi saj´atm˝ uveleteit. (inform´alisan: mennyivel gyorsabb” a bels˝ o blokk, mint a k¨ uls˝o) ” A k´eplet azt jelenti, hogy az ered˝ o ti fut´asi id˝o (azaz, hogy meddig foglalt a virtu´alis m˝ uvelet) nem m´ as, mint a Bi -re vett lappang´asi id˝o (trivi´alis), hozz´aadva ehhez azt az id˝ot, ameddig a bemenetre az egym´ as ut´ ani adatok ´erkeznek. Mivel a bemenetre Ri id˝onk´ent ´erkezhet adat, ´es ni az adatok darabsz´ ama, ez az id˝o (ni − 1) ∗ Ri lesz. Ha ti -t kisz´ amoltuk, akkor a Bi blokkot egyetlen virtu´alis m˝ uvelettel helyettes´ıtj¨ uk, amelynek fut´ asi ideje ti lesz. Az´ert fontos a virtu´alis m˝ uvelet fogalm´at bevezetni, mert ez a m˝ uvelet az eredeti adatfolyamgr´ afban nem tal´alhat´o meg, ezt az algoritmus hozza l´etre. A helyettes´ıt´es ut´ an minden olyan adatfolyam megmarad, amely a Bi blokkon bel¨ uli ´es azon k´ıv¨ uli m˝ uveleteket k¨ ot o uli m˝ uvelet helyett (annak ¨ssze, viszont a Bi blokkon bel¨ hi´any´aban) az u ´j virtu´ alis m˝ uvelet lesz a v´egz˝od´ese. (azaz az ´el egyik cs´ ucsa az u ´j virtu´alis m˝ uvelet lesz) Az im´enti algoritmust iterat´ıvan addig futtatjuk, m´ıg v´eg¨ ul a gy¨ok´er blokk is egyetlen virtu´alis m˝ uveletre reduk´ al´ odik. Ez az a pont, ahol m´ar minden blokkra megkaptuk annak u ´jraind´ıt´asi- ´es lappang´ asi idej´et. A gy¨ ok´er blokkra vett R ´es L ´ert´ekek lesznek az MREOGra R ´es L ´ert´ekei.
3.1.2. A bemeneti forr´ ask´ od A 3.1. k´epletet sokf´elek´eppen le´ırhatjuk Haskell nyelven, h´arom egyszer˝ u megval´os´ıt´ast a k¨ovetkez˝o k´odr´eszlet szeml´eltet. megoldas1 x = g ( x ) + s e g e d f 1023 where s e g e d f 0 = f x s e g e d f i = f ( x+i ) + s e g e d f ( i −1) megoldas2 x = g ( x ) + f s t \ $ i t e r a t e s e g e d f ( 0 , 0 ) ! ! 1024 where s e g e d f ( s , i ) = ( s+f ( x+i ) , i +1) megoldas3 x = g ( x ) + sum \ $ map ( \ i −> f ( x+i ) ) [ 0 . . 1 0 2 3 ]
52
Az els˝ o megold´ as rekurz´ıv f¨ uggv´enyt haszn´al, a m´asodik ´es a harmadik megold´as a rekurzi´ot magasabb rend˝ u f¨ uggv´enyek seg´ıts´eg´evel elrejti, ´es egy´ uttal bevezet egy-egy list´ at ´es az ahhoz sz¨ uks´eges m˝ uveleteket. (sum , map , (!!) ) Mindh´arom megold´asn´al egy´ertelm˝ u, hogy az x adott ´ert´ek´ere az f f¨ uggv´eny t¨obbsz¨or ker¨ ul alkalmaz´asra. Els˝o esetben a rekurzi´ob´ ol k¨ ovetkeztethet¨ unk erre, m´asodik ´es harmadik esetben amiatt, mert az iterate , ill. a map be´ agyazott f¨ uggv´eny´eben haszn´aljuk f -et. A rekurz´ıv f¨ uggv´enyek k¨ ozvetlen haszn´alat´at kiz´artuk, ez´ert az els˝o megold´ast nem engedhetj¨ uk meg. A harmadik megold´asnak a m´asodikkal szemben a le´ır´as egyszer˝ us´ege ´es az eredeti k´eplethez nagyon hasonl´o le´ır´asm´od az el˝onye, ´ıgy a k¨ovetkez˝o vizsg´alatokn´ al ezzel az esettel foglalkozom tov´ abb. A [0..1023] listamegad´ as egy szintaktikai ´edes´ıt˝oszer, amely az enumFromTo(0,1023) f¨ uggv´enyh´ıv´ asra k´epz˝ odik le. Ezek alapj´an a p´eldamegold´asban n´egy f¨ uggv´eny¨ unk van, amelyek pontosan a n´egy lehets´eges ki- ´es bemeneti t´ıpuskombin´aci´oval rendelkeznek: • (+) : skal´ ar bemenet ´es skal´ar kimenet, tov´abbi p´eld´ak lehetn´enek a 2.4. fejezetben bemutatott f¨ uggv´enyek (kiv´etel iterate ) • enumFromTo a b : skal´ ar bemenet ´es lista kimenet • map f xs : lista bemenet ´es lista kimenet, ´es a lista minden elem´ere lefut az f f¨ uggv´eny • sum xs : lista bemenet ´es skal´ar kimenet, tov´abbi p´eld´ak lehetn´enek a product , maximum ´es a foldl , ez ut´ obbi egy ´altal´anos lista ´es skal´ar k¨oz¨otti konverter A fejezet bevezet˝ oj´eben m´ ar sz´o volt r´ola, hogy az f f¨ uggv´enynek megfelel˝o m˝ uveletet egyszer hozzuk l´etre ´es egym´ as ut´an t¨obbsz¨or alkalmazzuk, azaz a bemeneti adatokat egyes´evel, id˝ oben elv´ alasztva adjuk ´at. Ezt a funkci´ot a Haskell megold´asban a map t¨olti be, ami a bemeneti lista elemeivel egym´as ut´an h´ıvja f -et. Ez azt jelenti, hogy a list´ at felfoghatjuk stream-k´ent, a map -nek megfelel˝o m˝ uvelet pedig eg´eszen egyszer˝ uen a streamen egym´ as ut´ an ´erkez˝ o elemeket egym´as-ut´an adja ´at f -nek. Ehhez a gondolatmenethez t¨ ok´eletesen kapcsol´odik a Stream Fusion [18] elj´ar´as, amelyet azonban m´ as c´ellal hoztak l´etre. Az volt a c´el, hogy az egym´as ut´ani listam˝ uveleteket (map , zip , foldr , stb.) a GHC a ford´ıt´as sor´an optimaliz´alj´ak, ´es egyetlen ´atalak´ıtott f¨ uggv´enybe t¨ om¨ or´ıts´ek. Ezzel az egym´as ut´ani listareprezent´aci´ok sz´am´at cs¨okkentik, adott esetben ak´ ar a list´ ak teljesen el is t˝ unnek az optimaliz´al´as sor´an, ami a processzorra ford´ıt´ as eset´eben is nagyon kedvez˝ o hat´ as´ u. Alkalmazva a Stream Fusion elj´ar´ast alapjait, fogalmi szinten ´ att´erhet¨ unk list´ akr´ ol stream-ek haszn´alat´ara. A skal´ ar bemenet˝ u ´es lista kimenet˝ u f¨ uggv´enyek gyors´ıt´ o f¨ uggv´enyek, hiszen egyetlen ´ert´ekb˝ ol egy list´ at (t¨ obb ´ert´eket, azaz stream-et) gener´alnak. A lista bemenet˝ u ´es skal´ ar kimenet˝ u f¨ uggv´enyek lass´ıt´ o f¨ uggv´enyek, mert list´at (t¨obb ´ert´eket, azaz stream-et) kapnak ´es ebb˝ ol egyetlen ´ert´eket adnak vissza. A p´eldameold´ asb´ ol a sebess´egszintek nagyon egyszer˝ uen kivehet˝oek. Mivel a g(x) a map-en k´ıv¨ ul van, ez´ert az minden bemenetre egyszer hajt´odik v´egre, a f(x+i) f¨ uggv´enyt 53
pedig a map-en bel¨ ulre ´ırtuk, ´ıgy azt meg kell h´ıvni a [0..1023] lista minden elem´ere, azaz a sebess´ege egy hierarchiaszinttel gyorsabb a g -n´el. (az ´altal´anosan fel´ırt map f xs f¨ uggv´enyh´ıv´ as eset´eben az f sz´ am´ıt bel¨ ulnek, hiszen ez a f¨ uggv´enyparam´eter) Sajnos ´altal´ anos esetben a helyzet nem ilyen egyszer˝ u, ennek demonstr´al´as´ara szolg´al a k¨ovetkez˝o k´odr´eszlet. maptest : : Int −> Int maptest x = let belso j = l e t a = sum \ $ map ( \ i b = sum \ $ map ( \ i c = sum \ $ map ( \ i d = sum \ $ map ( \ i in ( a , b , c , d ) in sum \ $ map b e l s o [ 0 . . 3 ]
−> −> −> −>
i +5) [ 0 . . 4 ] : : Int i+j +5) [ 0 . . 5 ] : : Int i+x+5) [ 0 . . 6 ] : : Int i+j+x+5) [ 0 . . 7 ] : : Int
A p´eld´aban egy 0 − 3 intervallumban mozg´o k¨ uls˝o ciklus (ciklusv´altoz´oja: j ), ´es az azon bel¨ ul helyet foglal´ o n´egy darab bels˝o ciklus (ciklusv´altoz´oja: i ) tal´alhat´o. L´athat´o, hogy b´ar az a v´ altoz´ o kisz´ am´ıt´ asa a k¨ uls˝o cikluson bel¨ ul tal´alhat´o, ´ert´ek´et el´eg a program fut´asa sor´an egyszer kisz´ am´ıtani, ugyanis nem f¨ ugg a bemenett˝ol. A c v´altoz´o m´ar f¨ ugg a bemenett˝ol, viszont a k¨ uls˝ o ciklus v´ altoz´oj´at´ol, j -t˝ol nem, ´ıgy el´eg minden x bemenetre egyszer kisz´ am´ıtani ´ert´ek´et. Adott esetben a vagy c kisz´am´ıt´asa nagyon hosszantart´o m˝ uvelet is lehet, ´ıgy kifejezetten h´ atr´ anyos, ha ezeket a m˝ uveleteket j -szer hajtjuk v´egre az el´egs´eges 1 helyett. Az a vagy a c ´ert´eke param´eterk´ent a k¨ uls˝o cikluson k´ıv¨ ulr˝ol is megkaphat´o lenne, ´es ilyen esetben a ford´ıt´ o az inlining-nak k¨osz¨onhet˝oen szint´en a belso f¨ uggv´enyen bel¨ ulre helyezn´e ezt a kifejez´est. Ebb˝ ol sajnos az k¨ovetkezik, hogy nem el´eg azt vizsg´alni, hogy az egym´asba ´agyazott map f¨ uggv´enyekben milyen m´elyen tal´alhat´o egy m˝ uvelet. Egy m´asik megold´ as lehet, ha minden m˝ uveletn´el megvizsg´aljuk, hogy operandusai milyen v´altoz´okt´ ol f¨ uggnek. Ezek a v´ altoz´ ok a ciklusv´altoz´ok ´es az egyetlen bemeneti v´altoz´o. Egy kiz´ar´olag konstans operandusokkal rendelkez˝o o¨sszead´as m˝ uvelet eredm´enye pl. konstans, ellenben ha az egyik operandus az x bemeneti v´altoz´ot´ol f¨ ugg, akkor az ¨osszead´as eredm´enye is x -t˝ ol fog f¨ uggni, ´es ´ıgy tov´abb. Ha egy m˝ uvelet f¨ ugg a bels˝o j ciklusv´altoz´ot´ol, ´es a j f¨ ugg a k¨ uls˝ o i ciklusv´ altoz´ot´ol, akkor a m˝ uvelet mindk´et ciklusv´altoz´ot´ol f¨ uggni fog, teh´ at a f¨ ugg´es tranzit´ıv. Ez ut´obbi sz´ am´ıt´ as m´ ar megfelel elv´ ar´asainknak, mert csak akkor v´egez el egy m˝ uveletet, ha a m˝ uvelet bemenetei v´ altoztak, ´es ´ıgy a m˝ uveletek felesleges fut´asait kisz˝ urt¨ uk. Ism´et megjegyzem, ez az inlining miatt egy kulcsfontoss´ag´ u k´erd´es.
3.1.3. Kimeneti hardverle´ır´ as A VHDL le´ır´ asban az egyes m˝ uveleteket megtestes´ıt˝o modulok a control bitek hat´as´ara l´epnek m˝ uk¨ od´esbe. MREOG eset´eben ez az egyszer˝ u vez´erl´es nem elegend˝o, ehhez pedig igazol´ask´ent el´eg csak a sum m˝ uvelet m˝ uk¨od´es´ere gondolni. A sum f¨ uggv´eny Haskell-ben a lista elemeinek ¨ osszeg´et sz´ amolja ki, azaz a MREOG sum m˝ uvelete a stream elemeire v´egzi 54
ezt. A sum VHDL modul a bemenet´ere ´erkez˝o ´ert´ekeket ¨osszegzi, de ezt csak addig szabad tennie, am´ıg egy adott stream-en bel¨ uli ´ert´ekek ´erkeznek. Amint u ´j stream kezd˝odik, a szumm´ az´ ast ism´et null´ ar´ ol kell kezden¨ unk, hiszen a sum a stream elemeit adja o¨ssze, nem a v´egtelens´egig ´erkez˝ o adatokat. C´elszer˝ u teh´ at bevezetni egy m´asodik control bitet, ami nem az adott skal´ar ´ert´ek mintav´etelezhet˝ os´eg´et jelzi, hanem a skal´arokat tartalmaz´o stream mintav´etelezhet˝os´eg´et, azaz a stream kezdet´et. Ez a control bit pontosan akkor lesz akt´ıv, amikor a stream els˝ o elem´enek (skal´ arj´ anak) control bitje akt´ıv. Egy olyan stream-n´el, amelynek minden eleme skal´arokat tartalmaz´o stream, be kell vezetn¨ unk egy harmadik control bitet, hiszen egy sum modul ¨osszegzi a bels˝o stream-eket, de ennek eredm´enye skal´ arokat tartalmaz´o stream, amit egy´ebk´ent ism´et szumm´azhatunk. Mindebb˝ ol tah´ at az k¨ ovetkezik, hogy minden MREOG m˝ uveleti csom´oponthoz a hierarchiaszintj´evel azonos bitsz´eless´eg˝ u vektort kell rendeln¨ unk vez´erl˝ojel gyan´ant. A 3.2. ´ abra. k´etszint˝ u stream vez´erl˝ojeleinek hull´amform´aj´at mutatja. A cq[2] jel a bemenet mintav´etelez´ese, a cq[1] magas szintje a minden bemenetre el˝o´all´o streamen ´erkez˝ o adatok mintav´etelez´ese, de mivel a stream-en bel¨ uli adatok szint´en stream-ek, ez´ert megjelenik egy harmadik szint is. A cq[0] jel a bels˝o streamen ´erkez˝o adatok mintav´etelez´es´et ´ jelenti. Altal´ anosan elmondhat, hogy a vez´erl˝o vektor 0. bitje mindig a leggyorsabb mintav´etelez´est fogja jelenteni, ugyanis ´ıgy biztos´ıthat´o egyszer˝ uen, hogy a skal´ar-skal´ar t´ıpus´ u m˝ uveletek mindig a legbels˝ o stream adatain oper´aljanak. 500 ns
1,000 ns
1,500 ns
3.2. ´ abra. Vez´erl˝o bitek stream eset´en
Mivel a vez´erl˝ obit helyett a vez´erl´eshez bitvektort haszn´alunk, ´es a bitvektor sz´eless´ege a hierarchiaszintt˝ ol f¨ ugg, ez´ert azt a VHDL modulok generikus param´eterek´ent c´elszer˝ u ´atadnunk. A generikus param´etereket a 2. fejezetben le´ırt m´odszer is t´amogatja, ´ıgy ez nem okoz plusz munk´ at. Innent˝ ol kezdve minden VHDL modul els˝o generikus param´etere a hierarchi´ aban elfoglalt szintet fogja jelezni.
3.2. A ford´ıt´ asi algoritmus kiterjeszt´ ese Az interf´eszek vizsg´ alata ´es m´ odos´ıt´asa ut´an r´at´erek a ford´ıt´o azon m´odos´ıt´asaira, amely lehet˝ov´e teszi a heterog´en sebess´eg˝ u m˝ uveletek haszn´alat´at. A Haskell-EOG ford´ıt´oban ehhez k´et u ´j algoritmust kellett bevezetnem, egyik a 3.2.1. fejezetben bemutat´asra ker¨ ul˝ o MapConversion, a m´ asikat pedig a 3.2.2. fejezetben mutatom be, ´es a m˝ uveletek hierarchi´aban elfoglalt hely´et hat´ arozza meg. Az EOG-VHDL ford´ıt´o minim´alis m´odos´ıt´asra szorul, itt a vez´erl˝ o signal -ok std_logic -r´ol (egy bites jel) std_logic_vector -ra (t¨obb bites vektor) val´ o´ at´ır´ asa elegend˝ o a sikerhez, ´ıgy ezt a k´es˝obbiekben nem fejtem ki b˝ovebben. 55
3.2.1. MapConversion transzform´ aci´ o A map magasabbrend˝ u f¨ uggv´eny defin´ıci´oja: map : : ( a −> b ) −> [ a ] −> [ b ] map [] = [] map f ( x : xs ) = f x : map f xs
A map f¨ uggv´eny els˝ o param´etere egy egyparam´eteres f f¨ uggv´eny, amely a m´asodik param´eterben megadott lista o ¨sszes elem´ere megh´ıv´odik. Az f visszat´er´esi ´ert´eke a m´asodik param´eterrel megegyez˝ o elemsz´ am´ u lista azonos hely´ere ker¨ ul. A MapConversion transzform´ aci´ o nagyon hason´o a 2.2.3. fejezetben bemutatott IterateConversionh¨oz, ´ıgy ez is egy egyszer˝ u Core2Core transzform´aci´o, amit a 3.3. ´abr´an a m´ar megszokott formalizmussal ismertetek.
01: app map 02: lam x 03: E 04: E2
01: let x = 02: E2 03: note "lam x" 04: E 3.3. ´ abra. IterateConversion a´ltal´anos k´eplet
Mint l´athat´ o, a transzform´ aci´ o nagyon egyszer˝ u, ´es tulajdonk´eppen a map f¨ uggv´eny elt˝ untet´es´er˝ol sz´ ol. A map kimenet´et az E kifez´es, azaz a bels˝o lambda absztrakci´o adja. Azokra a pontokra, ahol a bels˝ o lamda absztrakci´o param´eter´et (x -et) felhaszn´aljuk az E2 kifejez´es ker¨ ul, vagyis a m´ asodik param´eterk´ent megadott lista. (ami az MREOG nyelvezet szerint m´ar stream) Ezt a m˝ uk¨ od´est az u ´jonnan bevezetett let x = csom´opont val´os´ıtja meg. Fontos, hogy az E kifejez´es gy¨ oker´et egy note csom´oponttal megjel¨olj¨ uk, mert az OpTree f´aban ez a csom´ opont fogja jelezni az elt˝ untetett map bels˝o lambda absztrakci´oj´anak kezdet´et. A Haskell nyelv szempontj´ ab´ ol a Core a transzform´aci´o ut´an nem marad t´ıpuskonzisztens, ugyanis az E2 -nek a t´ıpusa lista, az E -n bel¨ ul felhaszn´alt x pedig a lista elemei, de x itt mag´at a list´ at, az E2 -t kapja meg. Az ilyen ´ertelemben vett t´ıpusinkonzisztencia nem okoz probl´em´ at, hiszen a gr´ afb´ ol MREOG reprezent´aci´o k´esz¨ ul, ahol a stream ´es a skal´ar csak a hierarchi´ aban elfoglalt szint vonatkoz´as´aban t´er el egym´ast´ol, egy´ebk´ent a kett˝o t´ıpusazonos. A MapConversion transzform´ aci´ ot a 2.6. ´abr´an v´azolt Haskell-EOG pipeline IterateConversion ´es AppRename transzform´ aci´oi k¨oz´e c´elszer˝ u be´ekeln¨ unk.
3.2.2. A hierarchia automatikus fel´ ep´ıt´ ese A t¨obbsebess´eg˝ u adatfolyamokat is t´ amogat´o ford´ıt´as legl´enyegesebb pontj´ahoz ´erkezt¨ unk. Most k¨ovetkezik annak az algoritmusnak a le´ır´asa, amely minden m˝ uveletre, azaz az OpTree minden csom´ opontj´ ara meghat´ arozza az MREOG hierarchi´aban elfoglalt hely´et, azaz fel´ep´ıti mag´ at az MREOG-t. Az algoritmust a 2.6. ´abr´an l´athat´o ford´ıt´oi pipeline Co56
reToTree ´es TreeSimplifier ´ atalak´ıt´asai k¨oz´e kell be´ekeln¨ unk, mert ez az a pont, ahol a Core-b´ ol m´ ar OpTree reprezent´ aci´o lett, ´es a sz¨ uks´eges seg´ed csom´opontok (mint pl. a note lam x”) m´eg nem t˝ untek el. ” Az algoritmus n´egy l´ep´esb˝ ol ´ all, ezek mindegyike az OpTree f´at j´arja be O(n) k¨olts´eggel. A l´ep´esek a k¨ ovetkez˝ ok: 1. Ciklusv´ altoz´ ok sorsz´ amoz´ asa: az OpTree preorder bej´ar´asa sor´an a MapConversion ´altal l´etrehozott Note lam csom´opontok eset´eben a kapcsol´od´o v´altoz´o (a MapConversion transzform´ aci´ on´ al l´ atott p´eld´aban ez x volt) neve el´e egy sorsz´amot ´ırunk, ami az egym´ asba ´ agyaz´ as sor´an egyre magasabb ´ert´eket vesz fel. Erre az´ert van sz¨ uks´eg, hogy a blokk azonos´ıt´ok sorrendhelyesen (el˝osz¨or a gy¨ok´erelem, majd annak gyereke, stb.) ker¨ ulhessenek felsorol´asra. 2. M˝ uveletek v´ altoz´ of¨ ugg´es´enek meghat´aroz´asa: az OpTree postorder bej´ar´as´an´al minden node-ra meg´ allap´ıtjuk, hogy az mely v´altoz´okt´ol f¨ ugg, azaz a node alatti r´eszf´ ak mely v´ altoz´ ok ´ert´ekeit haszn´alj´ak fel. A postorder bej´ar´as biztos´ıtja, hogy el˝osz¨or a levelekre ´ert´ekel˝ odj¨ on ki a f¨ ugg˝os´eg vizsg´alat, ´ıgy minden node sz´am´ıt´asakor csak a k¨ ozvetlen¨ ul alatta l´ev˝ o node-ok f¨ ugg˝os´egeit kell figyelembe venni. 3. V´ altoz´ of¨ ugg˝ os´egek tranzit´ıv kiterjeszt´ese: ha egy node az i ciklusv´altoz´ot´ol f¨ ug, ´es az i ciklusv´ altoz´ o pedig a j ciklusv´altoz´ot´ol, akkor a node is f¨ ugg j -t˝ol. Az OpTree bej´ arjuk preorder m´odon, ´es minden Note lam csom´opontn´al a hozz´a tartoz´ o v´ altoz´ ot ´es f¨ ugg˝ os´egeit feljegyezz¨ uk, majd a gyerekeinek a bej´ar´askor ezt ´atadjuk. Ha egy m˝ uvelet i -t˝ ol f¨ ugg, akkor a f¨ ugg˝os´egi halmazhoz hozz´avessz¨ uk az i v´altoz´ohoz rendelt f¨ ugg˝ os´egeket is. Ezt k¨onnyen megtehetj¨ uk, mert a Note lam i csom´opontn´ al i f¨ ugg˝ os´egeit feljegyezt¨ uk, ´es param´eterk´ent ´atadtuk a gyerekeknek. 4. Hierarchiaszintek meghat´ aroz´asa: preorder bej´ar´asn´al minden node-ra megsz´amoljuk az el˝ obbiekben m´ ar felt¨olt¨ott f¨ ugg˝os´egi lista elemeinek sz´am´at, ez lesz maga a hierarchiaszint. Az u ugg˝os´egi lista azt jelenti, hogy az adott m˝ uvelet eredm´enye ¨res f¨ konstans. Ilyen esetben a konstanst szinkroniz´alni kell az azt felhaszn´al´o nem konstans m˝ uvelettel, azaz a m˝ uvelet f¨ ugg˝os´egi list´aj´at a konstansra ´atm´asoljuk. Ez az´ert nagyon fontos, mert tal´ alkozhatunk stream konstansokkal is, amelyek a gyakorlatban nem konstansok, hiszen az adatokat egym´as ut´an felsorolva k¨ uldik. Ilyen esetben a felsorol´ ast v´egz˝ o m˝ uveletet (rendszerint EnumFromTo) a blokkj´anak megfelel˝o bemenettel triggerelni kell. Ha ez nem t¨ort´enik meg, az EnumFromTo m˝ uveletnek nem adjuk ´ at az inform´ aci´ ot, hogy mikor kell elkezdenie a felsorol´ast, ´ıgy az egym´as ut´ an t¨ obbsz¨ or semmik´epp nem tud lefutni. (ami pedig k¨ovetelm´eny lehet) Az algoritmus lefut´ asa ut´ an minden Node-hoz ismert lesz a hozz´a tartoz´o hierarchiaszint ´es a tartalmaz´ o blokkok gy¨ ok´erelemt˝ol ind´ıtott azonos´ıt´oi Az EOG sz¨ oveges reprezent´ aci´ oj´anak elk´esz´ıt´esekor a m˝ uvelet els˝o generikus param´etere a hierarchiaszint lesz, a harmadik oszlopba pedig a blokk azonos´ıt´ok ker¨ ulnek sorrendhelyesen. (a ciklusv´ altoz´ ok sorsz´ amoz´asa miatt ez alfanumerikus sorrendet jelent) 57
3.3. A m˝ uvelethalmaz kiv˝ ov´ıt´ ese A fejezet eddigi r´esz´eben a ford´ıt´ o m´ odszer´enek kib˝ov´ıt´es´evel foglalkoztam, hogy a rendszer alkalmas legyen t¨ obbsebess´eg˝ u adatfolyamok kezel´es´ere is. A m´odszert implement´altam, a ford´ıt´oprogram most m´ ar k´epes az MREOG-ben reprezent´alhat´o algoritmusok Haskellb˝ol VHDL-be t¨ort´en˝ o ford´ıt´ as´ ara. Egy dolog maradt h´atra, ez pedig a konkr´et m˝ uveletek defini´al´asa ´es VHDL-ben t¨ ort´en˝ o le´ır´ asa, hogy a ford´ıt´o u ´j k´epess´egeit t´enylegesen ki tudjuk haszn´alni Haskell nyelven ´ırt forr´ ask´ odokb´ol. A k¨ovetkez˝o k´et alfejezet sor´an a m˝ uvelethalmazt kib˝ov´ıtem a stream-, ill. a t¨ ombkezel˝o m˝ uveletekkel.
3.3.1. Stream m˝ uveletek A stream m˝ uveletek a Haskell lista kezel˝o f¨ uggv´enyeib˝ol ad´odnak. A tov´abbiakban a stream-ek fogalm´ an´ al maradok, ez´ert fontos megjegyezni, hogy a forr´ask´od szintj´en ezek m´eg listak´ent szerepelnek, ezt a m˝ uveletek t´argyal´as´an´al ´erdemes mindi ´eszben tartani. A 3.1.2. alfejezetben l´ attuk, hogy a 3.1. k´eplet sz´am´ıt´asa h´arom listam˝ uveleten alapszik: enumFromTo , map ´es sum . Ez a h´ arom m˝ uvelet m´ar el´egs´eges az MREOG l´etrej¨ott´ehez, mert tartalmaz gyors´ıt´ o (enumFromTo) ´es lass´ıt´o (sum) m˝ uveletet is. Mivel minden lass´ıt´o m˝ uvelet megegyezik az alapok szintj´en, ez´ert most p´eldak´ent csak a sum -mal foglalkozom. Ennek anal´ogi´ aj´ ara nagyon k¨ onnyen ´ att´erhetn´enk a product vagy a maximum , vagy egy´eb lass´ıt´o f¨ uggv´enyre is. A gyors´ıt´ o f¨ uggv´enyekn´el ugyan ez a helyzet. A Map -et a MapConversion transzform´aci´o elimin´alta, ´ıgy csak az EnumFromTo , ´es Sum modulok VHDL le´ır´ as´ ar´ ol kell sz´ ot ejtenem. Az EnumFromTo tulajdonk´eppen u ´gy viselkedik, mint egy for ciklus. A bemenet´en ´erkez˝o intervallumhat´ arokon bel¨ ul l´epteti a kimeneti v´altoz´oj´ara k¨ot¨ott sz´aml´al´o ´ert´ek´et, a generikus param´eterk´ent megadott k´esleltet´esi id˝ok¨oz¨onk´ent. Ez az id˝ok¨oz a blokkra alkalmazott, R u ´jraind´ıt´ asi id˝ o kisz´ am´ıt´ asa sor´an ad´odik. Ha a Bi blokk u ´jraind´ıt´asi ideje Ri , akkor a Bi -ben tal´ alhat´ o EnumFromTo k´esleltet´esi id˝ok¨oze pontosan az Ri ´ert´ek lesz. Ez egyszer˝ uen abb´ ol ad´ odik, hogy az EnumFromTo-nak k´et ´ert´ek k¨oz¨ott ki kell v´arnia az ut´ana k¨ovetkez˝ o m˝ uveletek minim´ alis u ´jraind´ıt´asi idej´et, hogy azok a m˝ uveletek rendben lefussanak. A Sum a bemenet´ere ´erkez˝ o stream ´ert´ekeit o¨sszegzi. A stream kezdet´et jelz˝o m´asodik szint˝ u vez´erl˝ obit a modulban tal´ alhat´o accum regisztert null´azza, ´ıgy minden stream kezdet´en a sz´ aml´ al´ as null´ ar´ ol indul. A modulok egy-egy lehets´eges VHDL k´odja a f¨ uggel´ekben megtal´alhat´o.
3.3.2. T¨ omb m˝ uveletek A stream-ekkel ´es m˝ uveleteikkel kapcsolatban egy fontos dologr´ol m´eg nem esett sz´o. Haskell-ben k¨ onnyen le´ırhatunk olyan algoritmust, ami el˝osz¨or el˝o´all´ıt egy list´at, majd ezen a list´an t¨ obbsz¨ or v´egigmegy. Egy egyszer˝ u p´elda, ha a lista maximum´at hozz´a kell adnunk a lista ¨ osszes elem´ehez. Nyilv´ anval´o, hogy el˝osz¨or ki kell v´alasztanunk a maxim´alis elemet (els˝o bej´ ar´ as), ´es csak ezut´ an kezd˝odhet az ¨osszead´as (m´asodik bej´ar´as). 58
Az el˝ obb felv´ azolt lista a ford´ıt´as sor´an stream-k´ent ker¨ ul l´etrehoz´asra, ami azt jelenti, hogy a lista elemei egym´ as ut´ an, ´es csak egyszer jelennek meg a stream-et megtestes´ıt˝ o adatfolyamon. A stream elemeit teh´at nem soroljuk fel k´etszer, ´ıgy a fent v´azolt algoritmus kudarcot vall. A probl´em´ ara k´et f˝obb megold´as l´etezhet. A stream el˝o´all´ıt´as´a´ert felel˝ os m˝ uveleteket esetleg r´ a lehet venni, hogy ism´etelten kisz´amolj´ak a stream elemeit, ´ıgy az u ´jra felsorolhat´ o. M´ asodik esetben az egyszer kiadott stream-et mem´ori´aban elt´aroljuk, ´es legk¨ozelebb a mem´ ori´ ab´ ol olvassuk vissza stream-k´ent, ´ıgy ameddig a mem´ori´aban fellelhet˝o az elmentett stream, azon b´ armennyiszer v´egig tudunk menni. Az els˝o eset az eddigi m˝ uveletekkel megoldhat´ o, de adott esetben el˝ofordulhat, hogy a stream u ´jra gener´al´asa csak nagyon k¨ olts´egesen lenne kivitelezhet˝o, ´es ´ıgy a m´asodik megold´as ker¨ ulhet el˝ot´erbe. Ebben az alfejezetben a m´ asodik megold´assal foglalkozom, vagyis azzal, hogy hogyan tudunk egy stream-et elmenteni, majd u ´jra felolvasni. Ezt kidolgozva m´as el˝ony¨okhez is jutunk, m´egpedig, hogy a let´ arolt lista adott index˝ u elemeihez a mem´ori´aban val´o t´arol´ as miatt O(1) id˝ o alatt hozz´ a tudunk f´erni, szemben a lista vagy a stream eset´eben, ahol ez az id˝o O(n). Haskell-ben l´etezik t¨ omb¨ ot megval´os´ıt´o adatstrukt´ ura, amelynek defin´ıci´oja a k¨ovetkez˝ok´epp n´ez ki: data (Ix a) => Array a b = MkArray (a,a) (a -> b) deriving ()
Egy t¨ omb¨ ot ezek szerint megadhatunk egy index intervallummal, ´es egy olyan f¨ uggv´ennyel, ami az indexb˝ ol ´ert´ekre k´epez le. A m˝ uk¨od´es´ebe enn´el r´eszletesebben nem kell belem´elyedn¨ unk, helyette az Array -el v´egezhet˝o alapm˝ uveletekre ´erdemes koncentr´alni: • listArray : Array l´etrehoz´ as, ´es az elemek felt¨olt´ese kezdeti ´ert´ekkel • (//) : adott index˝ u elem m´odos´ıt´asa • (!) : adott index˝ u elem lek´er´ese Ezzel a h´ arom m˝ uvelettel a felv´azolt probl´ema m´ar megoldhat´o. A listArray -t nem tekintem m˝ uveletnek, mert a l´etrehoz´as ford´ıt´asi id˝oben, statikusan m˝ uk¨odhet. (az elosztottan haszn´ alt mem´ ori´ ak ´es a mem´oriaallok´al´as k´erd´ese t´ ulmutat jelen dolgozat hat´arain) Az elemek kezdeti ´ert´ekkel val´ o felt¨olt´es´et pedig szint´en statikusan ford´ıt´asi id˝oben, vagy dinamikusan a (//) m˝ uvelet haszn´alat´aval meg tudjuk val´os´ıtani. Minden listArray-hez teh´ at egy-egy block RAM-ot kell l´etrehoznunk ford´ıt´asi id˝oben, amit ut´ ana az olvas´ asi ´es ´ır´ asi m˝ uveletekkel fut´asi id˝oben is kezelhet¨ unk. A (!) oper´ ator, vagyis a VHDL szinten nth -nak h´ıvott modul a bemeneti ´ert´ek´et a block RAM c´ımvonal´ ara k¨ uldi, a block RAM ´altal a kimeneti adatvonalon szolg´altatott ´ert´ek pedig az nth kimenet´ere fog ker¨ ulni egy ´orajel eltol´assal. (amennyiben a block RAM szint´en a rendszer ´ orajelre van k¨ otve, ami szinkron h´al´ozat l´ev´en persze indokolt) A (//) oper´ ator list´ at v´ ar, vagyis VHDL megfelel˝oje, a wr nev˝ u modul stream-et. A stream-en ´erkez˝ o adatok p´ aros´aval ´erkeznek (2-es tuple-k´ent), aminek egyik eleme az indexet jelenti, m´ asik eleme pedig az indexre be´ırand´o ´ert´eket. A m˝ uvelet megval´os´ıt´asa 59
szint´en egyszer˝ u, a wr modul az indexet a block RAM c´ımvonal´ara, az ´ert´eket pedig a bemeneti adatvonal´ ara k¨ oti, ´ıgy a k¨ ovetkez˝o ´orajelre az ´ert´ek beker¨ ul a block RAM index ´altal meghat´ arozott c´ım´ere. A modulok egy-egy lehets´eges VHDL k´odja a f¨ uggel´ekben megtal´alhat´o.
60
4. fejezet
A m´ odszer gyakorlati alkalmaz´ asa mintafeladatokon A 2. ´es a 3. fejezetekben ´ altalam kidolgozott m´odszert Haskell nyelven ´ırt ford´ıt´oprogramk´ent implement´ altam, melynek a ford´ıt´as sor´an keletkezett napl´oja a f¨ uggel´ekben megtekinthet˝ o. Az elk´esz¨ ult ford´ıt´ oprogramot egy PID szab´alyoz´o ´es egy MP3 dek´odol´o algoritmusr´eszleten teszteltem, jelen fejezetben a teszt eredm´enyeit mutatom be.
4.1. PID szab´ alyoz´ o Az elk´esz¨ ult ford´ıt´ oprogramot Cs´ak Bence Ph.D. ´ertekez´es´eben [14] p´eldak´ent haszn´alt PID szab´ alyoz´ o algoritmussal teszteltem, ennek eredm´eny´et ismertetem a most k¨ovetkez˝ o fejezetben. Az ´ertekez´es szerinti C nyelven ´ırt k´od a 4.1. ´abr´an olvashat´o. Ennek Haskell nyelvi v´altozat´ at elk´esz´ıtettem, ´es a 4.2. ´abr´an be is mutatom. A plant_algo ´es pid_algo f¨ uggv´enyek mindk´et megold´ asban ugyan azt a bels˝o m˝ uk¨od´est val´os´ıtj´ak meg, a legf˝obb elt´er´es az, hogy a Haskell tiszta funkcion´alis nyelv, teh´at a C verzi´o statikus v´altoz´oit (esum ´es e ) a f¨ uggv´eny param´eterek´ent ´es a visszat´er´esn´el is szerepeltetni kell. A C p´elda for ciklus´ anak belsej´et a Haskell k´ od iteration f¨ uggv´enyek´ent implement´altam, a for ciklus, teh´ at a teljes algoritmus pedig az algo_main f¨ uggv´enybe ker¨ ult. Ahhoz, hogy a hardveres oszt´ as min´el egyszer˝ ubben megval´os´ıthat´o legyen, a 8-al val´o oszt´ ashoz bevezettem egy quot8 nev˝ u f¨ uggv´enyt, amit ez´ert a m˝ uvelethalmazban is defini´alnom kellett.
4.1.1. A ford´ıt´ as l´ ep´ esei A ford´ıt´ oprogram els˝ o l´ep´esk´ent a Haskell forr´ask´odb´ol a GHC k¨onyvt´ari f¨ uggv´enyei seg´ıts´eg´evel el˝ o´ all´ıtja a 4.3. ´ abr´ an l´ athat´o Core reprezent´aci´ot. A CaseReduction algoritmus ebb˝ol a reprezent´ aci´ ob´ ol elimin´ al minden case kifejez´est, az ´ıgy kapott k´odot pedig az IterateConversion alak´ıtja ´ at, ennek eredm´enye l´athat´o a 4.4. ´abr´an. A m´eg mindig Core form´aj´ aban l´etez˝ o le´ır´ as az AppRename ´es CoreToTree f´azisokon kereszt¨ ulhaladva a 4.5. ´abr´an sz¨ ovegesen bemutatott gr´ afot eredm´enyezi, aminek a TreeSimplifier algoritmus ut´ a61
#include <s t d i o . h> char p l a n t a l g o ( char c , char y ) { y = (7∗ c + y ) / 8 ; } char p i d a l g o ( char x , char y ) { s t a t i c const char cp =2; s t a t i c const char c i =1; s t a t i c const char cd =2; s t a t i c char esum = 0 ; s t a t i c char e = 0 ; char p , i , d , e o l d , e d i f f ; eold = e ; e = x − y; e d i f f = e − eold ; esum += e ; p = cp ∗ e / 8 ;
i = c i ∗ esum / 8 ; d = cd ∗ e d i f f / 8 ; return p + i + d ; // c } in t main ( ) { char c , y , i , x=8; y = 0; f o r ( i =0; i <30; i ++) { c = pid algo (x , y ) ; y = plant algo (c , y ); p r i n t f ( ”%d\n ” , y ) ; } return 0 ; }
4.1. ´ abra. PID algoritmus C forr´ask´odja {−# LANGUAGE N o I m p l i c i t P r e l u d e #−} module Pid ( hwmain ) where import I n s t r u c t i o n S e t p l a n t a l g o : : Int −> Int −> Int p l a n t a l g o c y = quot8 ( 7 ∗ c + y ) ; p i d a l g o : : Int −> Int −> ( Int , Int ) −> ( Int , ( Int , Int ) ) p i d a l g o x y ( e , esum ) = let eold = e e2 = x − y e d i f f = e2 − e o l d esum2 = esum + e2 p = quot8 $ 2 ∗ e2 i = quot8 $ 1 ∗ esum2 d = quot8 $ 2 ∗ e d i f f in ( p+i+d , ( e2 , esum2 ) ) i t e r a t i o n : : ( Int , Int , Int ) −> Int −> ( Int , Int , Int ) i t e r a t i o n ( e , esum , y ) x = l e t ( c , ( e2 , esum22 ) ) = p i d a l g o x y ( e , esum ) y2 = p l a n t a l g o c y in ( e2 , esum22 , y2 ) a l g o m a i n : : Int −> [ ( Int , Int , Int ) ] a l g o m a i n i n p u t = i t e r a t e ( \ x −> i t e r a t i o n x i n p u t ) ( 0 , 0 , 0 ) hwmain = a l g o m a i n
4.2. ´ abra. PID algoritmus Haskell forr´ask´odja
ni, egyszer˝ us´ıtett v´ altozat´ at grafikusan a 4.6. ´abr´an szeml´eltetem. A ConvertToEOG algoritmus ennek a gr´ afnak az inorder bej´ ar´ as´aval adja a Haskell-EOG ford´ıt´omodul kimenet´et, azaz a a 4.7. ´ abr´ an sz¨ ovegesen, majd a 4.8. ´abr´an vizu´alisan megjelen´ıtett elemi m˝ uveleti gr´afot. Az EOG-VHDL ford´ıt´ omodul az EOG-b˝ol m´ar k¨ozvetlen¨ ul VHDL le´ır´ast tud gener´alni, az eredm´enyt a 4.9. ´ abr´ an szeml´eltetem. 62
nrec quot 8 reEp = app I n s t r u c t i o n S e t . quot 8 r e 4n [ 1 ] var GHC. Real . $ f I n t e g r a l I n t r e 0b − GHC. Real . I n t e g r a l GHC. Types . I n t nrec quot 8 1 r e E t = app I n s t r u c t i o n S e t . quot 8 r e 4n [ 1 ] var GHC. Real . $ f I n t e g r a l I n t r e 0b − GHC. Real . I n t e g r a l GHC. Types . I n t nrec Pid . hwmain redC = lam i n p u t aeBj app GHC. L i s t . i t e r a t e r e 4o<( I n t , In t , I n t )> [ 2 ] lam x aeBk case var x aeBk − (GHC. Types . I n t , GHC. Types . I n t , GHC. Types . I n t ) a l t ( , , ) e esum y l e t nrec e 2 s e E l = app GHC.Num. − 01F [ 3 ] var i n p u t aeBj − GHC. Types . I n t var y aeBd − GHC. Types . I n t l e t nrec esum 2 seEk = app GHC.Num.+ rdZC [ 3 ] var esum aeBc − GHC. Types . I n t var e 2 s e E l − GHC. Types . I n t app GHC. Tuple . ( , , ) 7 7 < I n t , I nt , I n t > [ 3 ] var e 2 s e E l − GHC. Types . I n t var esum 2 seEk − GHC. Types . I n t app quot 8 1 reEt<> [ 1 ] app GHC.Num.+ rdZC [ 3 ] app GHC.Num. ∗ rdZD [ 3 ] app GHC. Types . I # 6d<> [ 1 ] lit 7 app GHC.Num.+ rdZC [ 3 ] app GHC.Num.+ rdZC [ 3 ] app quot 8 reEp<> [ 1 ] app GHC.Num. ∗ rdZD [ 3 ] app GHC. Types . I # 6d<> [ 1 ] lit 2 var e 2 s e E l − GHC. Types . I n t app quot 8 reEp<> [ 1 ] app GHC.Num. ∗ rdZD [ 3 ] app GHC. Types . I # 6d<> [ 1 ] lit 1 var esum 2 seEk − GHC. Types . I n t app quot 8 reEp<> [ 1 ] app GHC.Num. ∗ rdZD [ 3 ] app GHC. Types . I # 6d<> [ 1 ] lit 2 app GHC.Num. − 01F [ 3 ] var e 2 s e E l − GHC. Types . I n t var e aeBb − GHC. Types . I n t var y aeBd − GHC. Types . I n t app GHC. Tuple . ( , , ) 7 7 < I n t , In t , I n t > [ 3 ] app GHC. Types . I # 6d<> [ 1 ] lit 0 app GHC. Types . I # 6d<> [ 1 ] lit 0 app GHC. Types . I # 6d<> [ 1 ] lit 0
4.3. ´ abra. GHC ´altal szolg´altatott Core k´od
63
nrec Pid . hwmain va = lam i n p u t vb l e t nrec x vc = app i t e r a t e od<> [ 2 ] var C ou − # app GHC. Tuple . ( , , ) oe [ 3 ] app GHC. Types . I # of <> [ 1 ] lit 0 app GHC. Types . I # og<> [ 1 ] lit 0 app GHC. Types . I # oh<> [ 1 ] lit 0 l e t nrec i t out 0 v i = l e t nrec s c r u t i n e e 0 v j = var x vc − (GHC. Types . I n t , GHC. Types . I n t , GHC. Types . I n t ) l e t nrec e vk = app s e l e c t <( , ,) ,0 > o l <> [ 1 ] var s c r u t i n e e 0 v j − # l e t nrec esum vm = app s e l e c t <( , ,) ,1 > on<> [ 1 ] var s c r u t i n e e 0 v j − # l e t nrec y vo = app s e l e c t <( , ,) ,2 > op<> [ 1 ] var s c r u t i n e e 0 v j − # l e t nrec e 2 vq = app GHC.Num. − or [ 3 ] var i n p u t vb − GHC. Types . I n t var y vo − GHC. Types . I n t l e t nrec esum 2 vs = app GHC.Num.+ ot [ 3 ] var esum vm − GHC. Types . I n t var e 2 vq − GHC. Types . I n t app GHC. Tuple . ( , , ) ou [ 3 ] var e 2 vq − GHC. Types . I n t var esum 2 vs − GHC. Types . I n t app quot 8 1 v8<> [ 1 ] app GHC.Num.+ ow [ 3 ] app GHC.Num. ∗ ox [ 3 ] app GHC. Types . I # oy<> [ 1 ] lit 7 app GHC.Num.+ oz [ 3 ] app GHC.Num.+ oA [ 3 ] app quot 8 v3<> [ 1 ] app GHC.Num. ∗ oC [ 3 ] app GHC. Types . I # oD<> [ 1 ] lit 2 var e 2 vq − GHC. Types . I n t app quot 8 v3<> [ 1 ] app GHC.Num. ∗ oF [ 3 ] app GHC. Types . I # oG<> [ 1 ] lit 1 var esum 2 vs − GHC. Types . I n t app quot 8 v3<> [ 1 ] app GHC.Num. ∗ oI [ 3 ] app GHC. Types . I # oJ<> [ 1 ] lit 2 app GHC.Num. − oK [ 3 ] var e 2 vq − GHC. Types . I n t var e vk − GHC. Types . I n t var y vo − GHC. Types . I n t var i t out 0 v i − #
4.4. ´ abra. CaseReduction ut´ani Core k´od
64
lam [ ] input { var [ i t out 0 v i ] l e t −var { op [ C ou ] { var [ e 2 vq ] l e t −var { op [ sub o r ] { var [ i n p u t vb ] lam−var { vv [ IN 1 a 0 ] } var [ y vo ] l e t −var { op [ s e l e c t <( , ,) ,2 > < > op ] { var [ s c r u t i n e e 0 v j ] l e t −var { var [ x vc ] l e t −var { op [ i t e r a t e <> od ] { vv [ C ou ] op [ C oe ] { op [ C o f ] { l i t [ c o n s t 0 ] } op [ C og ] { l i t [ c o n s t 0 ] } op [ C oh ] { l i t [ c o n s t 0 ] }}}}}}}}} var [ esum 2 vs ] l e t −var { op [ add o t ] { var [ esum vm ] l e t −var { op [ s e l e c t <( , ,) ,1 > < > on ] { lnk [ i t e r a t e <> od ] }} lnk [ sub o r ] }} capp [ quot 8 1 ] { var [ quot 8 1 v 8 ] ? { lam [ e t a kamu ] 1 { op [ quot8 o 9 i v ] { op [ add ow ] { op [ mul ox ] { op [ C oy ] { l i t [ c o n s t 7 ] } op [ add oz ] { op [ add oA ] { capp [ quot 8 ] { var [ quot 8 v 3 ] ? { lam [ e t a kamu ] 1 { op [ quot8 o 4 iB ] { op [ mul oC ] { op [ C oD ] { l i t [ c o n s t 2 ] } lnk [ sub o r ] }}}}} capp [ quot 8 ] { var [ quot 8 v 3 ] ? { lam [ e t a kamu ] 1 { op [ quot8 o 4 iE ] { op [ mul oF ] { op [ C oG ] { l i t [ c o n s t 1 ] } lnk [ add o t ] }}}}}} capp [ quot 8 ] { var [ quot 8 v 3 ] ? { lam [ e t a kamu ] 1 { op [ quot8 o 4 iH ] { op [ mul o I ] { op [ C oJ ] { l i t [ c o n s t 2 ] } op [ sub oK ] { lnk [ sub o r ] var [ e vk ] l e t −var { op [ s e l e c t <( , ,) ,0 > < > o l ] { lnk [ i t e r a t e <> od ] }}}}}}}}}} lnk [ s e l e c t <( , ,) ,2 > < > op ] }}}}}}}}
4.5. ´ abra. A CoreToTree algoritmus ut´ani gr´af
65
OUT
C_ou
sub_or
IN_1_a0
select_op
select_on
iterate_od
iterate_od
C_ou
const_0_l7
add_ot
quot8_o9_iv
sub_or
mul_ox
C_oe
const_0_l8
const_2_lm
add_ow
const_7_lh
select_op
add_oz
const_0_l9
add_oA
quot8_o4_iH
quot8_o4_iB
quot8_o4_iE
mul_oI
mul_oC
mul_oF
const_2_lu
sub_or
const_1_lq
add_ot
sub_oK
sub_or
select_ol
iterate_od
4.6. ´ abra. A TreeSimplifier algoritmus ut´ani gr´af
IN 1 a 0 const 0 l 7 const 0 l 8 const 0 l 9 C oe i t e r a t e od s e l e c t op sub o r s e l e c t on add o t const 7 lh c o n s t 2 lm mul oC quot 8 o 4 iB const 1 lq mul oF quot 8 o 4 iE add oA const 2 lu select ol sub oK mul o I quot 8 o 4 iH add oz mul ox add ow quot 8 o 9 i v C ou OUT
”IN<96>” ”Const <32,0>” ”Const <32,0>” ”Const <32,0>” ”C3 <0 ,0 ,32 ,32 ,32 >” ” I t e r a t e <96>” ” S e l e c t <96 ,64 ,32 >” ”Sub<32>” ” S e l e c t <96 ,32 ,32 >” ”Add<32>” ”Const <32,7>” ”Const <32,2>” ”Mul<32>” ”Quot8<32>” ”Const <32,1>” ”Mul<32>” ”Quot8<32>” ”Add<32>” ”Const <32,2>” ” S e l e c t <96 ,0 ,32 >” ”Sub<32>” ”Mul<32>” ”Quot8<32>” ”Add<32>” ”Mul<32>” ”Add<32>” ”Quot8<32>” ”C3 <0 ,0 ,32 ,32 ,32 >” ”OUT<96>”
const 0 l 7 const 0 l 8 const 0 l 9 C ou C oe i t e r a t e od IN 1 a 0 s e l e c t op i t e r a t e od s e l e c t on sub o r
c o n s t 2 lm sub o r mul oC c o n s t 1 l q add o t mul oF quot 8 o 4 iB quot 8 o 4 iE i t e r a t e od sub o r s e l e c t o l c o n s t 2 l u sub oK mul o I add oA quot 8 o 4 iH c o n s t 7 l h add oz mul ox s e l e c t op add ow sub o r add o t quot 8 o 9 i v C ou
4.7. ´ abra. A Haskell-EOG modul kimenete
66
const_0_l7 Const<32,0>
const_0_l8 Const<32,0>
const_0_l9 Const<32,0>
C_oe C3<0,0,32,32,32>
IN_1_a0 IN<96>
iterate_od Iterate<96>
select_on Select<96,32,32>
add_ot Add<32>
sub_or Sub<32>
const_2_lm Const<32,2>
const_1_lq Const<32,1>
mul_oC Mul<32>
select_op Select<96,64,32>
select_ol Select<96,0,32>
sub_oK Sub<32>
mul_oF Mul<32>
const_2_lu Const<32,2>
mul_oI Mul<32>
quot8_o4_iE Quot8<32>
quot8_o4_iB Quot8<32>
add_oA Add<32>
quot8_o4_iH Quot8<32>
add_oz Add<32>
const_7_lh Const<32,7>
mul_ox Mul<32>
add_ow Add<32>
quot8_o9_iv Quot8<32>
C_ou C3<0,0,32,32,32>
OUT SYSTEM
4.8. ´ abra. A Haskell-EOG modul kimenete grafikusan
67
l i b r a r y IEEE ; use IEEE . STD LOGIC 1164 .ALL; use IEEE . STD LOGIC ARITH .ALL; use IEEE . STD LOGIC UNSIGNED .ALL; use work . d e f s . a l l ; entity benchmark i s Port ( r e s t a r t , c l k : I N 1 a 0 : in Output : out c I N 1 a 0 : in cOutput : out ); end benchmark ;
in STD LOGIC ; STD LOGIC VECTOR ( 3 1 downto 0 ) ; STD LOGIC VECTOR ( 9 5 downto 0 ) ; std logic ; std logic
architecture B e h a v i o r a l of benchmark i s component c o n s t s o u r c e i s generic ( width : i n t e g e r ; v a l u e : i n t e g e r ) ; port ( out1 : out s t d l o g i c v e c t o r ( ( width −1)downto 0 ) : = ( others=> ’ 0 ’ ) ; cq : out s t d l o g i c ; c l k : in s t d l o g i c ) ; end component ; component c 3 a i s generic ( cwidth : i n t e g e r ; c v a l u e : i n t e g e r ; w1 : i n t e g e r ; w2 : i n t e g e r ; w3 : i n t e g e r ) ; port ( i n 1 : in s t d l o g i c v e c t o r ( ( w1−1)downto 0 ) ; i n 2 : in s t d l o g i c v e c t o r ( ( w2−1)downto 0 ) ; i n 3 : in s t d l o g i c v e c t o r ( ( w3−1)downto 0 ) ; q : out s t d l o g i c v e c t o r ( ( w1+w2+w3−1)downto 0 ) ; c1 : in s t d l o g i c ; c2 : in s t d l o g i c ; c3 : in s t d l o g i c ; cq : out s t d l o g i c ; c l k : in s t d l o g i c ) ; end component ; component i t e r a t e i s generic ( p1 : i n t e g e r ) ; port ( f e e d b a c k : in s t d l o g i c v e c t o r ( ( p1 −1)downto 0 ) ; f i r s t v a l u e : in s t d l o g i c v e c t o r ( ( p1 −1)downto 0 ) ; q : out s t d l o g i c v e c t o r ( ( p1 −1)downto 0 ) ; c f e e d b a c k : in s t d l o g i c ; c f i r s t v a l u e : in s t d l o g i c ; cq : out s t d l o g i c ; c l k : in s t d l o g i c ) ; end component ; s i g n a l c o n s t 0 l 7 : STD LOGIC VECTOR ((32 −1)downto 0 ) ; signal c c o n s t 0 l 7 : s t d l o g i c ; s i g n a l C oe : STD LOGIC VECTOR ((32+32+32 −1)downto 0 ) ; s i g n a l cC oe : s t d l o g i c ; s i g n a l i t e r a t e o d : STD LOGIC VECTOR ((96 −1)downto 0 ) ; signal c i t e r a t e o d : s t d l o g i c ; −− t o v a b b i s i g n a l −ok begin const 0 l7 o : const source generic map ( 3 2 , 0 ) port map( c o n s t 0 l 7 , c c o n s t 0 l 7 , c l k ) ; C oe o : c 3 a generic map ( 0 , 0 , 3 2 , 3 2 , 3 2 ) port map( c o n s t 0 l 7 , c o n s t 0 l 8 , c o n s t 0 l 9 , C oe , c c o n s t 0 l 7 , c c o n s t 0 l 8 , c c o n s t 0 l 9 , cC iterate od o : iterate generic map ( 9 6 ) port map( C ou , C oe , i t e r a t e o d , cC ou , cC oe , c i t e r a t e o d , c l k ) ; −− t o v a b b i p e l d a n y o s i t a s o k Output <= C ou ; cOutput <= cC ou ; end B e h a v i o r a l ;
4.9. ´ abra. A gener´alt VHDL k´od (r´eszlet)
68
4.1.2. Szimul´ aci´ o Az elk´esz¨ ult VHDL le´ır´ ast a Xilinx ISE 11.5 verzi´oj´ u programj´aval teszteltem, ´es ugyanezen programcsomag ISim alkalmaz´ as´ aval szimul´altam. A szimul´ al´ ast a Ph.D ´ertekez´es szerinti bemenettel v´egeztem, azaz a bemeneti jel a hls Project Status (05/30/2011 - 00:56:35)
0 ´ert´ekr˝ olProject alland´ ´ osult hls.ise 8 -ra v´ altozik, ezImplementation az ugr´asState: a 4.11. ´aPlaced br´an bemutatott id˝odiagramon File: and Routed Module Name: benchmark No Errors 50 ns id˝ opillanatban k¨ ovetkezik be. A PIDErrors: szab´alyz´o a cin_1_a0 bemenet felfut´o ´el´ere Target Device:
xc3s500e-4fg320
Warnings:
223 Warnings (0 new)
mintav´etelez, 16 cikluson kereszt¨ ul t¨ort´eRouting nik. Az outputAll ySignals jele szolg´ altatja a kimenetet, Productami Version: ISE 11.5 Results: Completely Routed Goal: Timing Constraints: a 16 ciklusDesign lefut´ asa ut´ aBalanced n ez 7 -n´el ´alland´osul. Design Strategy:
Xilinx Default (unlocked)
All Constraints Met
Final Timing Score:
0 (Setup: 0, Hold: 0) (Timing Report)
Device Utilization Summary Logic Utilization
Used
[-]
Available
Utilization
Note(s)
Number of Slice Flip Flops
194
9,312
2%
Number of 4 input LUTs
773
9,312
8%
Number of occupied Slices
430
4,656
9%
430
430
100%
0
430
0%
815
9,312
8%
232
56%
Number of Slices containing only related logic Number of Slices containing unrelated logic Total Number of 4 input LUTs Number used as logic
773
Number used as a route-thru
42
Number of bonded IOBs
131
1 szint´ 4.10. ´ abra. Az FPGA ezis 24 eredm´enye
Number of BUFGMUXs Number of MULT18X18SIOs
6
Average Fanout of Non-Clock Nets
20
4% 30%
2.27
0 ps
100,000 ps 200,000 ps Performance Summary
300,000 ps
400,000 ps
500,000 ps [+]
restart clk Detailed Reports
0
in_1_a0[31:0]
[+]
8
cin_1_a0 output[95:0]
Secondary Reports
4
7
6
[+]
e
U
8
5
4
3
esum
U
y
U
8 Date 12 Generated: 19 25 05/30/2011 30 35- 01:02:24 39 43 4 1 2 3 4
46
49
2
52
55
58
60
5
62
64
6
7
coutput 10000 ps
clk_period datas add_oa[31:0]
X
0
3
2
3
add_ot[31:0]
X
0
8
12
19
4
5
5
6
5
35
39
43
46
add_oz[31:0]
X
0
5
1
3
4
5
5
6
5
quot8_o4_ie[31:0]
X
0
1
1
quot8_o9_iv[31:0]
X
0
4
1
2
3
4
4
2
3
4
4
select_ol[31:0] (e)
U
0
8
4
7
6
select_on[31:0] (esum)
U
0
8
12
19
25
select_op[31:0] (y)
U
0
4
1
2
sub_ok[31:0]
X
0
8
-4
3
-1
sub_or[31:0]
X
0
8
4
7
6
25
30
5
5
58
35
39
-1
60
43
46
8
6
7
8
6
49
-1
4
7
52
2 55
58
0 2
1
cquot8_o9_iv coutput - cc_ou
coutput citerate_od
4.11. ´ abra. A szimul´aci´o eredm´enye
69
-1 1
csub_or
cquot8_o9_iv - cadd_oz - cmul cquot8_o9_iv - cadd_oz - cmul_ox - cadd_ow
64 7
-1
csub_or - cadd_ot - cmul_oc csub_or - cadd_ot - cmul_oc - cadd_oa - cmul_of - cquot8_o4_ie - cquot8_o4_ib
cmul_oi
62
6 0
3
60
cin_1_a0
cmul_oi - csub_ok - cquot8_ cmul_oi - csub_ok - cquot8_o4_ih
65
7
controls
coutput - cc_ou
64
6
5 0
8 62
3
4 0
55
4
3 -1
7
52
5
5 30
6 49
4.2. MP3 dek´ odol´ o algoritmus M´asodik tesztesetk´ent az MP3 dek´ odol´ o algoritmus egy r´eszlet´et v´alasztottam, hogy ezzel is megvil´ag´ıtsam a m´ odszer gyakorlati haszn´alhat´os´ag´at. Fontos c´el volt, hogy a teszteset a t¨obbsebess´eg˝ u kiterjeszt´es funkci´ oit haszn´alja, az el˝obbiekben bemutatott Pid algoritmus ugyanis egysebess´eg˝ u adatfolyamgr´ afot ad, ´ıgy a modell kiterjeszt´es´enek vizsg´alata nem v´egezhet˝o el seg´ıts´eg´evel. A v´alasztott MP3 algoritmusr´eszlet r´eszlet a dek´odol´as v´egfokozat´aban tal´alhat´o Synthesis Filter Bank nevet visel˝ o modul, amely a frekvenciatartom´anyban k´odolt jelsorozatb´ol el˝o´all´ıtja az id˝ otartom´ anybeli alakot, azaz a mintav´etelezet hanghull´amot. Az MP3 dek´ odol´ o algoritmusnak l´etezik Haskell forr´ask´od´ u v´altozata [8], ez viszont a Synthesis Filter Bank-et k¨ uls˝ o C nyelv˝ u modulk´ent tartalmazza (PC-n futtatva ´ıgy gyorsabb k´odot kaptak). A C k´ odot ´ at´ırtam Haskell-re, ´ıgy a modul tesztelhet˝ov´e v´alt k¨ozvetlen¨ ul az mp3 dek´ odol´ o rendszerben. Lebeg˝opontr´ ol ´ att´ertem fixpontos ´ abr´azol´asra, ´es az ´ıgy m´odos´ıtott algoritmust a teljes mp3 dek´odol´ asba beillesztve teszteltem a dek´odol´o funkcionalit´as´at. 7 bites pontoss´agn´al a zajos hanghat´ ast tapasztaltam, de 10 bitn´el m´ar nem volt hallhat´o, ´ıgy r´ahagy´assal a v´alaszt´asom 32 bites sz´ am´ abr´ azol´ asra, ´es ezen bel¨ ul 16 bites t¨ort´abr´azol´asra esett. Az ´ıgy m´odos´ıtott Synthesis Filter Bank algoritmust a 4.12. ´abr´an l´athat´o k´odr´eszlettel ´ırtam le. Az algoritmus n´egy f¨ uggv´enyb˝ ol ´ all: uconv , usum , ssum ´es synthH1 . Az usum nagyban hasonl´ıt a ssum -ra, ´ıgy modulszint˝ u tesztel´esn´el csak az ut´obbival foglalkozom. A synthH1 f¨ uggv´eny a tulajdonk´eppeni Synthesis Filter Bank algoritmus, ez haszn´alja seg´edf¨ uggv´enyk´ent a t¨obbi f¨ uggv´enyt. Az uconv modul forr´ ask´ odja ´es az abb´ol gener´alt EOG a 4.13-as ´abr´an, az ssum a 4.14-es ´abr´an, a synthH1 pedig a 4.14-es ´es 4.15-¨os ´abr´an l´athat´o. A VHDL szimul´aci´os eredm´enyeit a 4.21. fejezet hull´ amforma ´abr´aival foglalom o¨ssze. A szimul´aci´ob´ol j´ol l´athat´o, hogy a kimeneti eredm´enyek megegyeznek a Haskell futtat´as sor´an kapott list´akkal:
ssum: [(10416,5),(26288,6),(42160,7),(58032,8),(73904,9), (89776,10),(105648,11),(121520,12),(137392,13), (153264,14),(169136,15),(185008,16),(200880,17) .. uconv: [(157470,287),(176928,288),(237534,351),(261280,352) ..
70
{−# LANGUAGE N o I m p l i c i t P r e l u d e #−} module MP3( hwmain ) where import I n s t r u c t i o n S e t import SFBConstants infixr 0 $ ( $ ) : : ( a −> b ) −> a −> b f $ x = f x hwmain x = synthH1 i n p u t A r r a y ( s t a t e A r r a y , [ ] ) x uconv n e w s t a t e s t a r t k = l e t ( i , j ) = divMod64 k c o n v 1 i = i f ( j <32) then ( i ∗128 + j ) e l s e ( i ∗128 + ( j −32) + 9 6 ) conv1 = n e w s t a t e ! ( mod1024 ( c o n v 1 i+s t a r t ) ) conv2 = synthArray ! k in ( conv1 ‘ imul ‘ conv2 , k ) usum : : I n t A r r a y −> [ I n t ] usum uL = map sumn [ 0 . . 3 1 ] where sumn i = sum $ map ( f u n c i ) [ 0 . . 1 5 ] f u n c i j = uL ! ( j ∗32 + i ) ssum : : I n t −> I n t A r r a y −> [ ( I n t , I n t ) ] ssum s t a r t sL = map ( \ i −> ( sumn i , i+s t a r t ) ) [ 0 . . 6 3 ] where sumn i = sum $ map ( f u n c i ) [ 0 . . 3 1 ] f u n c i j = ( ( sL ! j ) ∗ ( lookupArray ! ( i ∗ ( 3 2 : : I n t ) + j ) ) ) synthH1 : : I n t A r r a y −> ( IntArray , [ I n t ] ) −> I n t −> ( IntArray , [ I n t ] ) synthH1 i n p u t ( s t a t e , ) s = l e t sL = map ( \ i −> ( i n p u t ! ( i ∗18 + s ) , i+s t a r t ) ) [ 0 . . 3 1 ] s2L = s l A r r a y // sL s t a r t = mod1024 (2048 −( s +1)∗64) n e w s t a t e = s t a t e // ( ssum s t a r t s2L ) uL = map ( uconv n e w s t a t e ( s t a r t ) [ 0 . . 5 1 1 ] u2L = u l A r r a y // uL in ( newstate , usum u2L )
4.12. ´ abra. MP3 Synthesis Filter Bank
71
hwmain ( s t a r t , k ) = uconv s t a t e A r r a y s t a r t k uconv n e w s t a t e s t a r t k = l e t ( i , j ) = divMod64 k c o n v 1 i = i f ( j <32) then ( i ∗128 + j ) e l s e ( i ∗128 + ( j −32) + 9 6 ) conv1 = n e w s t a t e ! ( mod1024 ( c o n v 1 i+s t a r t ) ) conv2 = synthArray ! k in ( conv1 ‘ imul ‘ conv2 , k )
IN_1_a0 IN<0,64>
synthArray_r0 SynthArray<0,32>
select_o14 Select<0,64,32,32>
divMod64_o18 DivMod64<0,32>
select_o2e Select<0,64,0,32>
const_128_lu Const<0,32,128>
select_o1k Select<0,64,32,32>
mul_o28 Mul<0,32>
const_32_lm Const<0,32,32>
const_32_ld Const<0,32,32>
add_o26 Add<0,32>
lt_o1y Lt<0,32>
select_o1Q Select<0,64,0,32>
sub_o1Y Sub<0,32>
const_96_ln Const<0,32,96>
ifcon_o24 Ifcon<0,32,1>
nth_o2m Nth<0,32>
const_128_lj Const<0,32,128>
mul_o1K Mul<0,32>
add_o1I Add<0,32>
add_o1G Add<0,32>
buf1 Buf<0,32>
ifcon_o1E Ifcon<0,32,0>
select_o10 Select<0,64,0,32>
buf2 Buf<0,32>
mux_o1C Mux<0,32>
add_o1u Add<0,32>
stateArray_r0 StateArray<0,32>
mod1024_o1s Mod1024<0,32>
nth_o1q Nth<0,32>
mul_o1o Mul<0,32>
C_o1m C2<0,0,0,32,32>
OUT1 OUT<0,64>
4.13. ´ abra. Az uconv modul forr´ask´odja ´es az abb´ol gener´alt EOG
72
hwmain x = ssum x s l A r r a y ssum : : I n t −> I n t A r r a y −> [ ( I n t , I n t ) ] ssum s t a r t sL = map ( \ i −> ( sumn i , i+s t a r t ) ) [ 0 . . 6 3 ] where sumn i = sum $ map ( f u n c i ) [ 0 . . 3 1 ] f u n c i j = ( ( sL ! j ) ∗ ( lookupArray ! ( i ∗ ( 3 2 : : I n t ) + j ) ) )
IN_1_a0 IN<0,32>
const_0_lf Constt<0,32,0>
const_32_lh Const<1,32,32>
mul_oA Mul<1,32>
const_63_lg Constt<0,32,63>
enumFromTo_oa EnumFromTo<1,32,64,70>
const_0_l8 Constt<1,32,0>
const_31_l9 Constt<1,32,31>
levelAdapter2 LevelAdapter<1,32>
enumFromTo_om EnumFromTo<2,32,32,2>
add_oE Add<1,32>
levelAdapter1 LevelAdapter<2,32>
slArray_r0 SlArray<0,32>
add_oy Add<2,32>
lookupArray_r0 LookupArray<0,32>
nth_ou Nth<2,32>
nth_ow Nth<2,32>
mul_os Mul<2,32>
sum_oi Sum<2,32,64>
C_og C2<1,0,0,32,32>
OUT1 OUT<1,64>
4.14. ´ abra. Az ssum modul forr´ask´odja ´es az abb´ol gener´alt EOG
hwmain x = sum $ synthH1 i n p u t A r r a y ( s t a t e A r r a y , [ ] ) x synthH1 : : I n t A r r a y −> ( IntArray , [ I n t ] ) −> I n t −> [ I n t ] synthH1 i n p u t ( s t a t e , ) s = l e t sL = map ( \ i −> ( i n p u t ! ( i ∗18 + s ) , i+s t a r t ) ) [ 0 . . 3 1 ] s2L = s l A r r a y // sL s t a r t = mod1024 (2048 −( s +1)∗64) n e w s t a t e = s t a t e // ( ssum s t a r t s2L ) for512 = [ 0 . . 5 1 1 ] uL = map ( uconv n e w s t a t e ( s t a r t ) ) [ 0 . . 5 1 1 ] u2L = u l A r r a y // uL in usum u2L
4.15. ´ abra. Sfb algoritmus Haskell forr´ask´odja
73
74
ulArray_r0 UlArray<0,32>
synthArray_r0 SynthArray<0,32>
nth_o2S Nth<1,32>
const_128_l15 Const<1,32,128>
sub_o2u Sub<1,32>
mul_o2g Mul<1,32>
add_o2e Add<1,32>
const_32_l18 Const<1,32,32>
select_o2m Select<1,64,0,32>
add_o2c Add<1,32>
const_96_l19 Const<1,32,96>
ifcon_o2a Ifcon<1,32,0>
lt_o24 Lt<1,32>
mux_o28 Mux<1,32>
ifcon_o2AA Ifcon<1,32,1>
nth_oQ Nth<1,32>
add_oS Add<1,32>
wr_oE Wr<1,32,32>
C_oO C2<1,0,0,32,32>
add_oY Add<1,32>
mul_oU Mul<1,32>
const_18_lo Const<1,32,18>
const_31_ln Constt<0,32,31>
enumFromTo_oI EnumFromTo<1,32,6,4>
const_0_lm Constt<0,32,0>
const_0_lB Constt<1,32,0>
nth_o1m Nth<2,32>
const_31_lC Constt<1,32,31>
const_32_l1u Const<2,32,32>
const_0_l1s Constt<1,32,0>
const_15_l1t Constt<1,32,15>
enumFromTo_o36 EnumFromTo<2,32,6,4>
enumFromTo_o2W EnumFromTo<1,32,6,4>
OUT1 OUT<0,32>
sum_o4 Sum<1,32,33>
sum_o32 Sum<2,32,33>
nth_o3c Nth<2,32>
add_o3e Add<2,32>
wr_oA Wr<1,32,32>
C_o18 C2<1,0,0,32,32>
sum_o1a Sum<1,32,33>
imul_o1k Imul<2,32>
nth_o1o Nth<2,32>
add_o1q Add<2,32>
add_o1w Add<1,32>
enumFromTo_o12 EnumFromTo<1,32,6,4>
enumFromTo_o1e EnumFromTo<2,32,6,4>
mul_o1s Mul<1,32>
const_32_lK Const<1,32,32>
const_63_lJ Constt<0,32,63>
const_31_l1x Constt<0,32,31>
wr_oo Wr<1,32,32>
stateArray_r0 StateArray<0,32>
inputArray_r0 InputArray<0,32>
const_0_lI Constt<0,32,0>
const_0_l1w Constt<0,32,0>
mul_o3g Mul<2,32>
4.16. ´ abra. sfb modul EOG
lookupArray_r0 LookupArray<0,32>
slArray_r0 SlArray<0,32>
mod1024_o8 Mod1024<0,32>
sub_oa Sub<0,32>
const_2048_lu Const<0,32,2048>
const_64_lz Const<0,32,64>
IN_1_a0 IN<0,32>
C_o1S C2<1,0,0,32,32>
imul_o1U Imul<1,32>
nth_o1W Nth<1,32>
mod1024_o1Y Mod1024<1,32>
add_o20 Add<1,32>
mul_o2E Mul<1,32>
add_o2CC Add<1,32>
mul_oe Mul<0,32>
const_128_l1g Const<1,32,128>
const_511_lY Constt<0,32,511>
select_o2K Select<1,64,0,32>
const_32_lZ Const<1,32,32>
select_o1Q Select<1,64,32,32>
divMod64_o1E DivMod64<1,32>
enumFromTo_os EnumFromTo<1,32,6,4>
const_0_lX Constt<0,32,0>
add_og Add<0,32>
const_1_ly Const<0,32,1>
4.2.1. VHDL szimul´ aci´ os eredm´ enyek : 0 us
2 us
4 us
6 us
8 us
4.17. ´ abra. Ssum modul szimul´aci´os hull´amform´aja 10 us nagys´ag´u intervallumban 700 ns
800 ns
900 ns
1,000 ns
1,100 ns
1,200 ns
4.18. ´ abra. Ssum modul szimul´aci´os hull´amform´aja 600 ns nagys´ag´u intervallumban
0 ns
100 ns
200 ns
300 ns
400 ns
4.19. ´ abra. Az uconv modul szimul´aci´os hull´amform´aja
75
500 ns
5. fejezet
Tov´ abbfejleszt´ esi lehet˝ os´ egek Az elk´esz¨ ult program k´epes leford´ıtani a defini´alt m˝ uvelethalmaznak megfelel˝o, le´ırt megk¨ot´esekkel rendelkez˝ o Haskell k´ odot. A m´odszer ´es a fejlesztett program sz´amtalan tov´abbfejleszt´esi lehet˝ os´eg el´e n´ez, amelyekb˝ ol n´eh´anyat a most kezd˝od˝o fejezetben ismertetek.
5.1. Optimaliz´ al´ asi l´ ep´ esek A ford´ıt´orendszer t´ amogatja optimaliz´ aci´os programok integr´al´as´at. Az IIT Tansz´eken fejlesztett PIPE optimaliz´ aci´ os tervez˝ orendszer EOG bemenetet v´ar, ´ıgy az ´altalam fejlesztett ford´ıt´oprogram Haskell-EOG ´es EOG-VHDL moduljai k¨oz´e be´ekelhet˝o lenne. Adott esetben az algoritmust EOG szinten optimaliz´alni tudjuk azzal a c´ellal, hogy pipeline m˝ uk¨ od´es sor´ an nagyobb ´ atereszt˝ok´epess´eget, vagyis az u ´jraind´ıt´asi id˝o cs¨okken´es´et ´erj¨ unk el. Ennek a gyakorlati haszna akkor szembet˝ un˝o, ha az EOG-vel meghat´arozott m˝ uveletsort egym´ as ut´ an sok adaton kell elv´egezn¨ unk, ekkor ugyanis a pipeline m˝ uk¨od´es hatalmas hat´ekonys´ agbeli n¨ oveked´est jelenthet. A PIPE rendszer az u ´jraind´ıt´ asi id˝ ot k´epes reduk´alni, a m˝ uveletek bemeneti csatorn´ait szinkroniz´alja, a feladat v´egrehajt´ o egys´egek t´ıpus´anak ´es sz´am´anak ismeret´eben biztos´ıtja az allok´aci´ot, majd meghat´ arozza az egyes m˝ uveletek kezd´esi idej´et.
5.2. Egyebek • A bemenetk´ent haszn´ alhat´ o Haskell k´odban jelenleg nem szerepelhet f¨ uggv´enyrekurzi´o, ´es ezzel algoritmusle´ır´ asok egy r´esz´et kiz´arjuk a ford´ıthat´o k´odok k¨oz¨ ul. Megold´as lehet pl., ha el˝ ore meghat´ arozott maxim´alis sz´am´ u rekurz´ıv h´ıv´ast megenged¨ unk, mert ´ıgy a hardveres megval´ os´ıt´ as realiz´alhat´ov´a v´alna. A rekurzi´o kezel´es´eben ezen k´ıv¨ ul is sok nyitott k´erd´es rejt˝ ozik, ´ıgy a j¨ov˝oben ´erdemes lehet ezzel behat´oan foglalkozni. • Egy ´erdekes ´es id˝ oszeri kutat´ asi t´ema lehet az LLVM [25] alapj´an t¨ort´en˝o automatikus HDL gener´ al´ as, erre a k¨ oztes reprezent´aci´ora ugyanis egyre t¨obb nyelvr˝ol lehet ford´ıtani, t¨ obbek k¨ oz¨ ott l´etezik egy Haskell-LLVM frontend is. • A kimeneti VHDL le´ır´ as egyszer˝ us´ıt´es´en ´erdemes lehet m´eg dolgozni. Jelenleg minden 76
EOG m˝ uvelet modulp´eld´ anyos´ıt´asra fordul, ´ıgy pl. a VHDL-ben egyszer˝ uen ´abr´azolhat´ o konstansok is, amik emiatt nagyobb ´es ´atl´athat´os´ag szempontj´ab´ol rosszabb kimeneti f´ ajlt eredm´enyeznek. • VHDL-r˝ ol a szint´ezerek ´ altal´aban EDIF (Electronic Design Interchange Format) form´ atumra ford´ıtanak, ´ıgy vizsg´alat t´argy´at k´epezheti az is, hogy a ford´ıt´o kimenete esetleg a VHDL-t˝ ol alacsonyabb szint˝ u, FPGA k¨ozeli k´odot jelentsen. • Elk´epzelhet˝ o lenne a list´ ak olyan kezel´ese, hogy a lista elmein v´egrehajtand´o m˝ uveleteket el˝ ore megadott n sz´am´ u feldolgoz´oegys´eg p´arhuzamosan v´egezze, ´ıgy a sebess´eg ´es az er˝ oforr´ ashaszn´alat k¨oz¨ott az n ´ert´ek´enek finomhangol´as´aval tudn´ank szab´ alyozni a szint´ezist. • Tervezem egy MicroBlaze l´agymagos processzor alap´ u tesztrendszer elk´esz´ıt´es´et, amellyel a ford´ıt´ oprogram kimenetek´ent l´etrej¨ott VHDL k´od val´odi FPGA-s k¨ ornyezetben is egyszer˝ uen, ak´ar automatikusan tesztelhet˝o lenne.
77
6. fejezet
¨ Osszefoglal´ as Dolgozatom sor´ an egy olyan m´ odszer alapelveit ´es megval´os´ıt´as´at dolgoztam ki, amely a Haskell nyelven bizonyos megk¨ ot´esekkel le´ırt algoritmusokat VHDL le´ır´ass´a alak´ıtja. Az elj´ar´as minden l´ep´es´ere (modulj´ ara) kidolgoztam algoritmusokat ´es azokat PC-n fut´o ford´ıt´oprogramk´ent implement´ altam is. A kidolgozand´ o m´ odszer ´es ford´ıt´ oprogram el´e a k¨ovetkez˝o k¨ovetelm´enyeket t´amasztottam:
1. a Haskell forr´ ask´ od ´es VHDL le´ır´as k¨oz¨otti ford´ıt´as legyen teljesen automatikus 2. ford´ıt´as sor´ an a felhaszn´ al´ o kapjon hiba¨ uzenetet, ha a forr´ask´od szintaxisa nem megfelel˝o, vagy ha egy Haskell kifejez´es a megk¨ot´esek miatt nem haszn´alhat´o 3. a program modul´ aris fel´ep´ıt´es˝ u legyen, hogy az egyes r´eszek a j¨ov˝oben minden tov´abbi n´elk¨ ul u ´jrahaszn´ alhat´ oak legyenek 4. a j¨ov˝oben k¨ onnyen, teh´ at a f˝ obb modulok legfeljebb minim´alis m´odos´ıt´asa ut´an implement´ alhat´ oak legyenek optimaliz´aci´os algoritmusok 5. a forr´ask´ od megk¨ ot´eseit ne kelljen teljes eg´esz´eben a fejleszt´esi peri´odus elej´en meghat´arozni, vagyis a haszn´ alhat´ o Haskell kifejez´esek lehet˝oleg a ford´ıt´oprogram ut´olagos fejleszt´ese n´elk¨ ul, dinamikusan b˝ ov´ıthet˝oek legyenek Az 1. ´es 3. k¨ ovetelm´eny a kidolgozott m´odszer ´es az ennek alapj´an elk´esz¨ ult modul´aris fel´ep´ıt´es˝ u ford´ıt´ oprogram eredm´enyek´ent teljes¨ ul. A szintaktikai hib´akat a m´odszerbe be´ep´ıtett GHC frontend jelzi, ´ıgy a felhaszn´al´o azonnal ´ertes¨ ul a forr´ask´odi el´ır´asokr´ol vagy a hib´as k´ odol´ asr´ ol. Amennyiben a szintaktikailag helyes forr´ask´odban olyan f¨ uggv´enyt haszn´alunk, ami a ford´ıt´ oprogram aktu´alis m˝ uvelethalmaz´aban nincs benne, szint´en hibajelz´est kapunk, ezzel teh´ at a 2. k¨ ovetelm´eny szint´en teljes¨ ul. K¨oztes reprezent´aci´ok´ent EOG-t haszn´ alok, ez´ altal optimaliz´ aci´ os algoritmusok be´ep´ıt´es´et a m´odszer messzemen˝oen t´amogatja, ezzel teljes¨ ul a 4. k¨ ovetelm´eny. Az 5. k¨ovetelm´eny a m˝ uvelethalmaz fogalm´anak bevezet´es´evel teljes¨ ul. A rendszert modul´ aris elven ´ep´ıtettem fel, hogy az egyes r´eszek k¨ ul¨on-k¨ ul¨on is min´el ´altal´anosabban felhaszn´ alhat´ oak legyenek. A nyelvi vagy technol´ogiai peremfelt´etelek m´odos´ıt´asa eset´en csak az elj´ ar´ as egy-egy r´esz´et, az annak megfelel˝o modult kell m´odos´ıtanunk. 78
Amennyiben Haskell forr´ asnyelv helyett m´as funkcion´alis nyelvb˝ol szeretn´enk kiindulni, akkor a GHC fokozat helyett egy arra specializ´alt ford´ıt´oprogramot kell k´esz´ıten¨ unk, ami a GHC Core nyelv˝ u k¨ oztes le´ır´ ast gener´alja. Ebb˝ol a le´ır´asb´ol az ´altalam elk´esz´ıtett rendszer k´epes VHDL-t gener´ alni. FPGA helyett ASIC integr´alt ´aramk¨or¨ok gy´art´as´ara is van lehet˝os´eg, a kimenetk´ent kapott VHDL ugyanis ASIC gy´art´as alapja lehet. A rendszer alkalmas optimaliz´ al´o fokozat be´ep´ıt´es´ere, ´ıgy pl. az IIT Tansz´eken fejlesztett PIPE optimaliz´ al´ o rendszert a ford´ıt´as r´esz´ev´e lehet tenni, ´ıgy pipeline algoritmusok eset´en a hardver hat´ekonys´ aga nagym´ert´ekben javulhat. A rendszer rugalmass´ ag´ at nagyban n¨oveli, hogy a m˝ uvelethalmaz dinamikusan b˝ov´ıthet˝o a ford´ıt´ oprogram fejleszt´ese n´elk¨ ul is. A b˝ov´ıt´eshez csup´an arra van sz¨ uks´eg, hogy egy adott Haskell f¨ uggv´enyhez l´etrehozzunk egy VHDL modult, ´es a m˝ uvelethalmaz megfelel˝o f´ajljaiban ezt a f¨ uggv´enyt regisztr´aljuk. Egy meg´ep´ıtett mp3 lej´atsz´o VHDL modulj´ at import´ alva pl. egyetlen haskell f¨ uggv´enyh´ıv´assal ak´ar egy mp3 lej´atsz´as is ind´ıthat´o. A rendszer t´ amogatja a hierarchikus tervez´est, teh´at a magasszint˝ u nyelven k´odol´o felhaszn´al´ o (pl. matematikus vagy informatikus) ´es a hardvertervez˝o egym´ast´ol f¨ uggetlen¨ ul dolgozhat az adott probl´em´ an. A matematikus le´ırja a szoftvert, ´es amennyiben nem haszn´al egyedi f¨ uggv´enyt, a k´ odja automatikusan ford´ıthat´o hardverre. Ha az algoritmus´ahoz k¨ ul¨onleges hardverre lenne sz¨ uks´egel (pl. optimaliz´aci´o miatt), akkor a hardvertervez˝o ezzel p´arhuzamosan meg´ırhatja a sz¨ uks´eges VHDL modult, ´es ennek v´egezt´evel a matematikus ´altal le´ırt f¨ uggv´eny ezt a k´ odot fogja p´eld´anyos´ıtani. A m´ odszert kiterjesztettem t¨obbsebess´eg˝ u adatfolyamok eset´ere. Ennek keret´eben kidolgoztam az EOG modell t¨ obbsebess´eg˝ u v´altozat´at, amire az MREOG nevet vezettem be. Algoritmust adtam az u ´jraind´ıt´asi- ´es lappang´asi id˝ok kisz´am´ıt´as´ara, hogy azok az u ´j modellben is meghat´ arozhat´ oak legyenek. Egy PID szab´ alyz´ o algoritmuson ´es az MP3 dek´odol´o algoritmus r´eszlet´en kereszt¨ ul bemutattam a ford´ıt´ as l´ep´eseit ´es a l´ep´esek k¨oz¨otti k¨oztes reprezent´aci´okat, a ford´ıt´ oi cs˝ovezet´ek v´eg´en megkapott VHDL k´odot pedig a Xilinx ISE FPGA fejleszt˝orendszerrel szimul´ altam.
79
Irodalomjegyz´ ek [1] http://www.mentor.com/esl/catapult/overview. [2] http://www.impulseaccelerated.com/. [3] http://www.c-to-verilog.com/index.html. [4] http://www.comlab.ox.ac.uk/geraint.jones/ruby/. [5] http://haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/ Prelude.html. [6] http://www.haskell.org/haskellwiki/Performance/GHC. [7] http://www.haskell.org/. [8] http://blog.bjrn.se/2008/10/lets-build-mp3-decoder.html. [9] Vhdl tutorial. http://www.seas.upenn.edu/~ese171/vhdl/vhdl_primer.html. [10] Peter Arato, Visegrady Tamas, and Istvan Jankovits. High Level Synthesis of Pipelined Datapaths. John Wiley & Sons, Inc., New York, NY, USA, 2001. [11] Zena M. Ariola and Matthias Felleisen. The call-by-need lambda calculus. J. Funct. Program., 7:265–301, May 1997. [12] C. P. R. Baaij. Cλash: From haskell to hardware. Master’s thesis, Univ. of Twente, December 2009. [13] Henk Barendregt and Erik Barendsen. Introduction to lambda calculus. 1994. [14] Cs´ak Bence. K¨ ozvetlen hardver gener´al´as magasszint˝ u nyelvi le´ır´asb´ol - phd ´ertekez´es, 2009. [15] Lauwereins R. Peperstraete J.A. Bilsen G., Engels M. Static scheduling of multi-rate and cyclo-static dsp-applications. VLSI Signal Processing, VII, 1994., 1994. [16] Per Bjesse, Koen Claessen, Mary Sheeran, and Satnam Singh. Lava: hardware design in haskell. SIGPLAN Not., 34:174–184, September 1998. [17] Joseph Buck and Edward A. Lee. The token flow model, 1992. 80
[18] Duncan Coutts, Roman Leshchinskiy, and Don Stewart. Stream fusion: From lists to streams to nothing at all. In Proceedings of the ACM SIGPLAN International Conference on Functional Programming, ICFP 2007, Apr 2007. [19] Simon Frankau. Hardware synthesis from a stream-processing functional language, 2004. [20] Shaori Guo and Wayne Luk. Compiling ruby into fpgas. In Proceedings of the 5th International Workshop on Field-Programmable Logic and Applications, FPL ’95, pages 188–197, London, UK, 1995. Springer-Verlag. [21] C. A. R. Hoare. Communicating sequential processes. Commun. ACM, 21:666–677, August 1978. [22] P. Z. Ingerman. Thunks: a way of compiling procedure statements with some comments on procedure declarations. Commun. ACM, 4:55–58, January 1961. [23] ISO/IEC. Ieee 1076-2008: Ieee standard vhdl language reference manual. Technical report, Institute of Electrical and Electronics Engineers, Computer Society, 26. January 2009. [24] M. Kooijman. Haskell as a higher order structural hardware description language, December 2009. [25] Chris Lattner. LLVM: An Infrastructure for Multi-Stage Optimization. Master’s thesis, Computer Science Dept., University of Illinois at Urbana-Champaign, Urbana, IL, Dec 2002. See http://llvm.cs.uiuc.edu. [26] E.A. Lee and D.G. Messerschmitt. Synchronous data flow. Proceedings of the IEEE, 75(9):1235–1245, Sept. 1987. [27] Edward Ashford Lee and David G. Messerschmitt. Static scheduling of synchronous data flow programs for digital signal processing. IEEE Trans. Comput., 36:24–35, January 1987. [28] Simon Marlow. Haskell 2010 language report, 2010. [29] Neil Mitchell. Rethinking supercompilation. SIGPLAN Not., 45:309–320, September 2010. [30] Simon Peyton Jones et al. The Haskell 98 language and libraries: The revised report. Journal of Functional Programming, 13(1):0–255, Jan 2003. http://www.haskell. org/definition/. [31] Simon Peyton Jones and Simon Marlow. Secrets of the glasgow haskell compiler inliner. J. Funct. Program., 12:393–434, July 2002. [32] Mary Sheeran. ufp, an algebraic vlsi design language - phd thesis, 1983. 81
[33] S. Sriram and S.S. Bhattacharyya. Embedded multiprocessors: scheduling and synchronization. Signal processing and communications. CRC Press, 2009. [34] The GHC Team. The glorious glasgow haskell compilation system user’s guide, version 6.12.2. [35] Andrew Tolmach. An external representation for the ghc core language, 2001. [36] Valentin F. Turchin. The concept of a supercompiler. ACM Trans. Program. Lang. Syst., 8:292–325, June 1986.
82
Fu ek ¨ ggel´ F.1. Stream m˝ uveletek VHDL k´ odja
entity sum i s generic ( c l : i n t e g e r port ( i n 1 : in s t d q : out s t d c1 : in s t d cq : out s t d c l k : in s t d end sum ;
; width : i n t e g e r ; d e l a y : i n t e g e r ) ; l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; l o g i c v e c t o r ( c l downto 0 ) ; l o g i c v e c t o r ( ( c l − 1 ) downto 0 ) ; logic );
architecture B e h a v i o r a l of sum i s s i g n a l accum : s t d l o g i c v e c t o r ( ( width − 1 ) downto 0 ) := c o n v s t d l o g i c v e c t o r ( 0 , width ) ; s i g n a l dc : i n t e g e r := 0 ; s i g n a l c d e l a y : s t d l o g i c v e c t o r ( ( c l − 1 ) downto 0 ) ; begin process ( c l k ) begin i f ( r i s i n g e d g e ( c l k ) ) then i f ( c1 ( 1 ) = ’ 1 ’ ) then dc <= 0 ; c d e l a y <= c1 ( c l downto 1 ) ; else dc <= dc +1; end i f ; i f ( dc=d e l a y −1) then q <= accum ; cq <= c d e l a y ; else cq <= c o n v s t d l o g i c v e c t o r ( 0 , c l ) ; end i f ; i f ( c1 ( 1 ) = ’ 1 ’ ) then accum <= i n 1 ; e l s i f ( c1 ( 0 ) = ’ 1 ’ ) then accum <= accum+i n 1 ; end i f ; end i f ; end process ; end B e h a v i o r a l ;
F.1.1. ´ abra. Sum m˝uvelet VHDL modulja
83
entity enumfromto i s generic ( c l : i n t e g e r port ( i n 1 : in s t d i n 2 : in s t d q : out s t d c1 : in s t d c2 : in s t d cq : out s t d c l k : in s t d end enumfromto ;
; width : i n t e g e r ; r a t e : i n t e g e r ; d e l a y : i n t e g e r ) ; l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; l o g i c v e c t o r ( ( c l − 1 ) downto 0 ) ; l o g i c v e c t o r ( ( c l − 1 ) downto 0 ) ; l o g i c v e c t o r ( c l downto 0 ) ; logic );
architecture B e h a v i o r a l of enumfromto i s signal signal signal signal
dc : rc : cqh : qc :
i n t e g e r := 0 ; i n t e g e r := r a t e ; s t d l o g i c v e c t o r ( ( c l − 1 ) downto 0 ) ; s t d l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ;
begin cqh <= c1 and c2 ; q <= qc ; process ( c l k ) begin i f ( r i s i n g e d g e ( c l k ) ) then cq ( c l downto 1 ) <= cqh ; i f ( cqh ( 0 ) = ’ 1 ’ ) then dc <= 0 ; r c <= 0 ; cq ( 0 ) <= ’ 1 ’ ; qc <= i n 1 ; else i f ( dc>=d e l a y −1) then dc <= 0 ; i f ( r c=r a t e −1) then cq ( 0 ) <= ’ 0 ’ ; qc <= qc ; e l s i f ( rc>r a t e −1) then cq ( 0 ) <= ’ 0 ’ ; qc <= qc ; else cq ( 0 ) <= ’ 1 ’ ; qc <= qc +1; end i f ; r c <= r c +1; else dc <= dc +1; cq ( 0 ) <= ’ 0 ’ ; qc <= qc ; end i f ; end i f ; end i f ; end process ; end B e h a v i o r a l ;
F.1.2. ´ abra. EnumFromTo m˝uvelet VHDL modulja
84
F.2. T¨ omb m˝ uveletek VHDL k´ odja
entity nth i s generic ( c l : i n t e g e r ; width : i n t e g e r ) ; port ( blockram : inout s t d l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; i n 2 : in s t d l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; q : out s t d l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; oe : out s t d l o g i c ; c2 : in s t d l o g i c v e c t o r ( c l downto 0 ) ; cq : out s t d l o g i c v e c t o r ( c l downto 0 ) ; c l k : in s t d l o g i c ) ; end nth ; architecture B e h a v i o r a l of nth i s s i g n a l c b u f : s t d l o g i c v e c t o r ( c l downto 0 ) ; begin p r o c e s s 1 : process ( c l k ) begin i f ( f a l l i n g e d g e ( c l k ) ) then i f ( c2 ( 0 ) = ’ 1 ’ ) then oe <= ’ 0 ’ ; blockram <= i n 2 ; else oe <= ’ 1 ’ ; blockram <= ( others => ’ Z ’ ) ; −− r e g e x m i a t t TODO end i f ; end i f ; i f ( r i s i n g e d g e ( c l k ) ) then c b u f <= c2 ; cq <= c b u f ; i f ( c b u f ( 0 ) = ’ 1 ’ ) then q <= blockram ; end i f ; end i f ; end process ; end B e h a v i o r a l ;
F.2.1. ´ abra. Nth m˝uvelet VHDL modulja
85
entity s y n t h a r r a y i s generic ( c l : i n t e g e r ; width : i n t e g e r ) ; port ( q : inout s t d l o g i c v e c t o r ( ( width − 1 ) downto 0 ) ; oe : in s t d l o g i c ; c l k : in s t d l o g i c ) ; end s y n t h a r r a y ; architecture B e h a v i o r a l of s y n t h a r r a y i s s i g n a l temp : s t d l o g i c v e c t o r ( 3 downto 0 ) ; s i g n a l output : s t d l o g i c v e c t o r ( 3 1 downto 0 ) ; s i g n a l a d d r e s s : s t d l o g i c v e c t o r ( 3 1 downto 0 ) ; begin process ( oe , q ) −− output nem v o l t begin i f ( oe = ’ 0 ’ ) then q <= ”ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ” ; a d d r e s s <= q ; else q <= output ; a d d r e s s <= a d d r e s s ; end i f ; end process ; RAMB16 S36 inst : RAMB16 S36 generic map ( INIT => X ”000000000 ” , −− Value o f output RAM r e g i s t e r s a t s t a r t u p SRVAL => X ”000000000 ” , −− Ouput v a l u e upon SSR a s s e r t i o n WRITE MODE => ”WRITE FIRST ” , −− WRITE FIRST , READ FIRST o r NO CHANGE −− The f o l l o w i n g INIT xx d e c l a r a t i o n s s p e c i f y t h e i n i t i a l −− c o n t e n t s o f t h e RAM INIT 00 => INIT 01 => −− . . . −− t o v a b a i −− . . . INIT 3e => I N I T 3 f =>
X ”0000000 a00000009000000080000000700000006000000050000000400000003 ” , X ”0000001200000011000000100000000 f0000000e0000000d0000000c0000000b ” , kezdoertekek X ”000001 fa000001f9000001f8000001f7000001f6000001f5000001f4000001f3 ” , X ”000002020000020100000200000001 ff000001fe000001fd000001fc000001fb ” ,
port map ( DO => output , ADDR => a d d r e s s ( 8 downto 0 ) , CLK => c l k , DI => c o n v s t d l o g i c v e c t o r ( 0 , 3 2 ) , DIP => c o n v s t d l o g i c v e c t o r ( 0 , 4 ) , EN => ’ 1 ’ , SSR => ’ 0 ’ , WE => ’ 0 ’ );
−− −− −− −− −− −− −− −−
32− b i t Data Output 9− b i t Address Input Clock 32− b i t Data Input 4− b i t p a r i t y Input RAM Enable Input Synchronous S e t / Re s e t Input Write Enable Input
end B e h a v i o r a l ;
F.2.2. ´ abra. A block RAM egy lehets´eges VHDL k´odja (ListArray m˝uvelet)
86
F.3. Az Haskell nyelven implement´ alt szint´ ezis program ford´ıt´ oi napl´ oja GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Loading package array-0.3.0.2 ... linking ... done. Loading package containers-0.4.0.0 ... linking ... done. Loading package bytestring-0.9.1.10 ... linking ... done. Loading package Win32-2.2.0.1 ... linking ... done. Loading package filepath-1.2.0.0 ... linking ... done. Loading package old-locale-1.0.0.2 ... linking ... done. Loading package old-time-1.0.0.6 ... linking ... done. Loading package directory-1.1.0.0 ... linking ... done. Loading package pretty-1.0.1.2 ... linking ... done. Loading package process-1.0.1.5 ... linking ... done. Loading package Cabal-1.10.1.0 ... linking ... done. Loading package ghc-binary-0.5.0.2 ... linking ... done. Loading package bin-package-db-0.0.0.0 ... linking ... done. Loading package hpc-0.5.0.6 ... linking ... done. Loading package template-haskell ... linking ... done. Loading package ghc-7.0.3 ... linking ... done. Loading package ffi-1.0 ... linking ... done. [ 1 of 14] Compiling CoreVisiting ( CoreVisiting.hs, interpreted ) [ 2 of 14] Compiling DotOutput ( DotOutput.hs, interpreted ) [ 3 of 14] Compiling Typconv ( Typconv.hs, interpreted ) [ 4 of 14] Compiling CorePrint ( CorePrint.hs, interpreted ) [ 5 of 14] Compiling Common ( Common.hs, interpreted ) [ 6 of 14] Compiling SearchCoreNode ( SearchCoreNode.hs, interpreted) [ 7 of 14] Compiling VarRename ( VarRename.hs, interpreted ) [ 8 of 14] Compiling AppRename ( AppRename.hs, interpreted ) [ 9 of 14] Compiling MapConversion ( MapConversion.hs, interpreted ) [10 of 14] Compiling IterateConversion( IterateConversion.hs, interpre [11 of 14] Compiling CaseReduction ( CaseReduction.hs, interpreted ) [12 of 14] Compiling SimplCore ( SimplCore.hs, interpreted ) [13 of 14] Compiling Flpc ( Flpc.hs, interpreted ) [14 of 14] Compiling Main ( Main.hs, interpreted ) Ok, modules loaded: SimplCore, Main, Flpc, CaseReduction, IterateConversion, MapConversion, AppRename, VarRename, Common, CorePrint, Typconv, DotOutput, SearchCoreNode, CoreVisiting. *Main> Loading package transformers-0.2.2.0 ... linking ... done. Loading package mtl-2.0.1.0 ... linking ... done. Loading package regex-base-0.93.2 ... linking ... done. Loading package regex-posix-0.94.4 ... linking ... done. Loading package regex-compat-0.93.1 ... linking ... done. Loading package time-1.2.0.3 ... linking ... done. Loading package random-1.0.0.3 ... linking ... done. Loading package haskell98-1.1.0.1 ... linking ... done. Loading package ghc-paths-0.1.0.8 ... linking ... done. Loading package HUnit-1.2.2.3 ... linking ... done. Loading package parsec-3.1.1 ... linking ... done. Loading package network-2.3.0.2 ... linking ... done. Loading package hslogger-1.1.5 ... linking ... done. Loading package MissingH-1.1.0.3 ... linking ... done.
87
T´ argymutat´ o α-konverzi´o, 9
GenerateVHDL, 44
β-redukci´o, 9
glob´alis azonos´ıt´o, 38
η-konverzi´o, 9
gyors´ıt´o, 53
uggv´eny, 22 ¨osszetett f¨ u ´jraind´ıt´asi id˝ o, 51
IterateConversion, 36
adatfolyamok, 22 alkalmaz´as, 9
k¨ot¨ott/szabad v´altoz´o, 9 kicsomagolja, 14
AppRename, 36
lambda lifting, 9
argumentum azonos´ıt´ o, 39
lambda-absztrakci´o, 9
AST, 12
lambda-kifejez´es, 9
backend, 30 becsomagolja, 14 behelyettes´ıt´es, 15 blokk, 49 blokk saj´atfrekvenci´ aja, 49 boxing, 14 CλasH, 6 call-by-name, 10 call-by-need, 10 call-by-reference, 10 call-by-value, 10 CaseReduction, 32
lappang´asi id˝o, 51 lass´ıt´o, 53 latency, 23 lok´alis azonos´ıt´o, 38 lusta ki´ert´ekel´es˝ u (lazy evaluation), 8 m˝ uveletei, 22 m˝ uvelethalmaz, 20 MakeModuleList, 43 MapConversion, 56 mintailleszt´esek, 32 MREOG, 49 OpTree, 37
CoreToTree, 37 csomagolt, 14
ParseEOG, 43
csupasz, 14
polimorf t´ıpusok, 8 ProduceComponents, 43
egysebess´eg˝ u, 20
ProduceOperations, 44
el´agaz´asok, 32
ProduceSignals, 43
elemi f¨ uggv´eny, 22 EOG, 20
saj´at m˝ uveletei, 49
er˝osen t´ıpusos, 8
scrutinee, 13 SDF, 20
f¨ uggv´eny, 9
stream, 53
frontend, 30
struktur´alis, 17 88
supercompiling, 37 t¨obbsebess´eg˝ u, 48 t´ıpusalternat´ıv´ akat, 11 t´ıpusalternat´ıv´ aval, 24 t´ıpusoszt´ aly, 11 tiszt´an funkcion´ alis (pure functional), 8 TreeSimplifier, 41 unboxing, 14 v´altoz´o, 9 viselked´esi, 17
89