FPGA实现与资源消耗-CDC(clock domain crossing 跨时钟域)一

总结:本节重点讨论解决跨时钟域问题,在本节设计实现了异步fifo,在设计实现时不同时钟对同一个寄存器进行了修改,激励仿真通过,最后布局布线不通过。

1、定义

跨时钟域问题是在一个数字系统中使用多个时钟域(时钟信号)时可能面临的挑战。当不同的时钟域存在时,由于时钟的相位差异、频率不同或者时钟边沿的不同步等原因,可能会导致数据在时钟域之间的传输出现问题。

2、代码描述

简单定义一个输入时钟和一个输出时钟模块

`timescale 1ns / 1ps
module CDC(
    input clk1,
    input clk2,
    input rst,
    input [7:0] data,
    output [7:0] out
);
    reg [7:0] reg1;
    reg [7:0] reg2;
    always @(posedge clk1 or posedge rst)begin
        if(rst)
            reg1 <= 0;
        else
            reg1 <= data;
    end

    always @(posedge clk2 or posedge rst)begin
        if(rst)
            reg2 <= 0;
        else
            reg2 <= reg1;
    end

    assign out = reg2;

endmodule

波形展现

module CDC_tb(

    );
  // Inputs
  reg clk1;
  reg clk2;
  reg rst;
  reg [7:0] data;

  // Outputs
  wire [7:0] out;

  // Instantiate the module
  CDC uut (
    .clk1(clk1),
    .clk2(clk2),
    .rst(rst),
    .data(data),
    .out(out)
  );

  // Clock generation
    initial begin
        clk1 = 0;
        clk2 = 0;
    end
    always #5 clk1 = ~clk1;
    always #3 clk2 = ~clk2;

  // Stimulus
  initial begin
    // Test case 1
    rst = 1;
    data = 8'b00000000;
    #6 rst = 0;

    // Test case 2
    data = 8'b10101010;
    #12;

    // Test case 3
    data = 8'b11001100;
    #18;
    // Test case 4
    data = 8'b11001111;


    #24;

    // Test case 5
    data = 8'b10101010;
    #30;
    // Test case 6
    data = 8'b11001111;

    $finish;
  end

endmodule

可以看到的输入时钟频率慢(10ns),输出时钟频率快(6ns),最终得到的数据不稳定,没有按照输出时钟周期固定输出。其中输出第一个aa值时在一个周期内输出,而cc则在4个始终周期内输出,这样不确定始终周期的读数会导致最终结果的异常,我们希望的是一个时钟周期输出一个值。

3、使用异步FIFO解决

设计实现一个简单的FIFO,输入与输出时钟不同,包括简单的FIFO空满验证,空满验证的方式采用计数器,即,计数器等于0为空,计数器为fifo深度为满。

`timescale 1ns / 1ps

module Asyn_fifo(
    input clk1,
    input clk2,
    input rst,
    input [7:0] data,
    output [7:0] out
);
    reg [7:0] fifo [0:15];
    reg [3:0] read_ptr, write_ptr;
    reg [3:0] count;
    reg [7:0] out_reg;

    always @(posedge clk1 or posedge rst) begin
        if(rst) begin
            read_ptr <= 4'b0;
            write_ptr <= 4'b0;
            count <= 4'b0;
        end
        else if(count < 16) begin
            fifo[read_ptr] <= data;
            read_ptr <= read_ptr + 1;
            count <= count + 1;
        end
        else begin
            read_ptr <= read_ptr;
            count <= count;
        end

    end

    always @(posedge clk2 or posedge rst)begin
        if(rst) begin
            read_ptr <= 4'b0;
            write_ptr <= 4'b0;
            count <= 4'b0;
        end
        else if(count > 0) begin
            out_reg <= fifo[write_ptr] ;
            write_ptr <= write_ptr + 1;
            count <= count - 1;
        end
        else begin
            write_ptr <= write_ptr;
            count <= count;
        end
    end
    assign out = out_reg;
endmodule

在上面设计中出现了问题,问题为在两个不同时钟中对同一个寄存器进行了写,其中的count用于判断当前fifo的空满,所以在两个模块中都进行了修改,在读模块(输入数据)中进行加,写模块(输出数据)中进行减,最终testbench是正常的,但是布局布线是异常的,这是由于最终实现过程count由触发器实现,触发器是边沿触发,只能在一个时钟边沿触发,在综合时会查看到两个count寄存器,寄存器中包含触发器。

测试代码如下

`timescale 1ns / 1ps

module Asyn_fifo_tb(

    );
  // Inputs
  reg clk1;
  reg clk2;
  reg rst;
  reg [7:0] data;

  // Outputs
  wire [7:0] out;

  // Instantiate the module
  Asyn_fifo uut (
    .clk1(clk1),
    .clk2(clk2),
    .rst(rst),
    .data(data),
    .out(out)
  );

  // Clock generation
    initial begin
        clk1 = 0;
        clk2 = 0;
    end
    always #5 clk1 = ~clk1;
    always #6 clk2 = ~clk2;

  // Stimulus
  initial begin
    // Test case 1
    rst = 1;
    data = 8'b00000000;
    #10
     rst = 0;

    // Test case 2
    data = 8'b10101010;
    #10;

    // Test case 3
    data = 8'b11001100;
    #10;
    // Test case 4
    data = 8'b11001111;


    #10;

    // Test case 5
    data = 8'b10101010;
    #10;
    // Test case 6
    data = 8'b11001111;
    # 100
    $finish;
  end

endmodule


在测试代码中输入的时钟频率要比输出时钟频率更快,输入时钟周期为10ns,输出时钟周期为12ns,数据就会缓存在FIFO中,测试使用的FIFO的深度比较小,当一次传输的数据量大时,要么采用更深的FIFO,要么就采用握手,当FIFO满时,就要限制输入数据。

测试波形

可以看到输出数据是比较稳定与正常的。

4、RTL实现

RTL实现的比较容易理解,reg1模块按照clk1存储输入数据,reg2模块按照clk2从右边

5、综合

综合存在问题,原本的一个count最终被综合为两个触发器,与原本设计是不相符合的。

6、实现

实现失败

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值