数字硬件建模SystemVerilog-决策语句-if-else语句
经过几周的更新,SV核心部分用户自定义类型和包内容已更新完毕,接下来就是RTL表达式和运算符。
马上HDLBits-SystemVerilog版本也开始准备了,基本这一部分完成后就开始更新~
决策语句(Decision statements)允许程序块的执行流程根据设计中信号的当前值分支到特定语句。SystemVerilog有两个主要的决策语句:if…else语句和case语句,使用关键字case、case…inside,casex和casez。
介绍
if-else语句对表达式求值并执行两个可能的分支之一,即true分支或false分支。
if-else表达式可以是任何向量大小的网络或变量,也可以是运算的返回值,如果表达式的一个或多个位设置为l,则向量表达式的计算结果为true。如果表达式的所有位均为0,则表达式的计算结果为false。例如:
a和b的按位AND运算的结果是8位向量(因为a和b都是8位向量)。如果AND操作导致任何位置1,那么将执行true分支。如果逻辑AND的结果为零,则将执行false分支,
最佳实践指南6-1 |
---|
对于if-else条件表达式,尽量只使用1位值或返回true/false操作。不要将向量用作if-else表达式。 |
之前的文章也详细介绍了返回true/false结果的运算符。
不要对向量进行true/false测试。评估向量为true/false可能会导致设计错误。在前面的示例中,编写代码的工程师打算测试(a & b)的true/false,但是它是8位向量值,它并不是true/false逻辑运算的1位结果。对于a和b的某些值,if-else决策执行的哪个分支可能不同,通过遵循仅使用标量(1位)值或返回具有true/false结果的操作的指南,可以避免这种模糊性和可能的编码错误。
对于4状态值,表达式可能既不是真的也不是假的,如值8’b0000000z。一个既不正确也不错误的表达被认为是未知的。当if-else决策的表达式计算为未知时,将执行false分支。这可能会导致RTL模型的仿真方式以及综合后门级模型的实际行为不匹配。后面我们会讨论关于SystemVerilog模型中的X-optimism 和 X-pessimism对这种情况进行了讨论。
if-else决策的每个分支可以是一条语句,也可以是一组包含在begin和end之间的语句,如下面的代码段所示,
没有else分支的if语句。if-else决策的else(false)分支是可选的。如果没有else分支,且表达式的计算结果为false(或unknown),则不执行任何语句。在下面的代码段中,如果enable为0,则out不会更改。由于out是一个变量,它保留了以前的值,仿真时会产生锁存器行为。
If-else-if。多个判断语句可以由一系列if-else语句组成,如下面的代码片段所示。
请注意,SystemVerilog不像某些编程语言那样具有elsif关键字。决策链由包含嵌套if-else语句的每个else分支组成。当上面的代码段使用不同的缩进编码时,这种嵌套更为明显,如下所示。
一系列if-else-if决策按照语句的列出时序进行评估。这将优先考虑首先列出的判断条件。下面的示例演示了一个可以set和reset的触发器。如果set和reset同时激活,reset具有优先级,因为它是在一系列决策中首先进行判断的。本例中的set和reset为低电平有效信号。
(该set和reset触发器示例存在潜在的仿真故障,后面我们再对此进行讨论。)
综合if-else语句。综合编译器实现if-else语句的方式取决于决策语句的上下文以及目标ASIC或FPGA中可用的组件类型。一般规则是:
-
组合逻辑中的if-else语句表现为多路复用器,通常在门级实现中实现为多路复用器。
-
如果没有其他语句分配给同一个变量,则组合逻辑中没有else的if将充当锁存器,这是因为分配的变量保留其先前的值。综合器通常将这种存储效果作为锁存器来实现,
-
组合逻辑中的if-else-if语句系列使用优先级编码行为进行仿真,其中每个if语句优先于该系列中的任何后续if语句。如果所有决策表达式都是互斥的(两个或多个表达式不可能同时为真),则综合编译器将删除优先级编码。
-
在时钟边沿评估的if-else语句表现为触发器,并将在门级实现中综合为某种类型的寄存器。
使用if-else作为多路复用器。图6-1中的示例6-1及其附带的综合结果显示了,综合器会在多路复用器的上下文中判断是否使用了else。
示例6-1:使用if-else对多路复用器功能进行建模
`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
module mux2to1
#(parameter N = 4) // bus size
(input logic sel, // 1-bit input
input logic [N-1:0] a, b, // scalable input size
output logic [N-1:0] y // scalable output size
);
timeunit 1ns; timeprecision 1ns;
always_comb begin
if (sel) y = a;
else y = b;
end
endmodule: mux2to1
`end_keywords
图6-1:示例6-1的综合结果:作为MUX的if-else
使用if-else作为锁存器。示例6-2显示了表示锁存器的if语句。
示例6-2:使用if不适用else来仿真锁存器功能
`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
module latch
#(parameter N = 4) // bus size
(input logic ena, // 1-bit input
input logic [N-1:0] in, // scalable input size
output logic [N-1:0] out // scalable output size
);
timeunit 1ns; timeprecision 1ns;
always_latch begin
if (ena) out <= in;
end
endmodule: latch
`end_keywords
图6-2:示例6-2的综合结果:if-else作为锁存器
用于生成图6-2的综合编译器将RTL功能转换为具有未使用的set和reset输入的通用锁存器。最终实现中使用的锁存器的具体类型将取决于目标ASIC或FPGA中可用的锁存器类型。
使用if-else作为优先级编码器。示例6-3说明了4对2优先级编码器中的if-else-if。
示例6-3:使用if else if系列对优先级编码器建模
`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
module priority_4to2_encoder (
input logic [3:0] d_in,
output logic [1:0] d_out,
output logic error
);
timeunit 1ns; timeprecision 1ns;
always_comb begin
error = '0;
if (d_in[3]) d_out = 2'h3; // bit 3 is set
else if (d_in[2]) d_out = 2'h2; // bit 2 is set
else if (d_in[1]) d_out = 2'h1; // bit 1 is set
else if (d_in[0]) d_out = 2'h0; // bit 0 is set
else begin // no bits set
d_out = 2'b0;
error = '1;
end
end
endmodule: priority_4to2_encoder
`end_keywords
图6-3;示例6-3的综合结果:if-else作为优先编码器
图6-3中的“优先级编码”被综合为一系列逻辑门,其中一级的输出成为“序列中下一级”的输入,而不是并行编码d_in的所有位。“该串行数据路径”是“if-else-if”系列中计算d_in数据位的优先级的结果。
使用if-else作为触发器。示例6-4显示了带有复位和芯片使能(也称为负载使能或数据使能)输入的时序逻辑触发器中的if-else-if。因为复位输入是首先评估的,所以它的优先级高于使能输入,图6-4显示了综合这个if-else-if决策序列的结果。
例6-4;使用if-else-if系列为带复位和芯片使能的触发器建模
module enable_ff
#(parameter N = 1) // bus size
(input logic clk, // posedge triggered clk
input logic rstN, // active low async reset
input logic enable, // active high chip enable
input logic [N-1:0] d, // scalable input size
output logic [N-1:0] q // scalable output size
);
timeunit 1ns; timeprecision 1ns;
always_ff @(posedge clk or negedge rstN) // async reset
if (!rstN) q <= '0; // active-low reset
else if (enable) q <= d; // store if enabled
endmodule: enable_ff
图6-4:示例6-4的综合结果:if-else作为芯片启用触发器
图6-4显示了综合如何将带低电平复位和使能的芯片触发器映射到通用组件。该过程的下一步是综合编译器将该通用组件映射到目标ASIC或FPGA设备中可用的特定类型的触发器,如果该目标设备没有芯片使能触发器,则综合将在触发器之外添加多路复用器功能,以模拟芯片使能行为,如果触发器使能,多路复用器将把新的数据值传递给D输入,并将触发器Q输出反馈给D输入。如果触发器未使能,则输入。以类似的方式,如果目标设备没有具有异步低电平有效的复位的触发器,则综合编译器将在触发器之外添加功能,以模拟这种行为,后面再讨论具有各种复位类型的建模和综合触发器。