UNIVERSITATEA UNIVERSITATEA TEHNICĂ "GHEORGHE ASACHI" IAŞI FACULTATEA DE ELECTRONIC Ă SI TELECOMUNICA ŢII
LUCRARE DE DIPLOMĂ
Coordonator ştiinţific: Dr.Ing. Dănuţ Burdia
Student Ieremie Ionu ţ grupa 5507
VHDL pentru SINTEZĂ
CUPRINS
Secţiunea I
Introducere..................................................................................................................................3 ASIC............................................................................................................................................4 Introducere............................................................................................................................4 ASIC - tipuri..........................................................................................................................5 Full-Custom ASICs...............................................................................................................6 Standard-Cell-Based ASICs..................................................................................................6 Gate-Array-Based ASICs......................................................................................................9 Structured Gate Array.........................................................................................................10 Dispozitive logice programabile.........................................................................................11 Limbajul VHDL ....................................................................................................................14 Design Compiler ....................................................................................................................15 ..................................................................................................................15 Modelsim şi Leonardo Spectrum..............................................................................................16
Secţiunea II
CY7C910
Descriere funcţională...........................................................................................................17 Proiectare Introducere..................................................................................................................19 Package-ul..................................................................................................................21 Instruction Decoder....................................................................................................23 Register-Counter........................................................................................................32 Stack...........................................................................................................................35 MicroProgram Counter...............................................................................................40 Interfaţa sursă.............................................................................................................43 Multiplexer.................................................................................................................44 Zero Detector..............................................................................................................44 TS Buffer....................................................................................................................44 CY7C910....................................................................................................................45 Sinteza circuitului CY7C910...........................................................................47 Testarea circuitului CY7C910.........................................................................52
CY7C901
Descriere funcţională...........................................................................................................67 Proiectare Package-ul..................................................................................................................71 ALU............................................................................................................................72 Q Register...................................................................................................................76 Q Shift........................................................................................................................80 Ram Addressable Registers........................................................................................83 Ram Shift....................................................................................................................86 ALU Data Source Selector.........................................................................................88 Output Data Selector..................................................................................................91 CY7C901....................................................................................................................93 Sinteza circuitului CY7C901...........................................................................94 Testarea circuitului CY7C901.........................................................................96 Concluzii.................................................................................................................................110 CD-ul anexă............................................................................................................................111 Bibliografie
Introducere
La nivelul anului 2003, circuitele integrate digitale (CID) conţinând peste 10 milioane de tranzistoare sunt deja banale (procesoarele Intel Pentium4 conţin peste 40 milioane tranzistoare), iar în cazul anumitor procesoare grafice, numărul tranzistoarelor depăşeşte 100 de milioane. Este evident că proiectarea unor astfel de circuite nu mai poate fi realizat ă manual. De fapt, la proiectarea manuală a CID sa renunţat începând de la sfâr şitul anilor 1970. O dată cu apariţia primelor instrumente soft pentru proiectarea CID, s-a intrat într-un fel de reacţie pozitivă care a f ăcut posibilă complexitatea CID actuale : prin apariţia unor procesoare mai puternice, acestea puteau rula aplicaţii mai complexe - deci şi programe de proiectare mai complexe -, iar aceste programe de proiectare au permis realizarea unor procesoare şi mai puternice, şi aşa mai departe. Prin renunţarea la proiectarea manuală, la nivel de schemă, şi trecerea la proiectarea asistată de calculator a apărut un nou tip de abordare a proiectării CID. Astfel, principala sarcină a proiectantului este aceea de a descrie, într-un limbaj HDL (VHDL sau Verilog), funcţionarea dorită de la circuit. După această operaţiune preponderent manuală, celelalte etape de proiectare sunt aproape complet automatizate. Astfel, după realizarea descrierii funcţionării circuitului într-un limbaj HDL, un soft va transforma această descriere în format RTL (register transfer logic), care reprezintă o implementare cu operatori logici a circuitului descris. Apoi alt soft realizează maparea fişierului RTL pe o anumită tehnologie, adică implementarea circuitului descris folosind componente (por ţi logice, bistabili, mux-uri, etc) dintr-o bibliotecă de componente, ţinând cont de constrângerile de arie, viteză sau consum de putere impuse de proiectant. În final alt soft preia fişierul de mapare şi realizează layout-ul circuitului (dispunerea pe chip a componentelor folosite la implementarea circuitului), ţinând cont de anumite constrângeri. Prin această lucrare mi-am propus să realizez descrierea, sinteza şi simularea a două circuite integrate digitale : CY7C910 şi CY7C901. Scopul principal a fost acela de a că păta experientă în programarea VHDL pentru sinteză, în vederea unei viitoare cariere în acest domeniu. M-am limitat doar la această etapă deoarece cunoaşterea fiecărei etape presupune o perioadă destul de mare de studiu, iar într-o firmă, un proiectant lucrează doar la una dintre etapele proiectului. În plus, în timp ce limbajul VHDL este standardizat şi a suferi foarte puţine modificări de la apariţia sa la începutul anilor 1980, programele de sinteză sufer ă modificări permanent, apărând altele noi, astel că în scurt timp s-ar putea ca această lucrare să nu mai prezinte interes. Mai trebuie precizat că, cu cât ne apropiem de siliciu, cu atât programele sunt tot mai greu de găsit şi de instalat pe PC-uri. Lucrarea are 2 secţiuni : o secţiune introductivă în care sunt prezentate circuitele ASIC, limbajul VHDL şi instrumentele soft folosite la realizarea proiectului şi secţiunea principală, în care sunt prezentate descrierile VHDL, programele de test, sinteza şi simularea circuitelor pe care le-am proiectat. 3
ASIC Introducere
Un ASIC (application specific integrated circuit ) este un circuit integrat dedicat unei aplicaţii specifice (cel putin aceasta este semnificatia acronimului) . Înainte de a vedea ce inseamnă in realitate ASIC, vom arunca o privire asupra evoluţiei circuitelor integrate (CI) . Figura 1(a) arată capsula unui CI (în acest caz este vorba despre un PGA ( pin-grid array) prezentat r ăsturnat : pinii vor intra prin găurile unei plăci cu cablaj imprimat) . Capsula este denumită adesea (impropriu) chip, dar, după cum se vede în figura 1(b), chiar chip-ul de siliciu (numit die) este montat iîn cavitatea de sub stratul de protecţie. O capsulă PGA este confecţionată, în mod obişnuit, din material ceramic, dar si capsulele din plastic sunt destul de r ăspândite.
Figura 1. Un circuit integrat
Dimensiunile fizice ale unui chip de siliciu variaz ă de la câţiva milimetri (latura unui dreptunghi) , la peste 3 centimetri, insă adesea dimensiunea unui CI este exprimată prin numărul por ţilor logice echivalente sau al tranzistoarelor conţinute de acel CI. Ca unitate de m ăsur ă, o poartă echivalentă corespunde unei por ţi NAND cu două intr ări. Apărută o dată cu primul CI la începutul anilor 1970, industria semiconductorilor s-a maturizat şi a evoluat rapid. Primele CI integrate pe scar ă mică conţineau câteva(1 → 10) por ţi logice (NAND, NOR) ce însumau câteva zeci de tranzistoare. Perioada CI integrate pe scar ă medie a crescut capacitatea logică a acestora, f ăcând posibilă realizarea primelor număr ătoare integrate. Era CI integrate pe sacr ă mare a f ăcut posibilă apariţia primelor procesoare realizate pe un singur chip. În zilele noastre, CI integrate pe scar ă foarte mare (VLSI) ofer ă procesoare pe 128 de biţi, cu memorie cache şi unităţi de calcul în virgulă mobilă – mult peste 10 milioane de tranzistoare – toate acestea pe un singur chip de siliciu. Primele CI foloseau tehnologia bipolar ă, iar majoritatea circuitelor digitale foloseau familiile logice TTL sau ECL. Deşi inventat înaintea tranzistorului bipolar, tranzistorul MOS (metal-oxide-silicon) era iniţial dificil de fabricat. Pe măsur ă ce problemele de realizare a tranzistorului MOS au fost rezolvate, sa dezvoltat tehnologia nMOS (metal-gate n-channel MOS) . La acea vreme tehnologia MOS necesita mai puţine măşti, era mai densă şi consuma mai puţină putere decât tehnologia bipolar ă echivalentă. Asta însemna că, pentru o anume performanţă, un integrat MOS era mai ieftin decât unul bipolar echivalent, ceea ce a dus la investiţii şi la creşterea pieţei circuitelor integrate MOS. La începutul anilor 1980 grilele din aluminiu ale tranzistoarelor au fost înlocuite cu grile din polisiliciu, însă numele MOS a r ămas. Introducerea polisiliciului ca material pentru grilă a constituit o îmbunătăţire major ă a tehnologiei MOS, f ăcând mai uşoar ă realizarea celor două tipuri de tranzistoare MOS (NMOS şi PMOS) pe acelaşi CI, ceea ce a dus la apariţia tehnologiei CMOS (complementar MOS) . Principalul avantaj al tehnologiei CMOS fa ţă de tehnologia nMOS este reducerea puterii consumate. Alt avantaj, urmare a introducerii grilei din polisiliciu, este simplificarea procesului de fabricare care, în plus, permite micşorarea dimensiunilor tranzistoarelor. 4
O poartă NAND cu două intr ări este realizată din 4 tranzistoare CMOS, deci, pentru a exprima dimensiunea unui CI ca număr de tranzistoare, se multiplică cu 4 dimensiunea acelui CI exprimată ca număr de por ţi echivalente. Procesul de fabricare a unui CI poate fi caracterizat şi de cea mai mică dimensiune rezolvabilă (cam jumătate din dimensiunea minimă permisă de fabricant pentru lungimea unui tranzistor) . În prezent se folosesc procese de 0.13µm şi chiar 0.09µm, ceea ce înseamnă că cel mai mic tranzistor are aproximativ 0.13µm(0.09µm) în lungime. Cea mai mică dimensiune rezolvabilă, pe care o vom nota λ, va avea dimensiunile λ = 0.065µm şi 0.045µm pentru procesele de 0.13µm, respectiv 0.09µm. Un proces CMOS submicronic modern este acum la fel de complicat ca şi un proces submicronic bipolar sau BiCMOS. Totuşi CI CMOS au o poziţie dominantă, fiind fabricate în volum mult mai mare decât circuitele bipolare şi BiCMOS (din considerentele prezentate mai sus) . Tehnologiile bipolare şi BiCMOS sunt în continuare utilizate pentru aplicaţii speciale. De exemplu, tehnologia bipolar ă este capabilă să lucreze cu tensiuni mai mari decât permite tehnologia CMOS. Astfel CI bipolare şi BiCMOS r ămân în continuare foarte utile în electronica de putere, electronica auto, circuite telefonice, etc . Unele CI sunt componente standard. Se poate alege un CI standard dintr-un catalog şi cumpăra de la distribuitori. Fabricanţii de sisteme şi proiectanţii pot utiliza acelaşi CI standard într-o mare varietate de sisteme microelectronice. O dată cu apariţia circuitelor VLSI, inginerii au început să realizeze avantajele proiectării unui CI pentru o aplicaţie specifică, decât utilizarea CI standard. Proiectarea sistemelor microelectronice a devenit o problemă de definire a funcţiilor care se pot implementa folosind CI standard, şi apoi de a implementa funcţiile logice r ămase (numite “glue logic”) cu unul sau mai multe CI dedicate (care trebuie proiectate) . Se poate realiza un sistem dintr-un număr mai mic de componente, combinând multe CI standard cu câteva CI dedicate. Construirea unui sistem microelectronic cu mai puţine CI dedicate permite reducerea costului şi îmbunătăţeşte fiabilitatea. Desigur, există multe situaţii în care nu este adecvată utilizarea CI configurabile pentru fiecare parte a unui sistem microelectronic. Dacă, de exemplu, o aplicaţie necesită o memorie de dimensiuni mari, este indicat utilizarea unui CI de memorie standard, DRAM sau SRAM. Deoarece este dificil de definit cu exactitate termenul ASIC, vom încerca să clarificăm ce înseamnă acest termen apelând la unele exemple. Exemple de circuite integrate care nu sunt ASIC-uri : microprocesoarele, memoriile destinate PC-urilor (SDRAM, DDRAM) . Exemple de CI ASIC : un CI pentru o pă puşă “vorbitoare”, un CI pentru un satelit, un CI care conţine un microprocesor ca celulă, împreună cu altă logică. Ca o regulă generală, dacă un CI poate fi găsit într-un catalog atunci este foarte probabil să nu fie ASIC.
ASIC – tipuri
Circuitele integrate sunt fabricate pe wafere circulare subţiri (câteva sute de microni) din siliciu, fiecare wafer conţinând sute de chip-uri. Tranzistoarele şi conexiunile sunt realizate în mai multe straturi (de obicei între 10 şi 15) suprapuse. Fiecare strat are o configuraţie definită cu ajutorul unei măşti. Straturile inferioare definesc tranzistoarele, iar straturile superioare conexiunile dintre tranzistoare. Un CI full-custom include câteva (sau toate) celule logice proiectate special şi măştile, care sunt toate proiectate special. Un microprocesor este un exemplu de CI full-custom. Proiectanţii au cheltuit foarte mult timp insistând asupra fiecărui µm² de pe chip. Proiectând astfel toate resursele circuitului integrat, este posibilă includerea pe chip a unor circuite analogice sau a unor celule de memorie optimizate. CI full-custom sunt cele mai scump de proiectat şi de fabricat. Aceste CI full-custom sunt adesea destinate unei aplicaţii specifice, deci am putea numi unele dintre acestea CI ASIC full-custom. Ceea ce ne interesează pe noi sunt însă CI ASIC semicustom, pentru care toate celulele logice sunt deja proiectate şi unele măşti (probabil toate) sunt configurabile. Folosind celule logice predefinite (dintr-o libr ărie de celule) viaţa proiectanţilor devine mult mai uşoar ă. Sunt două tipuri de CI ASIC 5
semicustom despre care vom vorbi : CI ASIC bazate pe celule standard (“standard cell based ASICs “) şi CI ASIC bazate pe arii de por ţi logice (“gate-array-based ASICs”) . Apoi vor fi descrise CI ASIC programabile. Full-Custom ASICs
Într-un CI ASIC full-custom un inginer configurează par ţial (sau în totalitate) celulele logice, circuitele şi layout-ul într-un mod specific. Aceasta înseamnă că proiectantul abandonează abordarea de a utiliza celule pretestate pentru realizarea întregului circuit. Această abordare full-custom are sens doar dacă nu există libr ării de celule care să permită realizarea întregului design. Aceasta se poate întâmpla deoarece celulele din libr ăriile de celule existente nu sunt suficient de rapide, sau nu sunt suficient de mici, sau consumă prea multă putere.; sau dacă tehnologia ASIC este nouă sau atât de specializată încât nu există libr ării de celule ; sau dacă circuitul este atât de specializat încât unele blocuri trebuie proiectate special. Din ce în ce mai puţine CI ASIC full-custom sunt realizate (există şi o excepţie :circuitele mixte analog/digital) . Tehnologia bipolar ă a fost utilizată dintotdeauna pentru funcţii analogice de precizie. Există câteva motive fundamentale pentru aceasta. În toate CI împerecherea caracteristicilor componentelor de pe chip-uri diferite este foarte slabă, dar foarte bună pentru componentele aflate pe acelaşi chip. Să presupunem că avem tranzistoarele T1, T2, T3 într-un CI ASIC analog/digital. Cele trei tranzistoare au dimensiuni identice şi sunt construite în acelaşi mod. Tranzistoarele T1 şi T2 sunt plasate foarte aproape unul de celălalt şi au aceeaşi orientare, în timp ce tranzistorul T3 este plasat pe chip pe partea opus ă şi are o orientare diferită. Circuitele integrate sunt fabricate în loturi, numite “wafer lots”. Un “wafer lot” este un grup de wafer-e de siliciu (intre 5 şi 30) care sunt procesate împreună. Fiecare wafer poate conţine zeci sau sute de chip-uri, în funcţie de dimensiunile CI şi ale wafer-ului. Dacă facem măsur ători asupra caracteristicilor tranzistoarelor T1, T2, T3 vom desprinde următoarele concluzii : - Tranzistoarele T1 şi T2 de pe acelaşi chip vor avea caracteristici aproape identice ; - Tranzistorul T3 se împerechează foarte bine cu tranzistoarele T1 şi T2 de pe acelaşi chip, dar nu atât de strâns ca împerecherea dintre T1 şi T2 ; - Tranzistoarele T1, T2 şi T3 se vor împerechea destul de bine cu tranzistoarele T1, T2, T3 de pe alt chip de pe acelaşi wafer ; împerecherea depinde de cât de depărtate sunt cele două chip-uri unul de celălalt ; - Tranzistoarele de pe chip-uri aflate pe afer-e diferite nu se vor împerechea foarte bine ; - Tranzistoarele de pe chip-uri din loturi de wafer-e diferite se vor împerechea foarte slab ; La proiectarea circuitelor analogice împerecherea tranzistoarelor este crucială pentru funcţionarea circuitului. Pentru aceste circuite sunt folosite perechi de tranzistoare situate adiacent pe chip. Fizica dispozitivului dictează că o pereche de tranzistoare bipolare se vor împerechea întotdeauna mult mai precis decât o pereche de tranzistoare CMOS de dimensiuni comparabile. Tehnologia bipolar ă a fost utilizată pe larg pentru circuite analogice full-custom datorită preciziei sporite. În ciuda slabelor sale carcteristici analogice, utilizarea tehnologiei CMOS pentru funcţii analogice este în creştere, şi aceasta din două motive: primul motiv este acela că în prezent tehnologia CMOS este cea mai larg disponibil ă tehnologie de realizare a CI ; al doilea motiv este acela că nivelul crescut de integrare necesită realizarea de funcţii analogice şi digitale pe acelaşi chip, ceea ce a obligat proiectanţii să folosească tehnologia CMOS pentru implementarea funcţiilor analogice. Standard-Cell-Based ASICs
Un CBIC (cell-based IC) foloseşte celule logice (por ţi NAND, NOR, multiplexoare, bistabili) predefinite, numite celule standard. Un CBIC este construit din rânduri de celule standard - la fel cum zidul este construit din căr ămizi. Ariile de celule standard pot fi utilizate în combinaţie cu celule predefinite mai mari, microcontrollere sau chiar microprocesoare, numite megacelule. 6
Proiectantul ASIC defineşte doar plasarea celulelor standard şi interconexiunile într-un CBIC. Celulele standard pot fi plasate oriunde pe chip, ceea ce înseamnă că toate măştile unui CBIC sunt configurabile. Avantajul circuitelor CBIC este acela că proiectanţii economisesc timp, bani şi reduc riscul prin utilizarea unei libr ării de celule standard gata proiectate, pretestate şi precaracterizate. Pe de altă parte, fiecare celulă standard poate fi optimizată individual. În timpul proiectării unei libr ării de celule fiecare tranzistor din fiecare celulă standard poate fi ales astfel încât să maximizeze viteza sau să minimizeze aria, de exemplu. Dezavantajul în acest caz este timpul şi banii cheltuiţi pentru proiectarea unei libr ării de celule. Figura 2 arată un CBIC. Caracteristicile principale ale acestui tip de ASIC sunt următoarele : - toate măştile sunt proiectate special – tranzistoarele şi interconexiunile ; - pot fi incluse blocuri custom - timpul de fabricare este în jur de 8 să ptămâni .
Figura 2. Un CBIC die
Fiecare celulă standard dintr-o libr ărie este construită folosind metode de proiectare full-custom, însă aceste celule standard gata proiectate se pot utiliza la realizarea circuitelor digitale f ăr ă a fi deloc necesar ă proiectarea full-custom. Acest stil de proiectare duce la obţinerea aceloraşi avantaje de performanţă şi flexibilitate ca în cazul ASIC full-custom, dar reduce riscul şi timpul de proiectare. Celulele standard sunt proiectate să se potrivească asemeni căr ămizilor într-un zid. Figura 3 arată exemplul unei celule standard simple (simplu în sensul că nu este optimizată pentru densitate, dar este ideală pentru a ar ăta construcţia internă). Liniile de putere şi de masă (VDD şi GND sau VSS) traversează orizontal celulele.
Figura 3.
Layout-ul unei celule standard (privire de sus)
Proiectarea standard cell permite automatizarea procesului de asamblare. Grupuri de celule standard sunt aranjate împreună pe orizontală pentru a forma rânduri. Rândurile sunt stivuite pe vertical ă pentru a 7
forma blocuri rectangulare flexibile (forma acestoara poate fi modificată pe durata proiectării) . Apoi un bloc flexibil construit din câteva rânduri de celule standard poate fi conectat la alt bloc de celule standard sau la alt bloc logic full-custom. De exemplu, s ă presupunem că vrem să includem pe acelaşi chip un circuit de interfaţă (proiectat de noi) pentru un microcontroller gata proiectat (megacelulă) , împreună cu o anumită cantitate de memorie. Blocul microcontrollerului este o megacelulă de dimensiuni fixe, memoria poate fi generată folosind un compilator de memorie, iar circuitul de interfată va fi construit din blocuri flexibile de celule standard a căror formă se poate modifică astfel încât să se potrivească în spaţiile r ămase libere pe chip. Circuitele integrate ASIC, atât cele “cell-based”, cât şi cele “gate-array”, utilizează celule predefinite, însă există o diferenţă: putem modifica dimensiunile tranzistoarelor într-o celul ă standard (pentru a optimiza viteza sau aria) , însă în cazul ariilor de por ţi logice dimensiunile tranzistoarelor sunt fixe. Aceasta determină o interdependenţă între arie şi viteză la nivel de siliciu în cazul “gate-array”, pe când, în cazul “standard-cell”, această interdependenţă se manifestă la nivelul libr ăriei de celule standard. Circuitele ASIC CMOS moderne utilizează două, trei sau mai multe straturi (layer–e) de metal pentru interconexiuni. Aceasta permite traseelor de interconexiune să traverseze diferite straturi, la fel ca în cazul traseelor de cupru de pe o placă cu cablaj împrimat. Într-o tehnologie CMOS cu 2 nivele de metal, conexiunile la intr ările şi ieşirile celulelor standard se realizează pe nivelul metal2 (nivelul superior de metal) , la extremităţile superioar ă şi inferioar ă ale celulelor. Într-o tehnologie cu 3 nivele de metal, conexiunile pot fi interne celulei standard (ca în Figura 3) , ceea ce permite programelor de rutare să folosească nivelul de metal în plus pentru a ruta interconexiunile pe deasupra celulelor standard. O conexiune care trebuie să treacă pe deaupra unui rând de celule standard foloseşte un “feedthrough” (fie o por ţiune de metal folosită pentru a trece un semnal printr-o celulă, fie un spaţiu l ăsat liber în interiorul celulei, spaţiu ce va fi ocupat de un traseu metalic) . Figura 4 prezintă două astfel de “feedtrough”-uri: unul în celula A.14 şi unul în celula A.23. Atât în tehnologia cu 2 nivele de metal, cât şi în cea cu 3 nivele de metal, bus-urile de putere (“power buses” – VDD şi GND) în interiorul celulelor utilizează în mod normal cel mai de jos (cel mai apropiat de tranzistoare) nivel de metal – metal1.Lăţimea fiecărui rând de celule standard este ajustată astfel încât acesea să poată fi aliniate prin intermediul celulelor de spaţiere (“spacer cells”) . Traseele “power buses” se conectează apoi la linii de power adiţionale verticale prin intermediul celulelor speciale de sfâr şit de rând (“row-end cells”) la capetele aliniate ale fiecărui bloc de celule standard. Dacă rândurile de celule standard sunt lungi, liniile de power verticale pot fi realizate pe nivelul metal2 şi vor parcurge rândurile de celule standard prin intermediul unor celule speciale, numite “power cells”, care realizează doar conectarea la VDD şi GND. În mod normal, proiectantul controlează manual numărul şi lăţimea liniilor de power verticale conectate la un bloc de celule standard în timpul proiectării la nivel fizic (layout) . O imagine a schemei de distribuţie a traseelor de power pentru un CBIC este ar ătată în Fig 4.
Figura 4. Rutarea CBIC-ului din fig2
8
Toate măştile pentru un CBIC sunt configurabile. Aceasta permite plasarea unor megacelule (SRAM, controller SCSI, decodor MPEG, etc) alături de celule standard pe acelaşi chip. Megacelulele sunt furnizate de un fabricant de ASIC-uri sau de libr ării, împreună cu modele comportamentale şi anumite strategeii de test pentru aceste megacelule. Companiile furnizoare de libr ării ASIC pot furniza, de asemenea, compilatoare pentru generarea flexibilă a blocurilor de memorie (DRAM, SRAM, ROM) . Întrucât în cazul unui design “standard cell” toate măştile sunt configurabile, proiectarea blocurilor de memorie este mult mai eficientă şi mai densă decât in cazul designului “gate arrays”. Libr ăriile “standard cell” şi “gate array” conţin sute de celule logice diferite, incluzând func ţii combinaţionale (por ţi NAND, NOR cu 2 sau mai multe intr ări) , precum şi latch-uri şî bistabili (cu diverse combinaţii de reset, preset şi opţiuni pentru semanlul de ceas) . Producătorul libr ăriilor furnizează documentaţia (descriere funcţională şi informaţii de timing) pentru fiecare element al libr ăriei.
Gate-Array-Based ASICs
Într-un ASIC de tip “gate-array” (prescurtat GA) tranzistoarele sunt predefinite pe wafer. Configuraţia predefinită a tranzistoarelor pe o arie de por ţi reprezintă aria de bază (“base array”) , iar cel mai mic element care este replicat pentru a forma aria de bază reprezintă celula de bază (“base cell”, numită şi “primitive cell”) . Doar câteva din straturile superioare de metal, care definesc conexiunile dintre tranzistoare, sunt definite de proiectant folosind măşti configurabile. Pentru a fi deosebit de alte tipuri de “gate array”, acest tip este numit “masked gate array” (MGA) . Proiectantul alege dintr-o libr ărie “gatearray” celule logice predefinite. Celulele logice dintr-o libr ărie “gate-array” sunt numite adesea macrouri (“macros” – de la asemănarea cu macrourile software ) deoarece layout-ul pentru o “base-cell” este acelaşi pentru fiecare celulă logică, şi doar conexiunile (în interiorul celulelor logice şi între acestea) sunt configurabile. Putem realiza etapele de difuzie până la definirea tranzistoarelor, după care waferele pot fi depozitate în vederea utilizării ulterioare. Deoarece doar interconexiunile metalice sunt unice pentru un MGA, putem utiliza waferele din depozit pentru diferite aplica ţii, după necesităţi. Folosind wafere prefabricate până la nivelul de metalizare, se reduce timpul necesar fabricării unui MGA (între 2 zile şi 2 să ptămâni) . Există 3 tipuri de MGA : - Channeled gate arrays - Chanelless gate arrays - Structured gate arrays Să explicăm pe scurt termenii “channeled”, “channelless” şi “structured”. Există două modalităţi uzuale de a aranja tranzistoarele într- un MGA : în cazul “channeled gate arrays”, între rândurile de tranzistoare se lasă un spaţiu liber destinat rutării ; rutarea în cazul dispozitivelor “channelless gate arrays” utilizează rânduri de tranzistorare neutilizate. Tipul “structured gate arrays” poate fi atât “channeled”, cât şi “channelless”, însă include şi un bloc configurabil. Channeled Gate Array Figura 5 prezintă un chip “channeled gate array”. Principalele caracteristici ale acestui tip de MGA sunt :
- Doar interconexiunile sunt “custom” - Interconexiunile utilizează spaţiile predefinite dintre rândurile de “base cells”
9
- Fabricarea durează între 2 zile şi 2 să ptămâni
Figura 5. Channeled gate array die
Un chip “channeled gate array” este asemănător cu un CBIC – ambele utilizează rânduri de celule separate de canale pentru interconexiuni. Diferenţa este dată de faptul că, în cazul “channeled gate array” canalele de rutare au dimensiuni fixe. Channelless Gate Array Figura 6 prezintă un chip “channelless gate array”. Principalele caracteristici ale acestui tip de MGA sunt :
- Doar câteva din layerele superioare sunt “custom” – interconexiunile - Fabricarea durează între 2 zile şi 2 să ptămâni Principala deosebire faţă de “channeled gate array” este absenţa spaţiilor de rutare predefinite. În acest caz rutarea se realizează pe deasupra tranzistoarelor. Aceasta se poate realiza deoarece proiectantul configurează stratul “contact layer” care defineşte conexiunile dintre nivelul metal1 şi tranzistoare. Când se utilizează o arie de tranzistoare pentru rutare, nu se realizează nici un contact către tranzistoarele de dedesubt; tranzistoarele sunt lăsate pur şi simplu neutilizate.
Figura 6. Channelless gate array die
Densitatea de integrare pentru “channelless gate arrays” este mai mare decât în cazul “channeled gate arrays”. Aceasta se datorează faptului că masca de contact este configurabilă în cazul “channelless gate arrays”. Prin configurarea stratului de contact se permite creşterea densităţii celulelor deoarece se poate realiza rutarea şi pe deasupra contactelor neutilizate. Structured Gate Array
Un chip “structured gate array” combină câteva dintre caracteristicile CBIC – urilor şi MGA – urilor. Unul dintre dezavantajele MGA este celula de baz ă neconfigurabilă, ceea ce face ca implementarea memoriei, de exemplu, să fie dificilă şi ineficientă. În cazul “structured gate array”, o parte din aria chipului este dedictă funcţiilor speciale (această arie poate conţine celule de bază mai adecvate pentru implementarea memoriei, sau poate conţine un bloc complet – un microcontroller de exemplu) . Figura 7 prezintă un chip “structured gate array”. Principalele caracteristici ale acestui tip de MGA sunt următoarele : 10
- doar interconexiunile sunt configurabile - pot fi incluse macrocelule - fabricarea durează între 2 zile şi 2 să ptămâni
Figura 7. Structured Gate Array die
Tipul “structured gate array” combină densitatea şi performanţa superioare ale unui CBIC cu costurile scăzute şi timpul de fabricare redus ale unui MGA. Unul din principalele dezavantaje provine tocmai de la blocul special (macrocelula) integrat care nu este configurabil. Dacă “strucured gate array” conţine o arie destinată implementării a 32 Kb de memorie, iar pentru o aplicaţie sunt necesari doar 16 Kb, înseamnă că jumătate din această arie de memorie r ămâne nefolosită şi inutilizabilă în alt scop; însă, chiar şi aşa, tot este mai eficient şi mai ieftin decât implementarea celor 16 Kb de memorie utilizând macrouri.
Dispozitive logice programabile
Dispozitivele logice programabile, (Programmable Logic Devices - PLD) sunt circuite integrate care au proprietatea că pot fi configurate (programate) de către utilizator, oferind astfel posibilitatea acestuia de a implementa diverse sisteme digitale. Dispozitivele logice programabile ofer ă un set de resurse logice care pot fi configurate, prin intermediul unor biţide configurare. Resursele logice sunt dispuse sub forma unei arhitecturi fixe, de tip modular.Prin arhitectur ă de tip modular se înţelege o arhitectur ă compusă dintr-un număr de blocuri identice care sunt inteconectate. Conexiunile dintre aceste blocuri sunt realizate pe baza unorcomutatoare programabile. Programarea unui PLD constă în setarea biţilor de configurare, care controlează starea comutatoarelor programabile şi configuraţia resurselor logice, pe baza unei descrieri a sistemului digital care se doreşte a fi implementat. În funcţie de starea biţilor de configurare se pot genera diverse configuraţii ale resurselor logice şi interconexiuni între blocurile din componenţa PLD-ului, în final obţinându-se arhitectura sistemului digital dorit. Programarea acestor dispozitive este realizată pe baza unor instrumente software complexe şi implică inserarea circuitului în unitaţi speciale de programare. Un pas înainte în proiectarea sistemelor digitale pe baza PLD-urilor a fost realizat recent prin posibilitatea configurar ării PLD-ului ”insistem” (f ăr ă a fi necesar ă extragerea lor din sistem). PLD-urile sunt utilizate în special în segmentul de piaţă ce cuprinde producerea desisteme digitale la un volum redus de producţie, fiind ideale pentru realizarea prototipurilor. Principalele avantaje pe care le ofer ă PLD-urile sunt: cost iniţial redus pentru realizarea proiectului (în faza de prototip), risc financiar redus în faza de realizare a prototipului, posibilitatea parcurgerii tuturor fazelor implicate în proiectarea unui produs chiar din faza de prototip, începând de la stabilirea cerinţelor de proiectare şi terminând cu implementarea finală a produsului şi nu în ultimul rând uşurinţa cu care se pot realiza modificările în proiect.digitale. Întrucât pot fi programate pentru a se obţine circuite pentru o aplicaţie specifică, PLD-urile pot fi incluse în familia ASIC-urilor. Primul PLD a fost realizat în anii ’70 şi a fost denumit ProgrammableLogic Array, pe scurt PLA. Dispozitivul PLA este un PLD de capacitate logică redusă. 11
Dispozitivele PLA sunt alcătuite din 2 nivele (plane) logice: un nivel logic alcătuit din por ţi logice AND - planul AND, la care sunt conectate intr ările dispozitivului şi un nivel logic alc ătuit din por ţi logice OR - planul OR, la care sunt conectate ieşirile dispozitivului. Cele două plane sunt conectate între ele astfel încât, ieşirile din por ţile AND reprezintă intr ările în por ţile OR. Distinctiv pentru acest tip de dispozitiv este faptul că ambele planuri logice pot fi programate. Cele 2 planuri logice mai poartă şi denumirea de arii logice programabile. Programarea acestor arii logice este realizată la nivelul conexiunilor (firelor), prin intermediul comutatoarelor (switch-uri) programabile, realizate în diverse tehnologii: fuzibil, antifuzibil, EPROM, EEPROM, Flash, SRAM. La nivelul planului AND, pot fi conectate oricare dintre intr ările dispozitivului, la ieşirea acestuia rezultând un set de termeni produs. La nivelul planului OR, pot fi conectate oricare dintre termenii produs, la ieşirea acestuia rezultând sume de termeni produs, deci funcþii logice care pot descrie un sistem digital. Versatilitatea dispozitivului, ca o consecinţă a faptului că ambele planuri logice din componenţa sa pot fi programate, ofer ă posibilitatea realizării unei game extinse de sisteme Dipozitivele PLA prezintă 2 dezavantaje importante: cost mare de fabricare (cost raportat la nivelul tehnologic al anilor ’70) şi viteză de lucru redusă. Ambele dezavantaje sunt determinate de programabilitatea ambelor plane logice: planele logice programabile sunt dificil de realizat şi introduc întârzieri în propagarea semnalului. Pentru eliminarea (par ţială) a acestor dezavantaje s-a încercat eliminarea problemei care a cauzat-o: programabilitatea planelor logice. Cum eliminarea conexiunilor programabile din cele 2 plane logice ar fi condus practic la dispariţia circuitului PLD, s-au eliminat numai conexiunile programabile din planul OR (conexiunile din acest plan au devenit fixe) şi astfel dezavantajele prezentate de dispozitivul PAL au fost diminuate. Noul dispozitiv creat a fost patentat de către firma AMD ( Advanced Micro Device) şi poartă denumirea de Programmable Array Logic, pe scurt PAL. Dispozitivele PAL au un plan AND programabil şi un plan OR fix. Structura unui dispozitiv PAL este prezentată în Figura.8, în care se remarcă o nouă deosebire faţă de dispozitivele PLA: ieşirile di. por ţile OR pot fi conectate fie la un set de bistabile de tip D (ca in figur ă), fie la un set de macrocelule logice.
Figura 8.
Structura unui dispozitiv PAL
Dispozitivele de tip PLA şi PAL sunt referite deseori în literatura de specialitate sub denumirea de Simple Programmable Logic Devices - SPLD. Aceste dispozitive au o densitate logică redusă. Astfel, dispozitivele SPLD au o capacitate logică de maxim 600 por ţi echivalente. Pe măsur ă ce sistemele digitale au devenit mai complexe, a ap ărut nevoia unor dispozitive PLD de mare densitate logică. Pe măsur ă ce tehnologia de fabricare a circuitelor integrate a avansat, s-au dezvoltat în timp dou ă mari categorii de dispozitive PLD. Prima categorie o reprezintă dispozitivele de tip Complex Programmable Logic Devices CPLD, a căror capacitate logică se situează, în mod uzual în jurul ordinului miilor de por ţi logice (deşi sunt câteva firme care produc dispozitive CPLD cu capacitate logică de câteva sute de mii de por ţi logice), arhitectura acestora fiind dezvoltată pe baza dispozitivelor SPLD. Alte denumiri sub care se pot referi aceste dispozitive sunt: Enhanced PLD, abreviat EPLD, Super PAL, Mega PAL, etc. Dispozitivele CPLD sunt destinate în special implementării sistemelor digitale cu un pronunţat caracter combinaţional, principalele domenii de aplicaţii ale acestora fiind: controlere LAN, sisteme UART, sisteme 12
de interfaţă cu bus-uri, comparatoare, respectiv decodoare complexe de viteză mare, automate secvenţiale complexe, controlere video, etc. A doua categorie de dispozitive PLD este reprezentată de circuitele Field Programmable Gate Array, abreviate FPGA, a căror arhitectur ă, remarcabilă prin numărul foarte mare de bistabile incluse, este diferită de precedentele tipuri de dispozitive PLD din punct de vedere al concepţiei, ceea ce permite atingerea unei capacităţi logice de până la 1 milion de por ţi logice. Dispozitivele FPGA sunt destinate în special implementării sistemelor digitale cu un pronunţat caracter secvenţial (datorită numărului mare de ă), principalele domenii de aplicaţii fiind: emularea sistemelor hardware, bistabile incluse în structur dispozitive de codare şi filtrare în comunicaţii, circuite aritmetice de dimensiuni mari, controlere utilizate în prelucrarea imaginilor, etc. Arhitectura dispozitivelor FPGA ( field programmable gate array) este compusă dintr-un set de celule logice (logic cells – LC) dispuse matricial, care comunică între ele şi/sau cu celulele I/O prin intermediul unor canale de rutare orizontale şi verticale. Canalele de rutare conţin un număr de fire de interconexiune. Acestea pot fi conectate între ele prin intermediul unor comutatoare programabile. Arhitectura celulelor logice precum şi modul în care este implementată schema de rutare variază în funcţie de producător. În general, celulele logice ofer ă o funcţionalitate mai redusă decât combinaţia termeni produs – macrocelule, oferită de dispozitivele CPLD, dar, în cazul dispozitivelor FPGA, implementarea unor func ţii logice complexe poate fi realizată prin conectarea în cascadă a celulelor logice. În figura9 este prezentată arhitectura generică a unui dispozitiv FPGA. Ţinând cont de specificul arhitecturii unui dispozitiv FPGA, în general, acestea sunt utilizate pentru implementarea sistemelor digitale cu un predominant caracter secvenţial, unităţi de calcul, sau diferite tipuri de interfeţe în sisteme de comunicaţie.
Figura 9.
Arhitectura generică a unui dispozitiv FPGA
Pentru a fi un produs competitiv pe piaţă, un dispozitiv FPGA trebuie să satisfacă anumite cerinţe. Între acestea, cele mai importante sunt: 1. performanţa – capacitatea de a implementa sisteme digitale care să poată funcţiona la frecvenţe ridicate 2. densitatea şi capacitatea logică – capacitatea de a majora nivelul de integrare, de a implementa sisteme digitale tot mai complexe într-un singur cip, prin utilizarea tuturor resurselor logice disponibile şi ob ţinerea astfel a unor soluţii ieftine de proiectare. 3. proiectare facilă – capacitatea de a realiza un proiect într-un interval de timp minim, fapt care depinde de instrumentul software de proiectare şi de posibilitatea de a fi efectuate modificări ulterioare în proiect f ăr ă a fi afectate pricipalele caracteristici legate de viteza de lucru şi alocarea pinilor dispozitivului. 4. programarea “in-system” şi reprogramarea “in-circuit ” – capacitatea de a programa şi reprograma un dispozitiv conectat într-un sistem. Satisfacerea acestor cerinţe de către dispozitivele FPGA depinde în mare măsur ă de tehnologia utilizată pentru proiectarea elementelor programabile. În prezent sunt utilizate două tehnologii: tehnologia SRAM şi antifuzibil (antifuse).
13
Limbajul VHDL
Limbajul VHDL a apărut la începutul anilor 1980 şi este acceptat în prezent ca unul dintre cele mai importante limbaje standard pentru descrierea, verificarea şi proiectarea circuitelor electronice. VHDL eliberează proiectantul de constrângerea de a folosi structuri von Neumann şi îi permite să lucreze cu evenimente concurente în locul maşinilor secvenţiale. Aceasta a dus la apariţia unor posibilităţi complet noi pentru proiectant. Două din motivele importante pentru care se utilizează VHDL în locul proiectării tradiţionale la nivel de schemă sunt : timpul mai scurt pentru dezvoltarea proiectelor electronice şi întreţinerea mai simplă. VHDL a apărut ca un limbaj pentru descriere şi verificare, primele simulatoare fiind dezvoltate la sfâr şitul anilor 1980. Proiectarea cu VHDL a apărut câţiva ani mai târziu. În prezent, toţi marii producători de instrumente soft de proiectare electronică suportă standardul VHDL. În prezent VHDL este un limbaj standardizat, cu avantajul că un cod VHDL poate fi uşor mutat pe diferite instrumente (platforme) comerciale. Aceasta înseamnă că un cod VHDL scris pentru un simulator al unui producător anume poate fi mutat pe simulatoarele altor producători f ăr ă a trebui să fie modificat. O nouă posibilitate, care a schimbat lumea proiectanţilor de circuite electronice, este modalitatea prin care câteva mii (sute de mii şi chiar milioane în prezent) de por ţi şi bistabili pot fi programate sub forma unui circuit integrat în doar câteva minute pe un singur PC şi f ăr ă a fi nevoie de echipamente costisitoare. Aceasta înseamnă că, plecând de la un cod VHDL, se poate genera automat un fi şier pentru programarea circuitelor ; această metodă se numeşte “rapid prototyping”. Scrierea de cod VHDL în locul utilizării componentelor schematice (ex : por ţi logice) , reprezintă o nouă cale de proiectare. Lucrul cu VHDL nu inseamnă doar scrierea de cod, existând facilităţi pentru construirea de ierarhii şi proiectarea cu o libr ărie de componente. VHDL se pretează, de asemenea, la scrierea de cod pentru circuite standard (ex: Motorola 680020) . Există companii care vând coduri VHDL pentru simularea circuitelor standard. Aceasta înseamnă că o întreagă placă ce conţine componente standard poate fi verificată printr-o simulare pe computer. Proiectarea cu VHDL presupune ca proiectantul să scrie cod VHDL şi să verifice funcţionarea acestuia într-un simulator, după care codul este sintetizat într-un netlist. Sinteza poate fi comparată cu procesul prin care un compilator transformă un cod scris într-un limbaj de programare în cod maşină. În hardware, codul VHDL este transpus într-o schemă cu por ţi şi bistabili. VHDL suportă diferite metode de proiectare : top-down (de la vârf spre baz ă) , bottop-up (de la bază spre vârf) şi orice combinaţie a acestora. Multe din produsele electronice de astăzi au o durată de viaţă mai mare de 10 ani şi, ca urmare, trebuie să fie reproiectate de câteva ori pentru a exploata avantajele noilor tehnologii. Cea mai simplă metodă pentru a face asta este proiectarea VHDL independentă de tehnologie, ceea ce permite modificarea tehnologiei folosind instrumente automate. Limbajul VHDL suportă ierarhii (diagrame bloc) , componente reutilizabile, managementul erorilor şi verificare. Ierarhiile sunt descrise folosind VHDL structural, proceduri şi funcţii. VHDL structural poate fi comparat cu o diagramă bloc. Multe sisteme suportă intr ări grafice care pot fi transferate automat în VHDL structural.
14
Design Compiler
Design Compiler sintetizează o descriere HDL (VHDL sau Verilog) într-un design la nivel de poartă (gatelevel) dependent de tehnologie. Folosind Design Compiler putem defini condiţiile de mediu, constrângerile, metodologia de compilare, regulile de proiectare şi libr ăriile “ţintă” (target) pentru a îndeplini sarcinile de proiectare. Design Compiler este “inima” suitei de produse software pentru sinteză Synopsys. Design Compiler realizează optimizarea, bazată pe constrângeri, a logicii secvenţiale şi suportă o mare diversitate de stiluri de proiectare. În continuare sunt prezentate succint câteva aspecte de bază ale Design Compiler care permit formarea unei imagini despre posibilităţile acestuia. Procesul de sinteză
Design Compiler optimizează designul logic pentru viteză, arie şi rutabilitate. Această optimizare este realizată pentru descrieri ierarhice ale circuitelor logice combinaţionale şi secvenţiale. Pornind de la cerinţele impuse asupra caracteristicilor măsurabile ale circuitului, Design Compiler sintetizează un circuit pe care îl transfer ă într-o tehnologie indicată. Aceasta permite generarea de fişiere schematics şi netlists compatibile cu instrumentele CAE (computer-aided engineering) . Procesul de sinteză, prezentat în figura de mai jos, urmează această schemă generală : - încărcarea proiectului şi a subproiectelor (blocurilor componente) acestuia ; - specificarea caracteristicilor de proiectare pentru proiectul “top-level” ; - impunerea de performanţe de viteză şi arie realistice ; - analiza “check_design” pentru verificarea proiectului ; identificarea şi corectarea tuturor erorilor ; - optimizarea proiectului cu Design Compiler ; - analiza fişierelor de raport privind constrângerile de arie şi viteză, pentru a se determina dacă sarcinile de proiectare au fost îndeplinite ; - reoptimizarea, după modificarea atributelor sau constrângerilor, în cazul în care sarcinile de proiectare nu au fost îndeplinite ; - generarea de rapoarte şi scheme suplimentare, pentru analiza aprofundată a rezultatelor
15
Stiluri de proiectare
Proiectele pot fi ierarhice sau plane (flat) , secvenţiale sau combinaţionale. Formate de intrare
Design Compiler suportă descrieri VHDL şi Verilog ca formate de intrare pentru descrierea proiectului. De asemenea, Design Compiler suportă formatele PLA şi EDIF 200. Formate de ieşire Alături de formatul
Synopsys binar (.db) , Design Compiler suportă formatele de ieşire VHDL, Verilog şi EDIF 200. De asemenea Design Compiler suportă şi formatele : ecuaţii. LSI, Mentor Graphics, PLA, statetable şi Tegas.
Modelsim
Modelsim, produs de Mentor Graphics, este la ora actuală cel mai popular simulator HDL de pe piaţă. Prin intermediul acestuia se pot simula atât fişiere VHDL, cât şi fi şiere Verilog. Toate fişierele din acest proiect au fost simulate cu Modelsim versiunea 5.6, formele de undă prezentate fiind generate de acesta. Leonardo Spectrum
Leonardo Spectrum, din cadrul pachetului FPGA Advanced, este un soft de sinteză semiprofesional, destinat în principal aplicaţiilor FPGA. Deşi are rezultate foarte slabe la sinteza standard cells, şi de şi nu generează fişiere SDF (generează fişîere EDIF, care însă nu pot fi simulate cu Modelsim), acest soft mi-a fost de mare ajutor pentru a testa dacă codurile VHDL scrise de mine erau sintetizabile.
16
CY7C910 Microprogram Controller Descriere funcţională
CY7C910 este un microprogram controller de sine stătător care selectează, testează, stochează, reface, manipulează şi testează adresele care controlează secvenţa de execuţie a instrucţiunilor stocate într-o memorie externă. Toate adresele sunt valori pe 12 biţi care desemnează o locaţie absolută de memorie. După cum se vede din diagrama bloc, CY7C910 constă dintr-o stivă LIFO (last in first out) de 17 locaţii a câte 12 biţi împreună cu un indicator de stivă (stack pointer – SP) , un registru/număr ător (Register/Counter) pe 12 biţi, un număr ător de program (Microprogram Counter – MPC) , un multiplexor de 4 intări de câte 12 biţi şi logica necesar ă pentru manipularea şi controlul datelor. Operaţia executată este determinată de 4 linii de instrucţiuni de intrare (I3 – I0) care selectează sursa (internă) următoarei microinstrucţiuni ce urmează a fi executată. Această adresă este scoasă la ieşirile Y11 – Y0. Două intr ări suplimentare (\CC şi \CCEN) sunt destinate pentru a fi examinate în timpul executării anumitor instrucţiuni, ceea ce permite utilizatorului să facă execuţia unei instrucţiuni fie necondiţionată, fie condiţionată de un test extern.
CY7C910 - diagrama bloc
Descrierea pinilor Nume I/O Descriere D0 – D11 I Intr ări directe către RC (Register/Counter) şi multiplexor.
\RLD
I
I 3 – I0
I
\CC
I
\CCEN
I
CP
I
D0 este LSB, iar D11 este MSB Intrare de control a RC care, atunci când este pe nivelul LOW, incarcă data de pe pinii de intrare D11 – D0 în RC, pe frontul crescător al semnalului de ceas (CP) Intr ările de instrucţiune care selectează una din cele 16 instrucţiuni pentru a fi executată de CY7C910 Intrare de control care, atunci când se află pe nivelul LOW, inseamnă că un test a fost trecut Intrare de activare a semnalului \CC. Dacă este pe nivel HIGH, \CC este ignorat şi este for ţată trecerea testului. Dacă este pe nivel LOW, starea semnalului \CC este examinată Intrarea pentru semnalul de ceas. Toate stările interne se 17
CI \OE
I I
Y11 – Y0
O
\FULL \PL
O O
\MAP
O
\VECT
O
modifică pe frontul crescător al semnalului de ceas Intrare de carry pentru LSB-ul incrementorului pentru MPC Intrare de control pentru ieşirile Y11 – Y0. LOW pentru activarea, HIGH pentru dezactivarea buferelor threee-state de pe ieşiri. Ieşirile de adresă către memoria program. Y0 este LSB, iar Y11 este MSB Când este pe nivel LOW indică faptul că stiva este plină Când este pe nivel LOW selectează registrul pipeline ca sursă pentruintr ările directe D Când este pe nivel LOW selectează PROM-ul mapat (sau PLA-ul) ca sursă pentru intr ările directe D Când este pe nivel LOW selectează vectorul de întrerupere ca sursă pentru intr ările directe D
Arhitectura CY7C910
CY7C910 este un microprogram controller care generează o secvenţă de adrese de 12 biţi care controlează execuţia unui microprogram. Adresele sunt selectate din una din cele 4 surse posibile, în func ţie de instrucţiunea în execuţie (I3 – I0) şi de alte semnale externe. Cele 4 surse sunt : 1.intr ările D11 – D0 ; 2.RC (register/counter) ; 3.stiva 4.MPC (microprogram counter) Câte 12 linii de un bit de la fiecare din aceste 4 surse reprezintă intr ările într-un multiplexor (după cum se vede în diagrama bloc) ale cărui ieşiri sunt aplicate intr ărilor driverelor three-state de ieşire Y11 – Y0 . Semnalele de intrare externe : D11 – D0
Semnalele de intrare externe sunt folosite ca sursă pentru adresele destinaţie în cazul instrucţiunilor de salt (jump) şi ramificare (branch) . O a doua utilizare a acestor intr ări este la încărcarea RC-ului. RC (register/counter) Registrul/număr ător RC este realizat din 12 bistabili de tip D activi pe frontul cresc ător al semnalului de ceas. Datele de pe intr ările D sunt încărcate sincron în RC atunci când semnalul de intrare pentru controlul încărcării, \RLD, este pe nivel LOW. Ieşirea RC este disponibilă ca intrarea R a multiplexorului şî poate fi transferată la ieşirile Y în timpul execu ţiei anumitor instrucţiuni, după cum este indicat de R în tabela de instrucţiuni. RC operează ca un număr ător pe 12 biţi, conţinutul său fiind decrementat şi testat dacă este zero în timpul instrucţiunilor 8, 9 şi 15. Aceasta permite repetarea de până la 4096 de ori a unor microinstrucţiuni. RC este conceput astfel încât, dacă este încărcat cu un număr N, secvenţa va fi executată de exact N+1 ori. Stiva şi indicatorul de stivă (SP) Stiva din 17 locaţii de 12 biţi este utilizată pentru furnizarea adreselor de revenire din subrutine sau cicluri. SP-ul indică (adresează) ultima dată salvată în stivă, ceea ce permite referirea la această dată f ăr ă a fi nevoie de extragerea acesteia din stivă (execuţia unei instrucţiuni POP) . SP-ul funcţionează ca un număr ător bidirecţional care este incrementat cănd se execută o operaţiune de tip PUSH (instrucţiunile 8, 10, 11, 13 sau 15) . Operaţia PUSH scrie in stivă adresa de revenire, iar operaţiunea POP o şterge efectiv de pe stivă. Operaţia propriuzisă este executată pe frontul crescător al semnalului de ceas care urmează instrucţiunea. Stiva este iniţializată prin execuţia instrucţiunii 0 (“salt la loca ţia zero” sau “reset”) . De fiecare dată când se execută o instrucţiune “salt la subrutină”(1, 5) sau de ciclare (4) , adresa de revenire este depusă pe stivă, şi de fiecare dată când se execută o instrucţiune de revenire din subrutină sau din ciclu, adresa de revenire este retrasă de pe stivă. 18
Când o subrutină apelează o altă subrutină sau un ciclu apare în interiorul altui ciclu (cicluri imbricate) adâncimea logică a stvei creşte. Adâncimea fizică a stivei este de 17 locaţii. Când această adâncime este atinsă, semnalul \FULL trece în starea LOW la următorul front crescător al semnalului de ceas. Orice altă operaţie PUSH asupra unei stive pline va determina ca data din vârful stivei s ă fie suprascrisă, dar nu va incrementa SP-ul.Similar, executând o operaţie POP asupra unei stive goale nu va decrementa SP-ul şi ar putea determina apariţia unor date f ăr ă sens la ieşirile Y. MPC (Microprogram counter ) : MPC-ul constă dintr-un incrementor pe 12 biţi, urmat de un registru de 12 bi ţi. În mod obişnuit, registrul reţine adresa instrucţiunii în curs de execuţie. Când instrucţiunile sunt executate secvenţial (succesiv, una după alta după cum se află în memorie) , intrarea de carry (CI) către incrementor este pe nivel HIGH şi, ca urmare, se adună 1 la ieşirile Y ale multiplexorului, care sunt încărcate în MPC la următorul front crescător
al semnalului de ceas. Când intrarea CI este pe nivel LOW, ieşirile Y ale multiplexorului sunt Incărcate direct în MPC, astfel încât aceeaşi instrucţiune este extrasă şi executată. Tabela de instrucţiuni
I3-I0 Mnemonic Name 0 1 2 3 4 5 6 7 8
JZ CJS JMAP CJP PUSH JSRP CJV JRP RFCT
9
RPCT
10 11 12 13 14 15
CRTN CJPP LDCT LOOP CONT TWB
Jump Zero Cond JSB PL Jump Map Cond Jump PL Push/Cond LD CNTR Cond JSB R/PL Cond Jump Vector Cond Jump R/PL Repeat Loop, CNTR ≠ 0 Repeat PL, CNTR ≠ 0 Cond Return Cond Jump PL & Pop LD Cntr & Continue
Test end Loop Continue Three-Way Branch
RC contents X X X X X X X X ≠0
=0 ≠0 =0 X X X X X ≠0 =0
Fail \CCEN=L \CC=H Y Stack 0 Clear PC Hold D Hold PC Hold PC Push R Push PC Hold R Hold F Hold PC Pop D Hold PC Hold PC Hold PC Hold PC Hold F Hold PC Hold F Hold D Pop
RESULT Pass RC \CCEN=H \CC=L Y Stack 0 Clear Hold D Push Hold D Hold Hold D Hold Hold PC Push Note D Push Hold D Hold Hold D Hold Hold F Hold Dec PC Pop Hold D Hold Dec PC Hold Hold F Pop Hold D Pop Hold PC Hold Load PC Pop Hold PC Hold Hold PC Pop Dec PC Pop Hold
Enable
PL PL Map PL PL PL Vect PL PL PL PL PL PL PL PL PL PL PL PL
Introducere
Proiectarea unui circuit integrat digital ( şi nu numai) presupune în primul rând înţelegerea deplină a funcţionării circuitului (a ceea ce doreşte beneficiarul proiectului) . 19
Presupunând că din datele de catalog s-a înţeles foarte bine funcţionarea circuitului, următoarea etapă este reprezentată de descompunerea circuitului în blocuri funcţionale. Această descompunere a circuitului are, în principal, următoarele motivaţii : - fiecare bloc component al circuitului poate fi încredin ţat câte unui proiectant, ceea ce duce la scăderea timpului de proiectare faţă de situaţia în care întreg proiectul ar fi încredinţat unui singur proiectant ; - detecţia, localizarea şi corectarea erorilor de proiectare sunt mult mai facile în cazul descompunerii circuitului în subcircuite ; În cazul circuitului CY7C910, pentru descompunerea acestuia în subblocuri am pornit de la diagrama bloc prezentată în catalog. Faţă de această diagramă bloc am f ăcut următoarele modificări : - blocurile “Microprogram Counter-Register” şi “Incrementer” au fost unite într-un singur bloc, numit MPC (Microprogram Counter) , deoarece : - se reduce aria consumată : un număr ător pe 12 biţi (Incrementer) şi un registru de 12 biţi (Microprogram Counter-Register) sunt înlocuiţi cu un număr ător pe 12 biţi (Microprogram Counter) . - se rezolvă unele probleme de timing : datele de la intrarea blocului Incrementer modifică ieşîrea acestuia după primul front activ al semnalului de ceas, iar încărcarea datelor de la ieşirea Incrementer-ului în Microprogram Counter-Register se face pe următorul front activ al semnalului de ceas (apare astfel o întârziere suplimentar ă de o perioadă de ceas între aplicarea datelor pe intrarea Incrementer-ului şi apariţia datelor la ieşirile blocului Microprogram Counter-Register, ceea ce ar da complet peste cap funcţionarea circuitului CY7C910) ; s-ar mai putea imagina o soluţie în care Incrementer-ul ar fi activ pe frontul negativ al semnalului de ceas, iar Microprogram-Counter-Register-ul aer fi activ pe frontul crescător al semnalului de ceas, însă şi această soluţie ar ridica anumite probleme de timing şi ar determina o scădere a frecvenţei maxime de funcţionare a circuitului CY7C910. - blocurile Stack Pointer şi 17 Word x 12 Bit Stack au fost înlocuite cu un singur bloc, numit STACK ; Iniţial am încercat să descriu separat cele două blocuri dar, în urma simulării post-sinteză a ansamblului format cu cele 2 blocuri, am constatat funcţionarea defectoasă a ansamblului. După mai mult de 10 descrieri VHDL încercate (trebuie spus că simulările pre-sinteză ar ătau funcţionarea corectă pentru fiecare din aceste descrieri), codul care a determinat funcţionarea corectă post-sinteză corespundea cazului de stivă monobloc. - apare, în plus faţă de diagrama bloc prezentată în catalog, blocul INTERFATA_SURSA care, deşi nu aduce circuitului îmbunătăţiri din punct de vedere al ariei sau vitezei (dar nici nu le influenţează negativ) , uşurează scrierea codului VHDL pentru blocul INSTRUCTION DECODER.
Diagrama bloc obţinută în urma modificărilor de mai sus
Blocurile componente pot fi la rândul lor descompuse în alte blocuri mai mici şi aşa mai departe, până când se obţin blocuri suficient de mici pentru a putea fi descrise cu uşurinţă în VHDL. În cazul circuitului CY7C910 nu am considerat necesar ă descompunerea suplimentar ă a blocurilor componente, dar am apelat la această metodă în cazul unor blocuri ale circuitului CY7C901. După descompunerea circuitului în blocuri funcţionale, se poate trece la proiectarea fiecărui bloc în parte. Pentru fiecare bloc trebuie parcurse următoarele etape : 20
1.scrierea unui program de test (test_bench) în VHDL, în care se precizează semnalele de intrare ce vor fi aplicate blocului testat şi semnalele de ieşire care ar trebui să fie determinate de semnalele de intrare. 2.scrierea unui cod VHDL care să descrie funcţionarea dorită pentru blocul proiectat ; la realizarea descrierii VHDL trebuie avut în grijă ca această descriere să fie sintetizabilă (aceasta presupune utilizarea unei sintaxe acceptate de instrumentul de sinteză) . 3.compilarea codului VHDL obţinut în etapa a 2-a şi corectarea eventualelor erori de sintaxă (erorile de funcţionare sau logice nu pot fi evidenţiate în urma compilării) ; în urma compilării este generată o entitate (entity) VHDL cu numele blocului descris ; 4. entitatea generată în etapa a 3-a este simulată cu programul de test realizat în etapa 1; dacă în urma simulării se constată o funcţionare incorectă a entităţii, trebuie să revenim la etapa a 2-a ; 5.dacă simularea cu programul de test a dovedit funcţionarea corectă a entităţii, se poate trece la sinteza descrierii VHDL obţinută în etapa a 2-a. În urma sintezei (realizate cu Design Compiler) sunt generate un fisier VHDL şi un fişier SDF (Standard Delay Format) . 6.se compilează fişierul VHDL obţinut în urma sintezei, iar entitatea generată în urma compilării este simulată (cu fişierul SDF aplicat) cu programul de test de la etapa 1. Dacă simularea arată o funcţionare corectă, îneamnă că proiectarea blocului respectiv este încheiată şi că descrierea VHDL de la etapa a 2-a poate fi folosită la realizarea circuitului CY7C910; în cazul în care simularea arată o funcţionare incorectă trebuie să ne dăm seama de cauză şi să revenim la etapa a 2-a ; această revenire la etapa de rescriere a codului VHDL poate părea ciudată întrucât simularea presinteză a dovedit corectitudinea descrierii realizate în etapa a 2-a, însă chiar eu m-am lovit de o asemenea situaţie în cazul proiectării stivei – amănunte vor fi prezentate când voi analiza proiectarea acestui bloc. După proiectarea tuturor blocurilor componente, acestea trebuie interconectate pentru a realiza împreună funcţionarea circuitului CY7C910. Această abordare corespunde metodei de proiectare “bottomup”. Package-ul
În cazul proiectelor de dimensiuni mari, întâlnim adesea funcţii, proceduri, tipuri de date sau constante care sunt folosite în mai multe componente ale proiectului sau/şi de mai mulţi proiectanţi. Dacă pe parcursul proiectării se modifică una din aceste funcţii, proceduri sau tipuri de date, este preferabil ca proiectul să fie modificat într-un singur loc, nu peste tot unde acestea au fost utilizate. Acest lucru este posibil prin utilizarea package-urilor. Package-urile sunt foarte utile şi din alt motiv: posibilitatea reutiliz ării codului VHDL pentru implementări ulterioare ale aceluiaşi circuit. De exemplu, în cazul circuitului CY7C910, stiva conţine 17 locaţii a 12 biţi ; este posibil ca in viitor să se dorească implementarea unei variante a acestui circuit dar care să dispună, de exemplu, de o stivă cu 24 de locaţii (de fapt, CY7C910 reprezintă o variantă îmbunătăţită a circuitelor din familia AM2910 ; astfel AM2910 dispune de o stiv ă cu 5 locaţii, iar AM2910A dispune de o stivă cu 9 locaţii) sau de un bus de adrese cu lăţimea de 16 biţi (în loc de 12 biţi) . Pentru acest proiect am conceput un package care să realizeze 2 funcţii : - posibilitatea reutilizării codului VHDL pentru implementări de variante ale circuitului CY7C910 cu dimensiuni diferite pentru stivă sau pentru bus-ul de adrese ; - facilitarea scrierii unui cod mai uşor de urmărit. packageCY7C910.vhd library IEEE ; use IEEE.std_logic_1164.all ; package packageCY7C910 is -- seciunea destinata reutilizarii codului si tipurilor de date care sunt -- folosite in mai multe blocuri ale proiectului constant address_bus_width : integer := 12 ; constant stack_depth : integer := 17 ; constant zero12 : std_logic_vector(address_bus_width - 1 downto 0) := "000000000000" ; subtype mem_width is std_logic_vector (address_bus_wid th - 1 downto 0) ; type mem is array (stack_depth - 1 downto 0) of mem_width ; -- sectiunea destinata scrierii unui cod usor de urmarit
21
-- sunt definite (botezate)
toate tipurile de date necesare in proiect
-- instructiunile de selectie a MULTILPEXER constant ZEROmux : std_logic_vector (2 downto 0) := "000" ; constant MPCmux : std_logic_vector (2 downto 0) := "001" ; constant Dmux : std_logic_vector (2 downto 0) := "010" ; constant Rmux : std_logic_vector (2 downto 0) := "011" ; constant Fmux : std_logic_vector (2 downto 0) := "100" ; -- instructiunile de comanda a stivei (STACK) constant Clear_s : std_logic_vector (1 downto 0) := "00" ; constant Hold_s : std_logic_vector (1 downto 0) := "01" ; constant Push_s : std_logic_vector (1 downto 0) := "10" ; constant Pop_s : std_logic_vector (1 downto 0) := "11" ; -- instructiunile de comanda a Register/Counter constant Hold : std_logic_vector (1 downto 0) := "00" ; constant DEC : std_logic_vect or (1 downto 0) := "01" ; constant Load : std_logic_vector (1 downto 0) := "10" ; -- insructiunile de comanda ale MPC (MicroProgram Counter) constant Clear : std_logic := '0' ; constant Count : std_logic := '1' ; -- instructiunile de comanda pentru INTERFATA_SURSA constant PL : std_logic_vector (1 downto 0) := "00" ; constant Mapp : std_logic_vector (1 downto 0) := "01" ; constant Vect : std_logic_vector (1 downto 0) := "10" ; -- instructiunile de comanda ale CY7C910 (I3 - I0) constant JZ : std_logic_vect or (3 downto 0) := "0000" ; constant CJS : std_logic_vector (3 downto 0) := "0001" ; constant JMAP : std_logic_vector (3 downto 0) := "0010" ; constant CJP : std_logic_vector (3 downto 0) := "0011" ; constant PUSH : std_logic_vector (3 downto 0) := "0100" ; constant JSRP : std_logic_vector (3 downto 0) := "0101" ; constant CJV : std_logic_vector (3 downto 0) := "0110" ; constant JRP : std_logic_vector (3 downto 0) := "0111" ; constant RFCT : std_logic_vector (3 downto 0) := "1000" ; constant RPCT : std_logic_vector (3 downto 0) := "1001" ; constant CRTN : std_logic_vector (3 downto 0) := "1010" ; constant CJPP : std_logic_vector (3 downto 0) := "1011" ; constant LDCT : std_logic_vector (3 downto 0) := "1100" ; constant LOP : std_logic_vector (3 downto 0) := "1101" ; constant CONT : std_logic_vector (3 downto 0) := "1110" ; constant TWB : std_logic_vector (3 downto 0) := "1111" ; -- definire de tipuri de date pt vizualizarea mai usoara a semnalelor type INSTR_type is (JZ_v, CJS_v, JMAP_v, CJP_v, PUSH_v, JSRP_v, CJV_v, JRP_v, RFCT_v, RPCT_v, CRTN_v, CJPP_v, LDCT_v, LOP_v, CONT_v, TWB_v, XXXX) ; type MUX_type is (ZEROmux_v, MPCmux_v, Dmux_v, Rmux_v, Fmux_v, XXX) ; type STACK_type is (Clear_v, Hold_v, Push_v, Pop_v, XXX) ; type RC_type is (Hold_v, Dec_v, Load_v, XXX) ; type MPC_type is (Clear_v, Count_v, XXX) ; type INT_S_type is (PL_v, Mapp_v, Vect_v, XXX) ; end packageCY7C910 ;
Acest package, numit “packageCY7C910” este salvat în fişierul “packageCY7C910.vhd”. Referitor la acest package trebuie să fac următoarea observaţie: dacă în cazul celor 16 instrucţiuni ale CY7C910 lucrurile sunt destul de clare, întrucât echivalentul binar al acestora este specificat în tabela de instrucţiuni, în cazul instrucţiunilor pentru blocurile componente ale circuitului apar unele probleme.; astfel, în mod normal, ar fi trebuit ca eu doar să definesc, pentru un anume set de instrucţiuni, tipul şi denumirea acestora (de exemplu ‘ type instr_stiva is Clear_s, Hold_s, Push_s, Pop_s ; ‘) , iar programul de sinteză, în urma optimizării, să atribuie echivalenţii binari pentru instrucţiuni ; din motive care mie îmi scap ă, doar Leonardo Spectrum acceptă această sintaxă, pe când Desing Compiler generează erori ; întrucât principalul instrument de sinteză utilizat la realizarea proiectului este Design Compiler, am preferat să folosesc package-ul de mai sus (care funcţionează şi cu Leonardo Spectrum) , în care am atribuit valori arbitrare pentru echivalenţii binari ai semnalelor interne circuitului CY7C910. 22
INSTRUCTION_DECODER Programul de test şi descrierea VHDL pentru acest bloc sunt prezentate în continuare : test_INSTRUCTION_DECODER.vhd library IEEE, STD ; use IEEE.std_logic_1164.all ; use IEEE.numeric_std.all ; use IEEE.std_logic_unsigned.all ; use IEEE.std_logic_arith.all ; use work.std_logic_arith.all ; use std.textio.all ; use work.packageCY7C910.all ; entity test_INSTRUCTION_DECODER is end ; architecture test of test_INSTRUCTION_DECODER is signal I : std_logic_v ector (3 downto 0) := "0000" ; signal nCC, nCCEN, ZERO_DET : std_logic ; signal MUX_SEL : std_logic_vector (2 downto 0) ; signal STACK_CNTL : std_logic_vector (1 downto 0) ; signal REG_CNTR_CNTL : std_logic_vector (1 downto 0) ; signal MPC_CNTL : std_logic ; signal ENABLE_CNTL : std_logic_vector (1 downto 0) ; signal test_OK : boolean := TRUE ; constant DELAY : time := 1 ns ; --DELAY_TIME ; constant T_CK : time := 10 ns ; --CK period ; component INSTRUCTION_DECODER port (I : in std_logic_vector (3 downto 0) ; nCC, nCCEN, ZERO_DET : in std_logic; MUX_SEL : out std_logic_vector (2 downto 0) STACK_CNTL : out std_logic_vector (1 downto 0) ; REG_CNTR_CNTL : out std_logic_vector (1 downto 0) ; MPC_CNTL : out std_logic ; ENABLE_CNTL : out std_logic_vector (1 downto 0) ) ; end component ;
;
-- definire de tipuri de date pt vizualizarea mai usoara a semnalelor type INSTR_type is (JZ_v, CJS_v, JMAP_v, CJP_v, PUSH_v, JSRP_v, CJV_v, JRP_v, RFCT_v, RPCT_v, CRTN_v, CJPP_v, LDCT_v, LOP_v, CONT_v, TWB_v, XXXX) ; type MUX_type is (ZEROmux_v, MPCmux_v, Dmux_v, Rmux_v, Fmux_v, XXX) ; type STACK_type is (Clear_v, Hold_v, Push_v, Pop_v, XXX) ; type RC_type is (Hold_v, Dec_v, Load_v, XXX) ; type MPC_type is (Clear_v, Count_v, XXX) ; type INT_S_type is (PL_v, Mapp_v, Vect_v, XXX) ; -- definirea semnalelor pentru vizualizarea mai usoara signal INSTRUCTION : INSTR_type ; signal MUX_SEL_v : MUX_type ; signal STACK_CNTL_v : STACK_type ; signal REG_CNTR_CNTL_v : RC_type ; signal MPC_CNTL_v : MPC_type ; signal ENABLE_CNTL_v : INT_S_type ; begin DUT : INSTRUCTION_DECODER port map
(I, nCC, nCCEN, ZERO_DET, MUX_SEL, STACK_CNTL, REG_CNTR_CNTL, MPC_CNTL, ENABLE_CNTL)
;
process begin wait for T_CK ; I <= I + 1 ; end process ; nCC <= '1', '0' after 16 * T_CK, 'X' after 32 * T_CK, '1' after 48 * T_CK, '0' after 64 * T_CK, 'X' after 80 * T_CK ; nCCEN <= '0', 'X' after 16 * T_CK, '1' after 32 * T_CK, '0' after 48 * T_CK, 'X' after 64 * T_CK, '1' after 80 * T_CK ; ZERO_DET <= 'X', '1' after 8 * T_CK, 'X' after 10 * T_CK, '1' after 15 * T_CK, 'X' after 16 * T_CK, '1' after 24 * T_CK, 'X' after 26 * T_CK, '1' after 31 * T_CK, 'X' after 32*T_CK, '0' after 40*T_CK, 'X' after 42*T_CK, '0' after 47*T_CK, 'X' after 48*T_CK, '0' after 56*T_CK, 'X' after 58*T_CK, '0' after 63 * T_CK ; process begin wait until i'event ; wait for DELAY ; case I is when JZ => if (nCC = '1' and nCCEN = '0') then if (MUX_SEL = ZEROmux and STACK_CNTL = Clear_s test_OK <= TRUE ; else test_OK <= FALSE ;
and REG_CNTR_CNTL = Hold and MPC_CNTL = Clear and ENABLE_CNTL = PL)
then
end if ; else if (MUX_SEL = ZEROmux and STACK_CNTL = Clear_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Clear and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when CJS => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Push_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when JMAP =>
23
if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = Mapp) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = Mapp) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when CJP => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when PUSH => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Push_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Push_s and REG_CNTR_CNTL = Load and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when JSRP => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Rmux and STACK_CNTL = Push_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Push_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when CJV => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = Vect) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = Vect) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when JRP => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Rmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when RFCT => case ZERO_DET is when '1' =>
24
if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Pop_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Pop_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ; end if ; end if ; when others => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Fmux and STACK_CNTL = Hold_s and REG_CNTR_CN TL = Dec and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
then
end if ; else if (MUX_SEL = Fmux and STACK_CNTL = Hold_s and REG_CNTR_CN TL = Dec and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; end case ; when RPCT => case ZERO_DET is when '1' => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ; end if ; end if ; when others => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CN TL = Dec and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Hold_s and REG_CNTR_CN TL = Dec and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; end case ; when CRTN => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Fmux and STACK_CNTL = Pop_s and REG_CNTR_CNT L = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when CJPP => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = Dmux and STACK_CNTL = Pop_s and REG_CNTR_CNT L = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ;
25
when LDCT=> if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Load and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Load and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when LOP => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Fmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Pop_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when CONT => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Hold_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; when others => -- TWB case ZERO_DET is when '1' => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Dmux and STACK_CNTL = Pop_s and REG_CNTR_CNT L = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Pop_s and REG_CNTR_CNTL = Hold and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ; end if ; end if ; when others => if (nCCEN = '0' and nCC = '1') then if (MUX_SEL = Fmux and STACK_CNTL = Hold_s and REG_CNTR_CN TL = Dec and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
then
end if ; else if (MUX_SEL = MPCmux and STACK_CNTL = Pop_s and REG_CNTR_CNTL = Dec and MPC_CNTL = Count and ENABLE_CNTL = PL) test_OK <= TRUE ; else test_OK <= FALSE ;
then
end if ; end if ; end case ; end case ; end process ; OK :
process (test_ok) begin if (test_OK'event and test_OK = FALSE) report " EROARE " severity warning ; end if ; end process ;
then
-- atribuirea de valori semnalelor destinate vizualizarii
26
process (I) begin if (I'event) then case I is when when when when when when when when when when when when when when when when when end case ;
JZ CJS JMAP CJP PUSH JSRP CJV JRP RFCT RPCT CRTN CJPP LDCT LOP CONT TWB others
end if ; end process ; process (MUX_SEL) begin if (MUX_SEL'event) then case MUX_SEL is when ZEROmux when MPCmux when Dmux when Rmux when Fmux when others end case ; end if ; end process ; process (STACK_CNTL) begin if (STACK_CNTL'event) then case STACK_CNTL is when Clear_s when Hold_s when Push_s when Pop_s when others end case ; end if ; end process ; process (REG_CNTR_CNTL) begin if (REG_CNTR_CNTL'event) then case REG_CNTR_CNTL is when Hold when Dec when Load when others end case ; end if ; end process ;
=> => => => => => => => => => => => => => => => =>
INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION
<= <= <= <= <= <= <= <= <= <= <= <= <= <= <= <= <=
=> => => => => =>
MUX_SEL_v MUX_SEL_v MUX_SEL_v MUX_SEL_v MUX_SEL_v MUX_SEL_v
=> => => => =>
STACK_CNTL_v STACK_CNTL_v STACK_CNTL_v STACK_CNTL_v STACK_CNTL_v
=> => => =>
REG_CNTR_CNTL_v REG_CNTR_CNTL_v REG_CNTR_CNTL_v REG_CNTR_CNTL_v
<= <= <= <= <= <=
JZ_v ; CJS_v; JMAP_v ; CJP_v ; PUSH_v ; JSRP_v ; CJV_v ; JRP_v ; RFCT_v ; RPCT_v ; CRTN_v ; CJPP_v ; LDCT_v ; LOP_v ; CONT_v ; TWB_v ; XXXX ;
ZEROmux_v ; MPCmux_v ; Dmux_v ; Rmux_v ; Fmux_v ; XXX ;
<= <= <= <= <=
Clear_v ; Hold_v ; Push_v ; Pop_v ; XXX ;
<= <= <= <=
Hold_v ; Dec_v ; Load_v ; XXX ;
process (MPC_CNTL) begin if (MPC_CNTL'event) then case MPC_CNTL is when Clear when Count when others end case ; end if ;
=> MPC_CNTL_v <= Clear_v ; => MPC_CNTL_v <= Count_v ; => MPC_CNTL_v <= XXX ;
end process ; process (ENABLE_CNTL) begin if (ENABLE_CNTL'event) then case ENABLE_CNTL is when PL when Mapp when Vect when others end case ; end if ; end process ; end test ;
=> => => =>
ENABLE_CNTL_v ENABLE_CNTL_v ENABLE_CNTL_v ENABLE_CNTL_v
<= <= <= <=
PL_v ; Mapp_v ; Vect_v ; XXX ;
INSTRUCTION_DECODER.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity INSTRUCTION_DECODER is port (I : in std_logic_vecto r (3 downto 0) ; nCC, nCCEN, ZERO_DET : in std_logic; MUX_SEL : out std_logic_vector (2 downto 0) ; STACK_CNTL : out std_logic_vector (1 downto 0)
;
27
REG_CNTR_CNTL : out std_logic_vector (1 downto 0) ; MPC_CNTL : out std_logic ; ENABLE_CNTL : out std_logic_vector (1 downto 0) ) ; end INSTRUCTION_DECODER ; architecture RTL of INSTRUCTION_DECODER is begin process (I, nCC, nCCEN, ZERO_DET) begin if (nCCEN = '0' and nCC = '1') then case I is when JZ => MUX_SEL <= ZEROmux ; STACK_CNTL <= Clear_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Clear ; when CJS => MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; when JMAP => MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= Mapp ; MPC_CNTL <= Count ; when CJP => MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; when PUSH => MUX_SEL <= MPCmux ; STACK_CNTL <= Push_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; when JSRP => MUX_SEL <= Rmux ; STACK_CNTL <= Push_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; when CJV => MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= Vect ; MPC_CNTL <= Count ; when JRP => MUX_SEL <= Rmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; when RFCT => if (
ZERO_DET = '1') then MUX_SEL <= MPCmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
else MUX_SEL <= Fmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Dec ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; end if ; when RPCT => if (
ZERO_DET = '1') then MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
else MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Dec ;
28
ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; end if ; when CRTN =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when CJPP =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when LDCT =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Load ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when LOP =>
MUX_SEL <= Fmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when CONT =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when others
=> -- TWB if (ZERO_DET = '1') then MUX_SEL <= Dmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; else MUX_SEL <= Fmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= DEC ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; end if ;
end case ; else case I is when JZ =>
MUX_SEL <= ZEROmux ; STACK_CNTL <= Clear_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Clear ;
when CJS =>
MUX_SEL <= Dmux ; STACK_CNTL <= Push_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when JMAP =>
MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= Mapp ; MPC_CNTL <= Count ;
when CJP =>
MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when PUSH =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Push_s ;
29
REG_CNTR_CNTL <= Load ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; when JSRP =>
MUX_SEL <= Dmux ; STACK_CNTL <= Push_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when CJV =>
MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= Vect ; MPC_CNTL <= Count ;
when JRP =>
MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when RFCT => if (
ZERO_DET = '1') then MUX_SEL <= MPCmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
else MUX_SEL <= Fmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Dec ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; end if ; when RPCT => if (
ZERO_DET = '1') then MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
else MUX_SEL <= Dmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Dec ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; end if ; when CRTN =>
MUX_SEL <= Fmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when CJPP =>
MUX_SEL <= Dmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when LDCT =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Load ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when LOP =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
30
when CONT =>
MUX_SEL <= MPCmux ; STACK_CNTL <= Hold_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ;
when others => --TWB if (ZERO_DET = '1') then MUX_SEL <= MPCmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= Hold ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; else MUX_SEL <= MPCmux ; STACK_CNTL <= Pop_s ; REG_CNTR_CNTL <= DEC ; ENABLE_CNTL <= PL ; MPC_CNTL <= Count ; end if ; end case ; end if ; end process ; end RTL ;
Descrierea VHDL pentru acest bloc nu reprezintă altceva decât transpunerea în limbaj VHDL a tabelei de instrucţiuni de la prezentarea circuitului CY7C910. Acest bloc nu a ridicat probleme deosebite de programare, însă au apărut unele probleme din cauza neatenţiei la citirea datelor din tabel, probleme care au fost evidenţiate în urma testării, fiind apoi corectate cu uşurinţă. Ar mai trebui precizat faptul că, pe cât posibil, am folosit instrucţiunea case în locul instrucţiunii if , aceasta fiind una dintre cele mai importante recomandări de proiectare.
INSTRUCTION_DECODER – (RTL)
31
Register/Counter Programul de test şi descrierea VHDL pentru acest bloc sunt prezentate în continuare : test_RC.vhd library IEEE, STD ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.packageCY7C910.all ; entity test_REGISTER_COUNTER is end ; architecture test of test_REGISTER_COUNTER is signal CK, nRLD : std_logic := '0' ; signal CNTL : std_logic_vecto r (1 downto 0) ; signal CNTL_v : RC_type ; -- pt vizualizare signal DATAIN, DATAOUT : std_logic_vector(address_bus_width - 1 downto 0) := "111000111000" ; signal DATAIN_v, DATAOUT_v : integer ; -- pentru vizualizare signal test_OK : BOOLEAN := TRUE ; signal last_DATAIN, last_DATAOUT : std_logic_vector(address_bus_width - 1 downto 0) ; constant CK_SPER : time := 5 ns ; --semiperioada semnalului de ceas constant DELAY : time := 3 ns ; component REGISTER_COUNTER port( CK, nRLD : in std_logic ; CNTL : in std_logic_vector (1 downto 0) ;
32
DATAIN : in std_logic_vector (address_bus_width - 1 downto 0) ; DATAOUT : buffer std_logic_vecto r (address_bus_w idth - 1 downto 0) ) end component ;
;
begin DUT : REGISTER_COUNTER port map (CK, nRLD, CNTL, DATAIN, DATAOUT) ; CK <= not CK after CK_SPER ; nRLD <= '0', '1' after 11 * CK_SPER ; CNTL <= Load, Dec after 4* CK_SPER, Hold after 8 * CK_SPER, Load after 14 * CK_SPER, Dec after 18 * CK_SPER, Hold after 28*CK_SPER, Load after 32*CK_SPER, Dec after 38*CK_SPER ; DATAIN <= ( (DATAIN - 5) nor (shl (DATAIN, "10") ) ) after 4 * CK_SPER ; -- generare pseudo_aleatoare a datelor de intrare DATAIN_v <= conv_integer (DATAIN) ; DATAOUT_v <= conv_integer (DATAOUT) ; process begin wait until CK = '1' ; wait for DELAY ; case nRLD is when '0' => if (DATAOUT = DATAIN) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity warning ; end if ; when others => case CNTL is when Load => if (DATAOUT = last_DATAIN) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity warning ;
then
end if ; when Dec => if (DATAOUT = last_DATAOUT - 1) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity warning ; end if ; when others => if (DATAOUT = last_DATAOUT ) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity warning ; end if ; end case ;
then
then
end case ; wait until CK = '0' ; last_DATAIN <= DATAIN ; last_DATAOUT <= DATAOUT ; end process ; process (CNTL) begin if (CNTL'event) then case CNTL is when Load => CNTL_v <= Load_v ; when Hold => CNTL_v <= Hold_v ; when Dec => CNTL_v <= Dec_v ; when others => CNTL_v <= XXX ; end case ; end if ; end process ; end test ;
33
REGISTER_COUNTER.vhd
library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.packageCY7C910.all ; entity REGISTER_COUNTER is port( CK, nRLD : in std_logic ; CNTL : in std_logic_vector (1 downto 0) ; DATAIN : in std_logic_vector (address_bus_width - 1 downto 0) ; DATAOUT : buffer std_logic_vecto r (address_bus_w idth - 1 downto 0) ) end REGISTER_COUNTER ;
;
architecture RTL of REGISTER_COUNTER is begin process (CK) begin if (CK'event and CK = '1') then case nRLD is when '0' => DATAOUT <= DATAIN ; when others => case CNTL is when Load => DATAOUT <= DATAIN ; when Dec => DATAOUT <= DATAOUT - 1 ; when others => null ; end case ; end case ; end if ; end process ; end RTL ;
REGEISTER_COUNTER – (RTL)
REGISTER_COUNTER – (RTL)
34
În cazul acestui bloc, se observă (prima figur ă) că programul de sinteză a recunoscut, din codul VHDL, structurile a 2 dintre macrocelule din biblioteca sa de componente şi anume : decoder_2 şi counter_dn_sload_clock_clk_en_12. În a doua figur ă sunt prezentate şi arhitecturile interne ale celor două macrocelule.
STACK
Programul de test şi descrierea VHDL ale acestui bloc sunt prezentate mai jos: test_STACK.vhd library IEEE, STD ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.std_logic_arith.all ; use work.packageCY7C910.all ; entity test_STACK is end ; architecture test of test_STACK is signal CK : std_logic := '0' ; signal nFULL : std_logic ; signal CNTL : std_logic_vector (1 downto 0) := "00" ; signal CNTL_v : STACK_type ; -- pentru vizualizare signal DATAIN, DATAIN_pre : std_logic_vecto r (address_bus_wi dth - 1 downto 0) signal DATAOUT : std_logic_vecto r (address_bus_wi dth - 1 downto 0) ; signal test_OK : BOOLEAN := TRUE ; constant CK_HPER : time := 5 ns ; constant DELAY : time := 3 ns ; subtype vec12 is std_logic_vecto r (11 downto 0) ; type mem20 is array (19 downto 0) of vec12 ; signal MEMORIE : mem20 ; signal DATAOUT_pre : std_logic_vector (address_bus_width - 1 downto 0) ; signal nFULL_PRE : std_logic ; signal DATAIN_v, DATAOUT_v : integer ; -- pentru vizualizare component STACK port( CK : in std_logic ; DATAIN : in std_logic_vecto r (address_bus_w idth - 1 downto 0) ; CNTL : in std_logic_vect or (1 downto 0) ; nFULL : out std_logic ; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) end component ; begin DUT : STACK port map
(CK, DATAIN, CNTL, nFULL, DATAOUT)
;
;
;
process (CK) begin MEMORIE (0) <= "111000111000" ; if (CK'event) then for k in 1 to 19 loop MEMORIE (k) <= (MEMORIE (k-1) - 57) xor (shl (MEMORIE (k-1) , "11") ) after 1 ns ; end loop ; end if ; end process ; CK <= not CK after CK_HPER ; CNTL <= Clear_s, Push_s after 4*CK_HPER, Hold_s after 44*CK_HPER, Pop_s after 48*CK_HPER ; process variable n : integer := 0 ;
35
begin wait until (CK'event and CK = '0') DATAIN_pre <= MEMORIE (n) ; if (n < 19) then n := n + 1 ; else n := n ; end if ;
;
end process ; DATAIN <= DATAIN_pre after 2*CK_HPER ; process variable n : integer := 0 ; variable EMPTY : bit ; begin wait until (CK'event and CK = '1') ; wait for DELAY ; case CNTL is when Clear_s => EMPTY := '1' ; if (DATAOUT = zero12 and nFULL = '1' ) then test_OK <= TRUE ; else test_OK <= FALSE ; report " Eroare la Clear" severity Warning ; end if ; when Push_s => case EMPTY is when '1' => EMPTY := '0' ; n := n ; when others => if (n = 16) then n := n ; else n := n + 1 ; end if ; end case ; if( (DATAOUT /= DATAIN) or (n = 16 and nFULL /= '0')) then test_OK <= FALSE ; report " EROARE la PUSH" severity Warning ; else test_OK <= TRUE ; end if ; when Pop_s => if (n = 16) then if (DATAOUT = MEMORIE (15) and nFULL = '1') then n := n - 2 ; test_OK <= TRUE ; else n := n - 1 ; test_OK <= FALSE ; report " Eroare la Pop " severity Warning ; end if ; else if (DATAOUT = MEMORIE (n) and nFULL = '1') then if (n = 0) then n := n ; EMPTY := '1' ; else n := n - 1 ; end if ; test_OK <= TR UE ; else if (n = 0) then n := n ; EMPTY := '1' ; else n := n - 1 ; end if ; test_OK <= FALSE ; report " Eroare la Pop " severity Warning ; end if ; end if ;
36
when others => -- Hold if (DATAOUT = DATAOUT_pre and nFULL = nFULL_pre) test_OK <= TRUE ; else test_OK <= FALSE ; report " Eroare la Hold" severity Warning ; end if ; end case ; end process ;
then
process -- se memoreaza starea anterioara a iesirii in DATAOUT_pre si nFULL_pre begin wait until (CK'event and CK = '0') ; DATAOUT_pre <= DATAOUT ; nFULL_pre <= nFULL ; end process ; DATAIN_v <= conv_integer (DATAIN) ; DATAOUT_v <= conv_integer (DATAOUT) ; process (CNTL) begin if (CNTL'event) then case CNTL is when Clear_s => CNTL_v <= Clear_v ; when Hold_s => CNTL_v <= Hold_v ; when Push_s => CNTL_v <= Push_v ; when Pop_s => CNTL_v <= Pop_v ; when others => CNTL_v <= XXX ; end case ; end if ; end process ; end test ;
STACK.vhd library IEEE ; use IEEE.std_logic_1164.all ; use IEEE.std_logic_unsigned.all ; use work.NUMERIC_STD.all ; use work.packageCY7C910.all ; entity STACK is port( CK : in std_logic ; DATAIN : in std_logic_vecto r (address_bus_w idth - 1 downto 0) ; CNTL : in std_logic_vector (1 downto 0) ; nFULL : out std_logic ; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) end STACK ; architecture RTL of STACK is signal ram : mem ; -- registrii stivei signal S_EMPTY : std_logic ; signal COUNT : std_logic_vecto r (4 downto 0)
;
;
begin process (CK) begin if (CK'event and CK = '1') then case CNTL is when Clear_s => COUNT <= "00000" ; ram(0) <= zero12 ; S_EMPTY <= '1' ; nFULL <= '1' ; DATAOUT <= zero12 ; when Push_s => if (COUNT = "01111" ) then nFULL <= '0' ; S_EMPTY <= '0' ; ram(TO_INTEGER(UNSIGNED(COUNT + 1)))<=DATAIN; COUNT <= COUNT + 1 ; DATAOUT <= DATAIN ; else if (S_EMPTY = '1' or COUNT = "10000") then ram(TO_INTEGER(UNSIGNED(COUNT)))<=DATAIN; S_EMPTY <= '0' ; DATAOUT <= DATAIN ; else
37
ram(TO_INTEGER(UNSIGNED(COUNT + 1)))<=DATAIN; COUNT <= COUNT + 1 ; DATAOUT <= DATAIN ; end if ; end if ; when Pop_s => if (COUNT = "00000") then DATAOUT <=ram(TO_INTEGER(UNSIGNED(COUNT))) ; nFULL <= '1' ; S_EMPTY <= '1' ; else DATAOUT<=ram(TO_INTEGER(UNSIGNED(COUNT)+ 31)); COUNT <= COUNT + 31 ; -- <=> COUNT <= COUNT - 1 nFULL <= '1' ; end if ; when others => -- Hold_s DATAOUT <= ram(TO_INTEGER(U NSIGNED(COUNT))) ; end case ; end if ; end process ; end RTL ;
Deşi forma finală a descrierii VHDL pentru acest bloc este destul de simplă, trebuie să spun că pentru a ajunge la această formă am rescris codul de mai mult de zece ori pe parcursul câtorva zile. Pentru implementarea regiştrilor stivei am folosit semnalul ram, pe care l-am declarat de tip mem, tip descris în packageCY7C910.vhd. Întrucât în cazul stivei memoria este desul de mică (17 x 12 = 208 biţi ~ 26 octeţi) , este ermisă descrierea memoriei sub forma unei matrici. Pentru memorii de dimensiuni mai mari, această metodă este total neindicată, în aceste cazuri utilizându-se compilatoare de memorie. Chiar şi în cazul acestei memorii de dimensiuni reduse, aria ocupată de aceasta reprezintă aproximativ 85% din aria totală a circuitului. Semnalul COUNT joacă rolul STACK_POINTER-ului, indicând locaţia din vârful stivei. Întrucât stiva are 17 regiştri, semnalul COUNT a fost definit ca vector std_logic de dimensiune 5. (2^4 < 17 < 2^5) . Am introdus un semnal intern, S_EMPTY, care semnalează dacă stiva este goală. Necesitatea acestui semnal rezultă din următoarea situaţie : - presupunem că, la un moment dat, COUNT = 1, ram(1) = N1, ram(0) = N0 deci DATAOUT = N1 ; - se execută o instrucţiune Pop_s => COUNT = 0, ram(0) = N0, DATAOUT = N0 ; - din acest moment consider ăm următoarele 2 situaţii : 1. se execută Push_s N => COUNT = 1, ram(1) = N, ram(0) = N0, DATAOUT = N ; 2. se execută Pop_s urmat de Push_s N ; - după Pop_s => COUNT = 0, ram(0) = N0, DATAOUT = N0, deci practic nu se modifică nimic ; - deci succesiunea POP_s, Push_s N ar avea acelaşi efect cu înstrucţiunea Push_s N de la situaţia 1. De fapt, se doreşte ca în urma situaţiei 2 să rezulte COUNT = 0, ram(0) = N, DATAOUT = N. Pentru aceasta, avem nevoie de un flag suplimentar, S_EMPTY, S_EMPTY devine activ atunci când COUNT = 0 şi se execută o instrucţiune Pop_s. S_EMPTY este dezactivat atunci când COUNT = 0, S_EMPTY = 1 şi se execută o instrucţiune Push_s. În această descriere am folosit funcţia TO_INTEGER() din package-ul std_logic_unsigned, funcţie care realizează conversia din vector std_logic în întreg. Dintre toate blocurile circuitului CY7C910, stiva mi-a creat cele mai multe probleme. Primele probleme au apărut chiar de la simularea presinteză. Iniţial, pentru instrucţiunea Push_s de exemplu, codul ar ăta cam aşa : if (CK’event and CK = ‘1’) then case CNTL is
.......................................... when Push_s => .................................. COUNT <= COUNT + 1 ; ram(TO_INTEGER (UNSIGNED (COUNT) ) ) <= DATAIN ; DATAOUT <= ram(TO_INTEGER (UNSIGNED (COUNT) ) ) ; ...................................................
38
O asemenea descriere ar da rezultatele scontate într-un limbaj de programare precum C –ul. În cazul VHDL situaţia este cu totul alta. Astfel, semnalul COUNT este incrementat corect, însă în instrucţiunea ram(TO_INTEGER (UNSIGNED (COUNT) ) ) <= DATAIN ; semnalul COUNT nu are valoarea incrementată (obţinută în urma executării instrucţiunii anterioare) , ci valoarea anterioar ă frontului pozitiv al semnalului de ceas. Ca urmare, am modificat descrierea VHDL astfel : ............................................................. when Push_s => .......................................... ram(TO_INTEGER (UNSIGNED (COUNT + 1) ) ) <= DATAIN ; COUNT <= COUNT + 1 ; DATAOUT <= DATAIN ; ......................................................................... when Pop_s => .................................................... DATAOUT <= ram(TO_INTEGER (UNSIGNED (COUNT - 1) ) ) ; COUNT <= COUNT – 1 ; .............................................................................
Această descriere a dat rezultatele aşteptate la simularea presinteză, însă au apărut probleme la simularea postsinteză. În cazul instrucţiunilor Push_s, circuitul funcţiona corect, însă în cazul instrucţiunilor Pop_s execuţia acestora era întârziată cu o perioadă de ceas. Acest fapt mi s-a părut ciudat, mai ales că, după părerea mea, execuţia instrucţiunii Pop_s este mult mai simplă decât execuţia instrucţiunii Push_s, întrucât data care trebuie scoasă la ieşirile DATAOUT se află deja în unul din regiştrii stivei. După mai multe modificări ale codului VHDL care nu au eliminat această problemă, mi-am dat seama că problema ar putea fi cauzată tocmai de folosirea operaţiei de scădere în cazul instrucţiunii Pop_s. Prin urmare, am încercat să elimin operaţia de scădere din codul VHDL, ceea ce am reuşit prin înlocuirea COUNT – 1 cu COUNT + 31 (31 = 11111B) În urma acestei modificări simulările presinteză şi postsinteză au ar ătat o funcţionare corectă a circuitului.
STACK – (RTL)
STACK – (RTL) – vedere parţială
39
MPC (MicroProgram Counter) Programul de testare şi descrierea VHDL pentru acest bloc sunt prezentate în continuare : test_MPC.vhd library IEEE, STD ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.std_logic_arith.all ; use work.packageCY7C910.all ; entity test_MPC is end ; architecture test of test_MPC is signal CK, CI : std_logic := '0' ;
40
signal MPC_CNTL : std_logic ; signal MPC_CNTL_v : MPC_type ; -- pentru vizualizare signal DATAIN : std_logic_vector (address_bus_width - 1 downto 0) := "111000111000" ; signal DATAOUT : std_logic_vector ( address_bus_wid th - 1 downto 0) ; constant CK_HPER : time := 5 ns ; -- semiperioada semnalului de ceas constant DELAY : time := 3 ns ; signal test_OK : boolean := TRUE ; signal DATAIN_v, DATAOUT_v : integer ; -- pentru vizualizare component MPC port (CK, CI : in std_logic ; DATAIN : in std_logic_vector ( address_bus_widt h - 1 downto 0) ; MPC_CNTL : in std_logic ; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) end component ;
;
begin DUT : MPC port map (CK, CI, DATAIN, MPC_CNTL, DATAOUT) ; CLOCK : CK <= not CK after CK_HPER ; process -- generare pseudo-aleatoare a DATAIN begin wait until (CK’event and CK = ‘0’) ; DATAIN_gen : DATAIN <= (DATAIN - 57) xor (shl (DATAIN, "11") ) ; end process ; CI <= DATAIN(5) ; -- generare pseudo aleatoare a semnalului CARRY MPC_CNTL <= Clear, Count after 6*CK_HPER, Clear after 12*CK_HPER, Count after 16*CK_HPER ; DATAIN_v <= conv_integer (DATAIN) ; DATAOUT_v <= conv_integer (DATAOUT) ; process variable DATAOUT_var : std_logic_vecto r (address_bus_widt h - 1 downto 0); begin wait until CK = '1' ; DATAOUT_var := DATAIN ; wait for DELAY ; case MPC_CNTL is when Clear => if (DATAOUT = zero12) then test_OK <= TRUE ; else test_OK <= FALSE ; report "Eroare la Clear" severity Warning ; end if ; when others => -- Count case CI is when '1' => if (DATAOUT = DATAOUT_var + 1) then test_OK <= TRUE ; else test_OK <= FALSE ; report "Eroare la numarare cu CI = 1" severity Warning ; end if ; when others => if (DATAOUT = DATAOUT_var) then test_OK <= TRUE ; else test_OK <= FALSE ; report "Eroare la numarare cu CI = 0" severity Warning ; end if ; end case ; end case ; end process ; process (MPC_CNTL) begin if (MPC_CNTL'event) then case MPC_CNTL is when Clear => MPC_CNTL_v <= Clear_v ; when Count => MPC_CNTL_v <= Count_v ; when others => MPC_CNTL_v <= XXX ; end case ; end if ; end process ; end test ;
41
MPC.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.packageCY7C910.all ; entity MPC is port (CK, CI : in std_logic ; DATAIN : in std_logic_vector ( address_bus_widt h - 1 downto 0) ; MPC_CNTL : in std_logic ; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) end MPC ; architecture RTL of MPC is begin process (CK) begin if (CK'event and CK = '1') then if (MPC_CNTL = Clear) then DATAOUT <= zero12 ; else DATAOUT <= DATAIN + CI ; end if ; end if ; end process ; end RTL ;
;
Se poate observa cu uşurinţă că în cazul acestui bloc programul de test este mult mai lung decât descrierea propriuzisă. În plus, realizarea unui program de test implică găsirea unei soluţii optime prin care, cu un număr suficient de mic de vectori de test, circuitul s ă poată fi adus în toate situaţiile de interes. După realizarea descrierilor VHDL şi a programelor de test pentru circuitele CY7C910 şi CY7C901, pot să spun că timpul consumat pentru realizarea programelor de test a fost de 5-6 ori mai mare decât pentru realizarea descrierilor.
MPC – (RTL)
42
interfaţa_sursă
Am introdus acest bloc pentru uşurarea scrierii codului VHDL pentru blocul Instruction Decoder. Acest bloc are o intrare pe 2 biţi care provine de la Instruction Decoder şi, în funcţie de valorile de pe intrare, activează (pune pe nivel LOW) un singur semanal din cele 3 semnale de ieşire (nPL, nVECT, nMAP) , celelalte două fiind dezactivate. Întrucât acest bloc este foarte simplu, voi include aici doar descrierea VHDL, programul de test putând fi găsit pe CD-ul anexat la proiect. interfata_sursa.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity interfata_sursa is port (DATAIN : in std_logic_vector (1 downto 0) nPL, nMAP, nVECT : out std_logic) ; end interfata_sursa ; architecture RTL of interfata_sursa is begin process (DATAIN) begin case DATAIN is when PL => nPL <= '0' ; nMAP <= '1' ; nVECT <= '1' ; when Mapp => nPL <= '1' ; nMAP <= '0' ; nVECT <= '1' ; when others => -- Vect nPL <= '1' ; nMAP <= '1' ; nVECT <= '0' ; end case ; end process ;
;
end RTL ;
interfata_sursa – (RTL)
43
Blocurile MULTIPLEXER, ZERO_DETECTOR şi TS_BUFFER sunt simple şi nu ridică probleme deosebite. Prin urmare, voi prezenta doar descrierile VHDL corespunzătoare acestor blocuri, programele de test putând fi găsite pe CD-ul anexat proiectului. MULTIPLEXER.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity MULTIPLEXER is port (D, R, F, MPC : in std_logic_vecto r (address_bus_width - 1 downto 0) ; MUX_SEL : in std_logic_vector (2 downto 0) ; MUXOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) ; end MULTIPLEXER ; architecture RTL of MULTIPLEXER is begin process (D, R, F, MPC, MUX_SEL) begin case MUX_SEL is when Dmux => MUXOUT <= D ; when Rmux => MUXOUT <= R ; when Fmux => MUXOUT <= F ; when ZEROmux => MUXOUT <= zero12 ; when others => MUXOUT <= MPC ; end case ; end process ; end RTL ;
ZERO_DETECTOR.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity ZERO_DETECTOR is port (DATAIN : in std_logic_vector (address_bus_wi dth - 1 downto 0) DATAOUT : out std_logic) ; end ZERO_DETECTOR ; architecture RTL of ZERO_DETECTOR is begin process (DATAIN) begin if (DATAIN = zero12) then DATAOUT <= '1' ; else DATAOUT <= '0' ; end if ; end process ; end RTL ;
;
TS_BUFFER.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity TS_BUFFER is port (DATAIN : in std_logic_vector (address_bus_wi dth - 1 downto 0) ; nOE : in std_logic ; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) end TS_BUFFER ; architecture RTL of TS_BUFFER is begin process (nOE, DATAIN) begin if (nOE = '0') then DATAOUT <= DATAIN ; else DATAOUT <= "ZZZZZZZZZZZZ" ; end if ; end process ; end RTL ;
;
ZERO_DETECTOR – (RTL)
44
MULTIPLEXER – (RTL)
TS_BUFFER – (RTL)
MULTIPLEXER – forme de undă
CY7C910
Blocurile funcţionale descrise anterior trebuie asamblate astfel încât împreună să aibă funcţionalitatea circuitului CY7C910. Codul VHDL care ralizează această asamblare este prezentat în continuare : CY7C910.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity CY7C910 is port ( D : in std_logic_vecto r (address_bus_wi dth - 1 downto 0) ; nRLD : in std_logic ; I : in std_logic_vecto r (3 downto 0) ; nCC :in std_logic ; nCCEN : in std_logic ; CP : in std_logic ; CI : in std_logic ; nOE : in std_logic ; Y : out std_logic_vect or (address_bus_width - 1 downto 0) ; nFULL : out std_logic ; nPL : out std_logic ; nMAP : out std_logic ; nVECT : out std_logic) ; end CY7C910 ; architecture structural of CY7C910 is signal Y_BUS, MPC_BUS, F_BUS, R_BUS : std_logic_vecto r(address_bus_wi dth - 1 downto 0); signal STACK_CNTL : std_logic_vector (1 downto 0) ;
45
signal signal signal signal signal
MPC_CNTL : std_logic ; MUX_CNTL : std_logic_vector (2 downto 0) ; RC_CNTL : std_logic_vecto r (1 downto 0) ; ZERO_DET : std_logic ; SURSA_DET : std_logic_vector (1 downto 0) ;
-- declararea blocurilor componente component INSTRUCTION_DECODER port (I : in std_logic_vector(3 downto 0) ; nCC, nCCEN, ZERO_DET : in std_logic; MUX_SEL : out std_logic_vector(2 downto 0) ; STACK_CNTL : out std_logic_vector(1 downto 0); REG_CNTR_CNTL : out std_logic_vector (1 downto 0) ; MPC_CNTL : out std_logic ; ENABLE_CNTL : out std_logic_vector (1 downto 0) ) ; end component ; component MPC port (CK, CI : in std_logic ; DATAIN : in std_logic_vector ( address_bus_widt h - 1 downto 0) ; MPC_CNTL : in std_logic ; DATAOUT : out std_logic_vector(address_bus_width - 1 downto 0) ); end component ; component MULTIPLEXER port (D, R, F, MPC : in std_logic_vecto r (address_bus_width - 1 downto 0) ; MUX_SEL : in std_logic_vecto r (2 downto 0) ; MUXOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) ; end component ; component REGISTER_COUNTER port (CK, nRLD : in std_logic ; CNTL : in std_logic_vector (1 downto 0) ; DATAIN : in std_logic_vector (address_bus_width - 1 downto 0) ; DATAOUT : buffer std_logic_vecto r (address_bus_w idth - 1 downto 0) ) end component ;
;
component STACK port(CK : in std_logic ; DATAIN : in std_logic_vector(address_bu s_width - 1 downto 0); CNTL : in std_logic_vector (1 downto 0) ;nFULL : out std_logic ; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) ; end component ; component TS_BUFFER port (DATAIN : in std_logic_vector(address_bus_width - 1 downto 0); nOE : in std_logic; DATAOUT : out std_logic_vector (address_bus_width - 1 downto 0) ) ; end component ; component interfata_sursa port(DATAIN : in std_logic_vector(1 downto 0) ; nPL, nMAP, nVECT : out std_logic); end component ; component ZERO_DETECTOR port(DATAIN : in std_logic_vector(address_bus_width - 1 downto 0) ; DATAOUT : out std_logic); end component ; begin -- Instanţierea blocurilor componente INSTR_DEC : INSTRUCTION_DEC ODER port map (I, nCC, nCCEN, ZERO_DET, MUX_CNTL, STACK_CNTL, RC_CNTL, MPC_CNTL, SURSA_DET) ; MPC_i : MPC port map (CP, CI, Y_BUS, MPC_CNTL, MPC_BUS) ; MUX_i : MULTIPLEXER port map (D, R_BUS, F_BUS, MPC_BUS, MUX_CNTL, Y_BUS) ; RC_i : REGISTER_COUNTE R port map (CP, nRLD, RC_CNTL, D, R_BUS) ; ZERO_i : ZERO_DETECTOR port map (R_BUS, ZERO_DET) ; STACK_i : STACK port map (CP, MPC_BUS, STACK_CNTL, nFULL, F_BUS) ; TSB_i : TS_BUFFER port map (Y_BUS, nOE, Y) ; INTF_SURSA : interfata_sursa port map (SURSA_DET, nPL, nMAP, NVECT) ; end structural ;
46
Sinteza circuitului CY7C910
După ce am realizat descrierea VHDL pentru circuitul CY7C910 şi, în urma simulărilor, m-am convins de corectitudinea acesteia, trebuie realizată sinteza acestei descrieri VHDL. Trebuie să precizez că în această lucrare nu mi-am propus să aprofundez metodele de optimizare a procesului de sinteză, întrucât sinteza este un domeniu cu totul diferit de scrierea de cod VHDL pentru sinteză. Învăţarea temeinică a tehnicilor de sinteză necesită o perioadă de timp îndelungată, iar, în cadrul firmelor din domeniu, scrierea codului VHDL şi sinteza acestui cod sunt activit ăţi separate, realizate de persoane diferite. Ceea ce am dorit eu, prin sinteza codului VHDL, a fost să mă conving că acest cod VHDL este întradevăr sintetizabil şi că circuitul generat de programul de sinteză se comportă conform aşteptărilor. Sinteza circuitului CY7C910 am realizat-o cu programul Design Compiler din cadrul pachetului de programe Synopsys. Pentru realizarea sintezei este nevoie, în primul rând, de fişiere tehnologice. Sinteza circuitului CY7C910 am realizat-o într-o tehnologie de 0.35 µm, fişierele tehnologice folosite fiin : - “tcb773pwc.db” – biblioteca de celule de CORE (standard cells) ; - “tcb773p.sdb” – biblioteca de simboluri pentru componentele din biblioteca de celule standard ; - “tcb773p.v” – fişier Verilog care conţine descrierile Verilog ale componentelor din biblioteca de celule standard ; acest fişier nu este folosit la sinteză, ci la simularea postsinteză ; Apoi, în fişierul “.synopsys_dc.setup” de configurare a programului de sinteză trebuie indicate căile către fişierele tehnologice, precum şi alte reguli care trebuie respectate la sinteză. .synopsys_dc.setup /* Setari pentru tehnologia TSMC035 - tcb773p - Worst Case */ /* tcb773pwc.db este biblioteca de celule de CORE (standard-cells) */ designer = "Ieremie Ionut" company = "ETC" search_path = { ., synopsys_root + /libraries/syn} search_path = {scripts} + search_path hdlin_translate_off_skip_text = TRUE link_library = {"*" tcb773pwc.db} target_library = {tcb773pwc.db} symbol_library = {tcb773p.sdb} default_schematic_options = "-size infinite" define_design_lib work -path work /* CACHE directory settings */ cache_write = ./cache cache_read = ./cache cache_write_info = "false" cache_read_info = "false" /* Site Specific Variables */ synthetic_library = {C:/Synopsys/libraries/syn/standard.sldb} command_log_file = "./command.log" view_command_log_file = "./view_command.log" plot_command = "lpr -Plw" text_print_command = "lpr -Plw" /* enable Text Viewer feature */ hdlin_source_to_gates_mode = "off" hdlin_report_inferred_modules = "verbose" /* Synopsys to Compass EDIF interface */ edifin_ground_name = "VSS" edifin_ground_net_name = "VSS" edifin_ground_net_property_name = "global" edifin_ground_net_property_value = "VSS" edifin_ground_pin_name = "VSS" edifin_ground_port_name = "VSS" edifin_netlist_only = "true" edifin_power_name = "VDD" edifin_power_net_name = "VDD" edifin_power_net_property_name = "global"
47
edifin_power_net_property_value = "VDD" edifin_power_pin_name = "VDD" edifin_power_port_name = "VDD" edifin_power_and_ground_representation = "net" edifout_ground_name = "VSS" edifout_ground_net_name = "VSS" edifout_ground_net_property_name = "global" edifout_ground_net_property_value = "VSS" edifout_ground_pin_name = "VSS" edifout_ground_port_name = "VSS" edifout_netlist_only = "true" edifout_no_array = "true" edifout_power_name = "VDD" edifout_power_net_name = "VDD" edifout_power_net_property_name = "global" edifout_power_net_property_value = "VDD" edifout_power_pin_name = "VDD" edifout_power_port_name = "VDD" edifout_power_and_ground_representation = "net" write_name_nets_same_as_ports = "true" compile_fix_multiple_port_nets = "true" verilogout_no_tri = "true" include TSMC_naming_rule.script /* change_names -rules asic_core_rules -verbose -hierarchy */
Apoi, pentru realizarea sintezei, se realizează un script, “compile.scr”, în care sunt grupate directivele de sinteză. compile.scr design = CY7C910 analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl elaborate -library work design
sources/packageCY7C910.vhd sources/INSTRUCTION_DECODER.vhd sources/interfata_sursa.vhd sources/MPC.vhd sources/MULTIPLEXER.vhd sources/REGISTER_COUNTER.vhd sources/Stack.vhd sources/TS_BUFFER.vhd sources/ZERO_DETECTOR.vhd sources/ + design + ".vhd"
set_wire_load_model -library tcb773pwc -name TSMC16K_Conservative set_wire_load_mode enclosed create_clock -name CLK -period 20 -waveform { 0 5 } { CP } set_output_delay 12 -clock CLK all_outputs() set_dont_touch_network { CLK } group_path -name fromI -from { I } group_path -name fromnCC -from { nCC } group_path -name fromnCCEN -from { nCCEN } group_path -name fromCI -from { CI } compile -map_effort high create_schematic -all report -area > "reports/" + design + "_area_report.txt" report -timing > "reports/" + design + "_timing_report.txt" check_design check_timing write -f db -hier -o "db/" + design + "_mapped.db" write_sdf "netlist/" + design + "_mapped.sdf" write -format vhdl -hierarchy -output "netlist/" + design + "_mapped.vhd" write -format verilog -hierarchy -output "netlist/" + design + "_mapped.v"
În urma sintezei sunt generate următoarele fişiere : - “CY7C910_mapped.vhd” – descrierea VHDL a circuitului implementat cu celule standard generat de programul de sinteză ; 48
- “CY7C910_mapped.v” - descrierea Verilog a circuitului implementat cu celule standard generat de programul de sinteză ; - “CY7C901_mapped.sdf” - conţine informaţiile despre întârzierile pe căile de semnal interne circuitului - “CY7C910_timing_report.txt” – fişier text în care se raportează modul în care au fost respectae constrângerile de timing ; - “CY7C910_area_report.txt” – fişier text în care se raporteză modul în care au fost respectate constrângerile de arie ; - “CY7C910_mapped.db” – fişier în format Synopsys ; Dintre aceste fişiere, voi reda în continuare doar fişierele de raport de timing şi arie, aceste fiind singurele atât scurte, cât şi relevante. CY7C910_timing_report.txt **************************************** Report : timing -path full -delay max -max_paths 1 Design : CY7C910 Version: 2000.05 Date : Tue May 13 10:49:02 2003 **************************************** Operating Conditions: WCCOM Library: tcb773pwc Wire Load Model Mode: enclosed Startpoint: RC_i/DATAOUT_reg[3] (rising edge-triggered flip-flop clocked by CLK) Endpoint: Y[11] (output port clocked by CLK) Path Group: CLK Path Type: max Des/Clust/Port Wire Load Model Library -----------------------------------------------CY7C910 TSMC16K_Conservative tcb773pwc ZERO_DETECTOR TSMC16K_Conservative tcb773pwc INSTRUCTION_DECODER TSMC8K_Conservative tcb773pwc TS_BUFFER TSMC8K_Conservative tcb773pwc MULTIPLEXER TSMC8K_Conservative tcb773pwc Point Incr Path -------------------------------------------------------------------------clock CLK (rise edge) 0.00 0.00 clock network delay (ideal) 0.00 0.00 RC_i/DATAOUT_reg[3]/CP (DFCNS1Q) 0.00 0.00 r RC_i/DATAOUT_reg[3]/Q (DFCNS1Q) 1.11 1.11 r RC_i/DATAOUT[3] (REGISTER_COUNTER) 0.00 1.11 r ZERO_i/DATAIN[3] (ZERO_DETECTOR) 0.00 1.11 r ZERO_i/U9/Z (OR3D1) 0.78 1.90 r ZERO_i/U11/ZN (NR8D3) 1.34 3.24 f ZERO_i/DATAOUT (ZERO_DETECTOR) 0.00 3.24 f INSTR_DEC/ZERO_DET (INSTRUCTION_DECODER) 0.00 3.24 f INSTR_DEC/U100/ZN (ND2D1) 0.23 3.47 r INSTR_DEC/U103/ZN (NR2D1) 0.21 3.68 f INSTR_DEC/U104/Z (MUX2D2) 0.59 4.27 f INSTR_DEC/U115/ZN (OAI21D0) 0.33 4.60 r INSTR_DEC/U87/ZN (IND2D1) 0.46 5.07 f INSTR_DEC/MUX_SEL[1] (INSTRUCTION_DECODER) 0.00 5.07 f MUX_i/MUX_SEL[1] (MULTIPLEXER) 0.00 5.07 f MUX_i/U9/Z (MUX2D1) 0.64 5.71 f MUX_i/U51/ZN (INV1) 0.52 6.23 r MUX_i/U48/ZN (MOAI22D0) 0.52 6.75 r MUX_i/U35/ZN (IOA221D0D) 0.77 7.52 r MUX_i/MUXOUT[11] (MULTIPLEXER) 0.00 7.52 r TSB_i/DATAIN[11] (TS_BUFFER) 0.00 7.52 r TSB_i/U14/ZN (INV1) 0.23 7.75 f TSB_i/DATAOUT_tri[11]/ZN (INVTN1) 0.22 7.97 r TSB_i/DATAOUT[11] (TS_BUFFER) 0.00 7.97 r Y[11] (out) 0.00 7.97 r data arrival time 7.97 clock CLK (rise edge) 20.00 20.00 clock network delay (ideal) 0.00 20.00 output external delay -12.00 8.00 data required time 8.00 -------------------------------------------------------------------------data required time 8.00 data arrival time -7.97 -------------------------------------------------------------------------slack (MET) 0.03
49
Startpoint: CI (input port) Endpoint: MPC_i/DATAOUT_reg[11] (rising edge-triggered flip-flop clocked by CLK) Path Group: fromCI Path Type: max Des/Clust/Port Wire Load Model Library -----------------------------------------------CY7C910 TSMC16K_Conservative tcb773pwc MPC TSMC8K_Conservative tcb773pwc Point Incr Path -------------------------------------------------------------------------clock (input port clock) (rise edge) 0.00 0.00 input external delay 0.00 0.00 r CI (in) 0.00 0.00 r MPC_i/CI (MPC) 0.00 0.00 r MPC_i/add_17/plus/plus/U1_0/CO (FA1D1) 0.95 0.95 r MPC_i/add_17/plus/plus/U1_1/CO (FA1D1) 0.60 1.54 r MPC_i/add_17/plus/plus/U1_2/CO (FA1D1) 0.59 2.13 r MPC_i/add_17/plus/plus/U1_3/CO (FA1D1) 0.59 2.73 r MPC_i/add_17/plus/plus/U1_4/CO (FA1D1) 0.59 3.32 r MPC_i/add_17/plus/plus/U1_5/CO (FA1D1) 0.59 3.92 r MPC_i/add_17/plus/plus/U1_6/CO (FA1D1) 0.59 4.51 r MPC_i/add_17/plus/plus/U1_7/CO (FA1D1) 0.59 5.11 r MPC_i/add_17/plus/plus/U1_8/CO (FA1D1) 0.59 5.70 r MPC_i/add_17/plus/plus/U1_9/CO (FA1D1) 0.59 6.29 r MPC_i/add_17/plus/plus/U1_10/CO (FA1D1) 0.57 6.87 r MPC_i/U27/Z (XOR2D1) 0.61 7.48 f MPC_i/DATAOUT_reg[11]/EN (DFCNE2Q) 0.00 7.48 f data arrival time 7.48 clock CLK (rise edge) 20.00 20.00 clock network delay (ideal) 0.00 20.00 MPC_i/DATAOUT_reg[11]/CP (DFCNE2Q) 0.00 20.00 r library setup time -0.52 19.48 data required time 19.48 -------------------------------------------------------------------------data required time 19.48 data arrival time -7.48 -------------------------------------------------------------------------slack (MET) 12.00 Startpoint: I[0] (input port) Endpoint: Y[11] (output port clocked by CLK) Path Group: fromI Path Type: max Des/Clust/Port Wire Load Model Library -----------------------------------------------CY7C910 TSMC16K_Conservative tcb773pwc INSTRUCTION_DECODER TSMC8K_Conservative tcb773pwc TS_BUFFER TSMC8K_Conservative tcb773pwc MULTIPLEXER TSMC8K_Conservative tcb773pwc Point Incr Path -------------------------------------------------------------------------clock (input port clock) (rise edge) 0.00 0.00 input external delay 0.00 0.00 r I[0] (in) 0.00 0.00 r INSTR_DEC/I[0] (INSTRUCTION_DECODER) 0.00 0.00 r INSTR_DEC/U83/ZN (INV0) 0.48 0.48 f INSTR_DEC/U109/ZN (OAI21D0) 0.42 0.90 r INSTR_DEC/U95/ZN (IAO21D0A) 0.43 1.33 f INSTR_DEC/U65/Z (MUX2D1) 0.68 2.01 f INSTR_DEC/U86/ZN (OAI21D0) 0.44 2.45 r INSTR_DEC/MUX_SEL[0] (INSTRUCTION_DECODER) 0.00 2.45 r MUX_i/MUX_SEL[0] (MULTIPLEXER) 0.00 2.45 r MUX_i/U11/ZN (INV0) 0.48 2.94 f MUX_i/U9/Z (MUX2D1) 0.69 3.63 f MUX_i/U51/ZN (INV1) 0.52 4.15 r MUX_i/U48/ZN (MOAI22D0) 0.52 4.67 r MUX_i/U35/ZN (IOA221D0D) 0.77 5.44 r MUX_i/MUXOUT[11] (MULTIPLEXER) 0.00 5.44 r TSB_i/DATAIN[11] (TS_BUFFER) 0.00 5.44 r TSB_i/U14/ZN (INV1) 0.23 5.67 f TSB_i/DATAOUT_tri[11]/ZN (INVTN1) 0.22 5.89 r TSB_i/DATAOUT[11] (TS_BUFFER) 0.00 5.89 r Y[11] (out) 0.00 5.89 r data arrival time 5.89 clock CLK (rise edge) 20.00 20.00 clock network delay (ideal) 0.00 20.00 output external delay -12.00 8.00 data required time 8.00 -------------------------------------------------------------------------data required time 8.00 data arrival time -5.89
50
-------------------------------------------------------------------------slack (MET) 2.11 Startpoint: nCC (input port) Endpoint: Y[11] (output port clocked by CLK) Path Group: fromnCC Path Type: max Des/Clust/Port Wire Load Model Library -----------------------------------------------CY7C910 TSMC16K_Conservative tcb773pwc INSTRUCTION_DECODER TSMC8K_Conservative tcb773pwc TS_BUFFER TSMC8K_Conservative tcb773pwc MULTIPLEXER TSMC8K_Conservative tcb773pwc Point Incr Path -------------------------------------------------------------------------clock (input port clock) (rise edge) 0.00 0.00 input external delay 0.00 0.00 f nCC (in) 0.00 0.00 f INSTR_DEC/nCC (INSTRUCTION_DECODER) 0.00 0.00 f INSTR_DEC/U97/ZN (IND2D1) 0.36 0.36 r INSTR_DEC/U71/ZN (ND2D0) 0.54 0.90 f INSTR_DEC/U94/ZN (IAO21D0B) 0.77 1.66 f INSTR_DEC/U88/ZN (OAI32D0) 0.84 2.50 r INSTR_DEC/MUX_SEL[2] (INSTRUCTION_DECODER) 0.00 2.50 r MUX_i/MUX_SEL[2] (MULTIPLEXER) 0.00 2.50 r MUX_i/U10/ZN (INV0) 0.33 2.83 f MUX_i/U9/Z (MUX2D1) 0.67 3.51 f MUX_i/U51/ZN (INV1) 0.52 4.03 r MUX_i/U48/ZN (MOAI22D0) 0.52 4.55 r MUX_i/U35/ZN (IOA221D0D) 0.77 5.32 r MUX_i/MUXOUT[11] (MULTIPLEXER) 0.00 5.32 r TSB_i/DATAIN[11] (TS_BUFFER) 0.00 5.32 r TSB_i/U14/ZN (INV1) 0.23 5.55 f TSB_i/DATAOUT_tri[11]/ZN (INVTN1) 0.22 5.77 r TSB_i/DATAOUT[11] (TS_BUFFER) 0.00 5.77 r Y[11] (out) 0.00 5.77 r data arrival time 5.77 clock CLK (rise edge) 20.00 20.00 clock network delay (ideal) 0.00 20.00 output external delay -12.00 8.00 data required time 8.00 -------------------------------------------------------------------------data required time 8.00 data arrival time -5.77 -------------------------------------------------------------------------slack (MET) 2.23 Startpoint: nCCEN (input port) Endpoint: Y[11] (output port clocked by CLK) Path Group: fromnCCEN Path Type: max Des/Clust/Port Wire Load Model Library -----------------------------------------------CY7C910 TSMC16K_Conservative tcb773pwc INSTRUCTION_DECODER TSMC8K_Conservative tcb773pwc TS_BUFFER TSMC8K_Conservative tcb773pwc MULTIPLEXER TSMC8K_Conservative tcb773pwc Point Incr Path -------------------------------------------------------------------------clock (input port clock) (rise edge) 0.00 0.00 input external delay 0.00 0.00 r nCCEN (in) 0.00 0.00 r INSTR_DEC/nCCEN (INSTRUCTION_DECODER) 0.00 0.00 r INSTR_DEC/U97/ZN (IND2D1) 0.57 0.57 r INSTR_DEC/U71/ZN (ND2D0) 0.54 1.11 f INSTR_DEC/U94/ZN (IAO21D0B) 0.77 1.88 f INSTR_DEC/U88/ZN (OAI32D0) 0.84 2.71 r INSTR_DEC/MUX_SEL[2] (INSTRUCTION_DECODER) 0.00 2.71 r MUX_i/MUX_SEL[2] (MULTIPLEXER) 0.00 2.71 r MUX_i/U10/ZN (INV0) 0.33 3.05 f MUX_i/U9/Z (MUX2D1) 0.67 3.72 f MUX_i/U51/ZN (INV1) 0.52 4.24 r MUX_i/U48/ZN (MOAI22D0) 0.52 4.76 r MUX_i/U35/ZN (IOA221D0D) 0.77 5.53 r MUX_i/MUXOUT[11] (MULTIPLEXER) 0.00 5.53 r TSB_i/DATAIN[11] (TS_BUFFER) 0.00 5.53 r TSB_i/U14/ZN (INV1) 0.23 5.76 f TSB_i/DATAOUT_tri[11]/ZN (INVTN1) 0.22 5.98 r TSB_i/DATAOUT[11] (TS_BUFFER) 0.00 5.98 r Y[11] (out) 0.00 5.98 r data arrival time 5.98
51
clock CLK (rise edge) 20.00 20.00 clock network delay (ideal) 0.00 20.00 output external delay -12.00 8.00 data required time 8.00 -------------------------------------------------------------------------data required time 8.00 data arrival time -5.98 -------------------------------------------------------------------------slack (MET) 2.02
CY7C910_area_report.txt report_area Information: Updating design information... (UID-85) **************************************** Report : area Design : CY7C910 Version: 2000.05 Date : Tue May 13 10:49:02 2003 **************************************** Library(s) Used: tcb773pwc (File: C:/Synopsys/libraries/syn/tcb773pwc.db) Number Number Number Number
of of of of
ports: nets: cells: references:
38 97 8 8
Combinational area: Noncombinational area: Net Interconnect area:
91385.000000 106802.500000 undefined (Wire load has zero net area)
Total cell area: Total area:
198187.500000 undefined
Testarea circuitului CY7C910
Pentru testarea întregului circuit CY7C910, nu am realizat un program de test original, ci am folosit programul de test pentru circuitul AM2910 (echivalent cu CY7C910) prezentat în [2]. Deşi acest testbench nu realizează o testare funcţională completă a circuitului CY7C910, am decis să-l utilizez astfel încât, prin compararea formelor de undă prezentate în [2] cu cele obţinute în urma simulării circuitului proiectat de mine, să pot stabili, cu destulă siguranţă, dacă circuitul meu funcţionează corect. Trebuie să precizez aici că formele de undă prezentate în [2] sunt obţinute în urma testării presinteză. Testarea lui CY7C910 se va realiza cu un circuit de test, în locul unui program de test. Arhitectura circuitului de test este prezentată în continuare :
CY7C910
ROM
PIPELINE 52
Ieşirile Y ale circuitului CY7C910 sunt folosite pentru a adresa o memorie ROM. Registrul pipeline are rolul de a elimina stările tranzitorii de pe intr ările lui CY7C910 (stări tranzitorii ce ar apărea în absenţa registrului pipeline din cauza întărzierilor diferite pe căile combinaţionale între intr ările lui CY7C910 şi ieşirile Y ale acestuia) . ROM-ul conţine un microprogram. Microprogramul următor a fost realizat pentru a verifica toate instrucţiunile lui CY7C910 : Program.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
1100 e 001 -- locatia 0(hexa) ; nRLD = 1, CI = 1, nCCEN = 0, nCC = 0 ; I = CONT(hexa) ; D = 001(hexa) 1100 4 002 -- 1 ; PUSH 0100 4 003 -- 2 ; PUSH 1100 4 004 -- 3 ; PUSH 1101 4 005 -- 4 ; PUSH 1100 4 006 -- 5 ; PUSH 1110 4 007 -- 6 ; PUSH 0100 4 008 -- 7 ; PUSH 1100 4 009 -- 8 ; PUSH 1111 4 00a -- 9 ; PUSH 1100 4 00b -- a ; PUSH 1100 4 00c -- b ; PUSH 1100 4 00d -- c ; PUSH 1100 4 00e -- d ; PUSH 1100 4 00f -- e ; PUSH 1100 4 010 -- f ; PUSH 1100 4 011 -- 10 ; PUSH 1100 4 012 -- 11 ; PUSH 1100 4 013 -- 12 ; PUSH 1110 d 014 -- 13 ; LOP(pop) 1100 d 015 -- 14 ; LOP(pop) 1100 d 016 -- 15 ; LOP(pop) 1100 d 017 -- 16 ; LOP(pop) 1110 d 018 -- 17 ; LOP(pop) 1100 d 019 -- 18 ; LOP(pop) 1110 d 01a -- 19 ; LOP(pop) 1100 d 01b -- 1a ; LOP(pop) 1111 d 01c -- 1b ; LOP(pop) 1100 d 01d -- 1c ; LOP(pop) 0100 d 01e -- 1d ; LOP(pop) 1111 d 01f -- 1e ; LOP(pop) 1110 d 020 -- 1f ; LOP(pop) 1100 d 021 -- 20 ; LOP(pop) 0111 d 022 -- 21 ; LOP(pop) 1110 d 023 -- 22 ; LOP(pop) 1100 d 024 -- 23 ; LOP(pop) 1100 d 025 -- 24 ; LOP(pop) 1100 e 026 -- 25 ; CONT 1100 e 027 -- 26 ; CONT 1100 0 035 -- 27 ; CJS la adresa 035(hexa) 1100 0 000 -- 28 ;de fapt nu conteaza ce se afla la adresele 028 - 034(hexa) deoarece se realizeaza un salt peste aceste adrese 1100 0 000 -- 29 ; 1100 0 000 -- 2a ; 1100 0 000 -- 2b ; 1100 0 000 -- 2c ; 1100 0 000 -- 2d ; 1100 0 000 -- 2e ; 1100 0 000 -- 2f ; 1100 0 000 -- 30 ; 1100 0 000 -- 31 ; 1100 0 000 -- 32 ; 1100 0 000 -- 33 ; 1100 0 000 -- 34 ; 1100 2 038 -- 35 ; JMAP a adresa 38(hexa) 1100 0 000 -- 36 ; nu conteaza 1100 0 000 -- 37 ; nu conteaza 1101 3 0ff -- 38 ; CJP, no jump 1100 3 03c -- 39 ; CJP, salt la 3c 1100 0 000 -- 3a ; nu conteaza 1100 0 000 -- 3b ; nu conteaza 1100 1 040 -- 3c ; CJS la 40(hexa) 1100 0 000 -- 3d ; nu conteaza 1100 0 000 -- 3e ; nu conteaza 1100 0 000 -- 3f ; nu conteaza 1100 4 003 -- 40 ; PUSH, load counter 3
53
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
1100 1100 1101 1100 1100 1100 1100 1100 1101 1100 1100 1100 1101 1100 1100 1100 1100 1101 1100 1100 1100 1100 1100 1101 1100 1100 1100 1100 1000
e 8 a a 4 d c 9 6 6 0 c 7 0 7 0 c 5 0 5 0 4 e f e e e e e
040 041 043 044 fff 046 002 048 000 04c 000 04f 000 000 051 000 054 000 000 056 000 003 aaa 05a bad d0e d0e d0e doe
----------------------------–-
41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
CONT RFCT, repeat Condition return, no return return load counter with fff pop LDCT, load counter and continue RFCT, repeat this instruction CJV, conditional jump, no jump CJV, salt la 04c nu conteaza LDCT, load counter 4f JRP, jump to counter address 4f nu conteaza JRP, jump to D nu conteaza LDCT 54 JSRP, jump to counter nu conteaza JSRP, jump to counter nu conteaza PUSH and load counter with 60 CONT TWB, three way branch to 5a when done CONT CONT CONT CONT CONT
Fiecare locaţie a memoriei ROM are 20 de bi ţi. Primii 4 biţi de la stânga reprezintă nRLD, CI, nCC, nCCEN ; următorii 4 sunt pentru intr ările de instrucţiuni I ; următorii 12 sunt pentru intr ările D. Liniile 2 – 19 testeaz ă instrucţiunea Push_s. Sunt 18 operaţii Push_s, astfel încât se poate testa comportamentul circuitului la umplerea stivei. Liniiile 20 – 37 testează operaţia Pop_s. Explicaţii detaliate despre microprogram vor fi date când vor fi prezentate formele de undă obţinute în urma simulării. În continuare trebuie descrise blocurile ROM şi PIPELINE utilizate la testare. ROM.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; use work.std_logic_arith.all ; use IEEE.std_logic_textio.all ; use STD.TEXTIO.all ; entity ROM is generic (SIZE : integer := 20 ; WORDS : integer := 94 ; ADSIZE : integer := 7 ; CODEFILE : string := "Program.txt") ; port (A : in std_logic_vecto r (ADSIZE - 1 downto 0) ; DOUT : out std_logic_vector (SIZE - 1 downto 0) ) ; end ROM ; architecture BEH of ROM is constant DELAYMIN : time := 0.01 ns ; type memorie is array (255 downto 0) of std_logic_vector (SIZE - 1 downto 0) ; signal mem_ROM : memorie ; begin process -- se încarcă ROM-ul cu datele din fişierul “Program.txt” file my_file : text open read_mode is CODEFILE ; variable INLINE : line ; variable i : integer := 0 ; variable N : integer ; variable bits4, OPCODE : std_logic_vector (3 downto 0) ; variable DATA : std_logic_vect or (address_bus_width - 1 downto 0) ; begin while not endfile(my_file) loop readline(my_fil e, INLINE ) ; -- se Incarcă o linie din “Program.txt” în variabila INLINE de tip LINE read (INLINE, N) ; -- se încarcă în variabila N primul întreg din linia INLINE read (INLINE, bits4) ; -- se încarcă în variabila bits4 următorii 4 biţi din INLINE hread (INLINE, OPCODE) ; --se tratează următoarea secvenţă de caractere din INLINE ca număr
54
--hexazecimal şi se ribuie variabilei OPCODE hread (INLINE, DATA) ; --se tratează următoarea secvenţă de caractere din INLINE ca număr --hexazecimal şi se ribuie variabilei DATA mem_ROM (i) <= bits4 & OPCODE & DATA ; --concatenarea celor 20 de biţi citiţi anterior şi înscrierea --acestora într-o locaţie a memoriei ROM i := i + 1 ; wait for DELAYMIN ; end loop ; wait for 10 ns ; wait ; end process ; process (A) -- se descrie funcţionarea ROM-ului begin DOUT <= mem_ROM (CONV_INTEGER (unsigned (A) ) ) end process ; end BEH ;
;
PIPELINE.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; entity pipeline is port (CP, R : in std_logic ; I : in std_logic_vector (19 downto 0) ; Q : out std_logic_vector (19 downto 0) ) ; end pipeline ; architecture RTL of pipeline is constant DELAY : time := 5 ns ; begin process begin wait until (CP'event and CP = '1') ; case R is when '1' => Q <= "00000000000000000000" after DELAY ; when others => Q <= I after DELAY ; end case ; end process ; end RTL ;
Circuitul de test se obţine prin asamblarea blocurilor CY7C910, ROM şi PIPELINE. test_CY7C910.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C910.all ; use work.std_logic_arith.all ; use work.std_logic_unsigned.all ; use IEEE.std_logic_textio.all ; use STD.TEXTIO.all ; entity test_CY7C910 is end ; architecture test of test_CY7C910 is component CY7C910 port ( D : in std_logic_vecto r (address_bus_wi dth - 1 downto 0) ; nRLD : in std_logic ; I : in std_logic_vecto r (3 downto 0) ; nCC :in std_logic ; nCCEN : in std_logic ; CP : in std_logic ; CI : in std_logic ; nOE : in std_logic ; Y : out std_logic_vect or (address_bus_width - 1 downto 0) ; nFULL : out std_logic ; nPL : out std_logic ; nMAP : out std_logic ; nVECT : out std_logic) ; end component ; component pipeline port (CP, R : in std_logic ; I : in std_logic_vect or (19 downto 0) Q : out std_logic_vect or (19 downto 0) ) ;
;
55
end component ; component ROM generic (SIZE : integer := 20 ; WORDS : integer := 94 ; ADSIZE : integer := 7 ; CODEFILE : string := "Program.txt") ; port (A : in std_logic_vecto r (ADSIZE - 1 downto 0) ; DOUT : out std_logic_vector (SIZE - 1 downto 0) ) ; end component ; signal D, Y : std_logic_vecto r (address_bus_width - 1 downto 0) ; signal nRLD, nCC, nCCEN, CP, CI, nOE, nFULL, nPL, nMAP, nVECT, R : std_logic ; signal I : std_logic_vector (3 downto 0) ; signal A : std_logic_vector (6 downto 0) ; signal DOUT, Q : std_logic_vector (19 downto 0) ; constant TPER : time := 50 ns ; -- 50 se înlocuieşte cu 14 pentru a doua simulare -- semnale ajutatoare pt analiza formelor de unda signal S1 : std_logic_vecto r (3 downto 0) ; -- nRLD CI nCC nCCEN signal D_v, Y_v : integer ; signal INSTRUCTION : INSTR_type ; signal Source_v : INT_S_type ; signal Source_v2 : std_logic_vector (2 downto 0) ; begin DUT : CY7C910 port map (D, nRLD, I, nCC, nCCEN, CP, CI, nOE, Y, nFULL, nPL, nMAP, nVECT) pipeline_i : pipeline port map (CP, R, DOUT, Q) ; ROM_i : ROM generic map (SIZE => 20, WORDS => 93, ADSIZE => 7, CODEFILE => "Program.txt") port map (A, DOUT) ; process begin CP <= '0' ; wait for TPER / 2 ; CP <= '1' ; wait for TPER / 2 ; end process ; R <= '1', '0' after 3 * TPER ; nRLD <= Q (19) ; CI <= Q (18) ; nCCEN <= Q (17) ; nCC <= Q (16) ; I <= Q (15 downto 12) ; D <= Q (11 downto 0) ; A <= Y (6 downto 0) ; S1(3) <= nRLD ; S1(2) <= CI ; S1(1) <= nCCEN ; S1(0) <= nCC ; D_v <= conv_integer (D) ; Y_v <= conv_integer (Y) ; Source_v2(2) <= nPL ; Source_v2(1) <= nMAP ; Source_v2(0) <= nVECT ; nOE <= '0' ; process (I) begin if (I'event) then case I is when when when when when when when when when when when when when when when when when end case ; end if ; end process ;
JZ CJS JMAP CJP PUSH JSRP CJV JRP RFCT RPCT CRTN CJPP LDCT LOP CONT TWB others
=> => => => => => => => => => => => => => => => =>
INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION INSTRUCTION
<= <= <= <= <= <= <= <= <= <= <= <= <= <= <= <= <=
;
JZ_v ; CJS_v; JMAP_v ; CJP_v ; PUSH_v ; JSRP_v ; CJV_v ; JRP_v ; RFCT_v ; RPCT_v ; CRTN_v ; CJPP_v ; LDCT_v ; LOP_v ; CONT_v ; TWB_v ; XXXX ;
56
process (Source_v2) begin if (Source_v2'event ) then case Source_v2 is when "011" => Source_v <= PL_v ; when "101" => Source_v <= Mapp_v ; when "110" => Source_v <= Vect_v ; when others => Source_v <= XXX ; end case ; end if ; end process ; end test ;
În continuare voi reproduce formele de undă prezentate în [2], împreună cu comentariile referitoare la acestea. Figura 1 arată formele de undă începând cu momentul anterior dezactivări semnalului de reset (rstn în figur ă) al registrului pipeline. Sunt prezentate formele de undă corespunzătoare multor semanle importante din design (Trebuie preciat că denumirile semnalelor şi a tipurilor corespunzătoare acestor semnale sunt diferite de cele din proiectul meu, dar destul de asemănătoare pentru ca formele de undă să poată fi analizate cu uşurinţă) . După cum se observă din figura 1, stiva şi MPC-ul sunt şterse (resetate) . MUX_CNTL este setat pe SEL_ZERO astfel încât Y va fi Zero. Register?Counter-ul este, de asemenea, încărcat cu Zero. După ce semnalul de reset (RSTn) este dezactivat, instrucţiunile din microprogramul stocat în memoria ROM sunt executate. Prima instrucţiune este o instrucţiune CONT (Continue) . MPC-ul este incrementat cu 1. MUX_CNTL este setat pe SEL_UPC. Următoarea instrucţiune, PUSH, este executată. Prima instrucţiune PUSH nu modifică SP-ul. Flagul EMPTYn este dezactivat. După aceasta, SPul va fi incrementat.
Figura 1
Figura 2 prezintă următoarele forme de undă, pentru situaţia în care stiva este plină. Ieşirea FULLn este activată după ce se scrie ultima locaţie liber ă a stivei. Următoarea instrucţiune PUSH suprascrie valoarea din vârful stivei, 12 (hexa) , cu 13 (hexa) . Apoi asupra stivei se execut ă operaţia POP. De notat că ieşirea stivei indică valoarea 11 (hexa) , care reprezintă valoarea înscrisă în penultima locaţie a stivei. Ieşirea FULLn este dezactivată. 57
Figura 2
Figura 3 prezintă formele de undă corespunzătoare golirii stivei. Flagul EMPTYn este activat. Stack Pointer-ul r ămâne zero. Ieşirea stivei r ămâne la valoarea 2, care reprezintă prima valoare înscrisă în stivă.
Figura 3
58
Figura 4 reproduce formele de undă corespunzătoare încărcării Register/Counter-ului cu valoarea 3. Instrucţiunile CONT şi RFCT sunt executate de 4 ori. De notat că Register?counter-ul este decrementat la fiecare instrucţiune RFCT.
Figura 4
Formele de undă din figura 5 prezintă testarea instrucţiunilor CRTN, CJS, LDCT, RPCT, CJV, JRP şi JSRP.
Figura 5
59
Figura 6 reproduce ultimele forme de undă ale simulării. Se testează instrucţiunea de ramificare TWB. În final, CI este setat pe 0. Se observă că ieşirea MPC-ului r ămâne la aceeaşi valoare.
Figura 6
Există, bineînţeles, multe funcţii şi combinaţii de instrucţiuni care nu sunt verificate de acest program de test. Eu mi-am permis să consider că, dacă circuitul proiectat de mine funcţionează corect pentru acest test incomplet, este foarte probabil ca să funcţioneze corect şi pentru un test mult mai complet (Bineîn ţeles, nam nici o dovadă cu care să susţin aceasta) . După ce, în prealabil, s-a realizat sinteza circuitului CY7C910, testarea postsinteză se realizează
astfel : - se compilează, cu ModelSim, fişierul “TCB773P.v” ; în acest fişier se află descrierile Verilog pentru componentele din biblioteca tehnologică “tcb773pwc.lib”, componente cu care programul de sinteză a implementat circuitul CY7C910 ; - se compilează fişierul “CY7C910_mapped.vhd” generat de Design Compiler în urma procesului de sinteză a designului CY7C910 ; - se compilează programul de test “test_CY7C910.vhd” ; în prealabil trebuiau compilate fişierele “ROM.vhd” şi “pipeline.vhd” ; - se încarcă arhitectura test din cadrul designului test_CY7C910, având grijă să ataşăm fişierul “CY7C910_mapped.sdf” (generat de programul de sinteză) instanţei DUT (instanţierea circuitului CY7C910) din cadrul circuitului de test ; în plus, rezoluţia de simulare trebuie setată pe ps (picosecunde) . Acestea fiind f ăcute, se poate trece la vizualizarea formelor de undă. Trebuie să spun că am simulat circuitul CY7C910 pentru diverse perioade (frecvenţe) ale semnalului de ceas. Am pornit de la o valoare de 100 ns a perioadei semnalului de ceas şi am coborât treptat această valoare, până când simularea a ar ătat o funcţionare incorectă a circuitului. Cea mai mică perioadă a semnalului de ceas pentru care circuitul a mai funcţionat corect a fost de 14 ns, ceea ce corespunde unei frecvenţe de funcţionare de aproximativ 70 MHz (mai mult ca sigur că, în urma realizării layout-ului , simularea postlayout va ar ăta o frecvenţă maximă de funcţionare mai mică) . Am hotărât să prezint formele de undă obţinute în urma simulării postsinteză în două cazuri : perioada semnalului de ceas de 50 ns şi perioada semnalului de ceas de 14 ns. Am ales cazul simulării cu 60
perioada semnalului de ceas de 50 ns întrucât simularea presinteză prezentată în [2] a fost realizată cu un semnal de ceas de aceeaşi perioadă, asfel putându-se pbserva mai uşor diferenţele dintre simularea postsinteză şi simularea presinteză. Am ales prezentarea simulării cu semnalul de ceas cu perioada de 14 ns întrucât aceasta corespunde frecvenţei maxime de funcţionare a circuitului, reprezentând cazul cel mai interesant din punct de vedere practic. Prezentarea simulării cu perioada semnalului de ceas de 50 ns este foarte importantă şi pentru a evidenţia funcţionarea corectă a circuitului în cazul semnaluli de ceas cu perioada de 14 ns, prin compararea formelor de undă obţinute în cele două cazuri (ar fi fost foarte greu de comparat rezultatele testării postsinteză cu perioada semanalului de ceas de 14 ns cu rezultatele testării presinteze prezentate în [2]) În continuare voi reproduce, în paralel, formele de undă obţinute în urma simulării postsinteze a circuitului CY7C910 pentru cele două cazuri.
61
62
63
64
65
66
CY7C901
Descriere funcţională CY7C901 este o unitate aritmetico-logică (ALU) pe 4 biţi, rapidă, expandabilă, care poate fi utilizată pentru implementarea componentei aritmetice a unui CPU, controller periferic sau controller programabil. Setul de instrucţiuni al CY7C901 este simplu însă foarte versatil, ceea ce permite emularea unităţii ALU a aproape oricărui calculator. După cum se observă din diagrama bloc, CY7C901 constă dintr-o memorie RAM (16 x 4 biţi) dual port, un ALU pe 4 biţi şi logica necesar ă pentru manipularea datelor şi control.
CY7C901 - diagrama bloc
Operaţia realizată este determinată de 9 linii de intrare de control (I0 – I9) , valorile aplicate pe acestea provenind de obicei de la un registru de microinstrucţiuni. Cy7C901 este expandabil în incrementări a câte 4 biţi, are ieşiri “three-states”, flag-uri, iar semnalul de carry poate fi folosit pentru implementarea fie a unui “look-ahead carry”, fie a unui “ripple carry”. Tabel 1.Descrierea pinilor
Nume
I/O
Descriere
A0 – A3
I
B0 – B3
I
I 0 – I8
I
D0 – D3
I
Y0 – Y3
O
aceste 4 linii de adresa selecteaza unul din registrii din stiva si pune continutul acestuia pe portul (intern) A aceste 4 linii de adresa selecteaza unul din registrii din stiva si pune continutul acestuia pe portul (intern) B ; aceste linii pot, de asemenea, sa reprezinte adresa destinatie atunci cand data este scrisa in registri Aceste 9 linii de insructiune selecteaza sursa de date pentru ALU (I(2), I(1) , I(0)) , operatia care trebuie realizata (I(5), I(4), I(3)) si ce data trebuie sa fie inscrisa in Registrul Q sau in registrii de memorie (I(8), I(7), I(6)) Reprezinta 4 linii de intrare de date care pot fi selectate de I(2)I(1)I(0) ca intrari ale ALU liinii three state de iesire date care pot fi selectate ca intrari 67
\OE CP
Q3 RAM3
Q0 RAM0 Cn Cn+4 \G \P OVR
F=0
F3
ale ALU de catre I(2) I(1) I(0) I OUTPUT ENABLE ; intrare activa pe LOW care controleaza iesirile Y ; cand este LOW, iesirile Y sunt activate, cand este HIGH iesireil Y sunt in inalta impedanta I Intrarea semnalului de ceas ; Nivelul LOW al ceasului inscrie data in memoria RAM ; Nivelul HIGH al ceasului inscrie data din RAM in latch-urile port A si port B Functionarea registrului QQ este similara ; Data intra in latch-ul master pe palierul LOW al ceasului si este transferata din master in slave pe palierul HIGH al ceasului I/O linii bidirectionale controlate de intrarile I(8) I(7) I(6) IESIRI : Cand codul destinatie pe liniile I(8) I(7) I(6) indica o operatie de deplasare la stanga(UP), Iesirile three state sunt activate si MSB_ul registrului Q este scos la pinul Q3 iar MSB_ul iesiri ALU (F3) este scos la pinul RAM3 INTRARI : Cand codul destinatie pe liniile I(8) I(7) I(6) indica o operatie de deplasare la dreapta(DOWN), pinul Q3 reprezinta intrarea de date catre MSB-ul registrului Q iar RAM3 reprezinta intrarea de date catre MSB-ul RAM-ului I/O linii bidirectionale care functioneaza similar cu Q3 si RAM3, doar ca reprezinta LSB_ul registrului Q respectiv al RAM-ului I carry-in catre ALU-ul intern O carry-out de la ALU-ul intern O iesiri pentru carry generat si carry propagat ale ALU ; pot fi utilizate pentru a realiza o operatie "carry look-ahead" asupra celor 4 biti ai ALU O OVERFLOW ; Acest semnal este dpdv logic rezultatul operatiei XOR intre carry-in si carry-out ale MSB al ALU ; indica daca rezultatul operatiei realizate de ALU a depasit capacitatea masinii ; valid doar pentru bitul de semn si se asuma codarea numerelor negative in complement fata de 2 ; O iesire "open drain" care trece in HIGH dacă data de pe iesirea ALU are toti bitii in LOW <=> F = 0000 ; indica faptul ca rezultatul unei operatii a ALU este zero O
MSB al iesirii ALU
Descriere arhitecturală RAM
RAM-ul este adresat de două intr ări de adresă de câte 4 biţi (A0 – A3 şi B0 – B3) care determină ca datele de la adresele selectate să apar ă la porturile interne A şi B. Dacă adresele A şi B sunt identice, atunci datele la porturile interne A şi B vor fi identice. Datele noi se înscriu în RAM la loca ţia specificată de intr ările de adresă B, atunci când semnalul de scriere a RAM-ului (WR_EN) este activ, iar semanlul de ceas se află pe nivelul LOW. Fiecare din cele 4 intr ări de date ale RAM-ului este comandată de câte un multiplexor, ceea ce permite ieşirii ALU (F0 – F3) să poată fi deplasată cu un bit la stânga sau la dreapta (sau să nu fie deplasată). În cazul unei deplasări la stânga, MSB-ul este scos pe pinul RAM3, iar LSB-ul este preluat de pe pinul RAM0. În cazul deplasării la dreapta, LSB-ul este scos la pinul RAM0, iar MSB-ul este preluat de la pinul RAM3. 68
Data care trebuie înscrisă în RAM se aplică pe intr ările de date D şi se trece nemodificată prin ALU, până la locaţia de adresă indicată de intr ările de adresă B. Ieşirile RAM-ului, porturile interne A şi B, sunt conectate la câte un latch pe 4 biţi, care devin active atunci când semnalul de ceas se află pe nivel HIGH. Ieşirile latch-urilor sunt conectate. prin intermediul unor multiplexoare, la cele două intr ări ale ALU (R 3 – R 0 şi S3 – S0) şi la ieşirile Y3 – Y0. ALU
ALU poate executa 3 operaţii aritmetice şi 5 operaţii logice cu 2 operanzi pe câte 4 biţi : R şi S. Intr ările R provin de la 4 multiplexoare de două intr ări, ale căror intr ări provin fie de la portul A intern, fie de la intr ările externe de date D. Intr ările S provin de la 4 multiplexoare de trei intr ări conectate la porturile interne A şi B şi la registrul Q. Ambele grupuri de multiplexoare sunt comandate de intr ările I2 – I0. Configuraţia multiplexoarelor de pe intr ările R şi S ale ALU permit utilizatorului s ă selecteze 8 perechi de combinaţii între A, B, D, Q şi “0000”(neselectat) ca operanzi ai ALU. Tabel 2. Selecţia operanzilor ALU
Mnemonic
AQ AB ZQ ZB ZA DA DQ DZ
I2
L L L L H H H H
Micro Code I1 I0 Octal
L L H H L L H H
L H L H L H L H
0 1 2 3 4 5 6 7
Operanzii ALU R S
A A 0 0 0 D D D
Q B Q B A A Q 0
Operaţia executată de ALU este selectată de intr ările I5 – I3. Cele 8 operaţii aritmetice şi logice între operanzii R şi S sunt prezentate în tabelul de mai jos. Tabel 3.Operaţiile ALU
Mnemonic
ADD SUBR SUBS OR AND NOTRS EXOR EXNOR
Micro Code I5 I4
L L L L H H H
L L H H L H H H
I3
L H L H L L L H
ALU Octal Function 0 R plus S 1 S minus R 2 R minus S 3 R OR S 4 R AND S
H 6 7
R5 AND S
R XOR S R XNOR S
Symbol R + S S − R R − S R ∨ S R ∧ S R ∧ S R∀S R∀S
ALU are intrare de carry-in (Cn) , ieşire carry-out (Cn+4) , ieşire carry-propagate (\P) , ieşire carry-generate (\G) şi ieşire pentru overflow (OVR) , ceea ce permite utilizatorului : 1.creşterea vitezei de execuţie a operaţiilor aritmetice prin implementarea transportului “carry-look-ahead” 2.să determine dacă a apărut o depăşire logică Ieşirile ALU-lui (F3 – F0) sunt rutate către intr ările RAM-lui şi ale registrului Qşi c ătre ieşirile Y în funcţie de semnalele de intrare de control I8 – I6. după cum se arată în tabelul următor :
69
Tabel 4. Setul de instrucţiuni
Mnemonic
Micro Code I8 L L L L H H H H
I7 L L H H L L H H
I6 L H L H L H L H
oct
RAM function shift load
Q-Reg function shift load
Y RAM Q out shifter shifter RAM0 RAM3 Q0 Q3
0 QREG X none none F X X X X F→Q 1 NOP X none X none F X X X X 2 RAMA none none A X X X X F→B X 3 RAMF none none F X X X X F→B X 4 RAMQD DOWN F/2→B DOWN Q/2→Q F F0 IN3 Q0 IN3 5 RAMD DOWN F/2→B X none F F0 IN3 Q0 X 6 RAMQU UP IN0 F3 IN0 Q3 2F→B UP 2Q→Q F 7 RAMU UP none F IN0 F3 X Q3 2f →B X În plus, bitul cel mai semnificativ al ie şirii ALU este scos la pinul F 3, astfel încât utilizatorul poate examina bitul de semn f ăr ă a activa buferele three-state de pe ieşire. Pinul F=0, folosit pentru detecţie de zero, este o ieşire open-drain, ceea ce permite implementarea unei funcţii SAU-cablat între semnalele F=0 de la mai multe circuite CY7C901 în cazul unei arhitecturi slice multiprocesor. Registrul Q
Registrul Q funcţionează ca un acumalator sau registru de stocare temporar ă. Fizic reprezintă un registru de 4 bi ţi implementat cu latch-uri master-slave. Intr ările registrului Q provin de la ieşirile a 4 multiplexoare cu 3 intr ări comandate de semnalele de intrare de control I8 – I8. Pinii Q3 şi Q0 funcţionează într-o manier ă similar ă cu pinii RAM3 şi RAM0. Multiplexoarele permit deplasarea la stânga sau la dreapta a conţinutului registrului Q, sau încărcarea latch-urilor master cu valoarea din ieşirea ALU. Datele sunt încărcate în latchurile master când nivelul semnalului de ceas este LOW şi sunt transferate în latch-urile slave (pe ieşiri) când semnalul de ceas trece din LOW în HIGH. Sursele de operanzi şi funcţiile ALU Semnalele I2 – I0 selectează una din cele 8 perechi de operaţia care trebuie executată.Semnalul carry-in (Cn) flag-urile interne, neintervenind în operaţiile logice.
surse de operanzi, iar semnalele I5 – I3 selectează afectează doar rezultatul operaţiilor aritmetice şi
Funcţiile logice pentru \G, \P, Cn+4 şi OVR Semnalele G, P, Cn şi OVR indică condiţiile de transport şi depăşire atunci când CY7C901 se află în unul din modurile adunare sau scădere. Tabelul următor indică ecuaţiile logice pentru aceste 4 semnale pentru fiecare din cele 8 funcţii ale ALU. R şi S reprezintă cele două intr ări selectate conform tabelul 4. Definiţii (+ inseamnă OR) :
P0 = R 0 + S0 ; G0 = R 0S0 ; P1 = R 1 + S1 ; G1 = R 1S1 ; P2 = R 2 + S2 ; G2 = R 2S2 ; P3 = R 3 + S3 ; G3 = R 3S3 ; C4 = G3 + P3G2 + P3P2G1 + P3P2G0 + P3P2P1P0Cn ; C3 = G2 + P2G1 + P2P1G0 + P2P1P0Cn ;
Tabel 5. Funcţiile logice pentru semnalele \P, \G, C n+4 şi OVR
I543 Function \P
0
R ÷ S
1
S − R
2
R − S
3
R ∨ S
P3 P2 P1 P0
\G G3 + P3G2 + P3 P2G1 + P3 P2 P1G0
Cn + 4
OVR
C4
C 3∀C 4
La fel ca la R+S, dar se inlocuieşte R cu R în definiţii i
La fel ca la R+S, dar se inlocuieşte LOW P3 P2 P1 P0
Si
i
cu
Si
în definiţii P3 P2 P1 P0 + C n
P3 P2 P1 P0 + C n
70
4
R ∧ S
LOW
5
R ∧ S
LOW
6
R∀S
7
R∀S
G3 + G2 + G1 + G0
G3 + G2 + G1 + G0 + C n
G3 + G2 + G1 + G0 + C n
La fel ca la R ∧ S , dar se inlocuieşte R cu R în definiţii i
i
La fel ca la R∀S , dar se inlocuieşte R cu R în definiţii i
G3 + G2 +
G3 + P3G2 + P3 P2G1 + P3 P2 P1 P0
i
Nota 1
Nota 2
G1 + G0
Nota 1 : Nota 2 :
(
G3 + P3G2 + P3 P2G1 + P3 P2 P1 P0 G0 + C n
)
P2 + G2 P1 + G2 G1 P0 + G2 G1 G0C n ∀ P3 + G3 P2 + G3 G2 P1 + G3 G2 G1 P0 + G3 G2 G1 G0C n
Package - ul
În acest package am definit câteva tipuri de date şi seturi de constante pentru a-mi uşura scrierea codului. PackageCY7C901.vhd library IEEE ; use IEEE.std_logic_1164.all ; package packageCY7C901 is subtype vec2 is std_logic_vector (1 downto 0) ; subtype vec3 is std_logic_vector (2 downto 0) ; subtype vec4 is std_logic_vector (3 downto 0) ; -- ALU Source Operand Control' s Mnemonic constant AQ : vec3 := "000" ; constant AB : vec3 := "001" ; constant ZQ : vec3 := "010" ; constant ZB : vec3 := "011" ; constant ZA : vec3 := "100" ; constant DA : vec3 := "101" ; constant DQ : vec3 := "110" ; constant DZ : vec3 := "111" ; -- ALU Function Control's Mnemonics ; --s-a folosit sufixul _i fiindca unele mnemonice sunt cuvinte rezervate in VHDL constant ADD_i : vec3 := "000" ; constant SUBR_i : vec3 := "001" ; constant SUBS_i : vec3 := "010" ; constant OR_i : vec3 := "011" ; constant AND_i : vec3 := "100" ; constant NOTRS_i: vec3 := "101" ; constant EXOR_i : vec3 := "110" ; constant EXNOR_i : vec3 := "111" ; -- ALU Destination Control's Mnemonics constant QREG : vec3 := "000" ; constant NOP : vec3 := "001" ; constant RAMA : vec3 := "010" ; constant RAMF : vec3 := "011" ; constant RAMQD : vec3 := "100" ; constant RAMD : vec3 := "101" ; constant RAMQU : vec3 := "110" ; constant RAMU : vec3 := "111" ; -- Semnale folosite pentru vizualizare in test_bench-uri type ALU_source is (AQv, ABv, ZQv, ZBv, zAv, DAv, DQv, DZv, XXX) ; type ALU_instruction is (ADDv, SUBRv, SUBSv, ORv, ANDv, NOTRSv, EXORv, EXNORv, XXX) ; type ALU_destination is (QREGv, NOPv, RAMAv, RAMFv, RAMQDv, RAMDv, RAMQUv, RAMUv, XXX)
;
end packageCY7C901 ;
71
ALU
Pentru acest bloc am decis să folosesc o metodă de testare completă. Astfel, pentru fiecare pereche de valori ale intr ărilor R şi S (în total 16 x 16 = 256) , am aplicat pe intrarea de control, succesiv, fiecare din cele 8 instrucţiuni şi, pentru fiecare instrucţiune, am atribuit intr ării Cn atât nivelul LOW, cât şi nivelul HIGH. Astfel, pentru testarea completă a acestui bloc se generează 16 x 16 x 8 x 2 = 4096 de vectori de test. Simularea circuitului pentru aceşti 4096 de vectori de test presupune un efort de calcul nesemnificativ. Testarea completă a fost posibilă în acest caz datorită caracterului pur combinaţional şi numărului foarte mic de intr ări (12) ale acestui bloc. test_ALU.vhd library IEEE ; use IEEE.std_logic_1164.all ; use IEEE.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity test_ALU is end ; architecture test of test_ALU is signal R, S, F : vec4 ; signal Rv, Sv, Fv : integer ; -- pentru vizualizare ; signal CNTL : vec3 ; signal CNTLv : ALU_instructio n ; -- pentru vizualizare signal Cn, nG, nP, Cn4, OVR : std_logic ; component ALU port (R, S : in vec4 ; CNTL : in vec3 ; Cn : in std_logic ; F : out vec4 ; std_logic) ; end component ; constant TPER : time := 30 ns ; constant DELAY : time := 10 ns ; signal nG_t, nP_t, Cn4_t, OVR_t : std_logic ; signal F_t : vec4 ; signal P, G : vec4 ; signal C4, C3 : std_logic ; signal test_OK : BOOLEAN := TRUE ; signal vec12 : std_logic_vect or (11 downto 0) := "000000000000" ; begin vec12 <= vec12 + 1 after TPER ; R <= vec12 (11 downto 8) ; S <= vec12 (7 downto 4) ; CNTL <= vec12 (3 downto 1) ; Cn <= vec12 (0) ;
nG, nP, Cn4, OVR : out
DUT : ALU port map (R, S, CNTL, Cn, F, nG, nP, Cn4, OVR) ; process begin wait until (R'event or S'event or CNTL'event or Cn'event) ; case CNTL is when ADD_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when SUBR_i => for k in 0 to 3 loop P(k) <= (not R(k)) or S(k) ; G(k) <= (not R(k)) and S(k) ; end loop ; when SUBS_i => for k in 0 to 3 loop P(k) <= R(k) or (not S(k)) ; G(k) <= R(k) and (not S(k)) ; end loop ; when OR_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when AND_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when NOTRS_i => for k in 0 to 3 loop P(k) <= (not R(k)) or S(k) ; G(k) <= (not R(k)) and S(k) ;
72
end loop ; when EXOR_i => for k in 0 to 3 loop P(k) <= (not G(k) <= (not end loop ; when others => -- EXNOR_i for k in 0 to 3 loop P(k) <= R(k) G(k) <= R(k) end loop ;
R(k)) R(k))
or S(k) ; and S(k) ;
or S(k) ; and S(k) ;
end case ; end process ; C4 <= G(3) or (P(3) and G(3)) or (P(3) C3 <= G(2) or (P(2) and G(1))
and P(2) and G(1)) or (P(3) and P(2) and G(0)) or (P(3) and P(2) and P(1) and P(0) and Cn);
or
(P(2) and P(1) and G(0))
or
(P(2) and P(1) and P(0) and Cn)
;
process begin wait until (R'event or S'event or CNTL'event or Cn' event or C4'event or C3'event or P'event or G'event); case CNTL is when ADD_i => F_t <= R + S + Cn; nP_t <= not (P(3) and P(2) and P(1) and P(0)) ; nG_t <= not(G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0))); Cn4_t <= C4 ; OVR_t <= C3 xor C4 ; when SUBR_i => F_t <= S - R - (not Cn) ; nP_t <= not (P(3) and P(2) and P(1) and P(0)) ; nG_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0)) ) ; Cn4_t <= C4 ; OVR_t <= C3 xor C4 ; when SUBS_i => F_t <= R - S - (not Cn) ; nP_t <= not (P(3) and P(2) and P(1) and P(0)) ; nG_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0)) ) ; Cn4_t <= C4 ; OVR_t <= C3 xor C4 ; when OR_i => F_t <= R or S ; nP_t <= '0' ; nG_t <= P(3) and P(2) and P(1) and P(0) ; Cn4_t <= (not (P(3) and P(2) and P(1) and P(0)) ) or Cn ; OVR_t <= (not (P(3) and P(2) and P(1) and P(0)) ) or Cn ; when AND_i => F_t <= R and S ; nP_t <= '0' ; nG_t <= not (G(3) or G(2) or G(1) or G(0) ) ; Cn4_t <= G(3) or G(2) or G(1) or G(0) or Cn ; OVR_t <= G(3) or G(2) or G(1) or G(0) or Cn ; when NOTRS_i => F_t <= (not R) and S ; nP_t <= '0' ; nG_t <= not (G(3) or G(2) or G(1) or G(0) ) ; Cn4_t <= G(3) or G(2) or G(1) or G(0) or Cn ; OVR_t <= G(3) or G(2) or G(1) or G(0) or Cn ; when EXOR_i => F_t <= R xor S ; nP_t <= G(3) or G(2) or G(1) or G(0) ; nG_t <= G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0)) ; Cn4_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0) and (G(0) or (not Cn)) ) ) ; OVR_t <= (P(2) or (G(2) and P(1)) or ((not G(2)) and (not G(1)) and (not P(0)))) xor ((not P(3)) or ((not G(3)) and (not P(2))) or ((not G(3)) and (not G(2)) and (not P(1))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not P(0))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not G(0)) and Cn));
when others => -- EXNOR_i F_t <= R xnor S ; nP_t <= G(3) or G(2) or G(1) or G(0) ; nG_t <= G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0)); Cn4_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0) and (G(0) or (not Cn)) )) ; OVR_t <= (P(2) or (G(2) and P(1)) or ((not G(2)) and (not G(1)) and (not P(0)))) xor((not P(3)) or ((not G(3)) and (not P(2))) or ((not G(3)) and (not G(2)) and (not P(1)) or ((not G(3)) and (not G(2)) and (not G(1)) and (not P(0))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not G(0)) and Cn)) ;
73
end case ; end process ; process begin wait until (R'event or S'event or CNTL'event or Cn'event) ; wait for DELAY ; if((F_t = F) and (Cn4_t = Cn4) and (OVR_t = OVR) and (nG_t = nG)
and
(nP_t = nP) )
then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity Warning ; end if ; end process ; -- Semnalele pentru vizualizare Rv <= conv_integer (R) ; Sv <= conv_integer (S) ; Fv <= conv_integer (F) ; process (CNTL) begin case CNTL is when ADD_i => when SUBR_i => when SUBS_i => when OR_i => when AND_i => when NOTRS_i => when EXOR_i => when EXNOR_i => when others => end case ; end process ; end test ;
CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv
<= <= <= <= <= <= <= <= <=
ADDv ; SUBRv ; SUBSv ; ORv ; ANDv ; NOTRSv ; EXORv ; EXNORv ; XXX ;
Descrierea VHDL a blocului ALU reprezintă transpunerea în cod VHDL a informaţiilor conţinute în tabelele 2 şi 5, solicitând mai mult atenţia decât inventivitatea. ALU.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; use IEEE.std_logic_unsigned.all ; entity ALU is port (R, S : in vec4 ; CNTL : in vec3 ; Cn : in std_logic ; F : out vec4 ; std_logic) ; end ALU ; architecture RTL of ALU is signal P, G : vec4 ; signal C3, C4 : std_logic ; begin process (R, S, CNTL, Cn) begin case CNTL is when ADD_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when SUBR_i => for k in 0 to 3 loop P(k) <= (not R(k)) or S(k) ; G(k) <= (not R(k)) and S(k) ; end loop ; when SUBS_i => for k in 0 to 3 loop P(k) <= R(k) or (not S(k)) ; G(k) <= R(k) and (not S(k)) ; end loop ; when OR_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when AND_i =>
nG, nP, Cn4, OVR : out
74
for k in 0 to 3 loop P(k) <= R(k) G(k) <= R(k) end loop ; when NOTRS_i => for k in 0 to 3 loop P(k) <= (not G(k) <= (not end loop ; when EXOR_i => for k in 0 to 3 loop P(k) <= (not G(k) <= (not end loop ; when others => -- EXNOR_i for k in 0 to 3 loop P(k) <= R(k) G(k) <= R(k) end loop ;
or S(k) ; and S(k) ;
R(k)) R(k))
or S(k) ; and S(k) ;
R(k)) R(k))
or S(k) ; and S(k) ;
or S(k) ; and S(k) ;
end case ; end process ; process (P, G, Cn) begin C4 <= G(3) or (P(3) and G(3)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and G(0)) or (P(3) and P(2) and P(1) and P(0) and Cn) ; C3 <= G(2) or (P(2) and G(1)) or (P(2) and P(1) and G(0)) or (P(2) and P(1) and P(0) and Cn) ; end process ; process (R, S, CNTL, P, G, Cn, C4, C3) begin case CNTL is when ADD_i => F <= R + S + Cn; nP <= not (P(3) and P(2) and P(1) and P(0)) ; nG <= not(G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0))) ; Cn4 <= C4 ; OVR <= C3 xor C4 ; when SUBR_i => F <= S - R - (not Cn) ; nP <= not (P(3) and P(2) and P(1) and P(0)) ; nG <= not(G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0))) ; Cn4 <= C4 ; OVR <= C3 xor C4 ; when SUBS_i => F <= R - S - (not Cn) ; nP <= not (P(3) and P(2) and P(1) and P(0)) ; nG <= not(G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0))) ; Cn4 <= C4 ; OVR <= C3 xor C4 ; when OR_i => F <= R or S ; nP <= '0' ; nG <= P(3) and P(2) and P(1) and P(0) ; Cn4 <= (not (P(3) and P(2) and P(1) and P(0)) ) or Cn ; OVR <= (not (P(3) and P(2) and P(1) and P(0)) ) or Cn ; when AND_i => F <= R and S ; nP <= '0' ; nG <= not (G(3) or G(2) or G(1) or G(0) ) ; Cn4 <= G(3) or G(2) or G(1) or G(0) or Cn ; OVR <= G(3) or G(2) or G(1) or G(0) or Cn ; when NOTRS_i => F <= (not R) and S ; nP <= '0' ; nG <= not (G(3) or G(2) or G(1) or G(0) ) ; Cn4 <= G(3) or G(2) or G(1) or G(0) or Cn ; OVR <= G(3) or G(2) or G(1) or G(0) or Cn when EXOR_i => F <= R xor S ; nP <= G(3) or G(2) or G(1) or G(0) ; nG <= G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0)) ; Cn4 <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0) and (G(0) or (not Cn)) ) ) ; OVR <= (P(2) or (G(2) and P(1)) or ((not G(2)) and (not G(1)) and (not P(0)))) xor ((not P(3)) or ((not G(3)) and (not P(2)))
or
((not G(3)) and (not G(2)) and (not P(1)))
or
((not G(3)) and (not G(2)) and
75
(not G(1))and (not P(0)))
or
((not G(3)) and (not G(2)) and (not G(1)) and (not G(0)) and Cn))
;
when others => -- EXNOR_i F <= R xnor S ; nP <= G(3) or G(2) or G(1) or G(0) ; nG <= G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0)) Cn4 <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0) and (G(0) or (not Cn)) ) ) ; OVR <= (P(2) or (G(2) and P(1)) or ((not G(2)) and (not G(1)) and (not P(0)))) xor ((not P(3)) or ((not
;
G(3)) and (not P(2))) or ((not G(3)) and (not G(2)) and (not P(1))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not P(0))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not G(0)) and Cn))
;
end case ; end process ; end RTL ;
Întrucât am realizat testarea completă a acestui bloc, prezentarea unor forme de undă obţinute în urma simulării ar fi irelevantă sau ar ocupa foarte mult spaţiu. Urmărirea funcţionării acestui bloc se poate realiza cu fişierele de pe CD-ul anexă.
ALU – RTL
Q_REGISTER test_Q_REGISTER.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity test_Q_REGISTER is end ; architecture test of test_Q_REGISTER is component Q_REGISTER port(CP : in std_logic ; F, Q : in vec4 ; CNTL : in vec3 ; Q_out : out vec4) ; end component ; signal CP : std_logic := '0' ; signal F : vec4 := "0001" ; signal Q : vec4 := "1001" ; signal Q_out : vec4 ; signal CNTL : vec3 := "000" ; signal CNTLv : ALU_destination ; -- pentru vizualizare constant TPER : time := 20 ns ; constant DELAY : time := 3 ns ; signal test_OK : BOOLEAN := TRUE ; begin DUT : Q_REGISTER port map (CP, F, Q, CNTL, Q_out) ; CP <= not CP after TPER / 2 ; process begin
76
wait wait CNTL F <= Q <=
until (CP'event and CP = '1') for TPER/4 ; <= CNTL + 1 ; F + 7 ; Q + 9 ;
;
end process ; process variable F_var, Q_var, Q_out_var : vec4 ; begin wait until (CP'event and CP = '0') ; F_var := F ; Q_var := Q ; Q_out_var := Q_out ; wait until (CP'event and CP = '1') ; wait for DELAY ; case CNTL is when QREG => if (Q_out = F_var) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; when RAMQD => if (Q_out = Q_var) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; when RAMQU => if (Q_out = Q_var) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; when others => if (Q_out = Q_out_var) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; end case ; end process ; -- pentru vizualizare process (CNTL) begin case CNTL is when QREG => CNTLv <= QREGv ; when NOP => CNTLv <= NOPv ; when RAMA => CNTLv <= RAMAv ; when RAMF => CNTLv <= RAMFv ; when RAMQD => CNTLv <= RAMQDv ; when RAMD => CNTLv <= RAMDv ; when RAMQU => CNTLv <= RAMQUv ; when RAMU => CNTLv <= RAMUv ; when others => CNTLv <= XXX ; end case ; end process ; end test ;
Întrucât de pe diagrama bloc a circuitului CY7C901 se observă că blocul Q_REGISTER realizează o dublă funcţie (registru master-slave + selecţia uneia dintre cele două intr ări) , am hotărât să-l descompun în două sub-blocuri : Q_REGISTER_SOURCE_SEL (realizează selecţia uneia dintre cele 2 intr ări, F şi Q, în funcţie de intrarea de control, CNTL) şi REG_MASTER_SLAVE. Blocul REG_MASTER_SLAVE are o intrare de activare, LD_EN, care se conectează la ieşirea cu acelaşi nume a blocului 77
Q_REGISTER_SOURCE_SEL. Semnalul LD_EN este activat sau dezactivat conform informaţiilor din tabelul 4. Şi în cazul acestui bloc am trecut peste specificaţiile circuitului (din acelea şi motive ca şi în cazul memoriei RAM) , încărcarea datelor în registru şi transferarea acestora pe ieşiri f ăcându-se pe front, nu pe palier. Descrierile VHDL pentru blocul Q_REGISTER şi pentru cele 2 sub-blocuri ale sale sunt date în continuare. Q_REGISTER_SOURCE_SEL.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity Q_REGISTER_SOURCE_SEL is port (F, Q : in vec4 ; CNTL : in vec3 ; Q_in : out vec4 ; LD_EN : out std_logic) ; end Q_REGISTER_SOURCE_SEL ; architecture RTL of Q_REGISTER_SOURCE_SEL is begin process (CNTL, F, Q) begin case CNTL is when QREG => Q_in <= F ; LD_EN <= '1' ; when RAMQD => Q_in <= Q ; LD_EN <= '1' ; when RAMQU => Q_in <= Q ; LD_EN <= '1' ; when others => Q_in <= "----" ; LD_EN <= '0' ; end case ; end process ; end RTL ;
REG_MASTER_SLAVE.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity REG_MASTER_SLAVE is port (CP : in std_logic ; Q_in : in vec4 ; LD_EN : in std_logic ; Q_out : out vec4) ; end REG_MASTER_SLAVE ; architecture RTL of REG_MASTER_SLAVE is signal Q_master : vec4 ; begin process (CP) begin if (CP'event and CP = '0') then if (LD_EN = '1') then Q_master <= Q_in ; end if ; end if ; end process ; process (CP) begin if (CP'event and CP = '1') Q_out <= Q_master ; end if ;
then
end process ; end RTL ;
Q_REGISTER library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity Q_REGISTER is port (CP : in std_logic ; F, Q : in vec4 ; CNTL : in vec3 ; Q_out : out vec4) ; end Q_REGISTER ; architecture RTL of Q_REGISTER is
78
signal Q_in : vec4 ; -- F sau Q in functie de CNTL signal LD_EN : std_logic ; component Q_REGISTER_SOURCE_SEL port (F, Q : in vec4 ; CNTL : in vec3 ; Q_in : out vec4 ; LD_EN : out std_logic) ; end component ; component REG_MASTER_SLAVE port(CP : in std_logic ; Q_in : in vec4 ; LD_EN : in std_logic ; Q_out : out vec4); end component ; begin SOURCE_SELECT_i : Q_REGISTER_SOURCE _SEL port map (F, Q, CNTL, Q_in, LD_EN) MASTER_SLAVE_i : REG_MASTER_SLAV E port map (CP, Q_in, LD_EN, Q_out) ; end RTL ;
;
Q_REGISTER (RTL)
Q_REGISTER_SOURCE_SELECTOR
(RTL)
REG_MASTER_SLAVE (RTL)
Q_REGISTER (RTL)
79
Q_SHIFT Deşi
aparent simplu (de fapt chiar aşa şi este) , blocul Q_SHIFT mi-a creat cele mai mari probleme dintre toate blocurile lui CY7C901. Cauzele acestor probleme sunt cele două porturi bidirecţionale, Q3 şi Q0, ale acestui bloc. Problemele au apărut pentru că, pe parcursul codului, un port bidirecţional devenea, pe rând, în funcţie de anumite condiţii, fie port de intrare, fie port de ieşire. Deşi codul iniţial părea corect, nici simularea presinteză, nici sinteza nu au dat rezultate satisf ăcătoare. Trebuie să precizez aici că în nici una din cele 6 căr ţi (indicate în bibliografie) care tratează limbajul VHDL, studiate de mine, nu am găsit măcar un exemplu care să trateze un circuit cu porturi bidirecţionale. Soluţia pentru rezolvarea acestor probleme am găsit-o după ce am studiat structura fizică a unui port bidirecţional. Pentru a transpune această structur ă fizică într-un cod VHDL, am apelat la un mic truc : am implementat mai întâi un bloc, pe care l-am numit Q_SHIFT_INTERN, care avea acelaşi aspect şi funcţionalitate cu blocul Q_SHIFT, cu singura diferenţă, dar esenţială, că fiecare din cele două porturi bidirecţonale, Q3 şi Q0, au fost înlocuite cu câte două porturi (unul de intrare şi unul de ieşire) şi anume Q3 IN şi Q 3 OUT , respectiv Q0 IN şi Q 0 OUT . De fiecare dată când unul din porturile bidirecţionale, de exemplu Q3, este folosit ca pin de intrare este necesar ca pinul de ieşire asociat, Q3 OUT în acest caz, să fie trecut în starea de înaltă impedanţă. Apoi blocul Q_SHIFT_INTERN este inclus în blocul Q_SHIFT, având pinii Q3 IN şi Q3 OUT conectaţi intern la pinul Q3 al lui Q_SHIFT, iar Q0 IN şi Q0 OUT fiind conectaţi la pinul Q0 . Q_SHIFT_INTERN.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity Q_SHIFT_INTERN is port ( F : in vec4 ; Q3_in, Q0_in : in std_logic ; Q3_out, Q0_out : out std_logic ; CNTL : in vec3 ; D : out vec4) ; end Q_SHIFT_INTERN ; architecture RTL of Q_SHIFT_INTERN is begin process (CNTL, F, Q3_in, Q0_in) begin case CNTL is when RAMQD => Q3_out <= 'Z' ; Q0_out <= F(0) ; D(2 downto 0) <= F (3 downto 1) ; D (3) <= Q3_in ; when RAMQU => Q3_out <= F(3) ; Q0_out <= 'Z' ; D (3 downto 1) <= F (2 downto 0) ; D(0) <= Q0_in ; when others => -- QREG,NOP, RAMA, RAMF, RAMD, RAMU Q3_out <= '-' ; Q0_out <= '-' ; D <= "----" ; end case ; end process ; end RTL ;
80
Q_SHIFT.vhd library IEEE ; use IEEE.std_logic_1164.all ; use IEEE.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity Q_SHIFT is port(Q_in : in vec4 ; CNTL : in vec3 ; Q3, Q0 : inout std_logic ; Q_out : out vec4); end Q_SHIFT ; architecture RTL of Q_SHIFT is component Q_SHIFT_INTERN port (F : in vec4 ; Q3_in, Q0_in : in std_logic ; Q3_out, Q0_out : out std_logic ; CNTL : in vec3 ; D : out vec4) ; end component ; begin INT_i : Q_SHIFT_INTERN port map (Q_in, Q3, Q0, Q3, Q0, CNTL, Q_out) ; end RTL ;
Probleme deosebite au apărut şi la realizarea test_bench-ului pentru Q_SHIFT. Astfel, pentru fiecare caz în care unul din porturile bidirecţionale avea rol de pin de ieşire, a fost necesar ă aplicarea nivelului HZ, din exterior, pe acel pin. (se înţelege mai bine de pe formele de undă) . test_Q_SHIFT.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_arith.all ; use work.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity test_Q_SHIFT is end ; architecture test of test_Q_SHIFT is component Q_SHIFT port(Q_in : in vec4 ; CNTL : in vec3 ; Q3, Q0 : inout std_logic ; Q_out : out vec4); end component ; signal Q_in, Q_out : vec4 ; signal CNTL : vec3 := "000" ; signal CNTLv : ALU_destination ; -- pentru vizualizare signal Q3, Q0 : std_logic ; signal DATAIN : std_logic_vector (5 downto 0) := "001101" ; constant TPER : time := 10 ns ; constant DELAY : time := 5 ns ; signal test_OK : BOOLEAN := TRUE ; begin DUT : Q_SHIFT port map (Q_in, CNTL, Q3, Q0, Q_out) ; --generare pseudo aleatoare a semnalului DATAIN si, dece, a semnalelor Q_in, Q3, Q0 DATAIN <= DATAIN + 37 after TPER ; Q_in <= DATAIN (4 downto 1) ; CNTL <= CNTL + 1 after TPER ; process (DATAIN, CNTL) begin case CNTL is when RAMQD => Q3 <= DATAIN(5) ; Q0 <= 'Z' ; when RAMQU => Q3 <= 'Z' ; Q0 <= DATAIN(0) ; when others => -- QREG,NOP, RAMA, RAMF, RAMD, RAMU Q3 <= '-' ; Q0 <= '-' ; end case ; end process ; process variable DATAIN_var : std_logic_vecto r (5 downto 0) ; begin wait until (DATAIN'event or CNTL'event) ; DATAIN_var := DATAIN ; wait for DELAY ; case CNTL is when RAMQD => if (Q_out = DATAIN_var (5 downto 2) and Q0 = DATAIN_var(1)) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ;
then
81
end if ; when RAMQU => if(Q_out = DATAIN_var(3 downto 0) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; when others => test_OK <= TRUE ; end case ;
and Q3 = DATAIN_var (4) )
then
end process ; -- pentru vizualizare process (CNTL) begin case CNTL is when when when when when when when when when end case ;
QREG => NOP => RAMA => RAMF => RAMQD => RAMD => RAMQU => RAMU => others =>
CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv
<= <= <= <= <= <= <= <= <=
QREGv ; NOPv ; RAMAv ; RAMFv ; RAMQDv ; RAMDv ; RAMQUv ; RAMUv ; XXX ;
end process ; end test ;
Q_SHIFT
Q_SHIFT (RTL)
82
RAM_ADDRESSABLE_REGISTERS
Programul de test pentru acest bloc realizează următoarele : Se încarcă pe rând câte o dată (aplicată pe intrarea B_DATAIN) într-un registru al memoriei (selectat de B_ADDRESS) , ceea ce presupune ca WR_EN = ‘1’ ; Pentru fiecare dată înscrisă în RAM, scrierea având loc efectiv pe frontul pozitiv al ceasului, se testează funcţionarea corectă a blocului prin compararea datei de la ieşirea RAMB_DATAOUT după frontul negativ imediat următor al ceasului cu data aplicată anterior pe intrarea B_DATAIN. După scrierea cu date a tuturor celor 16 locaţii de memorie, semnalul WR_EN este dezactivat şi în continuare se testează corectitudinea funcţionării memoriei, prin compararea ieşirilor RAMA_DATAOUT şi RAMB_DATAOUT cu valorile la care ne aşteptam cunoscând conţinutul memoriei la momentul respectiv. test_RAM_ADDRESSABLE_REGISTERS.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.NUMERIC_STD.all ; use work.packageCY7C901.all ; entity test_RAM_ADDRESSABLE_REGISTERS is end ; architecture test of test_RAM_ADDRESSABLE_REGISTERS is type mem is array (15 downto 0) of vec4 ; signal ram, buf : mem ; component RAM_ADDRESSABLE_REGISTERS port ( CP : in std_logic ; A_ADDRESS, B_ADDRESS, B_DATAIN : in vec4 ; WR_EN : in std_logic ; RAMA_DATAOUT, RAMB_DATAOUT : out vec4) end component ; signal CP : std_logic := '1' ; signal WR_EN : std_logic := '1' ; signal A, B, B_in : vec4 := "1111" ; signal A_out, B_out : vec4 ; constant TPER : time := 50 ns ; -- perioada semnalului de ceas constant DELAY : time := TPER/16 ; constant DELAY2 : time := 2 ns ; signal test_OK : BOOLEAN := TRUE ; signal TRUC : vec4 ;
;
begin DUT : RAM_ADDRESSABLE _REGISTERS port map (CP, A, B, B_in, WR_EN, A_out, B_out) ; CP <= not CP after TPER / 2 ; WR_EN <= '1' , '0' after 17.5 * TPER ; process begin buf(0) <= "0101" ; for k in 1 to 15 loop wait for 0.01 ns ; -- intarziere minima ; in absenta acesteia ar rezulta o eroare buf(k) <= buf(k - 1) + 7 ; end loop ; end process ; process variable B_in_var : vec4 ; begin for k in 0 to 15 loop wait until (CP'event and CP = '0') wait for TPER/8 ; B_in <= buf(k) ; wait for 0.1 ns ; B_in_var := B_in ; TRUC <= B_in_var ; end loop ; end process ;
;
process begin wait until (CP'event and CP = '0') wait for TPER/4 ; A <= A + 3 ; B <= B + 1 ;
;
end process ; process begin wait until
(CP'event and CP = '0')
;
83
wait for DELAY ; case WR_EN is when '1' => if (B_out = TRUC) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; when others => if (A_out = buf(TO_INTEGER(UNSIGNED(A))) and B_out = buf(TO_INTEGER(UNSIGNED(B)))) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; end case ; end process ; end test ;
Realizarea descrierii VHDL pentru acest bloc a fost destul de dificilă. Iniţial am înercat să respect specificaţiile din documentaţie, conform cărora o dată se înscrie în RAM pe palierul LOW al semnalului de ceas, iar datele apar pe ieşiri pe palierul HIGH al semnalului de ceas. Problemele au apărut pe durata procesului de sinteză, când au fost generate avertismente de tipul “time loop detected”. Apoi, la simularea postsinteză, am fost bombardat cu mesaje de eroare ce sesizau violări de timing (setup şi hold) . Cautând să înţeleg sursa acestor erori, am descoperit că descrierea VHDL a determinat programul de sinteză să implementeze memoria RAM utilizând latch-uri. Am aflat că aceste latch-uri creează cele mai mari probleme într-un proiect şi c ă descrierea VHDL a unui circuit trebuie realizată astfel încât programul de sinteză să folosească numai bistabili (în locul latch-urilor) la implementarea circuitului respectiv. Ca urmare, am trcut peste specificaţii şi am modificat descrierea VHDL în sensul că înscrierea datelor în RAM se face pe frontul pozitiv al semnalului de ceas, iar transferarea datelor pe ieşirile memoriei RAM se face pe frontul negativ al semnalului de ceas. În urma acestor modificări au dispărut atât erorile de la sinteză, cât şi cele de la simularea postsinteză. Trebuie, totuşi, să precizez că, prin înlocuirea latch-urilor cu bistabili, aria circuitului cre şte semnificativ. RAM_ADDRESSABLE_REGISTERS.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_unsigned.all ; use work.NUMERIC_STD.all ; use work.packageCY7C901.all ; entity RAM_ADDRESSABLE_REGISTERS is port ( CP : in std_logic ; A_ADDRESS, B_ADDRESS, B_DATAIN : in vec4 ; WR_EN : in std_logic ; RAMA_DATAOUT, RAMB_DATAOUT : out vec4) ; end RAM_ADDRESSABLE_REGISTERS ; architecture RTL of RAM_ADDRESSABLE_REGISTERS is type mem is array (15 downto 0) of vec4 ; signal memo : mem ; begin process (CP) begin if (CP'event and CP = '0') then RAMA_DATAOUT <= memo(to_integer (unsigned(A_ADDRESS))) ; RAMB_DATAOUT <= memo(to_integer (unsigned(B_ADDRESS))) ; end if ; end process ; process (CP) begin if (CP'event and CP = '1') then if WR_EN = '1' then memo(to_integer (unsigned(B_ADDRESS))) <= B_DATAIN ; end if ; end if ; end process ; end RTL ;
84
RAM_ADDRESSABLE_REGISTERS (RTL) : a) complet ; b) vedere parţială
Operaţiunea de scriere a datelor în RAM (iniţial conţinutul RAM-ului este nedeterminat)
Opearaţiunea de citire a datelor din RAM.
85
RAM_SHIFT
Acest bloc este aproape identic cu Q_SHIFT, observaţiile de la Q_SHIFT fiind deci valabile şi pentru acest bloc. test_RAM_SHIFT.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.std_logic_arith.all ; use work.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity test_RAM_SHIFT is end ; architecture test of test_RAM_SHIFT is component RAM_SHIFT is port(F : in vec4 ; CNTL : in vec3 ; RAM3, RAM0 : inout std_logic ; B : out vec4); end component ; signal F, B : vec4 ; signal CNTL : vec3 := "000" ; signal CNTLv : ALU_destination ; -- pentru vizualizare signal RAM3, RAM0 : std_logic ; signal DATAIN : std_logic_vector (5 downto 0) := "001101" ; constant TPER : time := 10 ns ; constant DELAY : time := 5 ns ; signal test_OK : BOOLEAN := TRUE ; begin DUT : RAM_SHIFT port map (F, CNTL, RAM3, RAM0, B) ; --generare pseudo aleatoare a semnalului DATAIN si, dece, a semnalelor F, RAM3, RAM0 DATAIN <= DATAIN + 37 after TPER ; F <= DATAIN (4 downto 1) ; CNTL <= CNTL + 1 after TPER ; process (DATAIN, CNTL) begin case CNTL is when RAMQD => RAM3 <= DATAIN(5) ; RAM0 <= 'Z' ; when RAMD => RAM3 <= DATAIN(5) ; RAM0 <= 'Z' ; when RAMQU => RAM3 <= 'Z' ; RAM0 <= DATAIN(0) ; when RAMU => RAM3 <= 'Z' ; RAM0 <= DATAIN(0) ; when others => -- QREG,NOP, RAMA, RAMF, RAMD, RAMU RAM3 <= '-' ; RAM0 <= '-' ; end case ; end process ; process variable DATAIN_var : std_logic_vecto r (5 downto 0)
;
begin wait until (DATAIN'event or CNTL'event) ; DATAIN_var := DATAIN ; wait for DELAY ; case CNTL is when RAMA => if (B = DATAIN (4 downto 1) ) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; when RAMF => if (B = DATAIN (4 downto 1) ) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; when RAMQD => if (B = DATAIN_var (5 downto 2) and RAM0 = DATAIN_var(1)) test_OK <= TRUE ;
then
86
else
when
when
when
when
test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; RAMD => if (B = DATAIN_var (5 downto 2) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; RAMQU => if (B = DATAIN_var (3 downto 0) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; RAMU => if (B = DATAIN_var (3 downto 0) test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; others => test_OK <= TRUE ;
and RAM0 = DATAIN_var(1))
then
and RAM3 = DATAIN_var (4) )
then
and RAM3 = DATAIN_var (4) )
then
end case ; end process ; -- pentru vizualizare process (CNTL) begin case CNTL is when when when when when when when when when end case ;
QREG => NOP => RAMA => RAMF => RAMQD => RAMD => RAMQU => RAMU => others =>
CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv
<= <= <= <= <= <= <= <= <=
QREGv ; NOPv ; RAMAv ; RAMFv ; RAMQDv ; RAMDv ; RAMQUv ; RAMUv ; XXX ;
end process ; end test ;
RAM_SHIFT_INTERN.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity RAM_SHIFT_INTERN is port ( F : in vec4 ; RAM3_in, RAM0_in : in std_logic ; RAM3_out, RAM0_out : out std_logic ; CNTL : in vec3 ; D : out vec4) end RAM_SHIFT_INTE RN ; architecture RTL of RAM_SHIFT_INTER N is begin process (CNTL, F, RAM3_in, RAM0_in) begin case CNTL is when RAMA => D <= F ; RAM3_out <= '-' ; RAM0_out <= '-' ; when RAMF => D <= F ; RAM3_out <= '-' ; RAM0_out <= '-' ; when RAMQD => RAM3_out <= 'Z' ; RAM0_out <= F(0) ; D(2 downto 0) <= F (3 downto 1) ;
;
87
D (3) <= RAM3_in ; when RAMD => RAM3_out <= 'Z' ; RAM0_out <= F(0) ; D(2 downto 0) <= F (3 downto 1) ; D (3) <= RAM3_in ; when RAMQU => RAM3_out <= F(3) ; RAM0_out <= 'Z' ; D (3 downto 1) <= F (2 downto 0) ; D(0) <= RAM0_in ; when RAMU => RAM3_out <= F(3) ; RAM0_out <= 'Z' ; D (3 downto 1) <= F (2 downto 0) ; D(0) <= RAM0_in ; when others => -- QREG si NOP RAM3_out <= '-' ; RAM0_out <= '-' ; D <= "----" ; end case ; end process ; end RTL ;
RAM_SHIFT.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity RAM_SHIFT is port(F : in vec4 ; CNTL : in vec3 ; RAM3, RAM0 : inout std_logic ; B : out vec4); end RAM_SHIFT ; architecture RTL of RAM_SHIFT is component RAM_SHIFT_INTERN port ( F : in vec4 ; RAM3_in, RAM0_in : in std_logic ; RAM3_out, RAM0_out : out std_logic ; CNTL : in vec3 ; D : out vec4) ; end component ; begin INT_i : RAM_SHIFT_INTERN port map (F, RAM3, RAM0, RAM3, RAM0, CNTL, B) ; end RTL ;
RAM_SHIFT (RTL)
ALU_DATA_SOURCE_SELECTOR
Acest bloc nu a ridicat probleme deosebite, descrierea VHDL a acestuia reprezentând transpunerea în cod VHDL a tabelului 2. test_ALU_DATA_SOURCE_SELECTOR.vhd library IEEE, arithmetic ; use IEEE.std_logic_1164.all ; use IEEE.std_logic_unsigned.all ; use arithmetic.std_logic_arith.all ; use work.packageCY7C901.all ; entity test_ALU_DATA_SOURCE_SELECTOR is end ;
88
architecture test of test_ALU_DATA_SOURCE_SELECTOR is component ALU_DATA_SOURCE_SELECTOR port (D, A, B, Q : in vec4 ; CNTL : in vec3 ;R, S : out vec4) end component ; signal D : vec4 := "1010" ; signal A : vec4 := "1100" ; signal B : vec4 := "1001" ; signal Q : vec4 := "0011" ; signal R, S : vec4 ; signal R_t, S_t : vec4 ; signal CNTL : vec3 := "000"; signal CNTLv : ALU_source ; -- pentru vizualizare constant TPER : time := 20 ns ; constant DELAY : time := 5 ns ; signal test_OK : BOOLEAN := TRUE ; begin DUT : ALU_DATA_SOURCE _SELECTOR -- generare pseudo aleatoare a D <= (D + 4) xnor (D rol 1) A <= (D + 8) xnor (A rol 1) B <= (D + 6) xor (B rol 1) Q <= (Q + 9) xnor (Q rol 1)
port map (D, A, B, Q, CNTL, R, S) semnalelor D, A, B, Q after TPER ; after TPER ; after TPER ; after TPER ;
;
;
-- generarea semnalului CNTL CNTL <= CNTL + 1 after TPER ; process begin wait until (D'event or A'event or B'event or Q'event or CNTL'event) case CNTL is when AQ => R_t <= A ; S_t <= Q ; when AB => R_t <= A ; S_t <= B ; when ZQ => R_t <= "0000" ; S_t <= Q ; when ZB => R_t <= "0000" ; S_t <= B ; when ZA => R_t <= "0000" ; S_t <= A ; when DA => R_t <= D ; S_t <= A ; when DQ => R_t <= D ; S_t <= Q ; when others => -- DZ R_t <= D ; S_t <= "0000" ; end case ; end process ;
;
process begin wait until (D'event or A'event or B'event wait for DELAY ; if (R_t = R and S_t = S) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; end process ; -- pentru vizualizare process (CNTL) begin case CNTL is when AQ => CNTLv <= AQv when AB => CNTLv <= ABv when ZQ => CNTLv <= ZQv when ZB => CNTLv <= ZBv
or Q'event or CNTL'event)
;
; ; ; ;
89
when when when when when end case ;
ZA => DA => DQ => DZ => others =>
CNTLv CNTLv CNTLv CNTLv CNTLv
<= <= <= <= <=
ZAv DAv DQv DZv XXX
; ; ; ; ;
end process ; end test ;
ALU_DATA_SOURCE_SELECTOR.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity ALU_DATA_SOURCE_SELECTOR is port (D, A, B, Q : in vec4 ; CNTL : in vec3 ;R, S : out vec4) end ALU_DATA_SOURCE_SELECTOR ; architecture RTL of ALU_DATA_SOURCE_ SELECTOR is begin process (D, A, B, Q, CNTL) begin case CNTL is when AQ => R <= A ; S <= Q ; when AB => R <= A ; S <= B ; when ZQ => R <= "0000" ; S <= Q ; when ZB => R <= "0000" ; S <= B ; when ZA => R <= "0000" ; S <= A ; when DA => R <= D ; S <= A ; when DQ => R <= D ; S <= Q ; when others => -- DZ R <= D ; S <= "0000" ; end case ; end process ;
;
end RTL ;
ALU_DATA_SOURCE_SELECTOR (RTL)
90
OUTPUT_DATA_SELECTOR
Nici acest bloc nu a ridicat probleme deosebite, reprezentând 4 multiplexoare de 2 intr ări având pe ieşiri bufere three-states. test_OUTPUT_DATA_CONTROL.vhd library IEEE, arithmetic ; use IEEE.std_logic_1164.all ; use arithmetic.std_logic_arith.all ; use IEEE.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity test_OUTPUT_DATA_SELECTOR is end ; architecture test of test_OUTPUT_DATA_SELECTOR is component OUTPUT_DATA_SELECTOR port (A, F : in vec4 ; nOE : in std_logic ; CNTL : in vec3 ; Y : out vec4) end component ; signal A, F : vec4 := "1010" ; signal Y, Y_t : vec4 ; signal nOE : std_logic := '0' ; signal CNTL : vec3 := "000" ; signal CNTLv : ALU_destination ; -- pentru vizualizare constant TPER : time := 20 ns ; constant DELAY : time := 5 ns ; signal test_OK : BOOLEAN := TRUE ; begin DUT : OUTPUT_DATA_SEL ECTOR port map (A, F, nOE, CNTL, Y) ;
;
-- generare pseudo aleatoare a semanlelor A si F A <= (A + 9) xnor (A rol 2) after TPER ; F <= (F +3) xnor (F rol 3) after TPER ; nOE <= not nOE after 9 * TPER ; CNTL <= CNTL + 1 after TPER ; process (A, F, nOE, CNTL) begin case nOE is when '0' => case CNTL is when RAMA => Y_t <= A ; when others => Y_t <= F ; end case ; when others => Y_t <= "ZZZZ" ; end case ; end process ; process begin wait until (A'event or F'event or nOE'event or CNTL'event) wait for DELAY ; if (Y_t = Y) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ;
;
end process ;
91
-- pentru vizualizare process (CNTL) begin case CNTL is when when when when when when when when when end case ;
QREG => NOP => RAMA => RAMF => RAMQD => RAMD => RAMQU => RAMU => others =>
CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv CNTLv
<= <= <= <= <= <= <= <= <=
QREGv ; NOPv ; RAMAv ; RAMFv ; RAMQDv ; RAMDv ; RAMQUv ; RAMUv ; XXX ;
end process ; end test ;
OUTPUT_DATA_SELECTOR.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity OUTPUT_DATA_SELECTOR is port (A, F : in vec4 ; nOE : in std_logic ; CNTL : in vec3 ; Y : out vec4) end OUTPUT_DATA_SELECTOR ; architecture RTL of OUTPUT_DATA_SELECTOR is begin process (A, F, nOE, CNTL) begin case nOE is when '0' => case CNTL is when RAMA => Y <= A ; when others => Y <= F ; end case ; when others => Y <= "ZZZZ" ; end case ; end process ; end RTL ;
;
OUTPUT_DATA_SELECTOR (RTL)
92
CY7C901 După descrierea tuturor blocurilor componente, acestea trebuie asamblate astfel încât, împreună, să realizeze funcţionalitatea circuitului CY7C901. Pe lângă blocurile descrise anterior, mai este necesar ă logica pentru semnalul intern WR_EN şi pentru ieşirile F3 (flagul de semn) şi F_eq_0 (flagul de zero) . CY7C901.vhd library IEEE ; use IEEE.std_logic_1164.all ; use work.packageCY7C901.all ; entity CY7C901 is port( A : in vec4 ; B : in vec4 ; I : in std_logic_vecto r (8 downto 0) ; D : in vec4 ; Y : out vec4 ; nOE : in std_logic ; CP : in std_logic ; Q3, RAM3 : inout std_logic ; Q0, RAM0 : inout std_logic ; Cn : in std_logic ; Cn4 : out std_logic ; nG, nP : out std_logic ; OVR : out std_logic ; F_eq_0 : out std_logic ; F3 : out std_logic ) ; end CY7C901 ; architecture STRUCTURAL of CY7C901 is signal I_210, I_543, I_876 : vec3 ; signal A_BUS, B_BUS, F_BUS, R_BUS, S_BUS, Q_BUS, B_DATAIN, Q_SHIFT_OUT : vec4 ; signal WR_EN : std_logic ; component ALU port (R, S : in vec4 ; CNTL : in vec3 ; Cn : in std_logic ; F : out vec4 ; nG, nP, Cn4, OVR : out std_logic) ; end component ; component ALU_DATA_SOURCE_SELECTOR port (D, A, B, Q : in vec4 ; CNTL : in vec3 ;R, S : out vec4) end component ;
;
component OUTPUT_DATA_SELECTOR port (A, F : in vec4 ; nOE : in std_logic ; CNTL : in vec3 ; Y : out vec4) end component ;
;
component RAM_SHIFT port(F : in vec4 ; CNTL : in vec3 ; RAM3, RAM0 : inout std_logic ; B : out vec4); end component ; component RAM_ADDRESSABLE_REGISTERS port ( CP : in std_logic ; A_ADDRESS, B_ADDRESS, B_DATAIN : in vec4 ; WR_EN : in std_logic ; RAMA_DATAOUT, RAMB_DATAOUT : out vec4) ; end component ; component Q_SHIFT port(Q_in : in vec4 ; CNTL : in vec3 ; Q3, Q0 : inout std_logic ; Q_out : out vec4); end component ; component Q_REGISTER port (CP : in std_logic ; F, Q : in vec4 ; CNTL : in vec3 ; Q_out : out vec4) ; end component ; begin I_210 <= I (2 downto 0) ; I_543 <= I (5 downto 3) ; I_876 <= I (8 downto 6) ; process (I_876) begin case I_876 is when QREG => WR_EN <= '0' ; when NOP => WR_EN <= '0' ; when others => WR_EN <= '1' ;
93
end case ; end process ; ALU_i : ALU port map (R_BUS, S_BUS, I_543, Cn, F_bus, nG, nP, Cn4,OVR) ; ALU_D_S_SEL_i : ALU_DATA_SOURCE_ SELECTOR port map (D, A_BUS, B_BUS, Q_BUS, I_210, R_BUS, S_BUS) OUT_D_SEL_i : OUTPUT_DATA_SEL ECTOR port map (A_BUS, F_BUS, nOE, I_876, Y) ; RAM_SHIFT_i : RAM_SHIFT port map (F_BUS, I_876, RAM3, RAM0, B_DATAIN) ; RAM_REG_i : RAM_ADDRESSABLE _REGISTERS port map (CP, A, B, B_DATAIN, WR_EN, A_BUS, B_BUS) ; Q_SHIFT_i : Q_SHIFT port map (Q_BUS, I_876, Q3, Q0, Q_SHIFT_OUT) ; Q_REG_i : Q_REGISTER port map (CP, F_BUS, Q_SHIFT_OUT, I_876, Q_BUS) ; F_eq_0 <= not (F_BUS(3) or F_BUS(2) or F_BUS(1) or F_BUS(0)) ; F3 <= F_BUS(3) ; end STRUCTURAL ;
;
CY7C901 – diagrama bloc obţinută în urma asamblării blocurilor componente
Sinteza CY7C901
Pentru sinteza circuitului CY7C901, r ămân valabile cele spuse la sinteza circuitului CY7C910. Voi reda aici doar fişierele “compile.scr”, “CY7C901_timing_report.txt” şi “CY7C901_area_report.txt”. compile.scr design = CY7C901 analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl analyze -library work -format vhdl elaborate -library work design
sources/packageCY7C901.vhd sources/ALU.vhd sources/ALU_DATA_SOURCE_SELECTOR.vhd sources/OUTPUT_DATA_SELECTOR.vhd sources/REG_MASTER_SLAVE.vhd sources/Q_REGISTER_SOURCE_SEL.vhd sources/Q_REGISTER.vhd sources/Q_SHIFT_INTERN.vhd sources/Q_SHIFT.vhd sources/RAM_ADDRESSABLE_REGISTERS.vhd sources/RAM_SHIFT_INTERN.vhd sources/RAM_SHIFT.vhd sources/ + design + ".vhd"
set_wire_load_model -library tcb773pwc -name TSMC16K_Conservative set_wire_load_mode enclosed create_clock -name CLK -period 24 -waveform { 0 12 } { CP } set_output_delay 5 -clock CLK all_outputs() set_dont_touch_network { CLK } compile -map_effort high create_schematic -all report -area > "reports/" + design + "_area_report.txt" report -timing > "reports/" + design + "_timing_report.txt"
94
check_design check_timing change_names -rules asic_core_rules -verbose -hierarchy write -f db -hier -o "db/" + design + "_mapped.db" write_sdf "netlist/" + design + "_mapped.sdf" write -format vhdl -hierarchy -output "netlist/" + design + "_mapped.vhd" write -format verilog -hierarchy -output "netlist/" + design + "_mapped.v"
CY7C901_timing_report.txt **************************************** Report : timing -path full -delay max -max_paths 1 Design : CY7C901 Version: 2000.05 Date : Mon May 19 23:57:40 2003 **************************************** Operating Conditions: WCCOM Library: tcb773pwc Wire Load Model Mode: enclosed Startpoint: RAM_REG_i/RAMB_DATAOUT_reg[0] (rising edge-triggered flip-flop clocked by CLK') Endpoint: Y[3] (output port clocked by CLK) Path Group: CLK Path Type: max Des/Clust/Port Wire Load Model Library -----------------------------------------------RAM_ADDRESSABLE_REGISTERS TSMC8K_Conservative tcb773pwc CY7C901 TSMC16K_Conserva tive tcb773pwc ALU_DATA_SOURCE_SELECTOR TSMC8K_Conservative tcb773pwc ALU TSMC8K_Conservat ive tcb773pwc OUTPUT_DATA_SELECTOR TSMC8K_Conservative tcb773pwc Point Incr Path -------------------------------------------------------------------------clock CLK' (rise edge) 12.00 12.00 clock network delay (ideal) 0.00 12.00 RAM_REG_i/RAMB_D ATAOUT_reg[0]/CP (DFF1) 0.00 12.00 r RAM_REG_i/RAMB_D ATAOUT_reg[0]/Q (DFF1) 0.77 12.77 r RAM_REG_i/RAMB_DATAOUT[0] (RAM_ADDRESSABLE_REGISTERS) 0.00 12.77 r ALU_D_S_SEL_i/B[ 0] (ALU_DATA_SOURCE _SELECTOR) 0.00 12.77 r ALU_D_S_SEL_i/U8 2/ZN (MAOI22D2) 0.74 13.51 f ALU_D_S_SEL_i/U8 3/ZN (OAI21D1H) 0.22 13.73 r ALU_D_S_SEL_i/S[ 0] (ALU_DATA_SOURCE _SELECTOR) 0.00 13.73 r ALU_i/S[0] (ALU) 0.00 13.73 r ALU_i/U472/ZN (INV3) 0.21 13.94 f ALU_i/U471/ZN (INV1) 0.29 14.23 r ALU_i/U587/ZN (ND2D1H) 0.26 14.50 f ALU_i/U593/ZN (OAI21D1H) 0.39 14.89 r ALU_i/U480/ZN (OAI21D1H) 0.35 15.24 f ALU_i/U479/ZN (OAI21D1H) 0.20 15.45 r ALU_i/U574/ZN (INV1) 0.28 15.73 f ALU_i/U483/ZN (OAI32D1H) 0.40 16.13 r ALU_i/U482/ZN (IND3D0) 0.30 16.43 f ALU_i/U584/Z (MUX2D2) 0.68 17.11 f ALU_i/U469/ZN (ND3D1H) 0.19 17.30 r ALU_i/U488/ZN (OAI21D1H) 0.24 17.54 f ALU_i/U485/ZN (AOI21D1H) 0.33 17.87 r ALU_i/U486/ZN (INV3) 0.19 18.06 f ALU_i/F[3] (ALU) 0.00 18.06 f OUT_D_SEL_i/F[3] (OUTPUT_DATA_SEL ECTOR) 0.00 18.06 f OUT_D_SEL_i/U30/ Z (MUX2D2) 0.56 18.62 f OUT_D_SEL_i/U31/ ZN (INV1) 0.18 18.81 r OUT_D_SEL_i/Y_tr i[3]/ZN (INVTN1) 0.19 19.00 f OUT_D_SEL_i/Y[3] (OUTPUT_DATA_SEL ECTOR) 0.00 19.00 f Y[3] (out) 0.00 19.00 f
95
data arrival time
19.00
clock CLK (rise edge) 24.00 24.00 clock network delay (ideal) 0.00 24.00 output external delay -5.00 19.00 data required time 19.00 -------------------------------------------------------------------------data required time 19.00 data arrival time -19.00 -------------------------------------------------------------------------slack (MET) 0.00
CY7C901_area_report.txt report_area Information: Updating design information... (UID-85) **************************************** Report : area Design : CY7C901 Version: 2000.05 Date : Mon May 19 23:57:40 2003 **************************************** Library(s) Used: tcb773pwc (File: C:/Synopsys/libraries/syn/tcb773pwc.db) Number Number Number Number
of of of of
ports: nets: cells: references:
38 70 9 9
Combinational area: Noncombinational area: Net Interconnect area:
47932.500000 33180.000000 undefined (Wire load has zero net area)
Total cell area: Total area:
81112.500000 undefined
Testarea circuitului CY7C901 După cum era de aşteptat, realizarea programului de test pentru circuitul CY7C901 a constituit una din cele mai dificile sarcini ale proiectului. În primul rând, o testare completă a circuitului nu ar fi fost posibil ă, atât din cauza numărului destul de mare de intr ări, cât, mai ales, din cauza caracterului secvenţial al circuitului. Ca urmare, a trebuit să găsesc o soluţie de testare a circuitului care, printr-un număr relativ mic de vectori de test, să pună circuitul în aproape toate tipurile de situa ţii posibile.Prima etapă a testării este verificarea RAM-ului. Mai întâi se încarcă un set de 16 date în RAM ; fiecare dată care se încarcă în RAM trebuie să fie aplicată pe intrarea de date D şi trebuie să ajungă nemodificată la intrarea blocului RAM_SHIFT, ceea ce presupune ca instrucţiunea aplicată circuitului să determine: a) cele 2 ieşiri ale ALU_DATA_SOURCE_SELECTOR să fie D şi ZERO ; b) operaţia executată de ALU să fie adunarea (ADD ; în plus, trebuie ca Cn s ă fie LOW) ; c) instrucţiunea de control al destinaţiei ieşirii ALU să fie : RAMA, RAMF, RAMQD, RAMD, RAMQU sau RAMU. Pe durata acestei prime etape se testeaz ă, prin intermediul ieşirii F a lui CY7C901, dacă datele introduse din exterior au ajuns corect (nemodifiate) la ieşirea ALU (ceea ce presupune, în plus, ca semnalul nOE să fie pe nivel LOW) . Am testat înc ărcarea memoriei pentru fiecare din instrucţiunile de încărcare ; aceasta a necesitat calcularea manuală a conţinutului memoriei după fiecare operaţiune de încărcare, în scopul compar ării rezultatelor teoretice cu
cele experimentale. Testarea ALU-lui s-a realizat astfel : cu datele aflate la un moment dat în memorie se execută cele 8 operaţii ale ALU, fiecare operaţie executându-se pentru 16 perechi de date din memorie. Testarea blocurilor Q_REGISTER şi Q_SHIFT a condus la modificarea conţinutului memoriei RAM, ceea ce a necesitat alte calcule manuale. În acest test_bench am folosit o variabilă, N_CK (în program N_CK este declarat ca semnal, întrucât o variabilă poate fi declarată doar în interiorul unui proces, fiind vizibilă doar în acel proces) , care reprezintă numărul de ordine al ciclului de ceas curent. Pentru evaluarea corectitudinii funcţionării circuitului, am folosit două variabile (declarate, de asemenea, ca 96
semnale) : test_OK şi test_OK1. Cu test_OK se testează dacă operaţiunile de scriere/citire a memoriei se execută corect. Valoarea lui test_OK1 depinde atât de valoarea lui test_OK, cât şi de corectitudinea executării operaţiilor aritmetice şi logice. test_CY7C901.vhd library IEEE ; use IEEE.std_logic_1164.all ; use IEEE.std_logic_unsigned.all ; use work.packageCY7C901.all ; entity test_CY7C901 is end ; architecture test of test_CY7C901 is component CY7C901 port( A : in vec4 ; B : in vec4 ; I : in std_logic_vecto r (8 downto 0) D : in vec4 ; Y : out vec4 ; nOE : in std_logic ; CP : in std_logic ; Q3, RAM3 : inout std_logic ; Q0, RAM0 : inout std_logic ; Cn : in std_logic ; Cn4 : out std_logic ; nG, nP : out std_logic ; OVR : out std_logic ; F_eq_0 : out std_logic ; F3 : out std_logic ) ; end component ; signal signal signal signal signal signal signal signal signal signal signal signal signal
;
N_CK : integer := 0 ; -- indica perioada de ceas curenta A, B : vec4 := "0000" ; D : vec4 := "0101" ; Y : vec4 ; I : std_logic_vector (8 downto 0) ; Cn4, nG, nP, OVR, F_eq_0, F3 : std_logic ; test_OK, test_OK1 : BOOLEAN := TRUE ; Q3, Q0, RAM3, RAM0 : std_logic := '0' ; nOE, Cn : std_logic := '0' ; CP : std_logic := '1' ; R : vec4 := "0101" ; S : vec4 := "0000" ; P, G : vec4 ;
signal F_eq_0_t : std_logic ; signal nG_t : std_logic := '1' ; signal nP_t : std_logic := '1' ; signal OVR_t : std_logic := '0' ; signal Cn4_t : std_logic := '0' ; signal F3_t : std_logic := '0' ; signal F_t : vec4 := "0101" ; signal Y_t : vec4 := "0101" ; signal C4, C3 : std_logic ; constant TPER : time :=40 ns ; constant HOLD : time := 10 ns ; constant DELAY : time := 15 ns ; constant DELAYMIN : time := 0.1 ns ; type mem is array (0 to 15) of vec4 ; signal ram_var : mem := ("0101", "0011", "1011", "0000", "1001", "1000", "0001", "1111", "0100", "1011", "0010", "0110", "1110", "1100", "0011", "1011") -- in ram_var sunt stocate datele ce vor fi aplicate pe intrarile D si inscrise in -- registri in prima faza signal ram_var2 : mem := ("0010", "0001", "0101", "1000", "1100", "1100", "0000", "0111", "1000", "0110", "0101", "1101", "1101", "1000", "0110", "0110") -- in ram_var2 sunt stocate datele ce ar trebui sa fie inscrise in registri in urma -- operatiilor de extragere, deplasare si rescriere a datelor din registri signal Q_var : mem := ("0001", "1000", "1100", "1110", "1111", "0111", "0011", "0001", "0010", "0100", "1000", "0000", "0001", "0011", "0111", "1111") signal ram_var3 : mem := ("0010", "0000", "0100", "0110", "0111", "1111", "1011", "1001", "0011", "0101", "1001", "0001", "0000", "0010", "0110", "1110") -- Q_var i ram_var3 sunt folosite la testarea blocului Q_REGISTER -- semnalele pentru vizualizare signal ALU_DESTINATIONv : ALU_destination ; signal ALU_SOURCEv : ALU_source ; signal ALU_INSTRUCTIONv : ALU_instruction ;
;
;
; ;
97
begin process begin wait until (CP'event and CP = '1') N_CK <= N_CK + 1 ;
;
end process ; DUT : CY7C901 port map
(A, B, I, D, Y, nOE, CP,Q3, RAM3, Q0, RAM0, Cn, Cn4, nG, nP, OVR, F_eq_0, F3) ; -- in primele 16 perioade de ceas se incarca cei 16 registri RAM cu date introduse de -- la intrarile D CP <= not CP after TPER / 2 ; process begin wait until (CP'event and CP = '1') ; wait for HOLD ; B <= B + 1 ; A <= A + 3 ; end process ; RAM3 <= 'Z', '0' after (16 * TPER + HOLD) , '1' after (19 * TPER + HOLD) , '0' after (22 * TPER + HOLD) , 'Z' after (24 * TPER + HOLD) , '0' after (177 * TPER + HOLD) , '1' after (181 * TPER + HOLD) , 'Z' after (184 * TPER + HOLD) ; RAM0 <= 'Z', '0' after (24 * TPER + HOLD) , '1' after (26 * TPER + HOLD) , '0' after (29 * TPER + HOLD) , 'Z' after (32 * TPER + HOLD) , '1' after (184 * TPER + HOLD) , '0' after (188 * TPER + HOLD) , 'Z' after (192 * TPER + HOLD) ; Q3 <= 'Z', '1' after (177 * TPER + HOLD) , '0' after (181 * TPER + HOLD) , 'Z' after (184 * TPER + HOLD) ; Q0 <= 'Z', '0' after (184 * TPER + HOLD) , '1' after (188 * TPER + HOLD) , 'Z' after (192 * TPER + HOLD) ; process begin wait until (CP'event and CP = '1') ; wait for HOLD ; if (N_CK <= 47) then Cn <= '0' ; elsif (N_CK <= 175) then Cn <= B(1) ; else Cn <= '0' ; end if ; end process ; process begin wait until (CP'event and CP = '1') ; wait for HOLD ; wait for DELAYMIN ; if (N_CK <= 15) then D <= ram_var (N_CK) ; elsif (N_CK <= 31) then D <= ram_var (N_CK - 16) else D <= "0001" ; end if ; end process ;
;
I <= "011000111" , -- RAMF ADD DZ <=> datele aplicate pe intrarea D sunt scoase pe iesirea Y si memorate -- in registri la adresa selectata de intrarea B "100000111" after (16 * TPER + HOLD) , -- RAMQD ADD DZ <=> datele aplicate pe intrarea D sunt scoase pe iesirea Y si memorate -- in registri deplasate spre dreapta cu un bit "101000111" after (20 * TPER + HOLD) , -- RAMD ADD DZ <=> datele aplicate pe intrarea D sunt scoase pe iesirea Y si memorate -- in registri deplasate spre dreapta cu un bit "110000111" after (24 * TPER + HOLD) , -- RAMQU ADD DZ <=> datele aplicate pe intrarea D sunt scoase pe iesirea Y si memorate -- in registri deplasate spre stanga cu un bit "111000111" after (28 * TPER + HOLD) , -- RAMU ADD DZ <=> datele aplicate pe intrarea D sunt scoase pe iesirea Y si memorate -- in registri deplasate spre stanga cu un bit "001000011" after (32 * TPER + HOLD) , -- NOP ADD ZB <=> datele memorate in registri sunt scoase la iesirea Y "001000001" after (48 * TPER + HOLD) , -- NOP ADD AB <=> se executa operatia ADD intre continuturile a cate doi registri -- selectati de datele aplicate pe intrarile A si D "001001001" after (64 * TPER + HOLD) , -- NOP SUBR AB <=> se executa operatia SUBR intre continutul registrului adresat de B -- si continutul registrului adresat de A
98
"001010001" after (80 * TPER + HOLD) , -- NOP SUBS AB <=> se executa operatia SUBS intre continutul registrului adresat de A --si continutul registrului adresat de B "001011001" after (96 * TPER + HOLD) , -- NOP OR AB <=> se executa operatia OR intre continutul registrului adresat de A si -- continutul registrului adresat de B "001100001" after (112 * TPER + HOLD) , -- NOP AND AB <=> se executa operatia AND intre continutul registrului adresat de A si -- continutul registrului adresat de B "001101001" after (128 * TPER + HOLD) , -- NOP NOTRS AB <=> se executa operatia AND intre continutul negat al registrului -- adresat de A si continutul registrului adresat de B "001110001" after (144 * TPER + HOLD) , -- NOP EXOR AB <=> se executa operatia XOR intre continutul registrului adresat de A – -- si continutul registrului adresat de B "001111001" after (160 * TPER + HOLD) , -- NOP EXNOR AB <=> se executa operatia XNOR intre continutul registrului adresat de A --si continutul registrului adresat de B "000000111" after (176 * TPER + HOLD) , -- QREG ADD DZ <=> se incarca Q_REGISTER cu valoarea lui D si apoi aceasta este scoasa la iesirea Y "100000010" after (177 * TPER + HOLD) , -- RAMQD ADD ZQ <=> Q <= F/2 si se scoate la iesirea Y "110000010" after (184* TPER + HOLD) , -- RAMQU ADD ZQ <=> Q <= 2F si se scoate la iesirea Y "001000001" after (192 * TPER + HOLD) -- NOP ADD AB <=> se executa operatia ADD intre continuturile a cate doi registri -- selectati de datele aplicate pe intrarile A si D ; process begin wait until (CP'event and CP = '0') ; wait for DELAY ; if (N_CK <= 15) then if (Y = ram_var (N_CK) ) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; elsif (N_CK <= 31) then if (Y = ram_var (N_CK - 16) ) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; elsif (N_CK <= 47) then if (Y = ram_var2 (N_CK - 32) ) then test_OK <= TRUE ; else test_OK <= FALSE ; report "EROARE" severity ERROR ; end if ; elsif (N_CK <= 63) then if (Y = (ram_var2(CONV_INTEGER(A)) + ram_var2(CONV_INTEGER(B)) + Cn)) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 79) then if (Y = (ram_var2(CONV_INTEGER(B)) - ram_var2(CONV_INTEGER(A)) - (not Cn)) ) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 95) then if (Y = (ram_var2(CONV _INTEGER(A)) - ram_var2(CONV_I NTEGER(B)) - (not Cn))) then test_OK <= TRUE ; else test_OK <= FALSE ;
99
report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 111) then if (Y = (ram_var2(CONV_INTEGER(A)) or ram_var2(CONV_INTEGER(B)))) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 127) then if (Y = (ram_var2(CONV_I NTEGER(A)) and ram_var2(CONV_INT EGER(B)))) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 143) then if (Y = ((not(ram_var2 (CONV_INTEGER (A)))) and ram_var2(CONV_IN TEGER(B)))) test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 159) then if (Y = (ram_var2(CONV_INTEGER(A)) xor ram_var2(CONV_INTEGER(B)))) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 175) then if (Y = (ram_var2(CONV_INTEGER(A)) xnor ram_var2(CONV_INTEGER(B)))) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 177) then if (Y = Q_var (0) ) then test_OK <= test_OK ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 183) then if ( (Y = Q_var (N_CK - 177) ) and (Q0 = Q_var (N_CK - 177)(0)) ) then test_OK <= test_OK ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK <= 191) then if ( (Y = Q_var (N_CK - 177) ) and (Q3 = Q_var (N_CK - 177)(3)) ) then test_OK <= test_OK ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; elsif (N_CK >= 192) then if (Y = (ram_var3(CONV_INTEGER(A)) + ram_var3(CONV_INTEGER(B)) + Cn)) then test_OK <= TRUE ; else test_OK <= FALSE ; report " EROARE" severity ERROR ; end if ; end if ; end process ;
then
100
process begin wait until (CP'event and CP = '1') ; wait for HOLD ; wait for DELAYMIN/2 ; if (N_CK <= 31) then S <= "0000" ; R <= ram_var (CONV_INTEGER (B) ) ; elsif (N_CK <= 47) then R <= "0000" ; S <= ram_var2 (CONV_INTEGER (B)) ; elsif (N_CK <= 175) then R <= ram_var2 (CONV_INTEGER (A) ) ; S <= ram_var2 (CONV_INTEGER (B) ) ; elsif (N_CK <= 177) then R <= "0000" ; S <= Q_var (0) ; elsif (N_CK <= 191) then R <= "0000"; S <= Q_var (N_CK - 177) ; elsif (N_CK >= 192) then R <= ram_var3 (CONV_INTEGER (A) ) ; S <= ram_var3 (CONV_INTEGER (B) ) ; end if ; end process ; process begin wait until (CP'event and CP = '1') ; wait for HOLD ; wait for DELAYMIN ; -- altfel nu s-ar folosi noile valori ale R si S case I (5 downto 3) is when ADD_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when SUBR_i => for k in 0 to 3 loop P(k) <= (not R(k)) or S(k) ; G(k) <= (not R(k)) and S(k) ; end loop ; when SUBS_i => for k in 0 to 3 loop P(k) <= R(k) or (not S(k)) ; G(k) <= R(k) and (not S(k)) ; end loop ; when OR_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when AND_i => for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; when NOTRS_i => for k in 0 to 3 loop P(k) <= (not R(k)) or S(k) ; G(k) <= (not R(k)) and S(k) ; end loop ; when EXOR_i => for k in 0 to 3 loop P(k) <= (not R(k)) or S(k) ; G(k) <= (not R(k)) and S(k) ; end loop ; when others => -- EXNOR_i for k in 0 to 3 loop P(k) <= R(k) or S(k) ; G(k) <= R(k) and S(k) ; end loop ; end case ; end process ;
101
C4 <= G(3) or (P(3) and G(3)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and G(0)) or (P(3) and P(2) and P(1) and P(0) and Cn) ; C3 <= G(2) or (P(2) and G(1)) or (P(2) and P(1) and G(0)) or (P(2) and P(1) and P(0) and Cn); process begin wait until (CP'event and CP = '1') ; wait for HOLD ; wait for 2 * DELAYMIN ; case I (5 downto 3) is when ADD_i => F_t <= R + S + Cn; nP_t <= not (P(3) and P(2) and P(1) and P(0)) ; nG_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0)) ) ; Cn4_t <= C4 ; OVR_t <= C3 xor C4 ; when SUBR_i => F_t <= S - R - (not Cn) ; nP_t <= not (P(3) and P(2) and P(1) and P(0)) ; nG_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0)) ) ; Cn4_t <= C4 ; OVR_t <= C3 xor C4 ; when SUBS_i => F_t <= R - S - (not Cn) ; nP_t <= not (P(3) and P(2) and P(1) and P(0)) ; nG_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and G(0)) ) ; Cn4_t <= C4 ; OVR_t <= C3 xor C4 ; when OR_i => F_t <= R or S ; nP_t <= '0' ; nG_t <= P(3) and P(2) and P(1) and P(0) ; Cn4_t <= (not (P(3) and P(2) and P(1) and P(0)) ) or Cn ; OVR_t <= (not (P(3) and P(2) and P(1) and P(0)) ) or Cn ; when AND_i => F_t <= R and S ; nP_t <= '0' ; nG_t <= not (G(3) or G(2) or G(1) or G(0) ) ; Cn4_t <= G(3) or G(2) or G(1) or G(0) or Cn ; OVR_t <= G(3) or G(2) or G(1) or G(0) or Cn ; when NOTRS_i => F_t <= (not R) and S ; nP_t <= '0' ; nG_t <= not (G(3) or G(2) or G(1) or G(0) ) ; Cn4_t <= G(3) or G(2) or G(1) or G(0) or Cn ; OVR_t <= G(3) or G(2) or G(1) or G(0) or Cn ; when EXOR_i => F_t <= R xor S ; nP_t <= G(3) or G(2) or G(1) or G(0) ; nG_t <= G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0)) ; Cn4_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0) and (G(0) or (not Cn)) ) ) ; OVR_t <= (P(2) or (G(2) and P(1)) or ((not G(2)) and (not G(1)) and (not P(0)))) xor ((not P(3)) or ((not G(3)) and (not P(2))) or ((not G(3)) and (not G(2)) and (not P(1))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not P(0))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not G(0)) and Cn)) ; when others => -- EXNOR_i F_t <= R xnor S ; nP_t <= G(3) or G(2) or G(1) or G(0) ; nG_t <= G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0)) ; Cn4_t <= not (G(3) or (P(3) and G(2)) or (P(3) and P(2) and G(1)) or (P(3) and P(2) and P(1) and P(0) and (G(0) or (not Cn)) ) ) ; OVR_t <= (P(2) or (G(2) and P(1)) or ((not G(2)) and (not G(1)) and (not P(0)))) xor ((not P(3)) or ((not G(3)) and (not P(2))) or ((not G(3)) and (not G(2)) and (not P(1))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not P(0))) or ((not G(3)) and (not G(2)) and (not G(1)) and (not G(0)) and Cn)) ; end case ; end process ; process begin wait until
(CP'event and CP = '1')
;
102
wait for HOLD ; wait for 3 * DELAYMIN ; case nOE is when '0' => case I (8 downto 6) is when RAMA => Y_t <= ram_var (CONV_INTEGER (A)) when others => Y_t <= F_t ; end case ; when others => Y_t <= "ZZZZ" ; end case ;
;
end process ; process (F_t) begin case F_t is when "0000" => F_eq_0_t <= '1' ; when others => F_eq_0_t <= '0' ; end case ; end process ; F3_t <= F_t (3)
;
process begin wait until (CP'event and CP = '0') ; wait for DELAY ; if((test_OK = TRUE) and (Y = Y_t) and (nP = nP_t) and (nG = nG_t) and (Cn4 = Cn4_t) and (OVR = OVR_t) and (F_eq_0_t = F_eq_0) and (F3_t = F3)) then test_OK1 <= TRUE ; else test_OK1 <= FALSE ; report "EROARE" severity ERROR ; end if ; end process ; -- pentru vizualizare process (I(2 downto 0)) begin case I(2 downto 0) is when AQ => ALU_SOURCEv <= AQv ; when AB => ALU_SOURCEv <= ABv ; when ZQ => ALU_SOURCEv <= ZQv ; when ZB => ALU_SOURCEv <= ZBv ; when ZA => ALU_SOURCEv <= ZAv ; when DA => ALU_SOURCEv <= DAv ; when DQ => ALU_SOURCEv <= DQv ; when DZ => ALU_SOURCEv <= DZv ; when others => ALU_SOURCEv <= XXX ; end case ; end process ; process (I(5 downto 3)) begin case I(5 downto 3) is when ADD_i => ALU_INSTRUCTIONv <= ADDv ; when SUBR_i => ALU_INSTRUCTIONv <= SUBRv ; when SUBS_i => ALU_INSTRUCTIONv <= SUBSv ; when OR_i => ALU_INSTRUCTIONv <= ORv ; when AND_i => ALU_INSTRUCTIONv <= ANDv ; when NOTRS_i => ALU_INSTRUCTIONv <= NOTRSv ; when EXOR_i => ALU_INSTRUCTIONv <= EXORv ; when EXNOR_i => ALU_INSTRUCTIONv <= EXNORv ; when others => ALU_INSTRUCTIONv <= XXX ; end case ; end process ; process (I(8 downto 6)) begin case I(8 downto 6) is when QREG => ALU_DESTINATION v <= QREGv ; when NOP => ALU_DESTINATION v <= NOPv ; when RAMA => ALU_DESTINATION v <= RAMAv ; when RAMF => ALU_DESTINATION v <= RAMFv ; when RAMQD => ALU_DESTINATION v <= RAMQDv ; when RAMD => ALU_DESTINATION v <= RAMDv ;
103
when RAMQU => ALU_DESTINATION v <= RAMQUv ; when RAMU => ALU_DESTINATION v <= RAMUv ; when others => ALU_DESTINATIONv <= XXX ; end case ; end process ; end test ;
Metodologia de testare este identică cu cea de la testarea ui CY7C910: se compilează fişierul “tcb773p.v”, apoi se compilează “CY7C910_mapped.vhd” (generat de programul de sinteză) , iar apoi se compilează fişierul “test_CY7C901.vhd”. Apoi se încarcă arhitectura test din cadrul designului test_CY7C901 având grijă să ataşăm fişîerul “CY7C901_mapped.sdf” instanţei DUT din cadrul arhitecturii test şi se setează rezoluţia de simulare pe picosecunde. În continuare voi prezenta formele de undă obţinute în urma simulării postsinteză.
Figura 1
În figura 1 sunt prezentate formele de undă rezultate în urma operaţiei de încărcare a memoriei cu datele aplicate pe intrarea D. Nu se poate vizualiza conţinutul locaţiilor de memorie întrucât aceasta ar presupune identificarea bistabililor care alcătuiesc fiecare locaţie de memorie şi afişarea ieşirilor acesto bistabili, ceea ce ar necesita redarea unui număr foarte mare de forme de undă. Ceea ce se poate observa cu uşurinţă este faptul că datele aplicate pe intrarea D ajung nemodificate la ieşirea Y.
Figura 2
104
În figura 2 (16 < N <= 31) este vizualizată operaţia de încărcare a memoriei RAM cu datele aplicate pe intrarea D, deplasate la stânga sau la dreapta în funcţie de instrucţiunea de control a destinaţiei ieşirii ALU aplicate (RAMQD, RAMD, RAMQU, RAMU) . Şi în această figur ă se poate observa că datele aplicate pe intrarea D ajung nemodificate la ieşirea Y. Ţinând cont de datele aplicate pe intrarea D, de locaţia de memorie selectată de data aplicată pe intrarea B, de tipul de deplasare (la stânga sau la dreapta) indicat de instrucţiunea de control a destinaţiei ieşirii ALU şi de semnalele aplicate pe pinii bidirecţionali RAM3 şi RAM0, se poate calcula conţinutul memoriei în urma operaţiilor de încărcare. Conform calculelor, la momentul N = 32, în locaţiile memoriei RAM ar trebui să se afle următoarele date : RAM[ 0 : 15 ] = ("0001", "1000", "1100", "1110", "1111", "0111", "0011", "0001", "0010", "0100", "1000", "0000", "0001", "0011", "0111", "1111") ; În continuare (31 < N <= 47) se testează dacă, într-adevăr, datele scrise în RAM sunt cele calculate. Pentru aceasta, se selectează (prin intermediul intr ării B) o locaţie de memorie, conţinutul acesteia fiind scos pe ieşirea Y în urma operaţiei de adunare cu zero (Figura 3) .
Figura 3
În continuare (47 < N <= 175) se verifică funcţionarea ALU, executând, pe rând, fiecare din cele 8 instrucţiuni asupra a câte 16 perechi de date din memorie.
Figura 4 – testarea operaţ operaţiei ADD
105
Figura 5 – testarea operaţiei SUBR
Figura 6 – testarea oparaţiei SUBS
Figura 7 – testarea operaţiei OR
106
Figura 8 – testarea operaţiei AND
Figura 9 – testarea operaţiei NOTRS
Figura 10 – testarea operaţiei EXOR
107
Figura 11 – testarea operaţiei EXNOR
În continuare (175 < N <= 191) am testat funcţionarea ansamblului Q_REGISTER – Q_SHIFT. Mai întâi , prin execuţia instrucţiunii QREG de control a destinaţiei ieşirii ALU, am încărcat Q_REGISTER cu data aplicată pe intrarea D. Apoi am testat execuţia instrucţiunilor RAMQU şi RAMQD asupra Q_REGISTER. Întrucât RAMQU şi RAMQD acţionează şi asupra RAM-ului, nu numai asura Q_REGISTER, execuţia acestora va determina şi modificarea conţinutului memoriei RAM. În figura 12 am prezentat şi formele de undă a mai multor semnale interne circuitului CY7C901 pentru a se putea observa mai uşor funcţionarea Q_REGISTER-lui, dar şi a celor două blocuri de deplasare : Q_SHIFT şi RAM_SHIFT.
Figura 12 – testarea blocurilor Q_REGISTER, Q_SHIFT şi RAM_SHIFT
În urma testării blocului Q_REGISTER, conţinutul memoriei RAM s-a modificat, la momentul N = 192 acesta trebuind să fie , după calcule, următorul : RAM[ 0 : 15 ] = ("0010", "0000", "0100", "0110", "0111", "1111", "1011", "1001", "0011", "0101", "1001", "0001", "0000", "0010", "0110", "1110") ;
108
În final, se verifică corectitudinea rescrierii anterioare a memoriei RAM prin executarea operaţiei de adunare între diferite perechi de date din RAM. Analizând formele de und ă din figura 13 se poate observa cu uşurinţă că datele de pe intr ările R şi S ale ALU, reprezentând datele de la locaţiile de memorie indicate de A, respectiv B, sunt aceleaşi cu datele calculate anterior.
Figura 13
Această simulare postsinteză dovedeşte funcţionarea corectă a circuitului CY7C901. Din păcate, frecvenţa maximă de funcţionare este destul de mică, aproximativ 25 MHz, însă acestă frecvenţă ar putea fi crescută destul de mult dacă sinteza circuitului ar fi realizată de un specialist în acest domeniu.
109
CONCLUZII
După cum am spus şi în introducere, scopul acestei lucr ări a fost aprofundarea problemelor ridicate de proiectarea VHDL pentru sinteză a circuitelor integrate digitale. Acum, dup ă terminarea proiectului, pot spune că, în mare măsur ă, scopul a fost atins, având ca principal argument faptul că cele două circuite, CY7C910 şi CY7C901, au putut fi sintetizate şi că rezultatele simulărilor postsinteză au fost corecte. În afar ă de aprofundarea limbajului VHDL, în special VHDL pentru sinteză, am deprins cunoştinţele de bază despre instrumentele soft pentru simulare (ModelSim) şi sinteză (Design Compiler şi Leonardo Spectrum). De asemenea, consider deosebit de importantă deprinderea strategiei de abordare a unui proiect : descompunerea circuitului în subcircuite mai simple, tratarea independentă a acestor subcircuite (descriere, testare, sinteză, testare postsinteză), îmbinarea subcircuitelor şi testarea circuitului astfel obţinut. Puse cap la cap, descrierile VHDL şi programele de test pentru aceste descrieri însumează peste 3000 de linii de cod. Proiectarea propriuzisă (descrierile VHDL, programele de test, sinteza descrierilor VHDL, simulările) s-a întins pe o perioadă de aproximativ 6 să ptămâni, perioada de proiectare efectivă fiind, după calculele mele, de aproximativ 300 de ore. Pe parcursul realizării proiectului am fost nevoit să refac de mai multe ori descrierile anumitor blocuri, iar g ăsirea unor soluţii pentru realizarea programelor de test a fost de cele mai multe ori mult mai lentă decât transpunerea acestor soluţii în cod VHDL. Realizarea acestui proiect a presupus descrierea pentru sinteză a multor blocuri foarte des întâlnite în activitatea de proiectant/programator VHDL : unitate aritmetico-logic ă, stivă, memorie RAM dual-port, număr ător, multiplexor, buffer three-states, registru master-slave, registru de deplasare cu porturi bidirecţionale. Prin numărul şi diversitatea blocurilor descrise, prin programele de test realizate pentru aceste blocuri, prin prezentarea amănunţită a problemelor deosebite întâlnite la descrierea anumitor blocuri, prin garanţia că toate descrierile VHDL sunt sintetizabile şi prin prezentarea simulărilor postsinteză (care dovedesc funcţionarea corectă a circuitelor sintetizate) , consider că acest material poate constitui cu succes îndrumătorul de laborator pentru o disciplină precum PAC2 sau VLSIR. În final vreau să le mulţumesc domnului dr.ing Dănuţ Burdia şi domnului doctorand Silviu Isarie pentru ajutorul dat la instalarea pachetului Synopsys, pentru furnizarea fişierelor tehnologice şi pentru sfaturile deosebit de utile pentru proiectare.
110