下面是一个小的真实verilog 代码,具有异步set/reset逻辑(低电平有效)的触发器模型。这个verilog模型可以正确地综合,但在一个 corner case情况下仿真结果不正确。这个 corner case是什么?
always_ff @( posedge clk
or negedge rst_n // active-low reset
or negedge set_n // active-low set
)
if (!rst_n) // reset has priority over set
q_out <= '0; // reset all bits to zero
else if (!set_n)
q_out <= '1; // set all bits to one
else
q_out <= data_in; // d input assignment
这个verilog模型按预期正确地进行综合,然而在某些仿真条件下功能错误。
当rst_n变低,它可以正确地异步复位触发器。然后拉低set_n,在rst_n和set_n同时为低的情况下,触发器将正确地保持复位,因为在verilog代码中复位的优先级比置位的优先级高。
到目前为止,一切都很好。接下来,rst_n变高,set_n保持低。由于敏感度列表只对rst_n和set_n的负边沿敏感,因此rst_n的拉高不会触发敏感列表。这意味着,当只有set_n为低电平时触发器仍然处于复位状态!
这个问题引入的关键在于,实际的异步置位/复位是电平敏感的,因此当复位信号rst_n被拉高时仍然会正确地发生置位。这就使得仿真和综合后的电路行为mismatch。
为了避免这种麻烦,有两种推荐的编码风格:
第一种方法:
1)在敏感度列表中新增一个敏感条件。
2)使用条件编译(\`ifdef/\`endif)或综合选项(translate_off/translate_on)对综合工具隐藏。
always_ff @( posedge clk
or negedge rst_n // active-low reset
or negedge set_n // active-low set
`ifndef SYNTHESIS // non-synthesizable simulation code
or posedge (rst_n & ~set_n) // trailing edge of reset when set is low
`endif
)
if (!rst_n) // reset has priority over set
q_out <= '0; // reset all bits to zero
else if (!set_n)
q_out <= '1; // set all bits to one
else
q_out <= data_in; // d input assignment
第二种方法:
使用 force/release来强制指定仿真行为。该方法需要在verilog代码中添加一个额外的always 语句块并使用条件编译对综合工具隐藏。
注意:此替代解决方案必须使用Verilog的“always ”过程块,不能利用SystemVerilog的always_comb块,因为always_comb不允许多个程序块写入相同的变量。
`ifndef SYNTHESIS // start non-synthesizable simulation code
always @*
if (rst_n && !set_n) force q_out = 1'b1;
else release q_out;
`endif // start synthesizable and simulatable code
always_ff @(posedge clk, negedge rst_n, negedge set_n)
if (!rst_n) // reset has priority over set
q_out <= '0; // reset all bits to zero
else if (!set_n)
q_out <= '1; // set all bits to one
else
q_out <= data_in; // d input assignment
作者:验证哥布林
原文链接:https://mp.weixin.qq.com/s/tt0CL9MSw_GNO0p3jVAumA
微信公众号:
推荐阅读
更多IC设计技术干货请关注IC设计技术专栏