在 VHDL 世界中,在时钟进程中,将信号初始化为默认值,然后根据需要覆盖它(通过 IF 或 CASE 语句)是很常见的。我想在 Verilog 中使用相同的技术,但被告知这可能会出现问题。
考虑这个示例代码:
always_ff @(posedge sys_ref_clk or negedge rst_n)
if (~rst_n) begin
mstate <= STATE1;
mysig <= '0;
end else begin
mysig <= '0;
case (mstate)
STATE1 : begin
if (go) begin
mstate <= STATE2;
end
end
STATE2 : begin
mysig <= '1;
mstate <= STATE3;
end
STATE3 : begin
mstate <= STATE1;
end
endcase
end
在这里,我希望 STATE2 导致
mysig
变为 1,所有其他状态导致 mysig
变为 0。我不想在 STATE1 和 STATE3 中键入 mysig <= '0;
,所以我只设置一个默认值仅在 STATE2 中覆盖它。
在VHDL中,以上是我多年来成功使用的技术。但有人告诉我,在 Verilog 中,这可能很危险——特别是因为非阻塞分配可能导致低效或不正确的硬件结构,特别是在用于初始化时。我还被告知,综合工具和模拟工具之间的非阻塞分配可能会有不同的解释。
上面的
mysig
初始化真的是危险的Verilog吗?它模拟得很好。除了(明显的,IMO)它的预期方式之外,综合工具还可以用什么其他方式来解释它?
我不认为上述内容有问题。当提到进程中的行为时,“最后的分配获胜”对于 VHDL 和 Verilog 来说很常见。只要您对同步进程使用 nb 分配,并对组合进程使用阻塞,就应该没问题。我在 case 语句之前对驱动程序使用了状态机样式,这样您就不需要在所有状态下指定一个值。在 Vivado 中工作时没有错误或警告。
Verilog 有一个
initial
处理块,它可能会也可能不会用于设置初始值,具体取决于综合工具以及您想要执行的操作。请参阅您所针对的特定部件系列的综合指南,了解它将如何处理 initial
块。
对于 Verilog
initial
块中的赋值等前卫结构(指综合),问题可能成为供应商可移植性之一。一个供应商可能支持该构造,而另一个供应商可能不支持。因此,使用这种风格进行编码存在风险。
使用这种 Verilog 编码风格可以保证按照您的预期进行仿真(对于遵守当前 IEEE Std 1800 的仿真软件)。最后一个非阻塞分配获胜。
我见过综合工具和 RTL linting 工具会生成类似于“多个非阻塞分配”的警告消息。我不记得具体原因,但指导是更改代码以避免这种情况。您可以悲观地假设综合工具对于这种编码风格会有问题。
我建议您在 Verilog 代码中避免这种做法。
这不是一种常见的做法,因此,它可能会使其他人更难理解设计。如果我在
case
之前看到第一个作业,我不会期望在 case
中看到另一个作业。
很多人陷入的陷阱是试图将太多逻辑塞入单个连续的
always
块中。就你的情况而言,我认为设计为 2 个 always
块会更清晰。将 mysig
从 always
块中移除到它自己的块中:
always_ff @(posedge sys_ref_clk or negedge rst_n)
if (~rst_n) begin
mysig <= '0;
end else begin
mysig <= (mstate == STATE2);
end