所谓数据流跨时钟域即:时钟不同但是时间段内的数据量一定要相同。
常用的数据流跨时钟域可以使用fifo或者ram实现。fifo的实现我们之前文章中fifo资源的介绍中已经详细讲解过了,xilinx FIFO 硬核的结构如下:
但是FIFO实现有一个问题,由于没有地址控制,需要固定时延是不方便,另外就是xilinx IP的fifo深度较大,可能存在资源浪费。
第二种方法就是使用ram自己搭建跨时钟域模块。我们使用bram做数据流跨时钟域。
例示代码如下 ,代码时钟比例为5:4,a时钟每5个clk写入4个数据,b时钟每个clk输出,代码中有两个点要注意:
1、0地址的写是能;
2、有一个防抖处理。
// ============================================================
// File Name: cm_cdc_bram
// VERSION : V1.0
// DATA : 2022/10/4
// Author : FPGA干货分享
// ============================================================
// 功能:数据流使用bram跨时钟域模块
// ============================================================
`timescale 1ns/1ps
module cm_cdc_bram (
input wire I_clk_a , ///输入时钟a,500Mhz
input wire I_clk_b , ///输入时钟b,400Mhz
input wire I_data_a_valid , ///输入时钟b
input wire [31:0] I_data_a , ///a时钟输入信号
output wire[31:0] O_data_b ///b时钟输出信号
);
// ============================================================
// wire reg
// ============================================================
reg [8:0] S_wr_addr ;
reg S_wr_zero_flag ;
wire S_wr_zero_flag_rd ;
reg [3:0] S_clk_cnt ;
reg S_wr_clr_falg_temp ;
reg S_wr_clr_falg ;
reg [8:0] S_rd_addr ;
// ============================================================
// main code
// ============================================================
// ============================================================
// clk_a
// ============================================================
always @(posedge I_clk_a)
if(I_data_a_valid)
S_wr_addr <= S_wr_addr + 9'd1;
else
S_wr_addr <= S_wr_addr ;
always @(posedge I_clk_a)
S_wr_zero_flag <= (!(|S_wr_addr));
// ============================================================
// clk_b
// ============================================================
cm_cdc_1bit cm_cdc_1bit (
.I_clk_a (I_clk_a ) , ///输入时钟a
.I_clk_b (I_clk_b ) , ///输入时钟b
.I_single_a (S_wr_zero_flag ) , ///a时钟输入信号
.O_single_b (S_wr_zero_flag_rd ) ///b时钟输出信号
);
always @(posedge I_clk_b)
if(S_wr_zero_flag_rd & (S_clk_cnt > 4'd2))
S_clk_cnt <= 4'd2;
else
S_clk_cnt <= S_clk_cnt + 4'd1;
always @(posedge I_clk_b)
if(S_wr_zero_flag_rd)
S_wr_clr_falg_temp <= 1'b1;
else if(&S_clk_cnt)
S_wr_clr_falg_temp <= 1'b0;
else
S_wr_clr_falg_temp <= S_wr_clr_falg_temp ;
always @(posedge I_clk_b)
S_wr_clr_falg <= S_wr_clr_falg_temp & (&S_clk_cnt) ;
always @(posedge I_clk_b)
if(S_wr_clr_falg)
S_rd_addr <= 9'd256;
else
S_rd_addr <= S_rd_addr + 'd1;
BRAM_SDP_MACRO #(
.BRAM_SIZE ("18Kb" ), // Target BRAM, "18Kb" or "36Kb"
.DEVICE ("7SERIES" ), // Target device: "7SERIES"
.WRITE_WIDTH (32 ), // Valid values are 1-72 (37-72 only valid when BRAM_SIZE="36Kb")
.READ_WIDTH (32 ), // Valid values are 1-72 (37-72 only valid when BRAM_SIZE="36Kb")
.DO_REG (1 ), // Optional output register (0 or 1)
.INIT_FILE ("NONE" )
) BRAM_SDP_MACRO_inst (
.DO (O_data_b ), // Output read data port, width defined by READ_WIDTH parameter
.DI (I_data_a ), // Input write data port, width defined by WRITE_WIDTH parameter
.RDADDR (S_rd_addr ), // Input read address, width defined by read port depth
.RDCLK (I_clk_b ), // 1-bit input read clock
.RDEN (1'b1 ), // 1-bit input read port enable
.REGCE (1'b1 ), // 1-bit input read output register enable
.RST (1'b0 ), // 1-bit input reset
.WE (4'hf ), // Input write enable, width defined by write port depth
.WRADDR (S_wr_addr ), // Input write address, width defined by write port depth
.WRCLK (I_clk_a ), // 1-bit input write clock
.WREN (I_data_a_valid ) // 1-bit input write port enable
);
endmodule
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
FPGA
+关注
关注
1624文章
21608浏览量
601081 -
Xilinx
+关注
关注
71文章
2154浏览量
120814 -
fifo
+关注
关注
3文章
386浏览量
43484 -
数据流
+关注
关注
0文章
119浏览量
14317 -
时钟域
+关注
关注
0文章
51浏览量
9524
发布评论请先 登录
相关推荐
评论