Costanti con una sorpresa
Un parameter è una costante: il compilatore ne sceglie il valore e lo incorpora nel progetto prima che la simulazione inizi. La sorpresa è che chi istanzia il modulo può cambiarne il valore. Lo stesso file sorgente di un modulo può produrre circuiti di dimensioni diverse a seconda di come viene parametrizzato.
È così che si costruiscono IP riutilizzabili. Un modulo FIFO con i parametri WIDTH e DEPTH può servire tutti i team di un'azienda. Un contatore con un parametro WIDTH ha lo stesso sorgente sia che conti fino a 16 sia che conti fino a 4 miliardi.
Dichiarazione di base di un parametro
Tre elementi di sintassi nuovi:
- Blocco dei parametri:
#( parameter WIDTH = 8 )tra il nome del modulo e l'elenco delle porte. Il valore predefinito8è quello che il modulo usa quando nessuno lo sovrascrive. - Punto di utilizzo:
output reg [WIDTH-1:0] count. Il parametro è solo una costante, che inseriamo nell'intervallo di bit. Lo stesso sorgente produce un'uscita a 8 o 16 bit a seconda diWIDTH. - Sintassi di sovrascrittura:
counter #(.WIDTH(16)) dut16(...)al momento dell'istanziazione. Il blocco#(...)va prima del nome dell'istanza, dopo il nome del modulo. I parametri che non citi mantengono i valori predefiniti.
localparam: costanti interne
Ci sono costanti che non vuoi far sovrascrivere a chi usa il modulo. Le codifiche degli stati sono il caso classico:
localparam rende disponibili IDLE, RUNNING e DONE dentro il modulo, ma non sovrascrivibili dall'istanziazione. È la scelta giusta: cambiare dall'esterno quale valore di stato significa IDLE sarebbe da incubo.
Usa parameter per ciò che chi usa il modulo deve poter configurare (larghezze, profondità, opzioni di comportamento) e localparam per tutto il resto. Un pattern comune è ricavare i localparam dai parameter:
parameter WIDTH = 32;
localparam WIDTH_M1 = WIDTH - 1; // computed once; not overrideable
Larghezze parametriche nella pratica
L'uso più comune dei parametri è rendere flessibili le larghezze dei bus. Ecco un sommatore che funziona con qualsiasi larghezza:
Un file sorgente, due istanze, due larghezze diverse, nessun copia e incolla. È tutto il vantaggio dei parametri.
Più parametri, sovrascrittura per nome
Nei moduli più grandi avrai spesso diversi parametri. Sovrascrivili per nome, in qualsiasi ordine:
module fifo #(
parameter WIDTH = 8,
parameter DEPTH = 16,
parameter AFULL = DEPTH - 2
)(
input wire clk,
input wire reset,
// ... ports ...
);
// ...
endmodule
// At the call site:
fifo #(.WIDTH(32), .DEPTH(1024)) cmd_queue (.clk(clk), .reset(reset), ...);
Non devi sovrascrivere tutti i parametri; quelli non citati mantengono i valori predefiniti. Nell'esempio il valore predefinito di AFULL è calcolato da DEPTH, quindi se sovrascrivi DEPTH, AFULL si adegua automaticamente: è esattamente il tipo di dipendenza che gestirebbe anche un localparam, se non volessi permettere di sovrascrivere AFULL in modo indipendente.
Errori comuni
Dimenticare il # nella sovrascrittura. counter (.WIDTH(16)) dut(...) sembra una sovrascrittura, ma Verilog legge (.WIDTH(16)) come un collegamento di porta. Ti serve counter #(.WIDTH(16)) dut(...).
Usare parametri dove non sono abbastanza costanti. I parametri si risolvono durante l'elaborazione, prima che esista qualsiasi segnale. Non puoi parametrizzare su un segnale a runtime: se il valore dipende da ciò che fa un ingresso durante la simulazione, non è un parametro, è logica.
Confondere parameter e localparam negli elenchi delle porte. Solo parameter va nel blocco #(...) in cima. localparam vive nel corpo. Se li scambi, il compilatore te lo segnala.
Cosa viene dopo
Ora puoi creare moduli la cui dimensione viene fissata in fase di compilazione. Le prossime due pagine trattano le regole per scrivere costanti letterali (8'h1F, 4'b1010, 32'd100) e i valori x e z che compaiono quando i segnali non sono pilotati o sono contesi. Poi passiamo agli operatori: tutto ciò che puoi fare con i vettori e i parametri che hai visto finora.
Domande frequenti
Cos'è un parameter in Verilog?
Un parameter è una costante definita in fase di compilazione e dichiarata dentro un modulo. Si può usare ovunque sia ammessa una costante: larghezze dei bus, profondità delle memorie, codifiche degli stati, valori predefiniti. L'aspetto fondamentale è che ogni istanza del modulo può sovrascrivere il parametro, quindi lo stesso file sorgente può produrre, per esempio, un contatore a 8 bit in un punto e uno a 32 bit in un altro.
Qual è la differenza tra parameter e localparam in Verilog?
I valori di parameter si possono sovrascrivere dall'esterno quando il modulo viene istanziato. Quelli di localparam no: sono solo costanti interne. Usa localparam per le codifiche degli stati e per le costanti derivate che chi scrive il modulo non vuole far toccare a chi lo usa.
Come si sovrascrive un parameter in Verilog?
Quando istanzi il modulo, aggiungi un blocco di sovrascrittura dei parametri prima del nome dell'istanza: counter #(.WIDTH(16)) my_inst (.clk(clk), .count(count));. La sintassi .WIDTH(16) imposta quel parametro specifico; i parametri che non elenchi mantengono i valori predefiniti. Più sovrascritture si separano con virgole dentro #(...).
Cos'è un modulo parametrico?
È un modulo che espone una o più dichiarazioni parameter che chi lo usa può sovrascrivere. Una FIFO parametrica può avere i parametri WIDTH e DEPTH, così lo stesso sorgente produce una FIFO da 32 bit per 16 posizioni in un punto e una da 8 bit per 1024 posizioni in un altro. È così che si scrivono le librerie di blocchi IP riutilizzabili.