當一個模塊被另一個模塊引用例化時,高層模塊可以對低層模塊的參數(shù)值進行改寫。這樣就允許在編譯時將不同的參數(shù)傳遞給多個相同名字的模塊,而不用單獨為只有參數(shù)不同的多個模塊再新建文件。
參數(shù)覆蓋有 2 種方式:
defparam
?可以用關(guān)鍵字 ?defparam
? 通過模塊層次調(diào)用的方法,來改寫低層次模塊的參數(shù)值。
例如對一個單口地址線和數(shù)據(jù)線都是 4bit 寬度的 ?ram
? 模塊的 ?MASK
? 參數(shù)進行改寫:
//instantiation
defparam u_ram_4x4.MASK = 7 ;
ram_4x4 u_ram_4x4
(
.CLK (clk),
.A (a[4-1:0]),
.D (d),
.EN (en),
.WR (wr), //1 for write and 0 for read
.Q (q) );
?ram_4x4
? 的模型如下:
module ram_4x4
(
input CLK ,
input [4-1:0] A ,
input [4-1:0] D ,
input EN ,
input WR , //1 for write and 0 for read
output reg [4-1:0] Q );
parameter MASK = 3 ;
reg [4-1:0] mem [0:(1<<4)-1] ;
always @(posedge CLK) begin
if (EN && WR) begin
mem[A] <= D & MASK;
end
else if (EN && !WR) begin
Q <= mem[A] & MASK;
end
end
endmodule
對此進行一個簡單的仿真,testbench 編寫如下:
`timescale 1ns/1ns
module test ;
parameter AW = 4 ;
parameter DW = 4 ;
reg clk ;
reg [AW:0] a ;
reg [DW-1:0] d ;
reg en ;
reg wr ;
wire [DW-1:0] q ;
//clock generating
always begin
#15 ; clk = 0 ;
#15 ; clk = 1 ;
end
initial begin
a = 10 ;
d = 2 ;
en = 'b0 ;
wr = 'b0 ;
repeat(10) begin
@(negedge clk) ;
en = 1'b1;
a = a + 1 ;
wr = 1'b1 ; //write command
d = d + 1 ;
end
a = 10 ;
repeat(10) begin
@(negedge clk) ;
a = a + 1 ;
wr = 1'b0 ; //read command
end
end // initial begin
//instantiation
defparam u_ram_4x4.MASK = 7 ;
ram_4x4 u_ram_4x4
(
.CLK (clk),
.A (a[AW-1:0]),
.D (d),
.EN (en),
.WR (wr), //1 for write and 0 for read
.Q (q)
);
//stop simulation
initial begin
forever begin
#100;
if ($time >= 1000) $finish ;
end
end
endmodule // test
仿真結(jié)果如下:
圖中黃色部分,當?shù)刂返谝淮螢?nbsp;c 時寫入數(shù)據(jù) 4, 當?shù)诙蔚刂窞?nbsp;c 時讀出數(shù)據(jù)為 4;可知此時 ?ram
? 行為正確,且 ?MASK
? 不為 3。 因為 ?ram
? 的 Q 端 bit2 沒有被屏蔽。
當?shù)谝淮蔚刂窞?nbsp;1 時寫入數(shù)據(jù)為 9,第二次地址為 1 時讀出的數(shù)據(jù)卻是 1,因為此時 ?MASK
? 為 7,?ram
? 的 Q 端信號 bit3 被屏蔽。由此可知,?MASK
? 參數(shù)被正確改寫。
第二種方法就是例化模塊時,將新的參數(shù)值寫入模塊例化語句,以此來改寫原有 ?module
? 的參數(shù)值。
例如對一個地址和數(shù)據(jù)位寬都可變的 ?ram
? 模塊進行帶參數(shù)的模塊例化:
ram #(.AW(4), .DW(4))
u_ram
(
.CLK (clk),
.A (a[AW-1:0]),
.D (d),
.EN (en),
.WR (wr), //1 for write and 0 for read
.Q (q)
);
?ram
? 模型如下:
module ram
#( parameter AW = 2 ,
parameter DW = 3 )
(
input CLK ,
input [AW-1:0] A ,
input [DW-1:0] D ,
input EN ,
input WR , //1 for write and 0 for read
output reg [DW-1:0] Q
);
reg [DW-1:0] mem [0:(1<<AW)-1] ;
always @(posedge CLK) begin
if (EN && WR) begin
mem[A] <= D ;
end
else if (EN && !WR) begin
Q <= mem[A] ;
end
end
endmodule
仿真時,只需在上一例的 testbench 中,將本次例化的模塊 ?u_ram
? 覆蓋掉 ?u_ram_4x4
?, 或重新添加之即可。
仿真結(jié)果如下。由圖可知,?ram
? 模塊的參數(shù) ?AW
? 與 ?DW
? 均被改寫為 4, 且 ?ram
? 行為正確。
u_ram
? 的例化可以描述為:ram #(4, 4) u_ram (......) ;
defparam
? 也可以改寫模塊在端口聲明時聲明的參數(shù),利用帶參數(shù)例化也可以改寫模塊實體中聲明的參數(shù)。例如 ?u_ram
? 和 ?u_ram_4x4
? 的例化分別可以描述為:defparam u_ram.AW = 4 ;
defparam u_ram.DW = 4 ;
ram u_ram(......);
ram_4x4 #(.MASK(7)) u_ram_4x4(......);
u_ram
? 的聲明還可以表示為(模塊實體中參數(shù)可自行實驗驗證):defparam u_ram.AW = 4 ;
ram #(.DW(4)) u_ram (......); //也只有我這么無聊才會實驗這種寫法
ram
? 模塊中加入 ?MASK
? 參數(shù),模型如下:module ram
#( parameter AW = 2 ,
parameter DW = 3 )
(
input CLK ,
input [AW-1:0] A ,
input [DW-1:0] D ,
input EN ,
input WR , //1 for write and 0 for read
output reg [DW-1:0] Q );
parameter MASK = 3 ;
reg [DW-1:0] mem [0:(1<<AW)-1] ;
always @(posedge CLK) begin
if (EN && WR) begin
mem[A] <= D ;
end
else if (EN && !WR) begin
Q <= mem[A] ;
end
end
endmodule
此時再用 ?defparam
? 改寫參數(shù) ?MASK
? 值時,編譯報 ?Error
?:
//都采用defparam時會報Error
defparam u_ram.AW = 4 ;
defparam u_ram.DW = 4 ;
defparam u_ram.MASK = 7 ;
ram u_ram (......);
//模塊實體中parameter用defparam改寫也會報Error
defparam u_ram.MASK = 7 ;
ram #(.AW(4), .DW(4)) u_ram (......);
重點來了?。?!如果你用帶參數(shù)模塊例化的方法去改寫參數(shù) ?MASK
? 的值,編譯不會報錯,?MASK
? 也將被成功改寫!
ram #(.AW(4), .DW(4), .MASK(7)) u_ram (......);
可能的解釋為,在編譯器看來,如果有模塊在端口聲明時的參數(shù),那么實體中的參數(shù)將視為 ?localparam
? 類型,使用 ?defparam
? 將不能改寫模塊實體中聲明的參數(shù)。
也可能和編譯器有關(guān)系,大家也可以在其他編譯器上實驗。
defparam
? 的方法。除了上述缺點外,?defparam
? 一般也不可綜合。
#
?表示)。這樣的代碼格式不僅有很好的可讀性,而且方便調(diào)試。點擊這里下載源碼
其實,介紹到這里,大家完全可以用前面學(xué)習到的 Verilog 語言知識,去搭建硬件電路的小茅草屋。對,是小茅草屋。因為硬件語言對應(yīng)實際硬件電路的這種特殊性,在用 Verilog 建立各種模型時必須考慮實際生成的電路是什么樣子的,是否符合實際要求。有時候 ?rtl
? 仿真能通過,但是最后生成的實際電路可能會工作異常。
所以,要為你的小茅草屋添磚蓋瓦,還需要再學(xué)習下進階部分。當然,進階部分也只能讓你的小茅草屋變成硬朗的磚瓦房,能抵擋風雪交加,可能遇到地震還是會垮塌。
如果你想鞏固下你的磚瓦房,去建一套別墅,那你需要再學(xué)習下 Verilog 高級篇知識,例如 ?PLI
?(編程語言接口)、?UDP
?(用戶自定義原語),時序約束和時序分析等,還需要多參與項目工程積累經(jīng)驗,特別注意一些設(shè)計技巧,例如低功耗設(shè)計、異步設(shè)計等。當然學(xué)會用 ?SystemVerilog
? 去全面驗證,又會讓你的建筑增加一層防護盾。
但是如果你想把數(shù)字電路、Verilog 所有的知識學(xué)完,去筑一套防炮彈的總統(tǒng)府,那真的是愛莫能助。因為,學(xué)海無涯,回頭沒岸哪。
限于篇幅,這里只介紹下進階篇。有機會,高級篇,技巧篇,也一并補上。
更多建議: