Menu

Verilog wire vs reg: quando usare l'uno o l'altro (con esempi)

I due tipi di dato principali di Verilog, wire per le connessioni continue e reg per la memorizzazione procedurale, e la regola per scegliere ogni volta quello giusto.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Due nomi, un solo compito

Ogni segnale in Verilog ha un tipo. I primi due tipi che incontrerai sono wire e reg. Entrambi possono contenere un valore. Entrambi possono essere a un bit o multi-bit. La differenza non riguarda cosa è il segnale, ma chi lo pilota.

  • I segnali wire sono pilotati fuori dai blocchi procedurali: da istruzioni assign, dalle uscite dei sottomoduli o dalle porte di ingresso del modulo.
  • I segnali reg sono pilotati dentro i blocchi procedurali: initial o always.

Questa è tutta la regola. I nomi delle parole chiave sono scomodi perché risalgono a prima del modo moderno di scrivere Verilog. reg non sempre diventa un registro nell'hardware. Continua a leggere per capire perché.

Wire: la connessione continua

Un wire è un filo elettrico. Trasporta in modo continuo qualunque cosa stia producendo il suo driver. Ecco due modi in cui un wire viene pilotato:

Tre cose da notare:

  • y e z sono dichiarati wire nel modulo e di nuovo wire nel testbench.
  • Sono pilotati da assign, cioè la forma di assegnazione continua. Il lato destro dell'= viene ricalcolato ogni volta che cambia uno qualsiasi dei segnali che contiene.
  • Non possiamo scrivere y = a & b dentro un blocco always lasciando y come wire. Il compilatore lo rifiuterebbe.

Se dimentichi la parola chiave wire, Verilog dichiara implicitamente il segnale come wire a un bit al posto tuo: a volte è comodo, a volte è un bug silenzioso. La maggior parte dei team attiva un'opzione dello strumento che dà errore sui wire impliciti. Sii esplicito ed eviti la trappola.

Reg: memorizzazione dentro un blocco procedurale

Un reg è un segnale a cui assegni un valore dentro initial o always. Il nome è un residuo dei primi tempi del linguaggio, quando "reg" suonava come "register"; nell'uso moderno un reg è semplicemente il tipo di qualsiasi segnale in cui scrive il codice procedurale.

count è reg dentro il modulo (perché il blocco always ci scrive) e wire nel testbench (perché lo pilota la porta di uscita del DUT). Stesso segnale, ruoli diversi, tipi diversi in ciascuno scope.

Perché "reg" non significa sempre "registro"

Ecco la trappola più comune per chi inizia. Questo modulo dichiara y come reg, ma l'hardware sintetizzato non contiene alcun flip-flop:

Il blocco always @(*) è sensibile a qualsiasi cambiamento degli ingressi. È combinatorio. Uno strumento di sintesi riconosce questo pattern e produce una porta AND: niente flip-flop, niente clock, solo logica. La parola chiave reg è un puro requisito sintattico, perché y viene assegnato dentro un always.

Per ottenere un vero flip-flop, il blocco always deve essere sensibile a un fronte di clock:

always @(posedge clk) begin
    q <= d;
end

Questo è il pattern "caro sintetizzatore, fammi un flip-flop": lista di sensibilità sul clock, assegnazione non-blocking. Stessa parola chiave reg, hardware completamente diverso. Approfondiamo la distinzione in Blocco always e Blocking e non-blocking.

La scelta in pratica

Ogni volta che dichiari un segnale, chiediti: come lo pilotarò?

  • Lo piloti con assign? → wire.
  • Lo colleghi alla porta di uscita di un sottomodulo? → wire.
  • Porta di ingresso del modulo? → wire. (Gli ingressi sono sempre wire.)
  • Lo piloti da initial o always? → reg.
  • Porta di uscita del modulo pilotata da codice procedurale? → output reg.
  • Porta di uscita del modulo pilotata da assign? → output wire. (Oppure solo output: la sola direzione equivale a wire per impostazione predefinita.)

Questo albero decisionale copre ogni situazione che incontrerai nel Verilog classico.

Conflitti tra driver

In teoria i segnali wire possono avere più driver: è così che funzionano i bus tri-state, dove più moduli possono pilotare lo stesso wire e quelli inattivi passano ad alta impedenza (z). Nella logica ordinaria, due istruzioni assign che scrivono sullo stesso wire producono un comportamento indefinito:

assign y = a;
assign y = b;   // BAD - y has two drivers

Il simulatore potrebbe sceglierne uno o portare il segnale a X: dipende dallo strumento. In ogni caso è un bug. Un solo driver per wire, a meno che tu non stia costruendo esplicitamente un bus.

I segnali reg possono essere pilotati da un solo blocco procedurale. Due blocchi always che assegnano entrambi lo stesso reg sono un errore di sintesi e producono risultati strani in simulazione. Stessa regola: un solo driver.

La novità di SystemVerilog: logic

SystemVerilog (il superset in cui si è evoluto Verilog) aggiunge un'unica parola chiave che sostituisce entrambe: logic. Un segnale logic può essere pilotato da assign oppure da un blocco procedurale, ma non da entrambi, e il compilatore ti impedisce di creare per sbaglio un bug con più driver.

module modern(input logic a, input logic b, output logic y);
    assign y = a ^ b;
endmodule

Se inizi un progetto da zero e il tuo strumento supporta SystemVerilog (come fa l'editor di questa pagina, con -g2012), usare logic ovunque semplifica le regole. I file .v classici hanno ancora bisogno della distinzione wire/reg, e nel codice reale vedrai entrambi gli stili per sempre.

Cosa viene dopo

La prossima guida, Vettori e array, prende gli stessi due tipi e mostra come renderli multi-bit. Larghezze dei bus, range, dimensioni packed, la differenza tra un vettore di bit e un array di vettori. Tutto ciò che ti serve prima di poter costruire qualcosa di più grande di un sommatore a un bit.

Domande frequenti

Qual è la differenza tra wire e reg in Verilog?

wire e reg mantengono entrambi un valore di segnale in ogni istante della simulazione, ma scegli tra i due in base a chi pilota il segnale. Un wire è pilotato dall'esterno di un blocco procedurale: da un assign o dall'uscita di un sottomodulo. Un reg è pilotato dall'interno di un blocco initial o always. I nomi sono storici e fuorvianti: reg non significa sempre 'registro'.

In Verilog reg significa flip-flop?

Non necessariamente. Un reg viene sintetizzato come flip-flop solo quando il suo blocco always è sensibile a un fronte di clock e usa l'assegnazione non-blocking. Un reg assegnato dentro un blocco combinatorio always @(*) viene sintetizzato come semplice logica combinatoria. La parola chiave sceglie il tipo di dato Verilog, non l'hardware.

Quando usare wire e quando reg?

Regola pratica: se pilotarai il segnale con assign o lo collegherai alla porta di uscita di un sottomodulo, usa wire. Se gli assegnerai un valore dentro un blocco always o initial, usa reg. Gli ingressi di un modulo sono sempre wire. Le uscite sono wire se pilotate da un assign e reg se pilotate da un blocco procedurale.

Si può assegnare un wire dentro un blocco always?

No, è un errore di sintassi. I segnali wire possono essere pilotati solo da assegnazioni continue (assign) o collegandoli come uscita di un'istanza di sottomodulo. Tutto ciò che sta dentro initial o always deve avere come destinazione un reg (o, in SystemVerilog, un logic). Il compilatore se ne accorge e segnala un 'left-hand side type mismatch'.

Cos'è logic in SystemVerilog?

logic è il tipo con cui SystemVerilog unifica wire e reg. Può essere pilotato da un'assegnazione continua oppure da un blocco procedurale (ma non da entrambi contemporaneamente). Il codice moderno usa sempre più spesso logic ovunque e si dimentica della distinzione wire/reg. I file Verilog classici devono ancora scegliere.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA