电子说
10. case,casez,casex语句
Verilog定义了case,casez和casex语句,用于做多种情况下的选择语句。
reg [1:0] sel;
reg [2:0] result;
always @(*)
case(sel)
2’b00: result = 3’d0;
2’b01: result = 3’d1;
2’b10: result = 3’d2;
endcase
使用case语句代替嵌套的if-else将会产生更易读的代码,更好的逻辑利用率和更高的性能。
casez和casex语句在比较中允许“don't care”条件。 casez将“z“”值视为"don't care",casex将“z”和“x”值都视为“don't care”。如果casez或casex表达式中的任何位都是"don't care value",那么该位将被忽略。以下是casez和casex的例子。
reg [1:0] sel;
reg [2:0] result;
// using casez
always @(*)
casez(sel)
2’b0?: result = 3’d0;
2’b10: result = 3’d1;
2’b11: result = 3’d2;
endcase
// using casex
always @(*)
casex(sel)
2’b0x: result = 3’d0;
2’b10: result = 3’d1;
2’b11: result = 3’d2;
Endcase
case的表达式可以是一个常量,如下例所示。
reg [1:0] sel;
reg [2:0] result;
always @(*)
case(1
~sel[1]: result = 3’d0;
sel[1] & ~sel[0]: result = 3’d1;
sel[1] & sel[0]: result = 3’d2;
Endcase
在案例中使用don't care条件很容易导致case 条件重叠或重复。而且,使用这些语句会导致综合和仿真不匹配。以下是案例case条件重叠的一个例子。
// casez statement contains overlapped case items
reg [1:0] sel;
reg [2:0] result;
always @(*)
casez(sel)
2’b0z: result = 3’d0;
2’b10: result = 3’d2;
2’b11: result = 3’d3;
2’b01: result = 3’d1; // overlap with 2’b0z
Endcase
允许重叠或重复的case条件,在大多数情况下不会触发任何仿真或综合警告。这是一种危险且难以调试的情况.。建议开发人员完全避免使用casex和casez语句。
在case语句中添加一个默认的条件是避免一系列问题的简单方法。 有两种方法可以达到相同的效果,如以下示例所示。
reg [1:0] sel;
reg [2:0] result;
// using default clause
always @(*)
case(sel)
2’b00: result = 3’d0;
2’b01: result = 3’d1;
2’b10: result = 3’d2;
default: result = 3’d3;
endcase
// 在case语句之前进行默认赋值
always @(*)
result = 3’d3;
case(sel)
2’b00: result = 3’d0;
2’b01: result = 3’d1;
2’b10: result = 3’d2;
Endcase
11. 在always块中混合阻塞和非阻塞赋值
Verilog指定了总是可以出现在块中的两种赋值类型:阻塞和非阻塞。阻塞和非阻塞赋值分别用于描述组合逻辑和时序逻辑。永远不要在同一个块中混合使用阻塞和非阻塞赋值。这样做可能会导致不可预知的综合和仿真结果。在许多情况下,综合工具不会产生任何警告,但综合结果将是不正确的。以下两个代码示例说明了阻塞和非阻塞赋值的混合使用。
reg blocking, non_blocking;
always @(posedge clk) begin
if(reset) begin
blocking = 0;
non_blocking
end
else begin
blocking = ^data;
non_blocking
end
end
always @(*) begin
blocking = ^data;
non_blocking
end
正确的方法是:
reg blocking, non_blocking;
always @(posedge clk) begin
if(reset) begin
non_blocking
end
else begin
non_blocking
end
end
always @(*) begin
blocking = ^data;
End
12. 多个阻塞赋值
always块中的阻塞赋值按其顺序执行。 尽管这样做通常很方便,但是建议开发者限制使用多个阻塞赋值来赋值always块中的相同变量。下面的两个代码示例显示了使用多个阻塞分配的潜在问题。
reg signal_a, signal_b, signal_c, signal_d;
always (*) begin
signal_a = signal_b & signal_c;
// …
// additional code
signal_d = signal_a & signal_e;
end
无意中改变signal_a和signal_d分配的顺序将会破坏signal_d的功能。
reg [15:0] signal_a, signal_b;
always (*) begin
signal_a[15:12] = 4’b0;
// …
// additional code
signal_a = signal_b;
End
signal_a的最后一个赋值优先,signal_a的位[15:12]永远不会被复位。
13. 使用命名的always块
以下是always块的例子。
reg reg_unnamed;
always @(posedge clk) begin : myname
// only visible in the “myname” block
reg reg_named;
// post-synthesis name : myname.reg_named
reg_named
// post-synthesis name : reg_unnamed
reg_unnamed
end // always
命名块可以在几种情况下有用。 因为always块是唯一标识的,所以在仿真中更容易找到它。 而且,限制变量的范围允许重复使用相同的变量名称。
编辑:hfy
全部0条评论
快来发表一下你的评论吧 !