所謂數(shù)據(jù)流跨時(shí)鐘域即:時(shí)鐘不同但是時(shí)間段內(nèi)的數(shù)據(jù)量一定要相同。
常用的數(shù)據(jù)流跨時(shí)鐘域可以使用fifo或者ram實(shí)現(xiàn)。fifo的實(shí)現(xiàn)我們之前文章中fifo資源的介紹中已經(jīng)詳細(xì)講解過(guò)了,xilinx FIFO 硬核的結(jié)構(gòu)如下:
但是FIFO實(shí)現(xiàn)有一個(gè)問(wèn)題,由于沒(méi)有地址控制,需要固定時(shí)延是不方便,另外就是xilinx IP的fifo深度較大,可能存在資源浪費(fèi)。
第二種方法就是使用ram自己搭建跨時(shí)鐘域模塊。我們使用bram做數(shù)據(jù)流跨時(shí)鐘域。
例示代碼如下 ,代碼時(shí)鐘比例為5:4,a時(shí)鐘每5個(gè)clk寫(xiě)入4個(gè)數(shù)據(jù),b時(shí)鐘每個(gè)clk輸出,代碼中有兩個(gè)點(diǎn)要注意:
1、0地址的寫(xiě)是能;
2、有一個(gè)防抖處理。
// ============================================================
// File Name: cm_cdc_bram
// VERSION : V1.0
// DATA : 2022/10/4
// Author : FPGA干貨分享
// ============================================================
// 功能:數(shù)據(jù)流使用bram跨時(shí)鐘域模塊
// ============================================================
`timescale 1ns/1ps
module cm_cdc_bram (
input wire I_clk_a , ///輸入時(shí)鐘a,500Mhz
input wire I_clk_b , ///輸入時(shí)鐘b,400Mhz
input wire I_data_a_valid , ///輸入時(shí)鐘b
input wire [31:0] I_data_a , ///a時(shí)鐘輸入信號(hào)
output wire[31:0] O_data_b ///b時(shí)鐘輸出信號(hào)
);
// ============================================================
// 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 ) , ///輸入時(shí)鐘a
.I_clk_b (I_clk_b ) , ///輸入時(shí)鐘b
.I_single_a (S_wr_zero_flag ) , ///a時(shí)鐘輸入信號(hào)
.O_single_b (S_wr_zero_flag_rd ) ///b時(shí)鐘輸出信號(hào)
);
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
+關(guān)注
關(guān)注
1626文章
21678瀏覽量
602022 -
Xilinx
+關(guān)注
關(guān)注
71文章
2164瀏覽量
121039 -
fifo
+關(guān)注
關(guān)注
3文章
387瀏覽量
43560 -
數(shù)據(jù)流
+關(guān)注
關(guān)注
0文章
119瀏覽量
14335 -
時(shí)鐘域
+關(guān)注
關(guān)注
0文章
52瀏覽量
9529
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論