跨越时钟域以便大幅改变数据

时间:2017-06-25 09:02:42

标签: clock system-verilog hdl

我需要将配置模块(以较慢的时钟运行)连接到以更高速度运行的工作线程。标准答案似乎是一个FIFO但我认为我想出了一个更简单的解决方案,它消耗更少的资源 - 缺点是具有更高的延迟。对我来说,好处是我不需要为每种可能的数据大小重新生成FIFO IP。在RTL模拟中它似乎有用(我遇到了使用与问题无关的后合成问题)。

我错过了什么或者以下代码是否正确:

module fifo_int#( // This is bad name. I haven't come up with better yet
    parameter type DATA = logic [31:0]
    )(
    input  logic rst,
    input  logic clk_in,
    input  DATA  din,
    input  logic clk_out,
    output DATA  dout
    );
    DATA dreg;

    enum logic [1:0] {
        IN,
        STABLE,
        WAIT_OUT
    } in_state;
    enum logic [1:0] {
        WAIT_IN,
        WRITE,
        INV
    } out_state;
    logic in_output[3], out_output[3];
    initial begin
        in_state <= IN;
        out_state <= WAIT_IN;
        for (int i = 0; i < 3; i++) begin
            in_output[i] <= 0;
            out_output[i] <= 0;
        end
    end
    always @(posedge clk_in)
    begin
        case (in_state)
        IN: begin
            dreg <= din;
            in_state <= STABLE;
        end
        STABLE: begin
            in_state <= WAIT_OUT;
            in_output[0] <= ~in_output[0];
        end
        WAIT_OUT: begin
            in_state <= (in_output[0] == out_output[2]) ? IN : WAIT_OUT;
        end
        endcase
        out_output[1] <= out_output[0];
        out_output[2] <= out_output[1];
    end
    always @(posedge clk_out)
    begin
        case (out_state)
        WAIT_IN: begin
            out_state <= (in_output[2] == out_output[0]) ? WAIT_IN : WRITE;
        end
        WRITE: begin
            dout <= dreg;
            out_state <= INV;
        end
        INV: begin
            out_output[0] <= ~out_output[0];
            out_state <= WAIT_IN;
        end
        endcase
        in_output[1] <= in_output[0];
        in_output[2] <= in_output[1];
    end
endmodule

1 个答案:

答案 0 :(得分:0)

如果您的时钟是异步的,那么您将需要同步。

对于同步时钟,由于您的慢速是产生数据的那一方,因此您不需要任何缓冲。无论如何,数据在多个(快速)时钟周期内保持稳定,因此您不需要域之间的任何逻辑。