1

我在我遇到的问题的 eda playground 上做了一个基本的例子。假设我有两个时钟 1x 和 2x。使用触发器分频器将 2x 从 1x 分频。

我有两个寄存器a和b。a 以 1x 计时,b 以 2x 计时。

b是a的采样值。

当我们有 1x 和 2x 时钟的上升沿时,b 没有取 a 的预期值,而是取下一个周期值。

这是因为这种时钟分频器方案,如果我们使用 icgs 进行分频并且 en 它工作正常。但是有没有办法让它使用这种带有触发器的时钟分频器方案?

EDA 游乐场链接:https ://www.edaplayground.com/x/map#

module race_test;

  logic clk1x = 0;
  logic clk2x = 0;

  always
    #5ns clk1x = !clk1x;

  int a, b;


  always @(posedge clk1x) begin
    a <= a+1;
    clk2x <= !clk2x;
  end

  // Problem here is that b will sample postpone value of a
  // clk2x is not triggering at the same time than clk1x but a bit later
  // This can be workaround by putting blocking assignment for clock divider
  always @(posedge clk2x) begin
    b <= a;
  end

  initial begin
    $dumpfile("test.vcd");
    $dumpvars;
    #1us
    $stop;
  end
endmodule
4

2 回答 2

1

数字时钟分频器在仿真和物理时序方面都存在问题。

Verilog 的非阻塞赋值运算符假设每个读写相同变量的人都同步到相同的时钟事件。通过使用 NBA 写入clk2x,您已经将读取转移a到另一个增量时间*,并且正如您所发现的,a已经更新。

在实际硬件中,通常会存在相当大的传播延迟,通常可以避免这种情况。但是,您使用相同的 D 触发器分配给clk2x,因此那里也会有传播延迟。您的最后一个always块现在代表时钟域交叉问题。因此,根据两个时钟之间的偏差,您仍然可能有竞争条件。

纠正此问题的一种方法是使用具有更高频率时钟的时钟发生器模块

always #2.5ns clk = !clk;

always @(posedge clk) begin
       clk1x <= !clk1x;
       if (clk1x == 1)
         clk2x = !clk2x;
于 2018-10-06T19:04:46.643 回答
0

当然你已经解决了这个问题,但我认为有更好的方法。这本书说可以使用阻塞分配来避免竞争。但是阻塞 assignmentemnt 会导致 synopsys lint 检查出现错误。因此,在没有 lint 错误的情况下避免竞争问题的一种方法是使用虚拟逻辑,如下所示

wire [31:0] a_logic;
wire dummy_sel;
assign dummy_sel = 1'b0;
assign a_logic = dummy_sel ? ~a : a;
always @(posedge clk2x) begin
  b <= a_logic;
end
于 2021-11-23T06:25:55.530 回答