我有以下代码。
module tb;
reg clk;
reg clk_2;
reg [15:0] from_flop;
reg [15:0] to_flop;
initial begin
clk = 0;
clk_2 = 0;
from_flop = 1;
end
always #10 clk = ~clk;
always @(posedge clk) begin
clk_2 <= ~clk_2;
end
always @(posedge clk) begin
from_flop <= from_flop + 1;
end
always @(posedge clk_2) begin
to_flop <= from_flop;
end
endmodule
但是,在时刻10ns,from_flop和to_flop都得到值= 2.这与我的预期相反。我期待from_flop在10ns时从1变为2,而to_flop在10ns时从x变为1。
为什么会发生这种情况以及如何进行编码以使其不发生?
答案 0 :(得分:2)
通常,顺序块中的分配使用非阻塞(<=
)分配。值得注意的除了用于生成派生时钟之外,其应该使用阻塞(=
)分配。阻止顺序块中的分配是合法的;但你需要知道自己在做什么,否则你会在RTL仿真和电路之间出现功能上的不匹配。也就是说,使用这种方法时,你仍然需要谨慎对待。
触发器具有Q延迟时钟,因此任何派生时钟都会与其父时钟产生相位偏移。有些合成工具可以为你补偿偏移量,但是你需要指定合成器发生这种情况的所有情况;它不会为你解决。这意味着您不应该在设计中偶尔创建派生时钟。所有派生的时钟信号需要从一个专用模块生成;这使它易于管理。
在大多数情况下,您不应创建任何派生时钟。相反,通过添加额外的触发器来对每隔一个时钟进行采样。
always @(posedge clk) begin
from_flop <= from_flop + 1;
if (transfer_n==1'b0) begin
to_flop <= from_flop;
end
transfer_n <= ~transfer_n;
end
此策略将设计保留在一个时钟域中,这通常使合成更容易,时间更好。额外触发器在最小值上的区域影响很容易小于保持派生时钟对齐所需的增加缓冲区的面积损失。
答案 1 :(得分:0)
问题在于这一行:
clk_2 <= ~clk_2;
您正在使用非阻止分配,或许您想要阻止分配:
clk_2 = ~clk_2;
阻止分配后会安排非阻止分配,因此always @(posedge clk) begin
将始终在always @(posedge clk_2) begin
之前计时。
显然,这不是可合成的代码。所以,这是一个模拟(调度)问题。如果您要使用此功能进行综合,请仔细考虑如何生成分频时钟。