Elektronikus dobókocka tervezési példa (file: kocka-pld-sp3, H.J., 2006-10-16) Ebben a mintapéldában egy elektronikus dobókockát tervezünk. Ezzel a tervezési példával a Mérés laboratórium I. gyakorlatok 5. méréséhez tartozó tervezési házi feladatokhoz szeretnénk ötleteket adni. 1. A tervezési feladat Elektronikus dobókocka (Feladatjel: M0) Realizálás: Spartan-3 FPGA mérőpanelen Az egység egy dobókockát szimulál. A dobókockához tartozik egy "Dobás" gomb, melynek megnyomására elindul a "dobás", és a gomb felengedésekor egy 1-től 6-ig terjedő szám jelenik meg a kockához tartozó számkijelzőn. A szám értéke véletlenszerűen kerül kiválasztásra. Az egység a dobásokat is számolja, és egy kijelzőn megjeleníti azok számát. A dobásszámkijelző 1 digites, és hexadecimális kódban jeleníti meg a dobásszámot. A Spartan-3 FPGA mérőpanelen realizált áramkörnél a Dobás gomb a BTN1, és az egység a BTN3 gombbal vihető alapállapotba. Alapállapotban mindkét szám 0 értékű. 2. Tervezési megfontolások 2.1 A fő egységek funkciójának meghatározása (elsődleges dekompozició) A dobókocka készülék 3 fő egységre bontható, melyek az 1. ábrán látható funkcionális tömbvázlatnak megfelelően kapcsolódnak egymáshoz. Ezek az egységek a következők: Egy kockaszám-generátor (Die), mely a hozzá tartozó gomb megnyomására egy véletlenszámot ad ki. A szám lehetséges értékei 1, 2, 3, 4, 5, és 6, illetve a Reset utáni 0. A számok legyenek binárisan kódoltak, ehhez 3 bit elegő. Egy számláló (Throw counter), mely a Dobás gomb megnyomásait számlálja. Két számjegyes display-vezérlő egység (Display controller), mely az FPGA panelen található hétszegmenses kijelzőt vezérli, és megjeleníti a két számot. 2.2 Következetes szinkron tervezési paradigma Minden sorri funkcionális egységnek közös órajele lesz, ami az FPGA globális órajele (CLK). Amelyik egység állapotváltásainak megkívánt üteme kisebb, mint a globális órajel frekvenciája, annak működését "engedélyező" funkciójú jelekkel ütemezzük, melyek szélessége egy CLK órajelnek felel meg. A dobásszámláló esetében ez azt jelenti, hogy a BTN1 jel nem lesz a dobásszámláló órajele, hanem a BTN1 jel egyik élénél előállítunk egy impulzust, mely a számláló léptetését fogja engedélyezni. Az elsődleges bemenő jelek tetszés szerinti időpillanatban megváltozhatnak, ezáltal a rszer órajeléhez képest aszinkron változnak. Azért, hogy ez az aszinkronitás ne okozzon esetleg metastabil állapotot, minden bemenő jelet szinkronizálni fogunk. 1/9
2.3 Tesztelhetőség A tesztelhetőség (és szimulálhatóság) érdekében minden sorri hálózatnak van alapállapotot beállító bemenete (RESET). A kijelző időmultiplexelt vezérlésű, a "multiplexelés" frekvenciáját 1 10 khz nagyságrűre célszerű választani. Ez több nagyságrdel kisebb a rszer-órajel frekvenciájánál. Ezért a hosszú tesztelési ill. szimulációs szekvenciák elkerülésére a tesztelés idejére célszerű felgyorsítani a multiplexelést. 2.4 Egyéb megfontolások Az alkalmazott FPGA kapuszáma, sebessége jóval nagyobb, mint amit ez a feladat igényel. Ezért külön nem törekedtünk az egységek "minimalizálására", és a megvalósítási lehetőségeket sebesség szempontjából sem vizsgáltuk. 3. Funkcionális tömbvázlat A tervezéshez kiindulásként használt funkcionális tömbvázlat az 1. ábrán látható. Az ábrán feltüntettük a használni kívánt jelneveket és modul-elnevezésket. BTN1 (Dobás) Throw counter (Dobásszámláló) module dcount RESET CLK Die (dobókocka) module die D2 D1 D2[3:0] Display controller module disp2d SEGM[6:0] DIGEN[3:0] D1[3:0] RESET CLK RESET CLK Functional block-diagram 1. ábra Az elektronikus dobókocka funkcionális tömbvázlata 4. A dobókocka modul (die) 4.1 A dobókocka modul (die) Verilog leírása A véletlenszerű kockaszám-generálást úgy valósítjuk meg, hogy a "dobás" közben egy 1- től 6-ig számláló viszonylag gyorsan, legalább több száz Hz frekvenciával lép. Az emberi gombnyomás időpontja a számláló ciklusidejéhez képest véletlenszerűnek tekinthető, ezen alapul a véletlenszám-generálás. Első menetben az egyszerűség kedvéért a rszer-órajelet gondoltuk a számláló léptetésére használni. Később kiderült, hogy a nyomógombot pergésmenetesíteni kell, ami egy néhány 100 Hz frekvenciájú mintavétellel történik. Az esetleges összeszinkronizá- 2/9
lódási problémák elkerülésére úgy határoztunk, hogy a számláló léptetését és a pergésmenetesítő áramkört ugyanazzal az ütemező jellel vezérlejük. Ezt az jelet a dobókocka modulban állítjuk elő CY néven. (Az előzetes funkcionális vázlaton ez a jel és a pergésmentesítő egység még nem szerepel.) A Reset utáni nulla, és a dobás közbeni 1 6 állapotokat binárisan kódoljuk, ehhez 3 bit elegő. A 3 bites számláló a BTN nyomógomb megnyomása alatt sebesen számol, a gomb felengedésekor leáll. A modul Verilog leírása: module die(clk,reset,btn,count,cy); input RESET; input BTN; //pushbutton output [2:0] COUNT; //die data output reg CY; //count rate reg[2:0] COUNT; reg[18:0] Q; //Generating ca 3 ms rate // CY = (Q == 19'd1); //divide by 2 for testing CY = (Q == 19'd330000); // for 3 ms sec rate if (RESET CY) Q <= 19'd0; else Q <= Q+1; //1-6 counter if (RESET) COUNT <= 3'd0; else if (BTN & CY) if(count == 3'd6) COUNT <= 3'd1; else COUNT <= COUNT+1; module 4.2 A dobókocka modul (die) ellenőrzése szimulációval A die modul leírását szimulációval ellenőriztük. Készítettünk egy "Testnech" hullámformát a modulhoz, majd megnéztük a viselkedést a WebPACK 8.2 "Generate Expected Simulation Results" moduljával. A szimuláció eredményét az alábbi diagramon mutatja. Az idődiagramon jól látható, hogy a számláló csak a BTN=1 időtartama (a gomb megnyomása) alatt számol, és a számlálás az 1->6 állapotokon keresztül történik. 3/9
5. A dobásszámláló modul (dcount) 5.1 A dobásszámláló modul (dcount) Verilog leírása A kockadobás eredménye a gomb elengedésekor alakul ki, ezért a dobásszámlálót is a gomb felengedésekor fogjuk léptetni. Ehhez elő kell állítani egy engedélyező pulzust a BTN gomb jelének lefutó élénél. Egyik lehetőség a jel élének felismerésére az, hogy tároljuk a jel előző értékét, és ha a mostani és az előző állapot eltérő, akkor jelváltás történt (2. ábra). CLK D D Q Q Signal Q0 Q1 Rising edge: Falling edge: Q0 & ~Q1 ~Q0 & Q1 2. ábra Jel felfutó és lefutó élének detektálása module dcount(clk,reset,btn,count); input RESET; input BTN; //pushbutton output [3:0] COUNT; //number of die throw // output FEDGE; //for testing reg [3:0] COUNT; reg [1:0] Q; reg FEDGE; //falling edge detector FEDGE = ~Q[0] & Q[1]; if (RESET) Q <= 2'd0; else Q[0] <= BTN; Q[1] <= Q[0]; //falling edge of BTN //counter if (RESET) COUNT <= 4'd0; else if (FEDGE) COUNT <= COUNT+1; module 4/9
5.2 A dobásszámláló modul (dcount) ellenőrzése szimulációval A dobásszámláló modul leírását ellenőriztük szimulációval is. Az ellenőrzés eredménye az alábbi ábrán látható. (A szimuláció WebPACK 6.3 verziójához tartozó ModelSim szimulátorral történt.) 6. A display-vezérlő modul (disp2d) 6.1 A display-vezérlő modul (disp2d) funkcionális vázlata Az FPGA mérőpanel leírása szerint a négy számjegyes kijelző időmultiplexelt vezérlésre van előkészítve. A szegmenseket kivilágító diódák katódjai szegmensek szerint vannak közösítve, a diódák anódjai pedig számpozíciónként vannak összekötve. A szegmens kigyulladásához a szegmensvezérlő jelnek (SEGMent) "0" értékűnek kell lenni. A megfelelő szegmens csak abban a számpozícióban fog világítani, ahol a számkiválasztó jel (DIGit ENable) is aktív. (A Spartan-3 panel esetében a jel "0" értéke engedélyezi a számpozíció világítását.) Az display-vezérlő modul viszonylag komplex funkciót valósít meg, ezért ezt a modult további, alacsonyabb hierarchia-szintű modulok összekapcsolásával valósítjuk meg a 3. ábrán látható funkcionális vázlatnak megfelelően. A számjegyeknek megfelelő szegmenskódokat (SEGM[6:0]) a szegmensdekóder modul (7 segment decoder) állítja elő. A dekóder bemenetére a szám-multiplexer modul (Digit multiplexer) adja rá egymás után a megjelenítő számok hexadecimális kódját. A multiplexert a digit-számláló (Digit counter) vezérli, mely ezzel szinkronban a számkiválasztó jelek (DIGEN[3:0]) aktiválását is vezérli. A MASK jellel a számjegy kivilágítását tilthatjuk le. 5/9
D1[3:0] Digit multiplexer D2[3:0] module mpx2to1 QA HEX [3:0] 7 segment decoder SEGM [6:0] module hex2led Digit counter module sqwgen "assign" DIGEN [3:0] RESET CLK MASK 2 digit display controller 3. ábra A két számjegyes display vezérlő funkcionális tömbvázlata A kijelzőn csak két számjegyet (D1 és D2) kell megjeleníteni, ezért a multiplexer 2 -> 1 típusú, és a számláló tulajdonképpeni digitválasztó része is csak 1 bites (QA jel). Maga a számláló több bitet tartalmaz, mert egyben elvégzi a rszer-órajel leosztását is a megfelelő időmultiplexelési ütemhez (1-10 khz). 6.2 A szegmensdekóder modul (hex2led) Verilog leírása A szegmensdekóder leírásához változtatás nélkül átvettük a WebPACK rszer Language Templates / Verilog / Synthesis Templates példatárából a HEX2LED modult. module hex2led(hex,led); //HEX-to-seven-segment decoder input [3:0] HEX; output [6:0] LED; reg [6:0] LED; // segment encoding // 0 // - // 5 1 // - <- 6 // 4 2 // - // 3 always @(HEX) case (HEX) 4'b0001 : LED = 7'b1111001; //1 4'b0010 : LED = 7'b0100100; //2 4'b0011 : LED = 7'b0110000; //3 4'b0100 : LED = 7'b0011001; //4 4'b0101 : LED = 7'b0010010; //5 4'b0110 : LED = 7'b0000010; //6 4'b0111 : LED = 7'b1111000; //7 4'b1000 : LED = 7'b0000000; //8 4'b1001 : LED = 7'b0010000; //9 6/9
4'b1010 : LED = 7'b0001000; //A 4'b1011 : LED = 7'b0000011; //b 4'b1100 : LED = 7'b1000110; //C 4'b1101 : LED = 7'b0100001; //d 4'b1110 : LED = 7'b0000110; //E 4'b1111 : LED = 7'b0001110; //F default : LED = 7'b1000000; //0 case module 6.3 A szám-multiplexer modul (mpx2to1) Verilog leírása A szám-multiplexer működését procedurálisan írtuk le, mert ezzel a vektorjelek (buszok) multiplexelését egyszerűen és szemléletesen le tudjuk írni. Mintának a WebPACK rszer Language Templates / Verilog / Synthesis Templates példatárából a "Mux built with gates" modult választottuk. module mpx2to1(in0,in1,sel,out); input [3:0] IN0; input [3:0] IN1; input SEL; output [3:0] OUT; reg [3:0] OUT; always @(SEL or IN0 or IN1) case (SEL) 1'b0 : OUT = IN0; 1'b1 : OUT = IN1; case module 6.4 A digit-számláló modul (sqwgen) Verilog leírása module sqwgen(clk,reset,qa); input RESET; output QA; reg [16:0] COUNT; assign QA = COUNT[14]; if (RESET) COUNT <= 16'd0; else COUNT <= COUNT+1; module 6.5 A display-vezérlő top-moduljának (disp2d) Verilog leírása A leírás a 3. ábrán látható funkcionális vázlat alapján történt 7/9
module disp2d(clk,reset,d1,d2,mask,segm,digen); input RESET; input [3:0] D1; //1. hex digit input [3:0] D2; //2. hex digit input [3:0] MASK; //digit enable mask output [6:0] SEGM; //active Low segment outputs output [3:0] DIGEN;//active Low display digit enable wire [3:0] HEX,MASK; wire QA; assign DIGEN[0] = MASK[0] ~QA; assign DIGEN[1] = MASK[1]; assign DIGEN[2] = MASK[2]; assign DIGEN[3] = MASK[3] QA; sqwgen digitc (CLK,RESET,QA); mpx2to1 digitmpx (D1,D2,QA,HEX); hex2led segm_decod (HEX,SEGM); module 7. A nyomógomb pergésmenetesítése Az egységnek a dobásokat számlálnia is kell. A panelt használva és Spartan-3 Board leírását tanulmányozva is kiderül, hogy a panelen lévő nyomógombok pereghetnek, és a panelen nincs külön pergésmenetesítő áramkör. A pergés azt jelenti, hogy a gomb megnyomásakor ill. elengedésekor a nyomógomb kimenő jele többször változhat. Ha nem végzünk pergésmenetesítést, akkor a számlálónk egy gombnyomáskor többet is léphet. A pergés időtartama nem több mint 2 ms. Ezt kihasználva a pergésmenetesítést úgy fogjuk végezni, hogy a nyomógomb jelét kb. 3 ms-onként mintavételezzük, és csak akkor tekintjük a nyomógomb állapotát megváltozottnak, ha a következő (a 3 ms-mal későbbi) minta is a megváltozott értéknek felel meg. module debounce( input CLK, //50 MHz system clock input RESET, input CY, //sample rate for debounce input BTNb, //bouncing signal output reg BTNdeb //debounced signal ); reg BTNs; //sampled input signal //Sampling bouncing signal if (RESET) BTNs <= 0; BTNdeb <= 0; else if (CY) BTNs <= BTNb; BTNdeb <= (BTNb & BTNs) (BTNdeb & (BTNb BTNs)); module 8/9
8. A készülék legfelső szintű moduljának (kocka) leírása A legfelső szintű modul tartalmazza az 1. ábrának megfelelő funkcionális modulok kapcsolódását egymáshoz és a vezérlő/kijelző szervekhez. Ebbe a modulba építettük be a BTN1 és BTN3 bemenő jelek szinkronizálását is. A nyomogomb pergésmenetesítését egy külön modul végzi. A készülék működésének vizsgálatát megkönnyíti, ha a bemenő/kimenő jelek másolatát és fontosabb belső jeleket kivezetünk a logikai analizátor vagy mixed signal oszcilloszkóp szokásos csatlakozási felületére. Ezt ez a leírás nem tartalmazza. module kocka(clk,btn3,btn1,segm,dp,digen,btn); input BTN3; //Reset input BTN1; //Die throw output [6:0] SEGM; //Display segments, active L output DP; //Decimal Point segment output [3:0] DIGEN;//DI[lay digit enable output BTN; //State of BTN1 reg RESET; reg BTNb; wire [3:0] D1,D2;//digits to be diplayed wire [2:0] DD; assign D1 = {0,DD}; //Die Data is 3 bit only assign DP = 1; //Decimal Point disabled wire [3:0] MASK; //digit mask wire BTN; assign MASK[3] = BTN; assign MASK[2] = 1; assign MASK[1] = 1; assign MASK[0] = 0; //assign MASK[3:0] = {BTN,1,1,0}; //Synchronize inputs BTNb <= BTN1; RESET <= BTN3; debounce btn (CLK,RESET,CY,BTNb,BTN); die die1 (CLK,RESET,BTN,DD,CY); dcount dcount1 (CLK,RESET,BTN,D2); disp2d displ_contr (CLK,RESET,D1,D2,MASK,SEGM,DIGEN); module 9/9