Verilog Parameters meistern: Wiederverwendbare, skalierbare Module erstellen
Parameter sind Verilog-Konstrukte, die es erlauben, ein Modul mit einer anderen Spezifikation wiederzuverwenden. Zum Beispiel kann ein 4-Bit-Adder parametrisiert werden, um einen Wert für die Anzahl der Bits zu akzeptieren, und neue Parameterwerte können bei der Modulinstanziierung übergeben werden. So kann ein N-Bit-Adder zu einem 4-Bit-, 8-Bit- oder 16-Bit-Adder werden. Sie sind wie Argumente einer Funktion, die bei einem Funktionsaufruf übergeben werden.
parameter MSB = 7; // MSB ist ein Parameter mit konstantem Wert 7
parameter REAL = 4.5; // REAL hält eine Reelle Zahl
parameter FIFO_DEPTH = 256, MAX_WIDTH = 32; // Deklariert zwei Parameter
parameter [7:0] f_const = 2'b3; // 2-Bit-Wert wird in 8 Bits konvertiert; 8'b3
Parameter sind im Grunde Konstanten, daher ist es illegal, ihren Wert zur Laufzeit zu ändern. Es ist illegal, einen Namen neu zu deklarieren, der bereits von einem Net, einer Variable oder einem anderen Parameter verwendet wird.
Es gibt zwei Haupttypen von Parametern: Modul- und Specify-Parameter, und beide akzeptieren eine Bereichsspezifikation. Normalerweise werden sie jedoch so breit gemacht, wie der zu speichernde Wert es erfordert, weshalb eine Bereichsspezifikation nicht notwendig ist.
Modulparameter
Modulparameter können verwendet werden, um Parameterdefinitionen innerhalb eines Moduls zu überschreiben, sodass das Modul zur Compile-Zeit einen anderen Parametersatz hat. Ein Parameter kann mit der defparam-Anweisung oder in der Modulinstanziierungsanweisung modifiziert werden. Es ist gängige Praxis, Großbuchstaben in Parameternamen zu verwenden, um sie sofort erkennbar zu machen.
Das unten gezeigte Modul verwendet Parameter, um die Busbreite, Datenbreite und die Tiefe der FIFO im Design zu spezifizieren, und kann mit neuen Werten überschrieben werden, wenn das Modul instanziiert wird oder durch defparam-Anweisungen.
// Verilog 1995 Stil Port-Deklaration
module design_ip (addr, wdata, write, sel, rdata);
parameter BUS_WIDTH = 32, DATA_WIDTH = 64, FIFO_DEPTH = 512;
input addr;
input wdata;
input write;
input sel;
output rdata;
wire [BUS_WIDTH-1:0] addr;
wire [DATA_WIDTH-1:0] wdata;
reg [DATA_WIDTH-1:0] rdata;
reg [7:0] fifo [FIFO_DEPTH];
// Design-Code kommt hier hin ...
endmodule
Im neuen ANSI-Stil der Verilog-Port-Deklaration können Sie Parameter wie unten gezeigt deklarieren.
module design_ip #(
parameter BUS_WIDTH=32,
parameter DATA_WIDTH=64
) (
input [BUS_WIDTH-1:0] addr,
// Andere Port-Deklarationen
);
Parameter überschreiben
Parameter können bei der Modulinstanziierung mit neuen Werten überschrieben werden. Der erste Teil instanziiert das Modul design_ip mit dem Namen d0, wobei neue Parameter innerhalb von #( ) übergeben werden. Der zweite Teil verwendet ein Verilog-Konstrukt namens defparam, um die neuen Parameterwerte zu setzen. Die erste Methode ist die am häufigsten verwendete Methode, um neue Parameter in RTL-Designs zu übergeben. Die zweite Methode wird häufig in Testbench-Simulationen verwendet, um Designparameter schnell zu aktualisieren, ohne das Modul neu instanziieren zu müssen.
module tb;
// Modulinstanziierung-Überschreibung
design_ip #(BUS_WIDTH = 64, DATA_WIDTH = 128) d0 ([port list]);
// Verwendung von defparam zum Überschreiben
defparam d0.FIFO_DEPTH = 128;
endmodule
Beispiel
Das Modul counter hat zwei Parameter N und DOWN, die mit Standardwerten 2 und 0 deklariert sind. N steuert die Anzahl der Bits im Ausgang und damit effektiv die Breite des Zählers. Standardmäßig ist es ein 2-Bit-Zähler. Parameter DOWN steuert, ob der Zähler inkrementieren oder dekrementieren soll. Standardmäßig wird der Zähler dekrementieren, da der Parameter auf 0 gesetzt ist.
2-Bit-Up-Counter
module counter #(
parameter N = 2,
parameter DOWN = 0
) (
input clk,
input rstn,
input en,
output reg [N-1:0] out
);
always @ (posedge clk) begin
if (!rstn) begin
out <= 0;
end else begin
if (en)
if (DOWN) out <= out - 1;
else out <= out + 1;
else
out <= out;
end
end
endmodule
Das Modul counter wird mit N als 2 instanziiert, obwohl dies nicht erforderlich ist, da der Standardwert ohnehin 2 ist. DOWN wird bei der Modulinstanziierung nicht übergeben und nimmt daher den Standardwert 0 an, was einen Up-Counter ergibt.
module design_top (
input clk,
input rstn,
input en,
output [1:0] out
);
counter #(.N(2)) u0 (
.clk(clk),
.rstn(rstn),
.en(en)
);
endmodule
Man sieht, dass Standardparameter verwendet werden, um den Zähler zu implementieren, wobei N gleich zwei ist (2-Bit-Zähler) und DOWN gleich null (Up-Counter). Der Ausgang vom Zähler ist auf der Top-Level-Ebene unverbunden.
4-Bit-Down-Counter
In diesem Fall wird das Modul counter mit N als 4 instanziiert, was einen 4-Bit-Zähler ergibt. DOWN erhält bei der Modulinstanziierung den Wert 1, weshalb ein Down-Counter implementiert wird.
module design_top (
input clk,
input rstn,
input en,
output [3:0] out
);
counter #(.N(4), .DOWN(1)) u1 (
.clk(clk),
.rstn(rstn),
.en(en)
);
endmodule
Specify-Parameter
Diese werden hauptsächlich für die Bereitstellung von Timing- und Delay-Werten verwendet und mit dem Schlüsselwort specparam deklariert. Es ist erlaubt, sie sowohl innerhalb des specify-Blocks als auch im Hauptmodul-Körper zu verwenden.
// Verwendung von specify-Block
specify
specparam t_rise = 200, t_fall = 150;
specparam clk_to_q = 70, d_to_q = 100;
endspecify
// Innerhalb des Hauptmoduls
module my_block ( ... );
specparam dhold = 2.0;
specparam ddly = 1.5;
parameter WIDTH = 32;
endmodule
Unterschied zwischen Specify- und Modulparametern
| Specify-Parameter | Modulparameter |
|---|---|
Deklariert mit specparam |
Deklariert mit parameter |
Kann innerhalb des specify-Blocks oder im Hauptmodul deklariert werden |
Kann nur im Hauptmodul deklariert werden |
| Kann Specparams und Parameter zugewiesen bekommen | Kann keine Specparams zugewiesen bekommen |
| SDF kann zum Überschreiben von Werten verwendet werden | Instanzdeklarations-Parameterwerte oder defparam können zum Überschreiben verwendet werden |
Verilog
- Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
- Verilog Concatenation meistern: Praktischer Leitfaden
- Verilog Essentials: Kurzer Überblick
- Verilog Assignments verstehen: Typen, Syntax und Best Practices
- Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
- Verilog Functions meistern für effizientes RTL-Design
- Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
- Verilogs hierarchischen Referenz-Gültigkeitsbereich meistern: Namenskonflikte in Modulen und Blöcken vermeiden
- Verilog Clock Generator: Design & Implementierungsleitfaden
- Verilog Math Functions meistern für effizientes Hardware-Design