4. mikroprocesori opšte namene -...

28
4. Mikroprocesori opšte namene Nasuprot namenskih mikroprocesora koji su sposobni da obavljaju samo jednu funkciju, procesori opšte namene, kakav je Pentium CPU, su u stanju da obavljaju mnogo različitih funkcija koje se obavljaju pod kontrolom programskih instrukcija. Za različite skupove instrukcija ili programa, procesor opšte namene može da obavlja različite funkcije. Ipak, mikroprocesori opšte namene se mogu takođe smatrati kao da su namenski mikroprocesori, pošto su i oni napravljeni da obavljaju samo jednu funkciju, a to je da se izvršavaju programske instrukcije. U tom smislu, mi ćemo konstruisati mikroporcesor opšte namene na isti način kao što smo i konstruisali namenske mikroprocesore. 4.1 Pogled na dizajn CPU-a Mikroprocesor opšte namene se često naziva centralna procesorska jedinica ( CPU). CPU je prosto rečeno namenski mikroprocesor koji izvršava softverske instrukcije. Na slici 4.1 prikazan je pogled na mikrorpocesor opšte namene. Diskusija koja sledi odnosi se na taj dijagram. Slika 4.1. Pogled na mikroprocesor opšte namene Kod projektovanja CPU-a neophodno je prvo definisati njegov skup instrukcija kao i način na koji će se instrukcije kodirati i izvršavati. Drugim rečima, neophodno je dati odgovor na sledeća pitanja: Koliko instrukcija želimo da postoji u skupu instrukcija? Koje će to instrukcije biti? Kakav binarni kôd (kodiranje se naziva operacioni kôd ili opkôd) će se dodeliti svakoj instrukciji? Koliko bitova će se koristiti za kodiranje instrukcije? Nakon što smo odlučili kakav će biti skup instrukcija, potrebno je nakon toga da se produži sa projektovanjem staze podataka koja će izvršavati sve instrukcije iz skupa instrukcija. U ovom koraku mi ćemo kreirati namensku stazu podataka, pa zbog toga je neophodno dati odgovor na sledeća pitanja: Koje su funkcionalne jedinice potrebne? Koliko registara je potrebno? Da li treba koristiti jedinstveno registarsko polje ili posebne registre? Kako su različite jedinice međusobno povezane?

Upload: others

Post on 16-Oct-2019

18 views

Category:

Documents


0 download

TRANSCRIPT

4. Mikroprocesori opšte namene

Nasuprot namenskih mikroprocesora koji su sposobni da obavljaju samo jednu funkciju, procesori opšte namene, kakav je Pentium CPU, su u stanju da obavljaju mnogo različitih funkcija koje se obavljaju pod kontrolom programskih instrukcija. Za različite skupove instrukcija ili programa, procesor opšte namene može da obavlja različite funkcije. Ipak, mikroprocesori opšte namene se mogu takođe smatrati kao da su namenski mikroprocesori, pošto su i oni napravljeni da obavljaju samo jednu funkciju, a to je da se izvršavaju programske instrukcije. U tom smislu, mi ćemo konstruisati mikroporcesor opšte namene na isti način kao što smo i konstruisali namenske mikroprocesore. 4.1 Pogled na dizajn CPU-a Mikroprocesor opšte namene se često naziva centralna procesorska jedinica (CPU). CPU je prosto rečeno namenski mikroprocesor koji izvršava softverske instrukcije. Na slici 4.1 prikazan je pogled na mikrorpocesor opšte namene. Diskusija koja sledi odnosi se na taj dijagram.

Slika 4.1. Pogled na mikroprocesor opšte namene

Kod projektovanja CPU-a neophodno je prvo definisati njegov skup instrukcija kao i način na koji će se instrukcije kodirati i izvršavati. Drugim rečima, neophodno je dati odgovor na sledeća pitanja:

• Koliko instrukcija želimo da postoji u skupu instrukcija? • Koje će to instrukcije biti? • Kakav binarni kôd (kodiranje se naziva operacioni kôd ili opkôd) će se dodeliti svakoj

instrukciji? • Koliko bitova će se koristiti za kodiranje instrukcije?

Nakon što smo odlučili kakav će biti skup instrukcija, potrebno je nakon toga da se produži sa projektovanjem staze podataka koja će izvršavati sve instrukcije iz skupa instrukcija. U ovom koraku mi ćemo kreirati namensku stazu podataka, pa zbog toga je neophodno dati odgovor na sledeća pitanja:

• Koje su funkcionalne jedinice potrebne? • Koliko registara je potrebno? • Da li treba koristiti jedinstveno registarsko polje ili posebne registre? • Kako su različite jedinice međusobno povezane?

Kreiranje staze podataka za mikroprocesor opšte namene je u potpunosti isto kao i kreiranje staze podataka za namenski mikroprocesor. Ipak, i pored toga što mikroprocesor treba da bude u stanju da obavi sve instrukcije iz skupa instrukcija, postoje i druge operacije koje manipulišu podacima i registrima koje moraju biti uzete u obzir kod projektovanja staze podataka kod mikroprocesora opšte namene. Ove operacije nad podacima i registrima tiču se toga kako će mikroprocesor opšte namene pribavljati instrukcije iz memorije i izvršavati ih. Posebno, postoji programski brojač (PC) koji čuva memorijsku lokaciju gde se nalazi naredna instrukcija u programu. Pored toga postoji i instrukcioni registar (IR) koji se koristi za memorisanje pribavljene instrukcije iz memorije. Svaki put kada se instrukcija pribavi iz memorijske lokacije na koju pokazuje PC, PC se inkrementira kako bi ukazao na narednu memorijsku lokaciju na kojoj se nalazi sledeća instrukcija. Alternativno, ako je instrukcija Jump tipa, PC mora da se napuni novom memorijskom adresom. Upravljačka jedinica mikroprocesora opšte namene u suštini izvvršava sledeća tri koraka, poznata kao ciklus instrukcije:

Korak 1 - pribavlljanje instrukcije Korak 2 - dekodiranje instrukcije Korak 3 - izvršenje instrukcije

Svaki korak se izvršava u jednom od stanja FSM-a. Kod Koraka 3, svaka instrukcija se obično izvršava za jedan taktni interval, mada kod nekih instrukcija koje pristupaju memoriji za njihovo kompletiranje ili završenje su potrebna dva ili veći broj taktnih intervala. S toga, za njihovo izvršenje je potrebno nekoliko stanja kako bi se ostvario korektan tajming. Kod pribavljanja instrukcija u Koraku 1, upravljačka jedinica jednostavno čita memorijsku lokaciju specificiranu od strane PC-a i kopira sadržaj te lokacije u IR. PC se zatim inkrementira za 1 (pretpostavljamo da svaka instrukcija zauzima samo jednu memorijsku lokaciju). Kod dekodiranja instrukcije u Koraku 2, upravljačka jedinica izdvaja opkod bitove iz IR-a i određuje koja će se tekuća instrukcija izvršiti prelaskom na stanje koje je dodeljeno za izvršenje toj instrukciji. Nakon prelaska u odgovarajuće stanje, upravljačka jedinica obavlja Korak 3 jednostavnim aktiviranjem odgovarajućih upravljačkih signala koji kontrolišu rad staze podataka radi izvršenja odgovarajuće instrukcije. Programske instrukcije su obično zapamćene u spoljnoj memoriji, tako da pored CPU-a postoji eksterna memorija koja je povezana na CPU preko magistrale za podatke i adrese. Shodno tome, Korak 1 (pribavljanje instrukcije) obično uslovljava upravljačku jedinicu da postavi memorijsku adresu na adresnu magistralu i da signalizira spoljnoj memoriji da preda instrukciju sa memmorijske lokacije preko magistrale za podatke. Upravljačka jedinica nakon toga čita instrukciju sa magistrale za podatke. Da bi dizajn bio jednostavan, umesto da se koristi spoljna memorija, mi ćemo smatrati da je memorija deo staze podataka. Na ovaj način ne treba da brinemo oko handschaking-a kao i timing aspektima koji se odnose na pristup spoljnoj memoriji. 4.2 Mikroprocesor opšte namene EC1 Prva verzija EC računara je ekstremno mala i veoma ograničena u odnosu na to šta taj računar može da obavi, a s toga, njen mikroprocesor opšte namene je pogodan za ručno projektovanje. Sa ciljem da se očuva manuelni dizajn mikroprocesora pod kontrolom, neophodno je da broj promenljivih bude mali. Pošto ove promenljive određuju broj stanja i ulazne signale za FSM, ove faktore treba držati na minimum. Nezavisno od svega, gradnja ovog računara pokazaće kako se projektuje mikroprocesor opšte namene i kako različite komponente treba spojiti u jedinstvenu celinu. Nakon ove vežbe, student biće u stanju da projektujete na VHDL-u, tj, na višem nivou apstrakcije, i koristiti to softversko sredstvo za potrebe automatske sinteze. Projektovaćemo sada mikroprocesor opšte namene za računar EC1. Nakon toga spregnućemo ovaj mikroporcesor sa spoljnim ulazima i izlazima, i implementirati kompletni računar koristeći FLEX FPGA čip na UP2 razvojnoj ploči kako bi ga učinili realno radnim računarom opšte namene. Koristeći nekoliko

dostupnih instrukcija, mi ćemo napisati program za izvršenje koji se izvršava na EC1 i ustanoviti da li on radi. 4.2.1 Skup instrukcija Instrukcije koje EC1 mikroprocesor opšte namene može da izvrši kao i odgovarajući načini njihovog kodiranja su prikazane na slici 4.2. Kolona Instruction se odnosi na sintaksu i mnemonik instrukcije koji se koristi kada se piše program na asemblerskom jeziku. Kolona Encoding prikazuje binarni kôd definisan za instrukciju, dok kolona Operation prikazuje operaciju koju obavlja instrukcija.

Napomene: A - akumulator; PC - programski brojač; aaaa - četiri bita za specifikaciju memorijske adrese; x - nije od važnost

Slika 4.2. Skup instrukcija za EC1 Kao što se može videti sa slike 4.2 skup instrukcija računara čini pet instrukcija. Za kodiranje pet instrukcija opkôdu su potrebna tri bita - što daje mogućnost za 8 različitih kombinacija. Kako je to dato u Encoding koloni, prva tri MS bita su opkod instrukcije. Na primer, opkod za IN A instrukciju je 001, opkod za OUT A je 100, i td. Tri kombinacije, 000, 001, 010 nisu definisane i mogu se koristiti kao NOP instrukcije. S obzirom da je obim svake instrukcije fiksiran na 8 bitova LS 5 bitova se ne koriste od strane svih instrukcija sa izuzetkom JNZ (Jump not zero) instrukcije. Normalno, za širii skup instrrukcija, ovi ekstra bitovi se koriste kao operandski bitovi kojim se specificiraju koji će registri ili koji drugi resursi biti iskorišćeni. U našem slučaju, samo JNZ instrukcija koristi zadnja četiri bita, koji su označeni kao aaaa, sa ciljem da specificiraju adresu memorije na koju se skače. Instrukcijom IN A prihvata se 8-bitna vrednost sa ulaznog porta podataka, Input, i smešta se ta vrednost u akumulator (A). Akumulator je 8-bitni registar koji se koristi kao izvorišni ili odredišni operand kod manipulisanja sa podacima. Instrukcija OUT A kopira sadržaj akumulatora u izlazni port Output. Kod EC1 sadržaj akumulatora je uvek dostupan na izlaznom portu, pa zbog toga OUT A instrukcija realno nije neophodna. Ona je uključena samo zbog toga što program treba da poseduje izlaznu instrukciju. Instrukcija DEC A dekrementira sadržaj A za 1 i ponovo smešta rezultat nazad u A. Instrukcija JNZ testira vrednost u A i proverava da li je ona jednaka 0 ili nije, ako je A=0 ne obavlja se akcija. Ako je A≠0 tada zadnja četiri bita (aaaa) instrukcije se pune u PC. Kada se ova vrednost napuni u PC u suštini se obavlja skok na novu memorijsku adresu, pošto vrednost koja se smešta u PC predstavlja lokaciju naredne instrukcije koju treba pribaviti. Konačno, instrukcija HALT zaustavlja CPU uslovljavajući upravljačku jedinicu da ostane u stanju Halt nedefinisano dugo sve dok se ne javi reset. 4.2.2 Staza podataka Nakon što smo definisali skup instrukcija mikroprocesora opšte namene EC1, sada smo u stan ju da projektujemo namensku stazu podataka koja će izvršiti sve operacije definisane skupom neredbi. Namenska staza podataka za EC1 je prikazana na slici 4.3.

Slika 4.3. Staza podataka za EC1 Staza podataka je sastavljena od tri celine: 1) deo koji obavlja pribavljanje instrukcije i inkrementiranje ili punjenje PC-a; 2) memorija; i 3) deo koji obavlja operacije nad podacima za sve instrukcije iz skupa instrukcija. Deo staze podataka koji obavlja pribavljanje instrukcije i inkrementiranje ili punjenje PC-a sadrži IR i PC. Obim instrukcije u bitovima određuje obim IR-a, dok broj adresibilnih memorijskih lokacija određuje veličinu PC-a. Za ovu stazu podataka mi koristimo memoriju sa 16 lokacija, svaka obima 8 bitova, pa je zbog toga potrebna 4-bitna adresa. To znači da je PC obima 4 bita a IR obima 8 bitova. 4-bitna inkrement jedinica se koristi za inkrementiranje PC-a za vrednost 1. PC je potrebno da se puni bilo vrednošću koji je rezultat inkrement jedinice, ili adresom od JNZ instrukcije. Za selekciju ove vrednosti se koristi multiplekser tipa 2-u-1. Jedan od ulaza u multiplekser je od inkrement jedinice, a drugi ulaz su četiri LS bita registra IR, IR3-0. Kao što smo naglasili u Sekciji 4.1, sa ciljem da dizajn bude jednostavan, umesto da se koristi spoljna memorija, mi smo uključili memoriju da bude sastavni deo staze podataka. U našem dizajnu, memorija ima 16 lokacija x 8 bitova i tipa je ROM. S obzirom da skup instrukcija ne poseduje instrukciju kojom se vrši upis u memoriju, nama je potrebna samo ROM memorija. Izlaz PC-a je direktno povezan na 4-bitne memorijske adresne linije, s obzirom da se memorijska lokacija uvek određuje na osnovu sadržaja PC-a. 8-bitni izlaz memorije, Q7-0, se povezuje na ulaz registra IR radi izvršenja operacije pribavljanje instrukcija (Korak 1 ciklusa instrukcije). Deo staze podataka koji obavlja operacije iz skupa instrukcija sadrži 8-bitni akumulator A, i 8-bitnu dekrement jedinicu. Multiplekser tipa 2-u-1 se koristi za selekciju ulaza u akumulator. Kod instrukcije IN A, ulaz u akumulator predstavlja ulazni port podatka, Input; dok za instrukciju DEC A ulaz predstavlja izlaz dekrement jedinice koja obavlja operaciju DEC A. Izlaz akumulatora je direktno povezan na izlazni port podataka, Output, pa zbog toga OUT A instrukcija ne zahteva neke specifične akcije staze podataka. Šta više, ovakvim direktnim načinom povezivanja, ekvivalentno je kao da se uvek obavlja instrukvcija OUT A. Instrukcija JNZ zahteva 8-ulazno OR logičko kolo koje se povezuje na izlazu akumulatora sa ciljem da se testira uslov (A≠0). Aktuelna operacija koja se zahteva od strane JNZ instrukcije ogleda se u punjenju PC-a sa LS 4 bita registra IR. HALT instrukcija ne zahteva neke specifične akcije od staze podataka.

Kontrolna reč ove staze popdataka ima pet upravljačkih signala: IRload, PCload, INmux, Aload, i Jnzmux. Staza podataka generiše jedan statusni signal (A≠0) koji se vodi ka upravljačkoj jedinici. Upravljačke reči za izvršenje instrukcionog ciklusa operacije kao i operacije iz skupa instrukcija biće diskutirani u narednoj sekciji. 4.2.3 Upravljačka jedinica Dijagram stanja upravljačke jedinice je prikazan na slici 4.4(a), a akcije koje se izvršavaju, odnosi se na upravlljačke signale koji se aktiviraju u toku svakog stanja, su prikazane na sllici 4.4(d). Stanjima koja se odnose na izvršenje instrukcije su data ista imena kao i mnemonicima instrukcija. Prvo stanje Start, 000, se koristi kao inicijalno reset stanje. U toku ovog stanja ne obavlja se akcija. Pored toga, stanje Start poseduje jedan dodatni taktni ciklus za instrukcije kojima je potreban ekstra taktni interval da bi kompletirali operaciju. Mada one instrukcije koje ne zahtevaju dodatni taktni interval za završetak svoje operacije u suštini se vraćaju nazad ka stanju Fetch, ipak mi smo tako izveli da se sve instrukcije ponovo vraćaju na stanje Start čime smo učinili da tabela naredno stanje i jednačina pobude budu jednostavne. Od pet instrukcija, samo JNZ instrukcija zahteva dodatni taktni interval da bi završila svoj rad. Razlog ovome je taj što PC mora da se napuni na novu vrednost adrese kada je uslov testa true. Nova vrednost adrese, u suštini, se puni u PC na početku narednog taktnog intervala. Zbog toga, ako mora FSM da pređe u stanje Fetch sa narednim taktnim intervalom, tada će se IR puniti iz memorije sa stare adrese a ne sa nove adrese. Za slučaj kada FSM prelazi nazad u stanje Start, PCB će se ažurirati u ovom stanju na novu adresu, a memoriji će se pristupiti u toku narednog Fetch stanja sa nove adrese.

Slika 4.4. Upravljačka jedinica za EC-1: (a) dijagram stanja; (b) naredno stanje i implementaciona tabela;

(c) jednačine pobude; (d) upravljačke reči i tabela izlaza; (e) jednačine izlaza; (f) kolo Iz stanja Start, upravljačka jedinica bezuslovno prelazi u stanje Fetch. U stanju Fetch, IR se puni sa sadržajem memorijske lokacije specificirane od strane PC-a aktiviranjem signala IRload. Nakon toga, PC se inkrementira za 1, a rezultat se ponovo puni u PC aktiviranjem signala PCload. Decode stanje testira tri MS bita registra IR, IR7-5, i prelazi u odgovarajuće stanje koje je kodirano od strane trobitnog opkoda radi izvršenja instrukcije. U pet stanja izvršenja koja odgovaraju pet instrukcijama, odgovarajući upravljački signali za stazu podataka se aktiviraju sa ciljem da se izvrši data instrukcija. Na primer, instrukcija IN A zahteva postavljanje signala INmux na 1 za ulaz multipleksera, i postavljanjem signala Aload na 1 za punjenje ulazne vrednosti u A. Naglasimo da, sa ciljem da bi ulazna instrukcija pročitala korektnu vrednost, ulazna vrednost mora biti postavljena pre resetovanja CPU-a. Šta više, pošto Input stanje ne čeka na unos Enter signala, samo jedna vrednost se može pročitati, i pored toga što postoji veči broj ulaznih iskaza. Instrukcija DEC A zahteva da se postavi INmux na 0, a Aload na 1, tako da izlaz iz dekrement jedinice se usmerava natrag ka akumulatoru sa ciljem da se on napuni. Instrukcija JNZ aktivira signal JNZmux da bi usmerila četiri adresna bita iz IR-a, IR3-0, u PC. Da li će se PC u suštini napuniti na ovu novu vrednost adrese zavisi od uslova statusnog signala (A≠0). Upravljački signal PCload se aktivira samo ako je uslov (A≠0) jednak 1. Aktiviranjem signala PCload koji uslovno zavisi od statusnog signala (A≠0), dijagramu stanja je potrebno jedno stanje manje, što čini FSM jednostavnijom i realizljivom kao Mealy-ev FSM. U drugom slučaju FSM-u biće potrebna dva stanja za instrukciju JNZ: jedno stanje za aktiviranje signala PCload kada je signal (A≠0) true, a jedno stanje za deaktiviranje signala PCload kada je uslov (A≠0) false. Kada FSM uđe u stanje Halt, on bezuslovno se vrti u petlji u stanju Halt stvarajući utisak da je CPU zaustavljen. Naredno stanje i implementaciona tabela za dijagram stanja i sve tri jednačine pobude, izvedene na osnovu implementacione tabele su prikazane na sllikama 4.4(b) i (c), respektivno. Za 8 stanja koriste

se tri D flip-flopa radi implementacije kola upravljačke jedinice. Naglasimo da izvođenje jednačina pobude se ostvaruje direktnim putem, pošto najveći broj ulaza u tabeli sadrži nule. Samo stanje Decode sadrži različita stanja. Izlazne jednačine su prikazane na slici 4.4(e) i direktno se izvode na osnovu tabele izlaza date na slici 4.4(d). Konačno, moguće je konstruisati kolo za upravlljačku jedinicu na osnovu jednačine pobude i izlaznih jednačina. Kompletno kolo upravljačke jedinice za mikroprocesor opšte namene EC-1 je prikazano na slici 4.4(f). 4.2.4 Kompletno kolo Kompletno kolo za mikroprocesor opšte namene EC-1 se izvodi povezivanjem staze podataka sa slike 4.3 i upravljačke jedinice sa slike 4.4(f). Koristeći namenske upravlljačke i statusne signale kako je to prikazano na slici 4.5.

Slika 4.5 Kompletno kolo za mikroporcesor opšte namene EC-1

4.2.5 Jednostavni problem Namenski procesori koje smo diskutirali u prethodnom poglavlju imaju ugrađeni algoritam u kolu mikroprocesora. Mikroprocesori opšte namene, sa druge strane, nemaju u sebi ugrađen algoritam. Ovi procesori su projektovani da izvršavaju programske instrukcije koje pribavljaju iz memorije. Zbog toga, da bi testirali računar EC-1, mi treba da napišemo program koji koristi instrukcije iz njegovog repertoara. Postoji samo pet instrukcija u skupu instrukcija mikroprocesora EC-1 i one su prikazane na slici 4.2. U našem prostom programu, koristićemo ove pet instrukcije da bi kreirali program za unos broja a zatim odbrojavati unazad od unete vrednosti broja do 0. Ovaj program je prikazan na slici 4.6(a).

Slika 4.6. Program za brojanje unazad koji se izvršava na EC-1: (a) asemblerski kod; (b) binarno izvršivi

kôd Pošto ne raspolažemo kompajlerom za EC-1 potrebno je da ručno kompajliramo program. Binarno izvršivi kôd za ovaj program je prikazan na slici 4.6(b). Binarni kôd se dobija zamenom svake instrukcije odgovarajućim trobitnim opkôdom, kakav je onaj na slici 4.2, iza koga sledi pet bita za operand. Sve operacije, sa izuzetkom instrukcije JNZ ne koriste ovaj petobitni operand, tako da je moguće napisati nule ili jedinice. Sa slike 4.2 mi vidimo da opkôd za instrukciju IN A je 011; što znači da kodiranje za ovu prvu instrukciju biće 01100000. Na sličan način opkod za OUT A instrukciju je 100, što znači da će kôdiranje biti 10000000. Za instrukciju JNZ, četiri LS bita odgovaraju memorijskoj adresi skoka za slučaj da je uslov true. U primeru koga smo dali, mi usvajamo da se prva instrukcija IN A, smešta u memorijsku lokaciju 0000. Pošto JNZ instrukcija skače na drugu instrukciju, OUT A, koja se smešta na memorijsku lokaciju 001, to četvorobitna adresa za JNZ instrukciju je 0001. Opkôd za JNZ instrukciju je 110; pa zbog toga kodiranje kompletne JNZ instrukcije je 11000001. Uobičajeno je da se programske instrukcije smeštaju u memoriju koja je eksterna u odnosu na CPU, a računar (pomoću operativnog sistema) obezbeđuje sredstvo da napuni instrukcije u memoriju. Sa ciljem da naš dizajn bude jednostavan, mi smo se odlučili da memorija bude deo CPU-a i ugrađena u okviru staze podataka. Šta više, ne koristimo operativni sistem za punjenje instrukcije u eksternu memoriju. Zbog toga, naš program mora da bude "napunjen" u memoriju pre sinteze staze podataka i mikroprocesora. Memorijsko kolo koje smo koristili pripada MAX+plus II LPM biblioteci komponenata. Informacija o korišćenju ove komponente se može naći u Help meniju MAX+plus II softvera. Ova memorija se inicijalizira sadržajem tekst fajla imenovan kao PROGRAM.MIF. Zbog toga, da bi napunili našu memoriju sa programom, mi moramo uneti binarno kodiranje programa u ovaj tekst fajl, a nakon toga resintetizovati kolo mikroporcesora. Sadržaj PROGRAM.MIF fajla za program brojanja naniže je prikazan na slici 4.7. Tekst nakon simbola (--) predstavlja komentar, dok sve reči napisane velikim slovima su ključne reči. Treba zapamtiti to da treba resintetizovati računar svaki put kada unosite promene u PROGRAM.MIF fajl. Za ovu namenu treba proveriti Processing i Smart Recompile opciju koja postoji u Compiler menu. Ako je ova opcije čekirana kompajler ne treba da resintetizuje celokupno kolo računara.

Slika 4.7. Fajl PROGRAM.MIF koji sadrži program za brojanje naniže koji se izvršava na EC-1

4.2.6 Simulacija Nakon što smo uneli program za brojanje naniže u PROGRAM.MIF fajl i resintetizovali računar, mi možemo sada da simuliramo rad mikroprocesora koji izvršava taj program. Jednostavna simulacija rada mikrorpocesora je prikazana na slici 4.8, sa koje se vidi da se broji naniže od unete vrednosti 3, a prikaz se vrši na signalu Output. Kompletno kolo mikroprocesora je dato na CDROM-u u fajlu MP.GDF i može se sintetizovati i simulirati.

Slika 4.8. Trase simulacije za program brojanja naniže na računaru EC-1 kada brojanje počinje od unosa

vrednosti 3 4.2.7 Hardverska implementacija Kompletan računar, u skladu sa von Neumann-ovim modelom, ne sadrži samo mikroprocesor nego i memoriju i ulazno/izlazne uređaje. U suštini, mi smo konstruisali samo mmikroprocesor opšte namene sa ugrađenom memorijom za računar EC-1 kako je to prikazano na slici 4.5. Konačni korak gradnje kompletnog EC-1 mikroprocesora sastoji se u dogradnji ulazno/izlaznih uređaja. Na slici 4.9 prikazan je interfejs između mikroprocesora i ulazno/izlaznih uređaja kod UP2 razvojne ploče. Ulaz čine

8 DIP prekidača, a izlaz su dva sedmo-segmentna LED displeja. Pošto mikroprocesor generiše 8-bitni binarni broj, potrebno je ugraditi 8-bitno binarni u dvo-cifarski BCD dekoder, tako da se 8-bitni binarni broj prikazuje kao dve decimalne cifre na dva sedmo-segmentna LED displeja. Jedna LED dioda se koristi za indikaciju stanja Halt mikroprocesora. Jedan taster se koristi kao Reset dirka. Konačno, taktni generator od 25 MHz ugrađen na ploči se dovodi na kolo brojača. Razlog za sniženje taktne frekvencije je taj što je potrebno da uočimo kako se menjaju međurezultati na displeju. Kompletna hardverska implementacija kola se nalazi u fajlu UP2FLEX.GDF u odgovarajućem direktorijumu na CDROM-u. Mi možemo koristiti ovaj fajl za punjenje kompletnog računara EC-1 u razvojnu ploču UP2 i videti brojanje naniže na sedmo-segmentnom displeju za bilo koji zadati broj postavljen pomoću DIP prekidača. FLEX_PB1 taster predstavlja Reset taster. Izlaz se prikazuje na dva sedmo-segmentna LED-a kao decimalan broj. Decimalna tačka na desnoj cifri svetli ako je broj 100. Decimalna tačka na levoj cifri odgovara Halt svetlu i pali se kada program završi sa Halt instrukcijom.

Slika 4.9. Hardverska implementacija računara EC-1

4.3 Mikroprocesor opšte namene EC-2 Projektovaćemo sada drugu verziju mikroprocesora opšte namene nazvanu EC-2. 4.3.1 Skup instrukcija Skup instrukcija mikroprocesora EC-2 čini 8 instrukcija prikazanih na slici 4.10. Razlog da ovaj broj bude 8 je taj što se one mogu kodirati samo sa tri bita.

Napomene: A - akumulator; M - memmorija; PC - programski brojač; aaaa - četiri bita za specifikaciju memorijske adrese; x - nije od važnost

Slika 4.10. Skup instrukcija mikroprocesora EC-2

Instrukcija LOAD puni sadržaj memorije specificirane adresom u akumulatoru A. Adresu specificiraju zadnja pet LS bita instrukcije. Instrukcija STORE je slična instrukciji LOAD, sa izuzetkom što ona smešta vrednost koja se čuva u A u memorijsku lokaciju na specificiranoj adresi. Instrukcije ADD i SUB, respektivno, sabiraju i oduzimaju sadržaj A sa/od sadržaja specificirane memorijske lokacije i rezultat smeštaju u A. Instrukcija IN prihvata vrednost sa ulaznog porta podataka, Input, i smešta rezultat u A. Instrukcija JZ puni PC na specificiranu adresu ako je A=0. Punjenje PC-a na novu adresu uzrokuje da CPU skoči na ovu novu memorijsku lokaciju. Instrukcija JPOS puni PC na specificiranu adresu ako je A pozitivan broj. Vrednost koja se čuva u A smatra se kao označeni broj u prezentaciji dvojičnog komplementa, tako da je broj popzitivan ako je MS bit jednak 0 a negativan ako je jednak 1. Konačno, instrukcija Halt zaustavlja rad CPU-a. 4.3.2 Staza podataka Staza podatakka za EC-a je prikazanan na slici 4.11. Deo staze podataka koji izvršava operacije svojstvene ciklusu instrukcija je sličan mikrorpocesoru EC-1, sa registrom IR, programskim brojačem PC, i jedinicom za inkrementiranje i dekrementiranje PC-a. Minorne razlike između ove dve jedinice ogledaju se u obimu PC-a i u jedinici za inkrementiranje. U drugom dizajnu memoriju čine 32 lokacije pa zbog toga adresa, a shodno tome i obim PC-a kao i njegova inkrement jedinica moraju biti obima 5 bitova. Glavna modifikacija ovog dela staze podataka sastoji se u dogradnji drugog multipleksera tipa 2-u-1 koji je povezan između izlaza PC-a i ulaza memorijske adrese. Jedan ulaz multipleksera dolazi od PC-a, a drugi ulaz dolazi od pet LS bitova registra IR, IR4-0. Razlog za ovo je u otme što sada postoje dva različita tipa operacije koje mogu pristupati memoriji. Prva je i dalje operacija Fetch, kod koje memorijska adresa je definisana sadržajem PC-a. Drugi tip se odnosi na četiri instrukcije LOAD, STORE, AND i SUB jer one koriste memoriju kao operand. Shodno tome, memorijska adresa za ove četiri instrukcije je definisana pomoću 5 LS bitova registra IR, IR4-0. Select signal za multiplekser je Meminst. Obim memorije za EC-2 je povećan na 32 lokacije, pa je zbog toga potrebno 5 adresnih bitova. Memorija je i dalje deo staze podataka, i nije nezavisna eksterna jedinica CPU-a. Sa ciljem da prilagodimo STORE instrukciju da memoriiše vrednost A u memoriji potrebno je da koristimo RAM umesto ROM kakav je bio slučaj kod EC-1. Da bi realizovali ovu operaciju, izlaz akumulatora A se povezuje na ulaz linija za podatke memorije, D7-0. Signal MemWr, kada je aktiviran, uzrokuje da memorija upisuje vrednost koja dolazi iz registra A u lokaciju koja je definisana od strane adrese specificirane instrukcijom. Izlaz memorije na linijama Q7-0 je povezan na ulaz IR-a i na ulaz akumulatora A, preko multipleksera tipa 4-u-1. Veza ka IR se koristi za operaciju Fetch na isti način kao i kod EC-1 dizajna. Veza ka akumulatoru se koristi za obavljanje LOAD instrukcije, pri čemu sadržaj memorije se puni u A. S obzirom da je memorija samo jedno od izvorišta informacije u odnosu na druga dva izvorišta koja se koriste za punjenje u A, neophodno je ugraditi multiplekser. Deo staze podataka koja izvršava operacije iz skupa instrukcija čini 8-bitni akumulator A, jedinica 8-bitni sabirač-oduzimač, i multipplekser tipa 4-u-1. Jedinica sabirač-oduzimač obavlja instrukcije ADD i SUB. Signal Sub, kada je aktivan, selektuje operaciju oduzimanja, a kada je deaktiviran operaciju sabiranja. Multiplekser tipa 4-u-1 obezbeđuje ulaz u akumulator koji može da dolazi od jednog od tri izvorišta. Za instrukcije ADD i SUB ulaz u A se dovodi sa izlaza jedinice sabirač-oduzimač. Za instrukciju IN, ulaz u A dolazi od ulaznog porta podataka, Input. Za instrukciju LOAD ulaz u A dolazi sa izlaza memorije Q7-0. Selekcija ovog multippleksera se izvodi pomoću dve signalne linije, Asel1-0. Četvrti ulaz multipleksera se ne koristi.

Slika 4.11. Staza podataka za EC-2

Na sličan način kao i u EC-1 dizajnu izlazni port je direktno povezan na izlaz akumulatora A. Zbog toga, vrednost akumulatora je uvek dostupna na izlaznom portu, pa zbog toga nije potrebna specifična instrukcija za generisanje izlaza iz A. Kod obe uslovne Jump instrukcije, JZ i JPOS, staza podataka obezbeđuje dva statusna signala (A=0) i (A≥0), respektivno, koji se generišu na izlazima dva komparatora. Izlaz statusnog signala (A=0) biće jednak 1 ako je vrednost u A jednaka 0, pa zbog toga, za potrebe detekcije je neophodno koristiti 8-ulazno NOR kolo. Izlaz statusnog signala (A≥0) biće jednak 1 ako vrednost A, koja se tretira kao označeni broj u prezentaciji dvojičnog komplementa, je pozitivan broj. Pošto za označeni broj u dvojičnom komplementu MS bit ukazuje na popzitivan broj, ako je MS bit jednak 1 to znači da je broj negativan, pa zbog toga uslov (A≥0) predstavlja samo negiranu vrednost od A7 (MS bit od A). Upravljačka reč staze podataka ima 9 upravljačkih signala, IRload, JMPmux, PCload, Meminst, MemWr,Asel1-0, Aload, i Sub. Staza podataka generiše dva statusna signala (A=0) i (A≥0) koji se vode ka upravljačkoj jedinici. Upravljačke reči za izvršenje instrukcionih ciklusa operacije i skupa operacija biće diskutirani u narednoj sekciji. 4.3.3 Upravljačka jedinica Dijagram stanja za kontrolnu jedinicu prikazan je na slici 4.12(a). Akcije koje se izvršavaju, posebno upravljački signali koji se aktiviraju u svakom stanju, su prikazani na slici 4.12(d). Stanjima izvršenja instrukcija su dodeljena ista imena kao i mnemonici instrukcija. Prva tri stanja Start, Fetch i Decode koriste se za istu namenu kao i kod prethodne upravljačke jedinice mikroprocesora EC-1. Stanje Decode kod drugog dizajna, treba da dekodira 8 opkodova granajući se na 8 različitih stanja radi izvršenja odgovarajućih 8 instrukcija. Kao i u prethodnom slučaju dekodiranje opkodova zavisi od triju MS bitova registra IR.

(e)

Slika 4.12. Upravljačka jedinica za EC-2: (a) dijagram stanja, (b) naredno stanje i implementaciona

tabela, (c) jednačine pobude, (d) upravljačke reči i tabela izllaza, (e) jednačine izlaza, (f) kolo

Veoma važna stvar za ovu upravljačku jedinicu je ta koja se odnosi na pristup memoriji u toku izvršenja instrukcija LOAD, STORE, ADD, i SUB. Problem koji se ovde javlja se sastoji u tome što tek nakon pribavljanja ovih instrukcija postaće dostupna adresa memorijske lokacije ovih instrukcija. Šta više, tek nakon dekodiranja instrukcija upravljačka jedinica znaće da treba pročitati memoriju. Ako se promeni memorijska adresa u toku stanja Execute, memorija neće imati dovoljno vremena da generiše vrednost za tu instrukciju. Normalno, instrukcije koje zahtevaju pristup memoriji radi pribavljanja svojih operanada, dodatno memorijsko read stanje biće ubačeno između stanja Decode i stanja Execute. Na ovaj način memorija će imati jedan taktni interval da generiše podatke za instrukciju koja operiše nad njim u narednom taktnom ciklusu. Pri ovome se naravno pretpostavlja da je memoriji potreban samo jedan taktni ciklus da bi se pročitala memorija. Ako je memorija sporija tada se veći broj stanja mora ubacivati. Da bi se minimizirao broj stanja u dizajnu mi smo koristili Decode stanje radi obavljanja operacije read memorije. Na ovaj način kada upravljačka jedinica prelazi u Execute stanje, memorija već ima spreman podatak. Da li će se podatak iz memorije u suštini koristiti ili ne zavisiće od instrukcije koja se izvršava. Ako instrukcija ne zahteva podatak iz memorije on se jednostavno ignoriše. Sa druge strane ako je instrukciji potreban podatak tada je on spreman za korišćenje. Ovo rešenje radi u ovom dizajnu jer ne postoji konflikt sa operacijama koje se odnose na ostale instrukcije iz skupa instrukcija. Operacija read memorije koja se obavlja u stanju Decode ostvaruje se aktiviranjem signala Meminst. Analizom tabele izlaza na slici 4.12(d) to se odražava vrednošću 1 u koloni Meminst u stanju Decode. Stvarno izvršenje svake instrukcije se ostvaruje aktiviranjem korektnih upravljačkih signala namenjenih za upravljanje radom staze podataka. Ovo je prikazano aktiviranjem signala u odgovarajućim vrstama izlazne tabele na slici 4.12(d). U ovom trenutku, treba biti u stanju da se razume zašto svaka dodela se ostvaruje analizom operacije staze podataka. Na primer, za instrukciju LOAD, signal Asel1 treba da se aktivira dok signal Asel0 treba da se deaktivira sa ciljem da se selektuje ulaz 2 multipleksera tako da izlaz iz memorije može da se dovede na ulaz akumulatora A. Punjenje A se obavlja aktiviranjem signala Aload. Dabi se obavila instrukcija STORE, meorijska adresa se dobavlja iz IR-a aktiviranjem signala Meminst. Write u memoriju se dešava kada se aktivira MemWr. U stanju Input kod ovog dijagrama stanja čeka se na pojavu signala sa tastature Enter pre nego što se ponovo vratimo u stanje Start. U toku ovoga, moguće je pročitati nekoliko vrednosti na korektan način ako postoje veći broj iskaza tipa input u ovom programu. Naglasimo da nakon aktiviranja signala Enter, ne postoji stanje u kome se čeka da se signal Enter deaktivira (tj. da se dirka Enter otpusti). Zbog ovoga, ulazni uređaj mora da razreši ovaj problem putem generisanja tačno po jedan taktni impuls svaki put kada se pritisne dirka Enter. Ovo se ostvaruje na nivou računara koristeći kolo monostabilni multivibrator koji generiše jednu kvazistabilnu periodu nezavisno od toga koliko se dugo dirka Enter drži pritisnuta. Naredno stanje i implementaciona tabela za dijagram stanja kao i sve tri izlazne jednačine pobude, izvode se iz implementacione tabele i prikazane su na slici 4.12(b) i (c), respektivno. Da bi tabela bila mala sve moguće kombinacije ulaznih signala nisu izlistane. Sva stanja sa izuzetkom stanja Input, zavise jedino od triju IR bitova, IR7-5, dok stanje Input zavisi samo od signala Enter. Ulazi blanko u tabeli zbog toga smatraćemo ih kao da su poopunjeni nulama. Za 11 stanja, četiri D flip-flopa se koriste sa ciljem da implementiramo kolo upravljačke jedinice. Jednačine izlaza su prikazane na slici 4.12(e) i direktno se izvode iz tabele izlaza sa slike 4.12(d). Konačno, možemo da nacrtamo kolo upravljačke jedinice na osnovu jednačina pobude i jednačina izlaza. Kompletno kolo upravljlačke jedinice za EC-2 je prikazano na slici 4.12(f). 4.3.4 Kompletno kolo Kompletno kolo za mikroprocesor opšte namene EC-2 se konstruiše povezivanjem staze podataka sa slike 4.11 i upravljačke jedinice sa slilke 4.12(f) u jedinstvenu celinu koristeći namenske upravljačke i statusne signale kako je to prikazano na slici 4.13.

Slika 4.13. Kompletno kolo za mikroprocesor opšte namene EC-2

4.3.5 Jednostavni problem Memorija računara EC-2 se inicijalizira pomoću sadržaja tekstualnog fajla PROGRAM.MIF. Jedan jednostavan fajl je prikazan na slici 4.14. Fajl sadrži tri programa: GCD izračunava najveći zajednički delitelj dva broja; SUM procenjuje sumu svih brojeva između unetih vrednosti n i 1; i COUNT prikazuje odbrojavanje od n do 0. Samo zadnji program COUNT izlistan u fajlu se izvršava. Da bi se izvršio drugi program kopiraj kod tog programa na kraju fajla, zatim rekompajliraj ukupno kolo mikroprocesora (tj. UP2FLEX.GDF fajl je objašnjen u narednoj sekciji), i napuni novi kôd u UP2 razvojnu ploču. -- Content of the RAM memory in the file PROGRAM.MIF DEPTH = 32; -- Depth of memory: 5-bit address WIDTH = 8; -- Width of memory: 8-bit data ADDRESS_RADIX = BIN;-- All values in binary (HEX, DEC, OCT, BIN) DATA_RADIX = BIN; -- Opcodes for the EC-2 -- 000 = load A,aaaaa -- 001 = store A,aaaaa -- 010 = add A,aaaaa -- 011 = sub A,aaaaa -- 100 = in A -- 101 = jz aaaaa -- 110 = jpos aaaaa -- 111 = halt -- Specify the memory content. -- Format of each memory location is -- address : data CONTENT BEGIN [00000..11111] : 00000000; -- Initialize locations range 00-1F to 0000

-------------------------------------------------------- -- There are three programs listed below: GCD, Sum, and Count -- Only the progam listed last is ran. -- To try out a different program, move the code for the program you -- want to the end of the list, re-compile, and download to the FPGA -------------------------------------------------------- -- GCD -- Program to calculate the GCD of two numbers 00000 : 10000000; -- input A 00001 : 00111110; -- store A,x 00010 : 10000000; -- input A 00011 : 00111111; -- store A,y 00100 : 00011110; -- loop: load A,x -- x = y? 00101 : 01111111; -- sub A,y 00110 : 10110000; -- jz out -- x=y 00111 : 11001100; -- jp xgty -- x>y 01000 : 00011111; -- load A,y -- y>x 01001 : 01111110; -- sub A,x -- y-x 01010 : 00111111; -- store A,y 01011 : 11000100; -- jp loop 01100 : 00011110; -- xgty: load A,x -- x>y 01101 : 01111111; -- sub A,y -- x-y 01110 : 00111110; -- store A,x 01111 : 11000100; -- jp loop 10000 : 00011110; -- load A,x 10001 : 11111111; -- halt 11110 : 00000000; -- x 11111 : 00000000; -- y -------------------------------------------------------- -- SUM -- Program to sum N downto 1 00000 : 00011101; -- load A,one -- zero sum by doing 1-1 00001 : 01111101; -- sub A,one 00010 : 00111110; -- store A,sum 00011 : 10000000; -- input A 00100 : 00111111; -- store A,n 00101 : 00011111; -- loop: load A,n -- n + sum 00110 : 01011110; -- add A,sum 00111 : 00111110; -- store A,sum 01000 : 00011111; -- load A,n -- decrement A 01001 : 01111101; -- sub A,one 01010 : 00111111; -- store A,n 01011 : 10101101; -- jz out 01100 : 11000101; -- jp loop 01101 : 00011110; -- out: load A,sum 01110 : 11111111; -- halt 11101 : 00000001; -- one 11110 : 00000000; -- sum 11111 : 00000000; -- n -------------------------------------------------------- -- COUNT

-- Program to countdown from input N to 0 00000 : 10000000; -- input 00001 : 01111111; -- Sub A,11111 00010 : 10100100; -- jz 00100 00011 : 11000001; -- jp 00001 00100 : 11111111; -- halt 11111 : 00000001; -- constant 1 END;

Slika 4.14. Fajl PROGRAM.MIF sadrži tri programa z amikroprocesor EC-2. Izvršava se samo zadnji program COUNT

4.3.6 Hardverska implementacija Na slici 4.15 prikazan je interfejs između mikroprocesora EC-2 i ulazno-izlaznih uređaja koji se nalaze na razvojnoj ploči UP2. Ulaz čine 8 DIP prekidača, a izlaz dva sedmo-segmentna LED displeja. S obzirom da mikroprocesor generiše na izlazu 8-bitni binarni broj, potreban je dekoder tipa 8-bitni binarni broj u dve BCD cifre tako da se može 8-bitni binarni broj prikazati kao broj sa dve cifre na dva sedmo-segmentna LED displeja. Jedna LED dioda se koristii da prikaže kada je mikroprocesor u stanju Halt. Taster prekidač se koristi kao Reset dirka, dok drugi taster prekidač se koristi kao Enter dirka. Kolo monostabilnog multivibratora se koristi za generisanje po jednog taktnog impulsa svaki put kada se pritisne dirka Enter. Konačno, frekvencija taktnog generatora od 25 MHz koji se nalazi na ploči se deli pomoću Clock Divider kola. Razlog za usporavanje taktne frekvencije sastoji se u tome da se učine vidljivim međurezultati koji se generišu na displeju.

Slika 4.15. Hardverska implementacija EC-2

Kompletna hardverska implementacija kola se nalazi u fajlu UP2FLEX.GDF u odogvarajućem direktorijumu na CDROM-u. Moguće je koristiti ovaj fajl radi punjenja kompletnog EC-2 računara u UP2 razvojnu ploču i videti kako mikrorpocesor izvršava program. Program COUNT koji je izlistan na kraju PROGRAM.MIF fajla je taj koji se izvršava. Kao Reset dirka koristi se FLEX_PB1 taster. Kao Enter dirka koristi se FLEX_PB2 taster. Osam DIP prekidača se koriste kao ulazni port za podatke. Izlaz se prikazuje na dva sedmo-segmentna LED-a kao decimalan broj. Decimalna tačka kod desne cifre se pali ako je broj u okviru stotine. Decimalna tačka koja je na levoj cifri se pali kod Halt stanja, tj. kada program završava izvršenjem instrukcije Halt. 4.4 VHDL za procesor opšte namene

U ovoj sekciji dat je VHDL kod za mikroprocesor opšte namene EC-2 kako na strukturnom tako i na behavioral nivou. Koa prvo, u sekciji 4.4.1 koristićemo VHDL strukturni opis kako bi definisali mikroprocesor baziran na FSM+D modelu kao što je onaj manuelno projektovan u sekciji 4.3. Sa ciljem da iskoristimo ovaj metod, mikrorpocesor mora da bude projektovan manuelno. Naglasimo da u praksi u principu ne želimo da koristimo ovaj metod. Ova vežba ima za cilj da pokaže kako je teško i komplikovano da se obavi ovaj posao, posebno ako je mikroprocesor realan. Sekcija 4.4.2 koristi VHDL opis na behavioral nivou radi definisanja EC-2 mikrorpocesora zasnovanog na FSMD modelu. Koristeći ovaj metod potrebno je samo manuelno da se nacrta dijagram stanja. Koristeći VHDL šablon za defiinisanje FSM-a moguće je prevesti dijagram stanja u behavioral VHDL kôd. Upoređujući behavioral kod sa strukturnim kodom, uočavamo koliko je lakše da se konstruiše kolo mikroprocesora koristeći behavioral metod, a time i uočiti moć sredstva za VHDL sintezu. 4.4.1 Strukturni FSM+D Na slici 4.16 prikazan je strukturni VHDL kôd za stazu podataka mikroprocesora opšte namene EC-2. Ovaj kôd se zasniva na kolu staze podataka koja je izvedena manuelno u sekciji 4.3.2. Memorija koja se koristi predstavlja MAX+plus II LPM bibliotečku komponentu. Na slici 4.17 prikazan je kôd upravljačke jedinice koji je ručne izrade na osnovu sekcije 3.3. Kod upravljačke jedinice je veoma blizak šablonu za generisanje FSM sekvencijalnog kola. Na slici 4.18 prikazan je strukturni kôd celokupnog mikroprocesora opšte namene EC-2. LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; LIBRARY lpm; -- for memory USE lpm.lpm_components.ALL; ENTITY dp IS PORT ( Clock, Clear: IN STD_LOGIC; -- datapath input Input: IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- control signals IRload, JMPmux, PCload, MemInst, MemWr: IN STD_LOGIC; ASel: IN STD_LOGIC_VECTOR(1 DOWNTO 0); Aload, Sub: IN STD_LOGIC; -- status signals IR: OUT STD_LOGIC_VECTOR(7 DOWNTO 5); Aeq0, Apos: OUT STD_LOGIC; -- datapath output Output: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END dp; ARCHITECTURE Structural OF dp IS COMPONENT reg GENERIC (size: INTEGER := 4); -- the actual size is defined in the instantiation GENERIC MAP PORT ( Clock, Clear, Load: IN STD_LOGIC; D: IN STD_LOGIC_VECTOR(size-1 DOWNTO 0); Q: OUT STD_LOGIC_VECTOR(size-1 DOWNTO 0)); END COMPONENT; COMPONENT increment GENERIC (size: INTEGER := 8); -- default number of bits PORT ( A: IN STD_LOGIC_VECTOR(size-1 DOWNTO 0); F: OUT STD_LOGIC_VECTOR(size-1 DOWNTO 0)); END COMPONENT;

COMPONENT mux2 GENERIC (size: INTEGER := 8); -- default size PORT ( S: IN STD_LOGIC; -- select line D1, D0: IN STD_LOGIC_VECTOR(size-1 DOWNTO 0); -- data bus input Y: OUT STD_LOGIC_VECTOR(size-1 DOWNTO 0)); -- data bus output END COMPONENT; COMPONENT mux4 GENERIC (size: INTEGER := 8); -- default size PORT ( S: IN STD_LOGIC_VECTOR(1 DOWNTO 0); -- select line D3, D2, D1, D0: IN STD_LOGIC_VECTOR(size-1 DOWNTO 0); -- data bus input Y: OUT STD_LOGIC_VECTOR(size-1 DOWNTO 0)); -- data bus output END COMPONENT; COMPONENT addsub GENERIC(n: INTEGER :=4); -- default number of bits = 4 PORT(S: IN std_logic; -- select subtract signal A: IN std_logic_vector(n-1 DOWNTO 0); B: IN std_logic_vector(n-1 DOWNTO 0); F: OUT std_logic_vector(n-1 DOWNTO 0); unsigned_overflow: OUT std_logic; signed_overflow: OUT std_logic); END COMPONENT; SIGNAL dp_IR, dp_RAMQ: STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL dp_JMPmux, dp_PC, dp_increment, dp_meminst : STD_LOGIC_VECTOR(4 DOWNTO 0); SIGNAL dp_Amux, dp_addsub, dp_A: STD_LOGIC_VECTOR(7 DOWNTO 0); BEGIN -- doing structural modeling for the datapath here -- IR U0: reg GENERIC MAP(8) PORT MAP(Clock, Clear, IRLoad, dp_RAMQ, dp_IR); IR <= dp_IR(7 DOWNTO 5); -- JMPmux U1: mux2 GENERIC MAP(5) PORT MAP(JMPmux,dp_IR(4 DOWNTO 0), dp_increment,dp_JMPmux); -- PC U2: reg GENERIC MAP(5) PORT MAP(Clock, Clear, PCLoad, dp_JMPmux, dp_PC); -- Meminst U3: mux2 GENERIC MAP(5) PORT MAP(Meminst,dp_IR(4 DOWNTO 0), dp_PC,dp_meminst); -- increment U4: increment GENERIC MAP(5) PORT MAP(dp_PC,dp_increment); -- memory U5: lpm_ram_dq GENERIC MAP ( lpm_widthad => 5, lpm_outdata => "UNREGISTERED", -- lpm_indata => "UNREGISTERED", -- lpm_address_control => "UNREGISTERED", lpm_file => "program.mif",-- fill ram with content of file program.mif lpm_width => 8) PORT MAP ( data => dp_A, address => dp_meminst, we => MemWr, inclock => Clock,

q => dp_RAMQ); -- A input mux U6: mux4 GENERIC MAP(8) PORT MAP ( Asel,dp_RAMQ,dp_RAMQ,Input,dp_addsub,dp_Amux); -- Accumulator U7: reg GENERIC MAP(8) PORT MAP(Clock, Clear, ALoad, dp_Amux, dp_A); -- Adder-subtractor U8: addsub GENERIC MAP(8) PORT MAP(Sub,dp_A,dp_RAMQ,dp_addsub,open,open); Aeq0 <= '1' WHEN dp_A = "00000000" ELSE '0'; Apos <= NOT dp_A(7); Output <= dp_A; END Structural;

Slika 4.16. VHDL kod za stazu podataka mikroprocesora EC-2

LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY cu IS PORT ( Clock, Reset : IN STD_LOGIC; -- control input Enter: IN STD_LOGIC; -- control signals IRload, JMPmux, PCload, MemInst, MemWr: OUT STD_LOGIC; Asel: OUT STD_LOGIC_VECTOR(1 DOWNTO 0); Aload, Sub: OUT STD_LOGIC; -- status signals IR: IN STD_LOGIC_VECTOR(7 DOWNTO 5); Aeq0, Apos: IN STD_LOGIC; -- control outputs Halt: OUT STD_LOGIC); END cu; ARCHITECTURE FSM OF cu IS TYPE state_type IS (s_start,s_fetch,s_decode, s_load,s_store,s_add,s_sub,s_in,s_jz,s_jpos,s_halt); SIGNAL state: state_type; BEGIN next_state_logic: PROCESS(Reset, Clock) BEGIN IF(Reset = '1') THEN state <= s_start; ELSIF(Clock'EVENT AND Clock = '1') THEN CASE state IS WHEN s_start => -- reset state <= s_fetch; WHEN s_fetch => state <= s_decode; WHEN s_decode => CASE IR IS WHEN "000" => state <= s_load; WHEN "001" => state <= s_store; WHEN "010" => state <= s_add; WHEN "011" => state <= s_sub; WHEN "100" => state <= s_in; WHEN "101" => state <= s_jz; WHEN "110" => state <= s_jpos;

WHEN "111" => state <= s_halt; WHEN OTHERS => state <= s_halt; END CASE; WHEN s_load => state <= s_start; WHEN s_store => state <= s_start; WHEN s_add => state <= s_start; WHEN s_sub => state <= s_start; WHEN s_in => IF (Enter = '0') THEN -- wait for the Enter key for inputs state <= s_in; ELSE state <= s_start; END IF; WHEN s_jz => state <= s_start; WHEN s_jpos => state <= s_start; WHEN s_halt => state <= s_halt; WHEN OTHERS => state <= s_start; END CASE; END IF; END PROCESS; output_logic: PROCESS(state) BEGIN CASE state IS WHEN s_fetch => IRload <= '1'; -- load IR JMPmux <= '0'; PCload <= '1'; -- increment PC Meminst <= '0'; MemWr <= '0'; Asel <= "00"; Aload <= '0'; Sub <= '0'; Halt <= '0'; WHEN s_decode => -- also set up for memory access IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '1'; -- pass IR address to memory MemWr <= '0'; Asel <= "00"; Aload <= '0'; Sub <= '0'; Halt <= '0'; WHEN s_load => IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '1'; MemWr <= '0'; Asel <= "10";-- pass memory to A Aload <= '1'; -- load A Sub <= '0'; Halt <= '0'; WHEN s_store => IRload <= '0'; JMPmux <= '0';

PCload <= '0'; Meminst <= '1'; -- pass IR address to memory MemWr <= '1'; -- store A to memory Asel <= "00"; Aload <= '0'; Sub <= '0'; Halt <= '0'; WHEN s_add => IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '1'; MemWr <= '0'; Asel <= "00";-- pass add/sub unit to A Aload <= '1'; -- load A Sub <= '0'; -- select add Halt <= '0'; WHEN s_sub => IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '1'; MemWr <= '0'; Asel <= "00";-- pass add/sub unit to A Aload <= '1'; -- load A Sub <= '1'; -- select subtract Halt <= '0'; WHEN s_in => IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '0'; MemWr <= '0'; Asel <= "01";-- pass input to A Aload <= '1'; -- load A Sub <= '0'; Halt <= '0'; WHEN s_jz => IRload <= '0'; JMPmux <= '1'; -- pass IR address to PC PCload <= Aeq0; -- load PC if condition is true Meminst <= '0'; MemWr <= '0'; Asel <= "00"; Aload <= '0'; Sub <= '0'; Halt <= '0'; WHEN s_jpos => IRload <= '0'; JMPmux <= '1'; -- pass IR address to PC PCload <= Apos; -- load PC if condition is true Meminst <= '0'; MemWr <= '0'; Asel <= "00"; Aload <= '0'; Sub <= '0'; Halt <= '0'; WHEN s_halt => IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '0'; MemWr <= '0'; Asel <= "00"; Aload <= '0'; Sub <= '0';

Halt <= '1'; WHEN OTHERS => IRload <= '0'; JMPmux <= '0'; PCload <= '0'; Meminst <= '0'; MemWr <= '0'; Asel <= "00"; Aload <= '0'; Sub <= '0'; Halt <= '0'; END CASE; END PROCESS; END FSM;

Slika 4.17. VHDL kôd za upravljačku jedinicu mikroprocesora EC-2

LIBRARY IEEE; USE IEEE.std_logic_1164.all; ENTITY mp IS PORT ( Clock, Reset: IN STD_LOGIC; Enter: IN STD_LOGIC; Input: IN STD_LOGIC_VECTOR(7 DOWNTO 0); Output: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); Halt: OUT STD_LOGIC); END mp; ARCHITECTURE Structural OF mp IS COMPONENT cu PORT ( Clock, Reset : IN STD_LOGIC; -- control input Enter: IN STD_LOGIC; -- control signals IRload, JMPmux, PCload, MemInst, MemWr: OUT STD_LOGIC; Asel: OUT STD_LOGIC_VECTOR(1 DOWNTO 0); Aload, Sub: OUT STD_LOGIC; -- status signals IR: IN STD_LOGIC_VECTOR(7 DOWNTO 5); Aeq0, Apos: IN STD_LOGIC; -- control outputs Halt: OUT STD_LOGIC); END COMPONENT; COMPONENT dp PORT ( Clock, Clear: IN STD_LOGIC; -- datapath input Input: IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- control signals IRload, JMPmux, PCload, MemInst, MemWr: IN STD_LOGIC; ASel: IN STD_LOGIC_VECTOR(1 DOWNTO 0); Aload, Sub: IN STD_LOGIC; -- status signals IR: OUT STD_LOGIC_VECTOR(7 DOWNTO 5); Aeq0, Apos: OUT STD_LOGIC; -- datapath output Output: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END COMPONENT; -- control signals SIGNAL mp_IRload, mp_JMPmux, mp_PCload, mp_MemInst, mp_MemWr: STD_LOGIC; SIGNAL mp_Asel: STD_LOGIC_VECTOR(1 DOWNTO 0); SIGNAL mp_Aload, mp_Sub: STD_LOGIC; -- status signals

SIGNAL mp_IR: STD_LOGIC_VECTOR(7 DOWNTO 5); SIGNAL mp_Aeq0, mp_Apos: STD_LOGIC; BEGIN -- doing structural modeling for the microprocessor here U0: cu PORT MAP ( Clock, Reset, -- control input Enter, -- control signals mp_IRload, mp_JMPmux, mp_PCload, mp_MemInst, mp_MemWr, mp_Asel, mp_Aload, mp_Sub, -- status signals mp_IR, mp_Aeq0, mp_Apos, -- control outputs Halt); U1: dp PORT MAP ( Clock, Reset, -- datapath input Input, -- control signals mp_IRload, mp_JMPmux, mp_PCload, mp_MemInst, mp_MemWr, mp_Asel, mp_Aload, mp_Sub, -- status signals mp_IR, mp_Aeq0, mp_Apos, -- datapath output Output); END Structural;

Slika 4.18. VHDL kôd za kompletni mikroprocesor opšte namene EC-2

4.4.2 Behavioral FSMD Na slici 4.19 prikazan je kompletan behavioral FSMD VHDL kôd za mikroprocesor opšte namene EC-2. Kao memorija je iskorišćena LPM bibliotečna komponenta iz MAX+plus II. Tri registra, IR, PC, i A su deklarisani kao signali u arhitekturnoj sekciji. Napomenimo da ako signalima nije dodeljena vrednost iz uslovnih puteva, tada se oni sintetizuju kao registri. Blok proces je struktuiran kao regularni FSM u saglasnosti sa dijagramom stanja datim na slici 4.12(a). Stanje Decode koristi CASE iskaz radi provere opkôda, a to su ustvari prva tri MS bita registra IR. Nakon toga, FSM skače na stanje izvršenja odgovarajuće instrukcije. Kod instrukcije STORE, potrebno je ekstra stanje da se deaktivira signal MemWr pre nego što se ponovo promeni memorijska adresa koja ukazuje na lokaciju naredne instrukcije. -- EC-2 Behavioral FSMD description LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; LIBRARY lpm; USE lpm.lpm_components.ALL; ENTITY mp IS PORT ( clock, reset: IN STD_LOGIC; enter: IN STD_LOGIC; -- data input

input: IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- data output output: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- control outputs halt: OUT STD_LOGIC); END mp; ARCHITECTURE FSMD OF mp IS TYPE state_type IS(s_start,s_fetch,s_decode,s_load,s_store,s_store2, s_add,s_sub,s_input,s_jz,s_jpos,s_halt);

SIGNAL state: state_type; -- states SIGNAL IR: STD_LOGIC_VECTOR(7 DOWNTO 0); -- Instruction register SIGNAL PC: STD_LOGIC_VECTOR(4 DOWNTO 0); -- Program counter SIGNAL A: STD_LOGIC_VECTOR(7 DOWNTO 0); -- Accumulator SIGNAL memory_address: STD_LOGIC_VECTOR(4 DOWNTO 0); -- memory address SIGNAL memory_data: STD_LOGIC_VECTOR(7 DOWNTO 0); -- memory data input SIGNAL MemWr: STD_LOGIC;

BEGIN memory: lpm_ram_dq -- 32 locations x 8 bits wide asynchronous memory GENERIC MAP (

lpm_widthad => 5, lpm_outdata => "UNREGISTERED", lpm_indata => "UNREGISTERED", lpm_address_control => "UNREGISTERED", lpm_file => "program.mif", -- fill ram with content of file program.mif lpm_width => 8) PORT MAP ( data => A, address => memory_address, we => MemWr, q => memory_data);

PROCESS(clock,reset) BEGIN IF(reset = '1') THEN

PC <= "00000"; IR <= "00000000"; A <= "00000000"; MemWr <= '0'; halt <= '0'; state <= s_start;

ELSIF(clock'EVENT AND clock = '1') THEN CASE state IS WHEN s_start => -- reset, start memory_address <= PC; state <= s_fetch; WHEN s_fetch => -- fetch IR <= memory_data; PC <= PC + 1; state <= s_decode; WHEN s_decode => -- decode -- memory access using last 5 bits of IR memory_address <= IR(4 DOWNTO 0); CASE IR(7 DOWNTO 5) IS -- decode first 3 bits of IR as opcode WHEN "000" => state <= s_load; WHEN "001" => state <= s_store; WHEN "010" => state <= s_add; WHEN "011" => state <= s_sub; WHEN "100" => state <= s_input; WHEN "101" => state <= s_jz; WHEN "110" => state <= s_jpos; WHEN "111" => state <= s_halt; WHEN OTHERS => state <= s_start;

END CASE; WHEN s_load => -- load A from memory A <= memory_data; state <= s_start; WHEN s_store => -- store A to memory MemWr <= '1'; state <= s_store2; WHEN s_store2 => -- need an extra state to de-assert MemWr MemWr <= '0'; -- before changing the memory address state <= s_start; WHEN s_add => -- add A <= A + memory_data; state <= s_start; WHEN s_sub => -- subtract A <= A - memory_data; state <= s_start; WHEN s_input => A <= input; IF (Enter = '0') THEN -- wait for Enter key state <= s_input; ELSE state <= s_start; END IF; WHEN s_jz => IF (A = 0) THEN -- jump if A is 0 PC <= IR(4 DOWNTO 0); END IF; state <= s_start; WHEN s_jpos => IF (A(7) = '0') THEN -- jump if MSB(A) is 0 PC <= IR(4 DOWNTO 0); END IF; state <= s_start; WHEN s_halt => halt <= '1'; state <= s_halt; WHEN OTHERS => state <= s_halt; END CASE; END IF; END PROCESS; output <= A; -- send value of Accumulator to the output END FSMD;

Slika 4.19. Behavioral VHDL kôd za kompletan mikrorpocesor opšte namene EC-2