# SystemVerilog

SystemVerilog, standardizzato come IEEE 1800, è un linguaggio di descrizione e verifica dell'hardware utilizzato per modellare, progettare, simulare, testare e implementare sistemi elettronici. SystemVerilog è basato su Verilog ed è comunemente usato nell'industria dei semiconduttori e della progettazione elettronica come evoluzione di Verilog. Dal 2008 Verilog e SystemVerilog fanno parte dello stesso standard IEEE.

## Storia

SystemVerilog nasce nel 2002, con la donazione del linguaggio Superlog ad Accellera da parte della startup Co-Design Automation. La maggior parte delle funzionalità di verifica si basa sul linguaggio OpenVera donato invece da Synopsys. Nel 2005, SystemVerilog è stato adottato come standard IEEE 1800-2005. Nel 2009, lo standard è stato unito allo standard di base Verilog (IEEE 1364-2005), creando lo standard IEEE 1800-2009. La versione attuale è lo standard IEEE 1800-2017.
Il set di funzionalità di SystemVerilog può essere suddiviso in due parti distinte:
* SystemVerilog per la progettazione a livello di trasferimento tra registri (RTL): è un'estensione di Verilog-2005 e tutte le funzionalità di quel linguaggio sono disponibili in SystemVerilog. Pertanto, Verilog può essere considerato un sottoinsieme di SystemVerilog.
* SystemVerilog per la verifica: utilizza estesamente tecniche di programmazione orientate agli oggetti ed è più strettamente correlato a Java piuttosto che a Verilog. Questi costrutti generalmente non sono sintetizzabili.
Il resto di questo articolo discute le caratteristiche di SystemVerilog non presenti in Verilog-2005.

## Caratteristiche a supporto della progettazione
### Durata delle variabili

Esistono due tipi di durata delle variabili specificate in SystemVerilog: static e automatic. Le variabili automatiche vengono create nel momento in cui l'esecuzione del programma rientra nello scope della variabile. Le variabili statiche vengono create all'inizio dell'esecuzione del programma e mantengono lo stesso valore durante l'intero ciclo di vita del programma, a meno che non venga assegnato un nuovo valore durante l'esecuzione.
Qualsiasi variabile dichiarata all'interno di un task o di una funzione senza specificare il tipo verrà considerata automatica. Per specificare che una variabile è statica si utilizza la parola chiave static nella dichiarazione del tipo, ad esempio static int x;. La parola chiave automatic viene utilizzata allo stesso modo.

### Nuovi tipi di dati

I tipi di variabili avanzati aggiungono nuove funzionalità al tipo "reg" di Verilog:
Verilog-1995 e Verilog-2001 limitano le variabili reg a statement comportamentali come nel caso del codice RTL. SystemVerilog estende il tipo reg in modo che possa essere guidato da un singolo driver come un gate o un modulo. SystemVerilog chiama questo tipo "logic" per ricordare questa capacità ulteriore e che non si tratta di un registro hardware. I nomi "logic" e "reg" sono intercambiabili. Un segnale con più di un driver (come un buffer a tre stati per input/output generico) deve essere dichiarato usando un tipo net come "wire" in modo che SystemVerilog possa risolverne il valore finale.
I Packed array multidimensionali unificano ed estendono la nozione di "registri" e "memorie" di Verilog:
Il Verilog classico consente di dichiarare solo una dimensione a sinistra del nome della variabile. SystemVerilog consente qualsiasi numero di tali dimensioni "impacchettate". Una variabile di tipo array packed mappa 1:1 su una quantità aritmetica intera. Nell'esempio precedente, ogni elemento di my_pack può essere utilizzato nelle espressioni come numero intero a sei bit. Le dimensioni a destra del nome (32 in questo caso) sono indicate come dimensioni "unpacked". Come in Verilog-2001, è consentito qualsiasi numero di dimensioni unpacked.
I tipi di dati enumerati (enums) consentono di assegnare nomi significativi a quantità numeriche. Le variabili dichiarate di tipo enumerato non possono essere assegnate a variabili di un diverso tipo enumerato senza conversione di tipo. Questo non è vero per i parametri, la tecnica di implementazione preferita per le quantità enumerate in Verilog-2005:
Come mostrato sopra, il progettista può specificare un tipo aritmetico sottostante (logic [2:0] in questo caso) che viene utilizzato per rappresentare il valore di enumerazione. Possono essere usati meta-valori X e Z, possibilmente per rappresentare stati illegali. La funzione name restituisce una stringa ASCII per il valore enumerato corrente, utile per la convalida e il test.
Nuovi tipi interi: SystemVerilog definisce byte, shortint, int e longint come tipi interi con segno a due stati con rispettivamente 8, 16, 32 e 64 bit. Un tipo bit è un tipo a due stati a larghezza variabile che funziona in modo molto simile a logic. I tipi a due stati mancano dei metavalori X e Z del Verilog classico; l'uso di questi tipi può consentire una simulazione più veloce.
Le strutture e le unioni funzionano in modo molto simile al linguaggio di programmazione C. I miglioramenti di SystemVerilog includono l'attributo tagged e l'attributo packed. L'attributo tagged consente il monitoraggio in fase di esecuzione di quali membri di un'unione sono attualmente in uso. L'attributo packed fa sì che la struttura o l'unione venga mappata 1:1 su un packed array di bit. I contenuti dei tipi di dati struct occupano un blocco continuo di memoria senza interruzioni, simile ai campi di bit in C e C++:
Come mostrato in questo esempio, SystemVerilog supporta anche typedef, come in C e C++.

### Blocchi procedurali

SystemVerilog introduce tre nuovi blocchi procedurali destinati a modellare l'hardware: always_comb (per modellare la logica combinatoria), always_ff (per i flip-flop ) e always_latch (per i latch ). Mentre Verilog utilizza un unico blocco generico always per modellare diversi tipi di strutture hardware, ciascuno dei nuovi blocchi di SystemVerilog ha lo scopo di modellare un tipo specifico di hardware, imponendo restrizioni semantiche per garantire che l'hardware descritto dai blocchi corrisponda all'uso previsto del modello. Un compilatore HDL o un programma di verifica può eseguire passaggi aggiuntivi per garantire che si verifichi solo il tipo di comportamento previsto.
Un blocco always_comb modella circuiti logici combinatori. Il simulatore deduce che la sensitivity list sia costituito da tutte le variabili dalle istruzioni contenute:
Un blocco always_latch modella latch sensibili al livello. Ancora una volta, la sensitivity list è dedotta dal codice:
Un blocco always_ff modella la circuiti sincroni (in particolare circuiti logici sequenziali sensibili al fronte):
Gli strumenti EDA (Electronic Design Automation) possono verificare l'intento del progetto controllando che il modello hardware non violi alcuna semantica di utilizzo dei blocchi. Ad esempio, i nuovi blocchi limitano l'assegnazione a una variabile consentendo solo una fonte, mentre Verilog blocca always l'assegnazione consentita da più fonti procedurali.

## Interfacce

Per progetti di piccole dimensioni, le porte Verilog descrivono in modo compatto la connettività di un modulo con l'ambiente circostante. Ma i blocchi principali all'interno di un'ampia gerarchia di progettazione in genere possiedono migliaia di porte. SystemVerilog introduce il concetto di interfacce sia per ridurre la ridondanza delle dichiarazioni dei nomi delle porte tra i moduli collegati, sia per raggruppare e astrarre i segnali correlati in un bundle dichiarato dall'utente. Un concetto aggiuntivo è quello di modport, che mostra la direzione delle connessioni logiche.
Ad esempio:

## Funzionalità di verifica

Le seguenti funzionalità di verifica in genere non sono sintetizzabili, il che significa che non possono essere implementate in hardware sulla base del relativo codice HDL. Esse aiutano invece nella creazione di test bench estensibili e flessibili.

### Nuovi tipi di dati

Il tipo di dati string rappresenta una stringa di testo di lunghezza variabile. Ad esempio:
Oltre agli array statici utilizzati nella progettazione, SystemVerilog offre array dinamici, array associativi e code:
Un array dinamico funziona in modo molto simile a un array unpacked, ma offre il vantaggio di essere allocato dinamicamente in fase di esecuzione (come mostrato sopra). Mentre la dimensione di un packed array deve essere nota in fase di compilazione (da una costante o espressione di costanti), la dimensione dell'array dinamico può essere inizializzata da un'altra variabile, consentendo all'array di essere dimensionato e ridimensionato arbitrariamente secondo necessità.
Un array associativo può essere considerato come un albero di ricerca binario con un tipo della chiave e un tipo dei dati specificati dall'utente. La chiave implica un ordinamento. Gli elementi di un array associativo possono essere letti in ordine lessicografico.
Infine, una coda fornisce gran parte delle funzionalità del tipo deque della Standard Template Library C++: gli elementi possono essere aggiunti e rimossi da entrambe le estremità in modo efficiente. Queste primitive consentono la creazione di strutture di dati complesse, necessarie ad esempio per lo scoreboard di un progetto di grandi dimensioni.

### Classi

SystemVerilog fornisce un modello di programmazione orientato agli oggetti.
In SystemVerilog, le classi supportano un modello di ereditarietà singola, ma possono implementare funzionalità simili all'ereditarietà multipla attraverso l'uso delle cosiddette "classi di interfaccia" (identiche nel concetto alla funzionalità interface di Java). Le classi possono essere parametrizzate per tipo, fornendo la funzione di base dei template C++. Tuttavia, la specializzazione dei template e le funzioni template non sono supportati.
Le funzionalità di polimorfismo di SystemVerilog sono simili a quelle di C++: il programmatore può definire una funzione virtual per fare in modo che una classe derivata ottenga il controllo della funzione.
L'incapsulamento e l'occultamento dell'informazione (information hiding) vengono eseguiti utilizzando le parole chiave local e protected, che devono essere applicate a qualsiasi elemento che deve essere nascosto. Per impostazione predefinita, tutte le proprietà della classe sono pubbliche.
Le istanze delle classi vengono create dinamicamente con laparola chiave new. È possibile definire un costruttore denotandolo come function new. SystemVerilog implementa la garbage collection, quindi non c'è alcuna funzione del linguaggio per distruggere in modo esplicito le istanze create dall'operatore new.
Ad esempio:

### Constrained random generation

Alle quantità intere, definite nella definizione di una classe o come variabili autonome in un certo scope lessicale, possono essere assegnati valori casuali sulla base di un insieme di vincoli. Questa funzionalità è utile per creare scenari randomizzati per la verifica.
Nella definizione di una classe, i modificatori rand e randc segnalano le variabili che devono essere randomizzate. randc specifica che la randomizzazione deve essere basata sulla permutazione, in cui una variabile assumerà tutti i possibili valori almeno una volta prima che qualsiasi valore venga ripetuto. Le variabili senza modificatori non sono randomizzate.
Nell'esempio precedente, il campo fcs non è randomizzato (e in pratica verrà calcolato con un generatore CRC), mentre il campo fcs_corrupt è usato per corromperlo e iniettare errori FCS. I due vincoli mostrati sono applicabili ai frame Ethernet. I vincoli possono essere attivati selettivamente; questa funzione sarebbe richiesta nell'esempio precedente per generare frame corrotti. I vincoli possono essere arbitrariamente complessi, comprendendo interrelazioni tra variabili, implicazioni e iterazioni. Il risolutore di vincoli SystemVerilog è necessario per trovare una soluzione, se ne esiste una, ma non garantisce il tempo necessario per farlo poiché si tratta in generale di un problema NP-difficile (soddisfacibilità booleana).

#### Metodi di randomizzazione

In ogni classe SystemVerilog ci sono 3 metodi predefiniti per la randomizzazione: pre_randomize, randomize e post_randomize. Il metodo randomize viene chiamato dall'utente per la randomizzazione delle variabili di classe. Il metodo pre_randomize viene chiamato dal metodo randomize prima della randomizzazione e il metodo post_randomize viene chiamato dal metodo randomize dopo la randomizzazione.
I metodi constraint_mode e random_mode sono usati per controllare la randomizzazione. constraint_mode viene utilizzato per attivare e disattivare un vincolo specifico e random_mode viene utilizzato per attivare o disattivare una randomizzazione di una variabile specifica. Il codice seguente descrive e verifica proceduralmente un frame Ethernet:

### Asserzioni

Le asserzioni sono utili per verificare le proprietà di un progetto che si manifestano dopo che è stata raggiunta una condizione o uno stato specifico. SystemVerilog ha un proprio linguaggio di specifica delle asserzioni, simile al Property Specification Language. Il sottoinsieme dei costrutti del linguaggio SystemVerilog che supporta le asserzioni è comunemente chiamato SystemVerilog Assertion o SVA.
Le asserzioni SystemVerilog sono costruite da sequenze e proprietà. Le proprietà sono un superinsieme di sequenze; qualsiasi sequenza può essere utilizzata come se fosse una proprietà, sebbene ciò non sia tipicamente utile.
Le sequenze sono costituite da espressioni booleane aumentate con operatori temporali. L'operatore temporale più semplice è l'operatore ## che esegue una concatenazione:
Si avrà una corrispondenza se il segnale gnt diventa alto un ciclo di clock dopo che req è diventato alto. Si noti che tutte le operazioni di sequenza sono sincrone a un clock.
Altri operatori sequenziali includono operatori di ripetizione e varie congiunzioni. Questi operatori consentono al progettista di esprimere relazioni complesse tra i componenti del progetto.
Un'asserzione tenta continuamente di valutare una sequenza o una proprietà. L'asserzione fallisce se la proprietà fallisce. La sequenza sopra fallirà ogni volta che req è basso. Per esprimere con precisione il requisito che gnt segue req è richiesta una proprietà:
Questo esempio mostra un operatore di implicazione |=>. La proposizione a sinistra dell'implicazione si chiama antecedente e quella a destra si chiama conseguente. La valutazione di un'implicazione inizia attraverso ripetuti tentativi di valutare l'antecedente. Quando la valutazione dell'antecedente ha successo, si tenta la valutazione del conseguente, e il successo dell'asserzione dipende dal successo del conseguente. In questo esempio, il conseguente non verrà tentato finché req non diventa alto, dopodiché la proprietà fallirà se gnt non è alto nel clock successivo.
Oltre alle asserzioni, SystemVerilog supporta le ipotesi e la copertura delle proprietà. Un'assunzione stabilisce una condizione che uno strumento formale di dimostrazione logica deve assumere come vera. Un'asserzione specifica una proprietà che deve essere dimostrata vera. Nella simulazione, sia le asserzioni che le ipotesi vengono verificate rispetto agli stimoli del test. La copertura della proprietà consente all'ingegnere di verifica di verificare che le asserzioni stiano monitorando accuratamente il progetto.

### Copertura

La copertura (coverage) applicata ai linguaggi di verifica hardware si riferisce alla raccolta di statistiche basate su eventi di campionamento all'interno della simulazione. La copertura viene utilizzata per determinare quando il dispositivo sottoposto a test (Device Under Test, DUT) è stato esposto a una varietà sufficiente di stimoli tale che vi sia un'elevata probabilità che il DUT funzioni correttamente. Si noti che questa definizione differisce dal concetto di copertura del codice (software), orientata a garantire che tutte le righe del codice nel progetto siano state eseguite. La copertura funzionale assicura che tutti i casi corner e marginali desiderati all'interno dello spazio di progettazione siano stati esplorati.
Un gruppo di copertura SystemVerilog crea un database di "contenitori" (bin) che memorizzano un istogramma di valori di una variabile associata. È inoltre possibile definire la copertura incrociata, che crea un istogramma che rappresenta il prodotto cartesiano di più variabili.
Un evento di campionamento controlla quando viene prelevato un campione. L'evento di campionamento può essere un evento Verilog, l'entrata o l'uscita di un blocco di codice o una chiamata al metodo sample del gruppo di copertura. È necessaria attenzione per garantire che i dati vengano campionati solo quando significativi.
Per esempio:
In questo esempio, l'ingegnere di verifica è interessato alla distribuzione dei frame broadcast e unicast, al campo size/f_type e alla dimensione del payload. Gli intervalli nel punto di copertura delle dimensioni del payload riflettono i corner case di interesse, inclusi i frame di dimensioni minime e massime.

### Sincronizzazione

Un ambiente di test complesso è costituito da componenti di verifica riutilizzabili che devono comunicare tra loro. La primitiva "event" di Verilog consente a diversi blocchi di istruzioni procedurali di attivarsi a vicenda, ma l'applicazione della sincronizzazione dei thread dipende dall'uso (intelligente) da parte del programmatore. SystemVerilog offre due primitive specifiche per la sincronizzazione tra thread: mailbox e semaphore. La mailbox è modellata come una coda di messaggi FIFO. Opzionalmente, una FIFO può essere parametrizzato dal tipo in modo che solo gli oggetti del tipo specificato possano essere passati attraverso di esso. Tipicamente, gli oggetti sono istanze di classi che rappresentano transazioni : operazioni elementari (ad esempio, l'invio di un frame) che vengono eseguite dai componenti di verifica. Il semaforo è modellato come un semaforo di conteggio.

## Miglioramenti generali al Verilog classico

Oltre alle nuove funzionalità di cui sopra, SystemVerilog migliora l'usabilità delle funzionalità linguistiche esistenti di Verilog. Di seguito sono riportati alcuni di questi miglioramenti:
* Gli operatori di assegnazione procedurale (<=, =) ora possono operare direttamente sugli array.
* Le definizioni delle porte (inout, input, output) sono ora espanse per supportare una più ampia varietà di tipi di dati: sono supportati i tipi struct, enum, real e multidimensionali.
* Il costrutto del ciclo for ora consente la dichiarazione automatica delle variabili all'interno dell'istruzione for. Il controllo del flusso del ciclo è migliorato dalle istruzioni continue e break.
* SystemVerilog aggiunge un ciclo do/while al costrutto del ciclo while.
* Le variabili costanti, cioè quelle designate come non modificabili durante il runtime, possono essere designate mediante l'uso della parola chiave const.
* L'inizializzazione delle variabili può operare sugli array.
* Gli operatori di incremento e decremento ( x++, ++x, x--, --x ) sono supportati in SystemVerilog, così come altri operatori di assegnazione composti ( x += a, x -= a, x *= a, x /= a, x %= a, x <<= a, x >>= a, x &= a, x ^= a, x |= a ) come nel linguaggio C e linguaggi discendenti.
* Il preprocessore ha migliorato le capacità di sostituzione di macro `define, in particolare la sostituzione all'interno di stringhe letterali (""), così come la concatenazione di più macro-token in una singola parola.
* Il costrutto fork/join è stato espanso con join_none e join_any.
* Le aggiunte alla direttiva `timescale consentono di controllare la scala temporale della simulazione in modo più prevedibile in un ambiente di simulazione di grandi dimensioni, con ogni file sorgente che utilizza una scala temporale locale.
* Ora le porte delle attività possono essere dichiarate rif. Un riferimento fornisce al corpo dell'attività l'accesso diretto agli argomenti di origine nell'ambito del chiamante, noto come "passaggio per riferimento". Poiché sta operando sulla variabile originale stessa, piuttosto che su una copia del valore dell'argomento, l'attività/funzione può modificare le variabili (ma non le net) nello scope del chiamante in tempo reale. Le dichiarazioni delle porte di tipo inout/output passano le variabili per valore e rinviano l'aggiornamento della variabile dello scope del chiamante fino al momento in cui l'attività termina.
* Le funzioni ora possono essere dichiarate void, il che significa che non restituiscono alcun valore.
* I parametri possono essere dichiarati di qualsiasi tipo, inclusi typedef definiti dall'utente.
Oltre a questo, SystemVerilog include un'interfaccia con altri linguaggi (come C/C++) detta SystemVerilog DPI (Direct Programming Interface).

## Software di verifica e sintesi

Nella progettazione di chip elettronici, SystemVerilog è ampiamente utilizzato nella verifica. I tre maggiori fornitori di strumenti EDA (Cadence Design Systems, Mentor Graphics, Synopsys) hanno incorporato SystemVerilog nei loro simulatori HDL in linguaggio misto. Sebbene nessun simulatore possa ancora rivendicare il supporto completo del SystemVerilog Language Reference Manual, rendendo l'interoperabilità dei test bench una sfida, sono in corso sforzi per promuovere la compatibilità tra fornitori. Nel 2008, Cadence e Mentor hanno rilasciato la Open Verification Methodology, una libreria di classi open source e un framework di utilizzo per facilitare lo sviluppo di test bench e IP di verifica riutilizzabili. Synopsys, che era stata la prima a pubblicare una libreria di classi SystemVerilog (VMM), ha successivamente risposto rendendo disponibile e open la propria VMM. Molti provider di terze parti hanno annunciato o già rilasciato IP di verifica SystemVerilog.
Nella sintesi del progetto (trasformazione di una descrizione del progetto hardware in una netlist), l'adozione di SystemVerilog è stata lenta. Molti team di progettazione utilizzano flussi di progettazione che coinvolgono più strumenti di fornitori diversi. La maggior parte dei team di progettazione non può migrare a progetti RTL basati su SystemVerilog fino a quando l'intera suite di strumenti front-end (linter, verifica formale e generatori di strutture di test automatizzate ) non supporta un sottoinsieme linguistico comune.