在Verilog中case語句經常用於多分支表決的結構,case後的表示式會與各分支表示式“全等”那麼對應的分支會被執行.其基本結構如下:
case(expression)
expr1 : statement_or_null;
…
exprn : statement_or_null;
default : statement_or_null;
endcase
雖然一般case經常被使用,但是在構建模擬驗證平臺時,經常會遇到case後的敏感表示式出現高阻態z和不定態x的情況,而對於部分位出現高阻態z和不定態x的情況有時需要忽略掉,如下例.
【示例】
`timescale 1 ns / 1 ps
module top_tb;
reg [1:0] d1,d2,d3,d4,d5,d6;
reg [1:0] sel;
reg [1:0] dout;
initial begin
d1 = 2'b00;d2 = 2'b10;d3 = 2'b0x;
d4 = 2'bz0;d5 = 2'bxx;d6 = 2'bzz;
sel = 2'b00;
#1 sel = 2'b10;
#1 sel = 2'b00;
#1 sel = 2'b0x;
#1 sel = 2'bz0;
#1 sel = 2'bxx;
#1 sel = 2'bzz;
#1 sel = 2'b11;
#1 $stop;
end
always @(sel)
begin
case(sel)
2'b00 : begin
dout = d1;
$display("Branch 2'b00!");
end
2'b10 : begin
dout = d2;
$display("Branch 2'b10!");
end
2'b0x : begin
dout = d3;
$display("Branch 2'b0x!");
end
2'bz0 : begin
dout = d4;
$display("Branch 2'bz0!");
end
2'b1x : begin
dout = d5;
$display("Branch 2'b1x!");
end
2'b1z : begin
dout = d6;
$display("Branch 2'b1z!");
end
default : begin
dout = 2'b00;
$display("Branch default!");
end
endcase
end
endmodule // top_tb
【模擬結果】
Sel | Result
2’b00 # Branch 2'b00!
2’b10 # Branch 2'b10!
2’b00 # Branch 2'b00!
2’b0x # Branch 2'b0x!
2’bz0 # Branch 2'bz0!
2’bxx # Branch default!
2’bzz # Branch default!
2’b11 # Branch default!
示例中確實可以將case後的敏感表示式與分支表示式進行全匹配,匹配包括表示式結果的每一位.但是如果期望2’b00和2’b0x或者2’b0z選擇執行相同的分支,或者2’b10和2’b1x或者2’b1z選擇執行相同的分支,使用原有的case語句是無法實現的,為此,為了滿足這種特殊的要求,case語句演變出了兩種變體casez和casex.
casez和casex的用法與傳統的case一樣,只是在敏感表示式和分支表示式匹配時稍有不同,casez語句中,如果分支表示式的結果中某些位的值位高阻z,那麼在對這些位進行比較時會忽略不進行比較,僅考慮其他對應位的比較.同理,casex也是會對某些位為z比進行比較,但是其進一步擴充套件為對包含x的位也不進行比較.
【示例】
`timescale 1 ns / 1 ps
module top_tb;
reg [1:0] d1,d2,d3,d4,d5,d6;
reg [1:0] sel;
reg [1:0] dout;
initial begin
d1 = 2'b00;d2 = 2'b10;d3 = 2'b0x;
d4 = 2'bz0;d5 = 2'bxx;d6 = 2'bzz;
sel = 2'b00;
#1 sel = 2'b10;
#1 sel = 2'b00;
#1 sel = 2'b0x;
#1 sel = 2'bz0;
#1 sel = 2'bxx;
#1 sel = 2'bzz;
#1 sel = 2'b11;
#1 $stop;
end
always @(sel)
begin
casez(sel)
2'b00 : begin
dout = d1;
$display("Branch 2'b00!");
end
2'b10 : begin
dout = d2;
$display("Branch 2'b10!");
end
2'b0x : begin
dout = d3;
$display("Branch 2'b0x!");
end
2'bz0 : begin
dout = d4;
$display("Branch 2'bz0!");
end
2'b1x : begin
dout = d5;
$display("Branch 2'b1x!");
end
2'b1z : begin
dout = d6;
$display("Branch 2'b1z!");
end
default : begin
dout = 2'b00;
$display("Branch default!");
end
endcase
end
endmodule // top_tb
【模擬結果】
Sel | Result
2’b00 # Branch 2'b00!
2’b10 # Branch 2'b10!
2’b00 # Branch 2'b00!
2’b0x # Branch 2'b0x!
2’bz0 # Branch 2'b00!
2’bxx # Branch default!
2’bzz # Branch 2'b00!
2’b11 # Branch 2'b1z!
此處將case替換為casez後,從模擬結果可以看出,2’bz0、2’bzz與2’b00結果一致,即不對敏感表示式與分支表示式中對應位存在z的位進行比較.這裡需要注意當sel位2’bzz時,因為不對任何位進行全等檢查,所以敏感表示式會與第一個分支匹配.可見casez語句中會忽略表示式中的高阻態位.
【示例】
`timescale 1 ns / 1 ps
module top_tb;
reg [1:0] d1,d2,d3,d4,d5,d6;
reg [1:0] sel;
reg [1:0] dout;
initial begin
d1 = 2'b00;d2 = 2'b10;d3 = 2'b0x;
d4 = 2'bz0;d5 = 2'bxx;d6 = 2'bzz;
sel = 2'b00;
#1 sel = 2'b10;
#1 sel = 2'b00;
#1 sel = 2'b0x;
#1 sel = 2'bz0;
#1 sel = 2'bxx;
#1 sel = 2'bzz;
#1 sel = 2'b11;
#1 $stop;
end
always @(sel)
begin
casex(sel)
2'b00 : begin
dout = d1;
$display("Branch 2'b00!");
end
2'b10 : begin
dout = d2;
$display("Branch 2'b10!");
end
2'b0x : begin
dout = d3;
$display("Branch 2'b0x!");
end
2'bz0 : begin
dout = d4;
$display("Branch 2'bz0!");
end
2'b1x : begin
dout = d5;
$display("Branch 2'b1x!");
end
2'b1z : begin
dout = d6;
$display("Branch 2'b1z!");
end
default : begin
dout = 2'b00;
$display("Branch default!");
end
endcase
end
endmodule // top_tb
【模擬結果】
Sel | Result
2’b00 # Branch 2'b00!
2’b10 # Branch 2'b10!
2’b00 # Branch 2'b00!
2’b0x # Branch 2'b00!
2’bz0 # Branch 2'b00!
2’bxx # Branch 2'b00!
2’bzz # Branch 2'b00!
2’b11 # Branch 2'b1x!
此處將case替換為casex後,從模擬結果可以看出,2’b0x、2’bxx與2’b00結果一致,2’bz0和2’bzz也與結果一致,即不對敏感表示式與分支表示式中對應位存在x和z的位進行比較.可見casex語句中會忽略表示式中的高阻態位和不定態.
【示例】
`timescale 1 ns / 1 ps
module top_tb;
reg [7:0] in;
reg [7:0] out;
initial begin
in = 8'b0000_0000;
#1 in = 8'b0000_0001;
#1 in = 8'b0000_0010;
#1 in = 8'b0000_0100;
#1 in = 8'b0000_1000;
#1 in = 8'b0001_0000;
#1 in = 8'b0010_0000;
#1 in = 8'b0100_0000;
#1 in = 8'b1000_0000;
#1 in = 8'b0010_0100;
#1 in = 8'b1111_0010;
#1 in = 8'b0000_1111;
#1 $stop;
end
always @*
begin
casez(in)
8'bzzzz_zzz1 : out = 0;
8'bzzzz_zz1z : out = 1;
8'bzzzz_z1zz : out = 2;
8'bzzzz_1zzz : out = 3;
8'bzzz1_zzzz : out = 4;
8'bzz1z_zzzz : out = 5;
8'bz1zz_zzzz : out = 6;
8'b1zzz_zzzz : out = 7;
default : out = 0;
endcase
end
endmodule
【模擬結果】
從模擬結果可以看出,在進行匹配時,當有多位匹配成功,從右側開始第一次匹配成功的分支會被執行.示例中in為’h24和’h02的結果是一致的,’h0f和’h01的結果是一致的.
從上述幾例可以看出case、casez和casex在對0/1/z/x進行比較時的對應關係如下表:
case |
0 |
1 |
X |
Z |
|
casez |
0 |
1 |
X |
Z |
|
casex |
0 |
1 |
X |
Z |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
||
1 |
0 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
1 |
||
X |
0 |
0 |
1 |
0 |
X |
0 |
0 |
1 |
1 |
X |
1 |
1 |
1 |
1 |
||
Z |
0 |
0 |
0 |
1 |
Z |
1 |
1 |
1 |
1 |
Z |
1 |
1 |
1 |
1 |
其中casez語句用來處理不考慮高阻值z的比較過程,casex語句則將高阻態z和不定態都視為忽略,即在表示式進行比較時,不將該位進行比較,這樣根據具體需要靈活使用casex和casez了.
綜上所述,case進行精確比較,會對每一位不管該位是0/1/z/x的任何值;casez進行忽略z的比較,如果敏感表示式和分支表示式中有一位為z,那麼在比較時該位的比較忽略;casex進行忽略x和z的比較,如果敏感表示式和分支表示式中有一位為x或者z,那麼在比較時該位的比較忽略,當有多位都可匹配時,僅從右側開始第一次匹配成功的分支會被執行.