目录
参考《Verilog 编程艺术》魏家明著
用于检查一个表达式是否与多个其他的表达式匹配,如果发现匹配,就做对应的跳转。
特性:
1.除了case,还支持casex和casez变种。
2.case_expression和case_item可以多种组合,变量/常数,常数/变量,变量/变量
3.既可以实现parrallel,也可以实现优先级编码
4.支持反向case,就是让case_expression是常量
5.如果使用时不仔细,就可能生成latch
6.仿真器和综合工具对x和z理解不同,容易导致前后仿真不一致
case语句定义:
包含在case和endcase之间的代码(也包括casex和casez)
case (case_expression)
case_item : case_item_expression1;
case_item : case_item_expression2;
..
default : case_item_expression;
endcase
casez语句是case语句的一个变种。casez语句允许“z”和“?”值在比较时被当作不关心的值。如果“z”和“?”在case_expression和case_item中,那么就不关心对应的位。“z”和“?”的等价的。注意:当编写可综合的代码时,要小心使用casez;使用casez时,最好使用?表示不关心。
casex语句是case语句的一个变种。casex语句允许“x”和“z”和“?”值在比较时被当作不关心的值。注意:在编写可综合代码时不要使用casex。
case语句的执行:
1.每次执行case语句时,括号内的case_expression只计算一次,然后按照从上到下的顺序与每个case_item比较。
2.如果有case default,那么在这个从上到下的比较过程中忽略它。
3.如果在比较时有一个case_item与case_expression匹配上,那么就执行此case_item的语句,然后终止case语句。
4.如果所有比较都失败,而且有case_default,那么就执行case_default语句,然后终止case语句
5.如果所有比较都失败,没有case_default,那么就终止case语句
在做case比较时,只有当每bit都是精确匹配的(0,1,z,x)比较才算成功。所有表达式的位长应该相等,这样才能精确的匹配。case提供精确匹配就是为了提供一种能够检测出x和z的机制。但是casez和casex这两个变种提供了比较时不关心x,z的机制。
case的应用:
例子:这段说明case可以检查x和z
case (sig)
1'bz : $display("signal is floating");
1'bx : $disolay("signal is unknwon");
default : $display("signal is %b", sig);
endcase
例子:case_item中有x和z,不可综合
case (select[2:1])
2'b00 : result = 0;
2'b01 : result = flaga;
2'b0x, 2'b0z : result = flaga ? 'bx : 0;
2'b10 : result = flagb;
2'bx0, 2'bz0 : result = flagb ? 'bx : 0;
default : result = 'bx;
endcase
casez的应用:
例子:优先级编码器
reg [7:0] ir;
casez (ir)
8'b1??????? : instruction1(ir);
8'b01?????? : instruction2(ir);
8'b00010??? : instruction3(ir);
8'b000001?? : instruction4(ir);
endcase
描述状态机:
module mealy (
input in1, in2, clk, reset,
output out
);
reg current_state, next_state, out;
always @(*) begin
next_state = current_state;
case (current_state)
0 : begin
if (in1)
next_state = 1;
out = 1'b0;
end
1 : if (in1) begin
next_state = 1'b0;
out = in2;
end
else begin
next_state = 1'b1;
out = !in2;
end
endcase
end
always @(posedge clk or negedge reset) begin
if (!reset)
current_state = 0;
else
current_state = next_state;
end
endmodule
casex的误用:
当case_expression中出现了x时,这时就会发生问题,因为前仿真在计算casex语句把x值的输入当作不关心,而后仿真在检查条件时会把x在门级模型中传播。
casez的误用:
当case_expression中出现了z时,这时就会发生问题,因为前仿真在计算casez语句把z值的输入当作不关心。
full_case:
是指每个可能的case_expression的取值都有case_item或case_default与之相匹配。即使case语句没有包含default,如果每个case_expression能够找到一个与之匹配的case_item,那么还是full_case.
例子:不是full的case
对于下面的3to1multiplexer,当sel=2'b11时,没有对应的y输出赋值。仿真时,当sel=2'b11,时y就表现为一个latch
module mux3a (y, a, b, c, sel);
output y;
input [1:0] sel;
input a, b, c;
reg y;
always @(*) begin
case (sel)
2'b00 : y = a;
2'b01 : y = b;
2'b10 : y = c;
endcase
end
endmodule
例子:是full的case
使用case_default变为full,但可能出现前后仿真不一致
module mux3a (y, a, b, c, sel);
output y;
input [1:0] sel;
input a, b, c;
reg y;
always @(*) begin
case (sel)
2'b00 : y = a;
2'b01 : y = b;
2'b10 : y = c;
default : y = 1'bx;
endcase
end
endmodule
如果在case语句前给输出一个默认值,那么这也被当作full的case语句,不会生成latch
module mux3a (y, a, b, c, sel);
output y;
input [1:0] sel;
input a, b, c;
reg y;
always @(*) begin
y = 1'b0;
case (sel)
2'b00 : y = a;
2'b01 : y = b;
2'b10 : y = c;
endcase
end
endmodule
parallel_case:
是指case_expression只能匹配一个case_item语句,如果发现case_expression匹配超过1个的case_item,那么这些匹配的case_item被称为overlapping case item,这个case语句就不是parallel
例子:不是parallel的case
当irq=3'b011,3'b101,3'b110或1'b111,就会有多余1个case_item与irq匹配。这在仿真时就像一个优先级编码器,irq[2]的优先级大于irq[1],irq[1]的优先级大于irq[0]。
module intctlla (int2, int1, int0, irq);
output int2, int1, int0, irq;
input [2:0] irq;
reg int2, int1, int0;
always @(irq) begin
{int2, int1, int0} = 3'b0;
casez (irq)
3'b1?? : int2 = 1'b1;
3'b?1? : int1 = 1'b1;
3'b??1 : int0 = 1'b1;
endcase
end
endmodule
例子:是parallel的case
每个case_item都是独立的。
module intctlla (int2, int1, int0, irq);
output int2, int1, int0, irq;
input [2:0] irq;
reg int2, int1, int0;
always @(irq) begin
{int2, int1, int0} = 3'b0;
casez (irq)
3'b1?? : int2 = 1'b1;
3'b01? : int1 = 1'b1;
3'b001 : int0 = 1'b1;
endcase
end
endmodule
case语句的编码原则:
1.对于编写表达式并行(像真值表一样)的设计,case语句是不错的选择,而且代码等价简洁清楚。
2.在设计可综合的代码时,要小心使用casez语句,不要使用casex
3.要小心使用反向case语句,最好只针对是parallel的case语句使用
4.要小心使用casez语句设计优先级编码器,也可以用if-else-if语句实现优先级编码器
5.使用casez语句时,用?表示不关心的位,最好不用z
6.最好为case语句添加case_default,而且不要把输出值赋值为x,当前也可以在case语句前面给所有的输出赋默认值