在Verilog 语法中case语句是最常用的语句之一,与if语句类似也是分支选择语句,只能用在顺序过程语句中。一般在非优先级的分支选择中,case语句往往结构清晰,得到广泛应用,特别是在状态机描述中,几乎是都选择case语句进行描述。
case语句的语法结构:
case(表达式) 表达式值0: begin ... end 表达式值1: begin ... end ... 表达式值n: begin ... end default: begin ... end endcase
在case语句中,先判断表达式的值,把各种用到的值列出来,如表达式0到表达式n,最后把所有未列出来的值归为default的分支进行处理。
在每个case分支后面由begin…end 括起来的可执行语句,且是顺序执行的;如果只有一条语句,begin与end也可以省略不写,如例1:
例1:
module selx
(
input [1:0] sel,
input [3:0] a, b, m, n,
output reg [3:0] c
);
always@(*)
case(sel)
0: c = a;
1: c = b;
2: c = m;
default: c = n;
endcase
endmodule
测试激励程序如下:
module top_sim( );
reg [1:0] sel;
reg [3:0] a, b, m, n;
wire [3:0] c;
initial
begin
sel = 0;
a = 1;
b = 2;
m = 3;
n = 4;
#10
sel = 2'b01;
#10
sel = 2'b10;
#10
sel = 2'b11;
#10
sel = 2'b0x;
#10
sel = 2'b1x;
#10
sel = 2'bx0;
#10
sel = 2'bx1;
#10
sel = 2'bxx;
end
selx selx_dut
(
.sel (sel),
.a (a),
.b (b),
.m (m),
.n (n),
.c (c)
);
endmodule
仿真波形如下:

图1
从图1的仿真结果可以看出,除了sel的值为2’b00, 2’b01, 2’b10外,其它全部是default引导的赋值语句。
case语句除了正常的数字选择分支语句外,还支持casex,casez的形式,这样将值为X,Z的信号也纳入选择分支。

在casez,casez的使用中还支持通配符选项”?”, “?” 代表 0,1,X ,Z
例2:
wire [2:0] irq;
always @( irq ) begin
{int2, int1, int0} = 3'b000;
casez ( irq )
3'b1?? : int2 = 1'b1;
3'b?1? : int1 = 1'b1;
3'b??1 : int0 = 1'b1;
default: {int2, int1, int0} = 3'b000;
endcase
end
形成的电路如图2所示:

图2
可见case语句虽然书写严格,也不缺乏灵活性,特别利用casez或casex利用通配符进行化简,极为方便,这就像数字电路中,充分利用无关项进行化简类似。
而且casez, casex, 通配符?等都是可综合的语句,合理使用可以简化程序设计。
case语句各个分支之间是没有优先级,即使某个值匹配case的表达式,其它的值也照样评估。
case语句与if语句的异同:
- 相同点:
- 都能描述分支选择语句
- 都只能在顺序过程中使用
- 都是可综合的语句结构
- 在RTL描述中使用最广泛的语句结构
- 不同点
- if语句有优先级;而case语句没有优先级,即使某个值已与表达式匹配了,还要继续评估后面的值。
- if语句对表达式的值判断是严格的;而case是灵活的,不仅支持严格判断的case语句,还支持casex,casez带有通配符的结构。
- 在分支较少的描述中if语句更简单,在分支较多的描述中,case语句更清晰。
- 在if … else if …. else if …. else … 等多重分支情况下, 如果逻辑上并不需要优先级, 可以使用case 语句代替, 使用case 语句的好处是:减少了逻辑的级联结构, 提高时序效果
对应视频: