Lär dig Verilog: En kort Tutorial serie på Digital elektronik Design med FPGAs och Verilog HDL (15 / 21 steg)
Steg 15: VM 3.3: Hur att instansiera en modul
I modulen tidigare nämnde jag likheterna mellan instansieras moduler i Verilog och anropa funktioner i C/C++.Låt oss titta på hur vi skulle initiera en modul i Verilog.
Här är den modul som vi kommer att arbeta med:
"tidsskala 1ns / 1ps
modul srlatch)
ingång S,
input R,
produktionen Q
);
Wire Q_int, Qn_int;
tilldela Q_int = ~ (S & Qn_int);
tilldela Qn_int = ~ (R & Q_int);
tilldela Q = Q_int;
endmodule
Av nu det inte ska finnas någon Verilog i denna modul inte kunde du förklara.
Så låt oss säga vi ville göra en krets med två SR-lås (oavsett hur meningslösa denna krets är i verkligheten), alla med en switch för deras "set" drift och en delad återställningsknapp. Utdata för varje lås blir en LED.
Med dessa specifikationer i åtanke, låt oss göra övre modulens definition. Kom ihåg att översta modul deklarationer innehåller bara in- och utgångar som kommer och går från den verkliga världen.
"tidsskala 1ns / 1ps
Utmaning: Att skriva denna modul förklaring med bussar
topp () modul
ingång switch0,
ingång VÄXEL1,
ingång btn0,
utgång led0,
output led1
);
endmodule
Stor! Nu måste vi lägga till två SR-lås till vår krets. Hur skulle vi göra detta?
Säg inte "Hårt kod uppförandet av två SR-lås och tilldela sina ingångar och utgångar respektive." Vi kommer att skapa en instans av två instanser av en SR-spärren. Här är hur vår topp modul ser ut efter instansieringen:
"tidsskala 1ns / 1ps
topp () modul
ingång switch0,
ingång VÄXEL1,
ingång btn0,
utgång led0,
output led1
);
srlatch () sr0
. S(switch0),
. R(btn0),
. Q(led0)
);
() srlatch sr1
. S(switch1),
. R(btn0),
. Q(LED1)
);
endmodule
Så vad återstår för att göra? Ingenting; absolut ingenting (förutsatt att du redan har en UCF fil redo). Varför?
Orsaken ligger i modul instansieringen. Låt oss ta en närmare titt på en.
srlatch () sr0
. S(switch0),
. R(btn0),
. Q(led0)
);
Första raden: srlatch sr0 (
Detta är en mycket viktig linje vars formulär du behöver att engagera sig i minnet. Först kommer srlatch. Detta är namnet på basmodulen vi instansieras. sr0 är namnet på instansen. Parentesen öppnas instansieringen. Varje instansiering börjar sådär; "< modul att instansieras >< förekomstnamn >(".
Det finns vissa mindre vanliga fall där instansiering kommer att skilja sig något, men även då denna form fortfarande kommer att vara närvarande.
De följande tre raderna:
. S(switch0),
. R(btn0),
. Q(led0)
Ta en titt på srlatch port Modulnamn och sedan ser tillbaka på dessa tre rader. Detta är i en omväg, liknande till hur vi anropa en funktion i C/C++; Det är där vi passerar parametrarna.
Skillnaden är att i Verilog vi går båda ingångar till modulen och utgångar till modulen. D.v.s. talar vi om den specifika instansen av modulen var dess ingångar kommer från och där vi vill utgångarna att gå.
Ett annat sätt att se på detta är att vi passerar modulen en uppsättning ingångar och utgångar, alla vars värde är kontinuerligt uppdaterade antingen från modulen (resultat) eller utanför modulen (input).
Låt oss bryta ner uttalande: . S(switch0)
Varje modul instansiering måste en rad uttalanden som liknar detta en, ett uttalande per ingång/utgång. Den ". S"hänvisar till ingången S i modulen srlatch och (switch0) hänvisar till ingående switch0 finns i den översta modulen. Ser ett mönster?
. < portnamnet i instansierad modul > (< portnamnet i nuvarande modul->)
Detta begrepp är också liknande att anropa funktioner i andra programmeringsspråk som C/c ++; i funktionsanropet passerar vi värden (som vi känner av variabel namn) i funktionen. Vi kallar detta värde en sak i, till exempel huvudsakliga, men i funktionen det kallas något annat. I det här exemplet Verilog, vi har en ingång i den översta modul som kallas "swtich0", och vi vill "S" värdet av "sr0" ska vara lika oavsett "switch0" är.
Som jag nämnde tidigare, behöver du en port initiering instruktion per port i modulen du instansieras, men om du instansieras en modul som har, säg, en [7:0] buss ingång kallas "T", du behöver inte göra 8 uttalanden som ". T[0](input[0]) ". Du kan skicka hela bussar genom att hänvisa till namnen bara, så du kunde passera "Input" till "T"genom att säga". T(input) ". Kom ihåg dock att buss dimensioner måste matcha upp (dvs. du inte kan passera en 5 port buss i en modul som har en 3 port buss).
Dessutom måste porttyper matcha. Du kan endast skicka indata till en ingång och en utgång (eller en tråd, mer om det senare) till en utgång.
Separat port initiering uttalanden med ett enda komma. Bra kodning stil dikterar att varje rad innehåller endast en exemplifiering. Från detta bör du kunna förstå dessa tre rader kod.
Nära instansieringen med en matchande parentesen och semikolon.
Efter instansieringen sker framgångsrikt, blir utgångarna av modulen instansierad i huvudsak tillgänglig inom den aktuella modulen. Du kan sedan skicka dessa utgångar till översta nivån hamnar och även andra instansierad moduler ingångar.
Innan vi avslutar denna diskussion, låt oss sammanfatta hur man initiera en modul (kom ihåg att "nuvarande modul" hänvisar till den modul som gör instansieringen):
< modulnamn >< () namnet på instansen >
. < portnamnet i modulen till instantieras > (< port/wire namn i nuvarande modul->),
... < upprepa ovan så många gånger som behövs >...
. < portnamnet i modulen till instantieras > (< port/wire namn i nuvarande modul->)
);