Lär dig Verilog: En kort Tutorial serie på Digital elektronik Design med FPGAs och Verilog HDL (16 / 21 steg)
Steg 16: VM 3.3: avancerad instansiering ämnen
(Bilden ursprungligen skapad av Digilent Inc., modifierad av mig för detta denna tutorial)
Den tidigare modulen införde, och förhoppningsvis körde hem, begreppet instansiering i Verilog. Nu tar vi en titt på ett par avancerade ämnen (andra ämne som skall läggas till snart) när det gäller modul instansiering.
Motverka kontrollerade instansieringen:
Vad händer om vi behövde för att generera en massa (ta 50 som exempel) DFFs som var alla anslutna tillsammans i en klocka divider krets... Vi vet redan hur man gör en allmän DFF modul, så nu behöver vi initiera den 50 gånger och ansluta den klocka pin av var och en att produktionen av DFF som är sekventiellt innan det, ansluta återställa till en global återställning, och D i stift till inversen av den DFF utdata (Q). Använd bifogat diagram för referens.
Detta skulle vara en massa instansieringar för dig att skriva (50 instansieringar gånger 6 rader per instansiering är 300 rader!) för hand. Men i Verilog kan vi använda en disk controller loop, närmare bestämt en "för" loop, att skapa (generera) alla dessa moduler (utom den första) för oss i mycket några rader kod. Men det finns en varning; Vi måste noggrant planera vår design så att vi kan använda en "generera loop" ordentligt.
Observera att det sätt vi ansluta varje DFF till nästa är enhetlig och förutsägbar. Naturligtvis, den första DFF klockan blir klockan input från våra översta nivån modul, och produktionen av den senaste DFF kommer att gå någonstans i modulen toppnivå, men kan vi behandla dem var för sig. under generationen ges varje inre tråd i designen med undantag för den första klocka som vi utser manuellt och sista utgång tråd uttryckligen en källa och ett avlopp. Mjukvaran vet att de två återstående kablarna behöver antingen en källa (första klocka) eller avlopp (senaste data) och det är den ingenjörens ansvar att tillhandahålla en.
Som tidigare nämnts, måste du ställa in designen ordentligt för att kunna använda en generera loop. Vad innebär detta? Tja, är det vettigt att eftersom varje DFF kommer att ha en klocka i beroende på den tidigare (inte inklusive den första en!) att vi kan gruppera dessa liknande signaler i en buss! Detta låter oss se signal grupper som en array i C/C++ och samtal individuella ledningar av index med operatorn [].
Återställ PIN-koden för varje DFF kommer från en gemensam återställning, eftersom varje DFF behöver för att kunna återställa samtidigt.
Utan att ännu veta detaljerna i en generera slinga, kan vi fortfarande göra vår buss som ska användas i designen. Vilken typ av buss kommer vi göra? Eftersom dessa endast bär en signal från en källa till ett avlopp, vi sladdar.
tråd ut [49:0] //50 bitars brett buss för DFF utgång/ingång
Vi kan också initiera våra första DFF. Använda DFF-modulen från Tutorial modulen 3.2, och förutsatt att vår klocka divider har en ingång clk (en klocka stift), en ingång rst (en Återställ PIN-kod) och en utgång ut (Låt oss säga det kommer att driva en LED, skapa en blinkande effekt).
(DFF) dff0
.CLK(CLK),
.rst(rst),
. D(~Out[0]),
. Q(Out[0])
);
Nu, generera slingan. Det liknar en slinga i C/C++ men har sina egna nyanser. Vi måste först skapa en variabel. I Verilog variabeltyp kallas "genvar" och det används för att deklarera en variabel, kalla det "y", som så:
genvar y;
Generera loopen börjar med nyckelordet "generera" och slutar med "endgenerate".
Obs: Du måste deklarera alla genvar variabler utanför räckvidden för generera slingan.
Vi har nu:
genvar y; endgenerate
Generera
Direkt efter nyckelordet "generera" är den faktiska loopen. Sitt uttalande är som en loop i C/C++, men i Verilog, vi har inte lyxen att vänster och höger lockigt klammerparenteser ({och}) men vi har Verilog motsvarande: börjar och slutar. Dessutom Verilog inte stöder postfix operationer, så vi kan inte ange "y ++" och måste i stället ange "y = y + 1". När de bygger den för loop, kom ihåg att vi redan skapat den första DFF (DFF0) så vi kommer att generera från 1 till 49 (mindre än 50).
genvar y; slutet
Generera
för (y = 1; y < 50; y = y + 1) //spaces utelämnas
börja
endgenerate
Med en generera loop, vi kommer att "börja" en instansiering loop och måste ange ett namn för denna process. Vi kommer inte att använda detta namn för andra ändamål och inte kommer att hänvisa till det senare i vår design (det används internt i syntet). Vi gör detta genom att lägga till ett uttalande efter formatet ":" och placera den på samma rad som den "börja" för bra stil. Låt oss kalla denna "dff_generation":
genvar y; slutet
Generera
för (y = 1; y < 50; y = y + 1) //spaces utelämnas
börja: dff_generation
endgenerate
Nu är den avgörande och svåraste delen: att skapa instansiering modell. Detta kommer att se precis som alla andra instansiering förutom att trådarna du passerar modulen är tillåtna att använda genvar som ett värde eller värde modifierare. Minns att det genvar värdet kommer att förändras av en i detta fall efter varje instansiering.
I stället för att gå igenom varje rad av instansieringen ska jag ge dig hela kodblocket och peka på saker du inte kanske känner igen. Var noga med att hänvisa till medföljande bilden för att se hur denna krets är implementerad.
genvar y;
Generera
för (y = 1; y < 50; y = y + 1) //spaces utelämnas
börja: dff_generation
den nedan instans namn spelar ingen roll
(DFF) dff_insts
.CLK(Out[y-1]), //clk i av DFF "y" är ur "y-1"
.rst(rst), //each DFF får samma Återställ
. D(~Out[y]), //input matas inverterad utdata
. Q(Out[y]) //output
);
slutet
endgenerate
Jag uppmuntrar dig att spåra några upprepningar av slingan att se hur generationen behandla fungerar. Syntet ger varje instans skapas ett unikt indexerade namn som "dff_insts1" och "dff_insts2".