Verilog 如何处理从一个时钟域到另一个时钟域(其时钟除以第一个时钟的2)的数据?

Verilog 如何处理从一个时钟域到另一个时钟域(其时钟除以第一个时钟的2)的数据?,verilog,system-verilog,Verilog,System Verilog,我有以下代码 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 al

我有以下代码

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
模块tb;
注册时钟;
reg clk_2;
reg[15:0]来自_-flop;
reg[15:0]到_-flop;
初始开始
clk=0;
clk_2=0;
from_flop=1;
结束
始终#10 clk=~clk;
始终@(posedge clk)开始

clk_2问题在于这条线路:

clk_2 <= ~clk_2;
非阻塞分配安排在阻塞分配之后,因此
始终@(posedge clk)开始
将始终在
始终@(posedge clk_2)开始
之前计时

显然,这不是可合成的代码。因此,这是一个模拟(调度)问题。如果你要用这个功能合成一些东西,仔细考虑你如何产生分裂的时钟。< /P>

通常,顺序块中的赋值使用非块(
我发布的代码是对实际代码的简化。代码是用来合成的。我们使用触发器进行2除运算,对吗?编码准则是在顺序块中使用非阻塞分配,对吗?那么,你认为对2除运算的触发器进行编码的正确方法是什么?@Rakraks在你的模型中,是这样的clk和clk_2之间的一种调度延迟,因为非阻塞分配总是在阻塞后执行。实际触发器在时钟输入和Q输出之间有一个实际延迟:时钟到Q的延迟。因此,如果仅使用触发器进行除法,而不使用其他方法,则实际clk_2将相对于clk进行延迟,因此实际电路might也表现出同样的行为。如果你在使用FPGA,我建议你阅读说明书,了解如何生成派生时钟。如果你在设计IC,你有一个陡峭的学习曲线。我同意在现实中(硅)clk_2将被延迟w.r.t clk,但合成工具知道这一点,并将确保from_触发器的Q在到达to_触发器的D引脚之前也会被延迟,因此这将在硅中以及门级模拟中正常工作。问题是如何对其进行编码,以使其在RTL和门中显示相同的行为。@Rakraks,恐怕您是这样的尝试做一些我从未做过的事情。我对派生时钟一直非常小心,所以从来没有把这类事情留给合成器。嗨,格雷格,你有没有参考过“除了生成派生时钟,应该使用分块(=)赋值”这句话?谢谢。我现在还看不到任何论文。可能就藏在其中一篇(我知道他有一些很好的论文,解释了多时钟域的挑战和解决方案),或我的个人资料中列出的其他资源之一。这与verilog调度程序的工作方式有关,再加上您的合成器可以保证它可以保持边缘对齐。具有多个时钟(派生和独立)增加了复杂性和风险。最好的选择是尽可能让一切都在同一个时钟上运行。
clk_2 = ~clk_2;
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