SystemVerilog je standardni strojno-opisni jezik (angl. Hardware Description Language). Nastal je kot nadgradnja jezika Verilog in danes predstavlja najpogosteje uporabljen jezik za razvoj digitalnih sistemov na ravni registrov (angl. Register Transfer Level). SystemVerilog združuje preprostost jezika Verilog z dodatnimi možnostmi za opis sodobnih digitalnih vezij. Omogoča jasnejši zapis kombinacijskih in sekvenčnih vezij, uporabo naprednejših podatkovnih tipov, struktur, tabel, vmesnikov ter objektno usmerjenih pristopov pri verifikaciji. Zaradi tega je pogosto enostavnejši za učenje in preglednejši pri razvoju večjih projektov.
Model vezja opisujejo stavki, ki so nekoliko podobni stavkom v programskih jezikih. Komentarji in operatorji uporabljajo podobne simbole kot jezik C. Bloke stavkov zapišemo med begin in end, zaviti oklepaji pa imajo poseben pomen pri združevanju signalov. Pomembna značilnost jezika je paralelno izvajanje opisov strojne opreme, saj posamezni deli kode predstavljajo sočasno delujoče dele digitalnega vezja.
Modul je v jeziku SystemVerilog osnovna enota za opis strojne opreme. Predstavlja digitalno komponento z vhodnimi in izhodnimi priključki ali pa testni modul brez zunanjih priključkov. Module lahko povezujemo hierarhično, tako da znotraj enega modula uporabljamo druge module in na ta način gradimo kompleksnejše digitalne sisteme.
SystemVerilog omogoča zapis več modulov v eni datoteki, vendar dobra praksa priporoča, da je vsak pomembnejši modul zapisan v svoji datoteki, pri čemer je ime datoteke enako imenu modula. Takšna organizacija izboljša preglednost projekta ter poenostavi simulacijo, sintezo in ponovno uporabo kode.
Primer enostavnega modula
module and_gate (
input logic a,
input logic b,
output logic y
);
assign y = a & b;
endmodule
Ime modula in priključnih signalov so identifikatorji za katere veljajo podobna pravila pisanja kot v jeziku C. SystemVerilog razlikuje velike in male črke. Ime je lahko sestavljeno iz črk angleške abecede, številk, podčrtaja in znaka $, prvi znak pa mora biti črka ali podčrtaj.
Priključke deklariramo tako, da zapišemo smer signala (input, output, inout) in podatkovni tip.
Za običajne povezave v vezju uporablja SystemVerilog podatkovni tip logic. Večbitne signale predstavljajo vektorji, kjer ob deklaraciji zapišemo obseg indeksov v oglatih oklepajih. Najprej navedemo indeks najpomembnejšega (MSB), nato dvopičje in indeks najmanj pomembnega bita (LSB), naprimer [7:0] za 8-bitne vektorje:
module sum8 (
input logic [7:0] a,
input logic [7:0] b,
output logic [7:0] c
);
Sitaksa jezika SystemVerilog ne zahteva zamikanja, vendar pravilno zamikanje zelo poveča preglednost in berljivost kode. Podobno je s komentarji, ki olajšajo razumevanje in kasnejše popravljanje kode. Komentar naj dodatno razlaga kodo in ne opisuje očitnega. Primer slabega in dobrega komentiranja:
// SLAB komentar:
// vsota vrednosti a in b
c = a + b;
// DOBER komentar:
// 8-bitni nepredznačen seštevalnik
c = a + b;
SystemVerilog omogoča tudi uporabo parametrov, s katerimi lahko izdelamo prilagodljive module:
module counter #(
parameter WIDTH = 8
)(
input logic clk,
input logic rst,
output logic [WIDTH-1:0] count
);
endmodule
Signali predstavljajo povezave med posameznimi deli vezja. V modelu vezja deklariramo zunanje signale modula in notranje signale. Kombinacijski signali opisujejo povezovalne žice ali večbitna vodila, sekvenčni pa modelirajo registre oziroma flip-flope. Signale pred uporabo deklariramo, kjer navedemo podatkovni tip. Najbolj uporabni podatkovni tipi signalov so:
bit – dvo-vrednostni tip (0 ali 1),logic – štiri-vrednostni tip (0, 1, X, Z),int, byte, shortint, longint – celoštevilski tipi,enum, struct, typedef – tipi za preglednejši opis kompleksnejših podatkov.Primer deklaracij signalov:
logic x; // enobitni signal
bit flag; // dvo-vrednostni signal (0 ali 1)
logic [3:0] y; // 4-bitno vodilo
logic signed [9:0] s; // 10-bitni predznačeni signal
int d; // 32-bitni celoštevilski signal
V SystemVerilogu tip logic v večini primerov nadomešča stare tipe wire in reg iz Veriloga. Tip logic podpira štiri logične vrednosti (0, 1, X, Z) in je primeren tako za kombinacijske kot sekvenčne opise vezij.
*Posebnost tipa wire ostaja možnost povezovanja več izhodov (driverjev) na isti signal. Takšne povezave uporabljamo predvsem pri tri-stanjskih vodilih (tri-state). Končna vrednost signala se določa po pravilih logične razrešitve:
Pri večbitnih signalih območje indeksov navedemo pred imenom signala:
logic [7:0] data; // 8-bitni vektor
logic [31:0] address; // 32-bitno vodilo
SystemVerilog podpira tudi podatkovne zbirke (arrays), ki so uporabne za opis pomnilnika.
Primer: logic [7:0] mem[0:255] predstavlja pomnilnik 256 8-bitnih vrednosti.
Zapis mem[0] je prvi element, ki predstavlja 8-bitni vektor, drugi bit tega vektorja pa dobimo: mem[0][1].
Celoštevilske konstante so v SystemVerilogu zapisane v obliki: <velikost>'<osnova><vrednost>
Velikost določa število bitov, osnova je b (binarna), d (desetiška), h (šestnajstiška) ali o (osmiška),
vrednost pa sestavljajo števke v izbrani osnovi. Osnovo smemo zapisati tudi z velikimi črkami B, D, H
ali O. Če opustimo velikost, je privzeta 32 bitov.
Verilog po potrebi razširi podano vrednost na predpisano velikost ali pa skrči, tako da odstrani
najvišje bite. Med števkami smemo vriniti podčrtaj za boljšo preglednost. Dvojiške vrednosti so:
1'b0 // enobitna logična 0
4'b0101, 4'b101 // 4-bitna vrednost 0101
15, 'hf // 32-bitna vrednost 15
Osmiške števke predstavljajo tri, šestnajstiške pa štiri bite. Če je med njimi zapisana z ali x, se razširi na ustrezno število bitov. Celoštevilske konstante predstavljajo nepredznačene vrednosti ali pa predznačene (dvojiški komplement), če pred osnovo dodamo s ali S.
Nad celoštevilskimi vrednostmi
delamo binarne aritmetične operacije: +, -, *, /, %
in unarni + in -. Rezultat seštevanje n-bitnih
vektorjev ima n+1 bitov, množenja pa 2n bitov. Če rezultat priredimo n-bitnemu vektorju, bodo najvišji
biti izgubljeni. Kadar imamo operanda različnih velikosti, se pred operacijo najmanjši razširi na
velikost večjega. Operatorja deljenja in ostanka zahtevata kompleksno logiko in običajno nista
primerna za sintezo vezja.
Binarne operacije nad biti: & and, | or, ^ xor, ~^ xnor in
unarno ~ not predstavljajo
logične operacije nad posameznimi biti.
Rezultat logičnih operatorjev !, && in || je enobitni signal:
0=narobe (false), 1=pravilno (true).
Delujejo tudi nad večbitnimi vektorji, ki imajo pravilno vrednost, če je vsaj en bit na 1.
Relacijski operatorji: >, <, >=, <=,
==, != delujejo podobno kot v programskih jezikih. Rezultat je enobitna
vrednost 0 ali 1, če so vsi vhodni biti na 0 ali 1. Če je katerikoli bit x ali z, bo rezultat operacije
nedefinirana vrednost x. Posebna operatorja === in !== pa znata primerjati tudi vrednosti, ki vsebujejo
x ali z.
SystemVerilog pozna logično pomikanje: <<, >> in aritmetično pomikanje vrednosti:
<<<, >>>.
Aritmetični pomik v levo daje enak rezultat kot logični, pri pomiku v desno pa pride do razlike kadar pomikamo predznačene vrednosti.
Operatorji reduciranja: &, ~&, |, ~|, ^,
~^ so unarni operatorji, ki izvajajo logično operacijo nad
vsemi biti vektorja in določijo enobitni rezultat. Npr. &x naredi konjukcijo vseh bitov vektorja.
Indeksiranje opišemo z oglatimi oklepaji, da pridemo do posameznega bita vektorja ali elementa niza. Če zapišemo v oklepajih območje indeksov, je rezultat ustrezno velik podvektor. Z zavitimi oklepaji pa opišemo združevanje, ko iz posameznih signalov ali podvektorjev naredimo večji vektor. Z operatorjem repliciranja pa opišemo večkratno združevanje signalov. Npr.
logic [7:0] x;
logic [3:0] y;
{x[2:0], y} // x[2], x[1], x[0], y[3], y[2], y[1], y[0]
{x[3], x[2], x[1]} // enako kot x[3:1]
{y[0], y[1], y[2], y[3]} // obrne signal y
{1'b0, x} // doda vodilno 0 signalu x
{4{x[0]}} // repliciranje bita, enako kot {x[0], x[0], x[0], x[0]}
{2{y[1:0]}} // repliciranje podvektorja, kot {y[1:0], y[1:0]}