横穿时钟域,用于稀有变化的数据



我需要将配置模块(以较慢的时钟运行(连接到以较高速度运行的工人。标准答案似乎是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

如果您的时钟异步,则需要同步。

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

最新更新