我面临一个奇怪的问题。代码用于简单的ALU。这里只粘贴感兴趣的代码:
always @(posedge clk or posedge rst)
begin
if (rst == 1) begin
mul_valid_shr = 3'b000;
end else begin
if (op_mul_i == 1) begin
mul_valid_shr = 3'b111;
end else begin
mul_valid_shr <= mul_valid_shr << 1;
end
end
end
在总是阻止之外:
assign mul_valid = mul_valid_shr[2];
我的测试台上的POST综合功能模拟有以下结果:
复位已经很低了,为什么sim卡第一次不工作但第二次和第三次工作正常?如果我在100ns标记之前触发op_mul_i
,即使rst
很低,即使mul_result
第一次停止工作也是如此。
欢迎任何猜测。
更新:此处的完整代码:https://www.edaplayground.com/x/28Hx
答案 0 :(得分:2)
Xilinx仿真器模拟任何综合后仿真的前100ns的FPGA全局复位,因此您基本上必须将逻辑保持在复位状态并且时钟至少持续100ns才能获得合理的结果。这在第13页的UG900中有所提及。
答案 1 :(得分:1)
Verilog有非决定论和种族歧视的概念。下面是各种版本的Verilog和SystemVerilog解释概念:
非确定性的一个来源是活动事件可以从队列中取出并以任何顺序处理。另一个非确定性的来源是行为块中没有时间控制结构的语句不必作为一个事件执行。时间控制语句是#表达式和@表达式构造(参见9.7 [9.4 for IEEE1800] )。在评估行为语句的任何时候,模拟器可以暂停执行并将部分完成的事件作为待处理的活动事件放在事件队列上。这样做的结果是允许交错执行流程。请注意,交错执行的顺序是不确定的,不受用户控制。
因为表达式评估和净更新事件的执行可能混合在一起,所以竞争条件是可能的:
assign p = q; initial begin q = 1; #1 q = 0; $display(p); end
模拟器在显示1或0时是正确的。将0分配给q可启用p的更新事件。模拟器可以继续并执行$ display任务或执行p的更新,然后执行$ display任务。
简而言之,这意味着即使同时更改了clk
和op_mul_i
,也可以在更新clk
之前或之后评估op_mul_i
上触发的始终阻止。 -步。这种不确定性和种族条件行为是有意的;允许该语言模仿FPGA和硅上关键路径可能发生的相同行为。
无论解决方案和最佳实践是在时钟和输入激励之间存在偏移(时间或调度区域)。您可以在第一个#delay上使用±1的时间偏移;就像我在评论中建议的那样。或者使用非阻塞分配(<=
)分配输入激励;它将始终在时钟之后更新,并且任何时钟都依赖于时钟。 (这就是为什么应该为flops分配非阻塞)。您采取的路线由您或您的团队决定。
答案 2 :(得分:0)
如何生成op_mul_i? 它是否与clk同步?我问,因为在模拟的第二部分,当op_mul_i是逻辑1时,我看到mul_valid被驱动到逻辑1。如果它是同步的,我希望mul_valid在200ns边缘旁边的时钟边缘处为逻辑1。 由于这是后合成,我怀疑亚稳态导致了这个问题。 在100ns时,op_mul_i在故障窗口内发生变化,时钟边沿不会将op_mul_i检测为逻辑1,因此您看不到任何内容。
将op_mul_i同步到clk,并使用synchronized信号来驱动mul_valid_shr。 另外,不要在顺序块中使用阻塞语句。
希望有所帮助。 VK
答案 3 :(得分:0)
您使用op_mul_i作为异步信号创建了一个异步触发器。它在您的初始块中被修改,并且此修改不与clk同步。所以,它看起来像是对我的竞赛。并且硬件是正确的,忽略了一些步骤。
因此,由于模拟工件,您的模拟结果可能是正确的。我想正确的rtl方法是通过为该信号提供另一个触发器来使信号与时钟同步。
除此之外,您可以尝试在此信号的模拟中使用非阻塞分配或初始模块中的#0延迟。