在 Verilog 中,(* full_case *) 是一个综合指令(synthesis directive),用于告诉综合工具某个 case 语句覆盖了所有可能的输入情况。
一、语法和作用
(* full_case *)
case (sel)
2'b00: out = a;
2'b01: out = b;
2'b10: out = c;
// 2'b11 情况没有明确写出
endcase
二、主要用途
1. 避免锁存器(Latch)生成
当 case 语句没有覆盖所有可能情况时,综合工具会推断出锁存器来保持之前的值。使用 full_case 可以避免这种情况。
// 没有 full_case - 可能生成锁存器
module without_full_case(
input [1:0] sel,
input a, b,
output reg out
);
always @(*) begin
case (sel)
2'b00: out = a;
2'b01: out = b;
// 缺少 2'b10 和 2'b11 的情况
endcase
end
endmodule
// 使用 full_case - 不会生成锁存器
module with_full_case(
input [1:0] sel,
input a, b,
output reg out
);
always @(*) begin
(* full_case *)
case (sel)
2'b00: out = a;
2'b01: out = b;
// 工具会为其他情况分配默认值
endcase
end
endmodule
2. 优化电路面积
告诉工具所有情况都已覆盖,可以进行更好的优化。
三、注意事项
1. ⚠️ 重要警告
full_case 只是告诉综合工具所有情况已覆盖,但仿真器会忽略这个指令:
module risky_design(
input [1:0] sel,
output reg out
);
always @(*) begin
(* full_case *)
case (sel)
2'b00: out = 1'b0;
2'b01: out = 1'b1;
// 仿真时如果 sel=2'b10 或 2'b11,out 会保持原值
// 这可能导致仿真与综合结果不一致!
endcase
end
endmodule
四、更好的实践
1. 使用 default 语句(推荐)
always @(*) begin
case (sel)
2'b00: out = a;
2'b01: out = b;
2'b10: out = c;
default: out = 1'b0; // 明确处理所有剩余情况
endcase
end
2. 完整列出所有情况
always @(*) begin
case (sel)
2'b00: out = a;
2'b01: out = b;
2'b10: out = c;
2'b11: out = d; // 明确写出所有情况
endcase
end
五、与 parallel_case 的区别
(* full_case, parallel_case *)
case (1'b1)
a[0]: result = 4'b0001;
a[1]: result = 4'b0010;
a[2]: result = 4'b0100;
a[3]: result = 4'b1000;
endcase
-
full_case: 所有输入情况都已覆盖 -
parallel_case: 所有情况互斥,不会同时匹配多个分支
六、总结
-
full_case是综合指令,仿真器会忽略 -
主要用于避免锁存器生成和优化电路
-
使用时需谨慎,确保真的覆盖了所有情况
-
推荐使用
default语句代替full_case,以保证仿真和综合的一致性
在现代设计流程中,通常建议使用完整的 case 语句或明确的 default 分支,而不是依赖综合指令。

被折叠的 条评论
为什么被折叠?



