资讯动态

zynq的stream数据mock和fifo缓冲和同步

发布时间:2026/8/8 6:48:43 来源:尧图企业网站定制
readme.md# 文件根目录setroot_dirD:/workspace/gitee/999/ming_zynq_wave_prj/ming_zynq_wave/v2/vivado/src# 源文件add_files$root_dir/stream_fifo/axis_generator.v add_files$root_dir/stream_fifo/axis_stream_fifo.v# tb文件add_files-filesetsim_1$root_dir/stream_fifo/tb_axis_generator.v add_files-filesetsim_1$root_dir/stream_fifo/tb_axis_stream_fifo.v add_files-filesetsim_1$root_dir/stream_fifo/tb_ip_axis_data_fifo.vaxis_generator.v生成axi_stream数据流timescale 1ns / 1ps // // 示例: // P_AD_COUNT 4 // seq ad0 ad1 ad2 ad3 // 0000 0001 0002 0003 0004 // 0001 0005 0006 0007 0008 // 0002 0009 000a 000b 000c // module axis_generator #( // 时钟频率 parameter P_CLK_FREQ 100_000_000, // 采样周期(P_SAMPLE_PERIOD个时钟周期采集一次) parameter P_SAMPLE_PERIOD 100, // AD数量 parameter P_AD_COUNT 4 )( input wire i_clk, input wire i_rst_n, //(P_AD_COUNT1)个u32 output reg [(P_AD_COUNT1)*32-1:0] m_axis_tdata, output reg m_axis_tvalid, input wire m_axis_tready ); localparam P_AXIS_WIDTH (P_AD_COUNT1)*32; // 采样计时器 reg [31:0] r_timer; // 行号 reg [31:0] r_seq; // AD数据计数 reg [31:0] r_ad_counter; integer i; //////////////////////////////////////////////////////// // AXIS DATA GENERATOR //////////////////////////////////////////////////////// always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_timer 0; r_seq 0; r_ad_counter 0; m_axis_tdata 0; m_axis_tvalid 0; end else begin //-------------------------------------------------- // AXIS握手 //-------------------------------------------------- if(m_axis_tvalid) begin if(m_axis_tready) m_axis_tvalid 0; end //-------------------------------------------------- //旧数据收到后,才生成新数据 //-------------------------------------------------- else if(r_timer P_SAMPLE_PERIOD-1) begin r_timer 0; // 清空 m_axis_tdata 0; // seq m_axis_tdata[P_AXIS_WIDTH-1 -:32] r_seq; //AD for(i0;iP_AD_COUNT;ii1) begin m_axis_tdata[P_AXIS_WIDTH-33-i*32 -:32] r_ad_counteri1; end //数据有效 m_axis_tvalid 1b1; // 行号1 r_seq r_seq 1; // AD计数增加AD数量 r_ad_counter r_ad_counter P_AD_COUNT; end else begin r_timer r_timer 1; end end end endmoduletb_axis_generator.vtimescale 1ns / 1ps module tb_axis_generator; //////////////////////////////////////////////////////// // Clock //////////////////////////////////////////////////////// reg i_clk; reg i_rst_n; initial begin i_clk 0; forever #5 i_clk ~i_clk; end //////////////////////////////////////////////////////// // Reset //////////////////////////////////////////////////////// initial begin i_rst_n 0; #100; i_rst_n 1; end //////////////////////////////////////////////////////// // AXIS //////////////////////////////////////////////////////// wire [159:0] m_axis_tdata; wire m_axis_tvalid; reg m_axis_tready; initial begin m_axis_tready 1b1; end //////////////////////////////////////////////////////// // DUT //////////////////////////////////////////////////////// axis_generator #( .P_SAMPLE_PERIOD(10), .P_AD_COUNT(4) )u_axis_generator ( .i_clk(i_clk), .i_rst_n(i_rst_n), .m_axis_tdata(m_axis_tdata), .m_axis_tvalid(m_axis_tvalid), .m_axis_tready(m_axis_tready) ); wire [31:0] seq; wire [31:0] ad0; wire [31:0] ad1; wire [31:0] ad2; wire [31:0] ad3; assign seq m_axis_tdata[159:128]; assign ad0 m_axis_tdata[127:96]; assign ad1 m_axis_tdata[95:64]; assign ad2 m_axis_tdata[63:32]; assign ad3 m_axis_tdata[31:0]; //////////////////////////////////////////////////////// // Monitor //////////////////////////////////////////////////////// always (posedge i_clk) begin if(m_axis_tvalid m_axis_tready) begin $display(time%0t seq%d ad0%d ad1%d ad2%d ad3%d, $time,seq,ad0,ad1,ad2,ad3); if(seq0) begin if(ad0!1 ||ad1!2 ||ad2!3 ||ad3!4) begin $display(ERROR first sample); $stop; end end end end //////////////////////////////////////////////////////// // Simulation end //////////////////////////////////////////////////////// initial begin #2000; $display(Simulation finish); $stop; end endmoduleaxis_stream_fifo.v将 xpm_fifo_async 转换位 axi_stream接口timescale 1ns / 1ps // // 模块名称axis_stream_fifo // // 功能说明 // 1. 将 AXI4-Stream 数据写入 Xilinx XPM 异步 FIFO实现跨时钟域缓存。 // 2. s_axis_* 为写入侧接口工作在 s_axis_clk 时钟域。 // 3. m_axis_* 为读出侧接口工作在 m_axis_clk 时钟域。 // 4. FIFO 使用 READ_MODEfwftFirst Word Fall Through模式 // 当 FIFO 非空时队首数据会直接出现在 dout 上读侧用 tvalid/tready // 握手后rd_en 再弹出当前数据并切到下一笔。 // // 复位注意事项 // XPM FIFO 复位释放后内部仍会保持 wr_rst_busy / rd_rst_busy 一段时间。 // busy 期间不能拉高 wr_en 或 rd_en否则仿真/硬件中可能出现丢数据或读序错乱。 // 所以本模块用 busy 信号约束 AXIS 的 tready/tvalid。 // module axis_stream_fifo #( // AXIS 数据位宽只包含 tdata不包含 tlast。 parameter P_DATA_WIDTH 32, // FIFO 写深度单位是 P_FIFO_WIDTH 宽度的数据字。 // XPM FIFO 对深度取值有约束工程中建议使用 2 的幂。 parameter P_FIFO_DEPTH 1024, // 是否携带 tlast // 0FIFO 中只保存 tdata。 // 1FIFO 中保存 {tlast, tdata}读侧同步恢复 tlast。 parameter P_HAS_TLAST 1 )( //-------------------------------------------------- // 写时钟域AXIS Slave 输入侧 //-------------------------------------------------- input wire s_axis_clk, // 写侧低有效复位同时作为 XPM FIFO 的统一复位来源。 input wire s_axis_rst_n, //-------------------------------------------------- // AXIS Slave 输入 //-------------------------------------------------- input wire [P_DATA_WIDTH-1:0] s_axis_tdata, // 写入 FIFO 的 AXIS 数据 input wire s_axis_tvalid, // 上游数据有效 output wire s_axis_tready, // FIFO 可接收数据 input wire s_axis_tlast, // 可选包结束标志P_HAS_TLAST1 时有效 //-------------------------------------------------- // 读时钟域AXIS Master 输出侧 //-------------------------------------------------- input wire m_axis_clk, // 读侧低有效复位只约束读侧 AXIS 输出握手。 input wire m_axis_rst_n, //-------------------------------------------------- // AXIS Master 输出 //-------------------------------------------------- output wire [P_DATA_WIDTH-1:0] m_axis_tdata, // 从 FIFO 读出的 AXIS 数据 output wire m_axis_tvalid, // FIFO 当前有有效输出数据 input wire m_axis_tready, // 下游准备接收数据 output wire m_axis_tlast // 可选包结束标志P_HAS_TLAST1 时恢复 ); // FIFO 内部存储宽度。 // 当 P_HAS_TLAST1 时最高位额外保存 tlast否则宽度等于 P_DATA_WIDTH。 localparam P_FIFO_WIDTH P_DATA_WIDTH P_HAS_TLAST; //////////////////////////////////////////////////////// // FIFO 内部信号 //////////////////////////////////////////////////////// wire [P_FIFO_WIDTH-1:0] w_fifo_din; // 写入 XPM FIFO 的打包数据 wire [P_FIFO_WIDTH-1:0] w_fifo_dout; // 从 XPM FIFO 读出的打包数据 wire w_fifo_full; // FIFO 满标志写时钟域有效 wire w_fifo_empty; // FIFO 空标志读时钟域有效 wire w_fifo_wr_en; // XPM FIFO 写使能 wire w_fifo_rd_en; // XPM FIFO 读使能 wire w_wr_rst_busy; // XPM 写侧复位忙busy 期间禁止写 wire w_rd_rst_busy; // XPM 读侧复位忙busy 期间禁止读 //////////////////////////////////////////////////////// // AXIS 写端 //////////////////////////////////////////////////////// // 只有在写侧复位已释放、XPM 写侧不 busy、FIFO 未满时才允许上游写入。 // 这样可避免 reset busy 阶段 s_axis_tready 提前拉高导致上游误以为数据已写入。 assign s_axis_tready s_axis_rst_n ~w_wr_rst_busy ~w_fifo_full; // AXIS 写握手成功时向 XPM FIFO 写入一拍数据。 assign w_fifo_wr_en s_axis_tvalid s_axis_tready; //////////////////////////////////////////////////////// // 打包数据 //////////////////////////////////////////////////////// generate if(P_HAS_TLAST) begin // 带 tlast 时FIFO 最高位保存 tlast低位保存 tdata。 assign w_fifo_din {s_axis_tlast,s_axis_tdata}; end else begin // 不带 tlast 时FIFO 只保存 tdata节省 1 bit 存储宽度。 assign w_fifo_din s_axis_tdata; end endgenerate //////////////////////////////////////////////////////// // AXIS 读端 //////////////////////////////////////////////////////// // FWFT 模式下FIFO 非空时 dout 已经是当前队首数据。 // 读侧复位未释放或 XPM 读侧 busy 时不对外声明 valid也不产生 rd_en。 assign m_axis_tvalid m_axis_rst_n ~w_rd_rst_busy ~w_fifo_empty; // AXIS 读握手成功时弹出当前队首数据。 // 若 FIFO 中还有下一笔数据FWFT 会自动把下一笔送到 dout。 assign w_fifo_rd_en m_axis_tvalid m_axis_tready; //////////////////////////////////////////////////////// // 解包 //////////////////////////////////////////////////////// generate if(P_HAS_TLAST) begin // 与写侧打包顺序对应低 P_DATA_WIDTH 位是 tdata最高位是 tlast。 assign m_axis_tdata w_fifo_dout[P_DATA_WIDTH-1:0]; assign m_axis_tlast w_fifo_dout[P_FIFO_WIDTH-1]; end else begin // 不带 tlast 时读侧 tlast 固定为 0。 assign m_axis_tdata w_fifo_dout; assign m_axis_tlast 1b0; end endgenerate //////////////////////////////////////////////////////// // Xilinx XPM Async FIFO //////////////////////////////////////////////////////// xpm_fifo_async #( // FIFO 深度与宽度由模块参数控制写读宽度保持一致。 .FIFO_WRITE_DEPTH(P_FIFO_DEPTH), .WRITE_DATA_WIDTH(P_FIFO_WIDTH), .READ_DATA_WIDTH(P_FIFO_WIDTH), // FWFT 模式要求读延迟为 0empty 拉低时dout 已是有效队首数据。 .FIFO_READ_LATENCY(0), // 跨时钟域同步级数。级数越大CDC 更稳健但空/满标志延迟也更大。 .CDC_SYNC_STAGES(2), // First Word Fall Through读侧无需先打一拍 rd_en 才看到第一笔数据。 .READ_MODE(fwft) ) u_xpm_fifo_async ( // 未使用休眠和错误注入功能必须显式绑 0避免仿真出现 X/Z。 .sleep(1b0), // 写侧端口 .wr_clk(s_axis_clk), .wr_en(w_fifo_wr_en), .din(w_fifo_din), .full(w_fifo_full), // 读侧端口 .rd_clk(m_axis_clk), .rd_en( w_fifo_rd_en), .dout( w_fifo_dout), .empty(w_fifo_empty), // XPM FIFO 只有一个 rst 输入这里使用写侧复位作为 FIFO 全局复位。 .rst( ~s_axis_rst_n), // ECC/错误注入未启用相关输入固定为 0。 .injectsbiterr(1b0), .injectdbiterr(1b0), // 复位忙信号用于保护 AXIS 握手busy 期间禁止读写 FIFO。 .wr_rst_busy(w_wr_rst_busy), .rd_rst_busy(w_rd_rst_busy) ); endmoduletb_axis_stream_fifo.vtimescale 1ns / 1ps module tb_axis_stream_fifo; //////////////////////////////////////////////////////// // Clock //////////////////////////////////////////////////////// reg i_clk; reg m_clk; initial begin i_clk 0; forever #5 i_clk ~i_clk; //100MHz end initial begin m_clk 0; forever #7 m_clk ~m_clk; //71MHz end //////////////////////////////////////////////////////// // Reset //////////////////////////////////////////////////////// reg i_rst_n; reg m_rst_n; initial begin i_rst_n 0; m_rst_n 0; #100; i_rst_n 1; m_rst_n 1; end //////////////////////////////////////////////////////// // AXIS generator //////////////////////////////////////////////////////// wire [159:0] s_axis_tdata; wire s_axis_tvalid; wire s_axis_tready; axis_generator #( // 每10个clk产生一次数据 .P_SAMPLE_PERIOD(10), // 4路AD .P_AD_COUNT(4) ) u_axis_generator ( .i_clk(i_clk), .i_rst_n(i_rst_n), .m_axis_tdata(s_axis_tdata), .m_axis_tvalid( s_axis_tvalid), .m_axis_tready( s_axis_tready) ); //////////////////////////////////////////////////////// // AXIS FIFO //////////////////////////////////////////////////////// wire [159:0] m_axis_tdata; wire m_axis_tvalid; reg m_axis_tready; axis_stream_fifo #( .P_DATA_WIDTH(160), .P_FIFO_DEPTH(16), .P_HAS_TLAST(0) ) u_axis_fifo ( //-------------------------------------------------- // 输入 //-------------------------------------------------- .s_axis_clk(i_clk), .s_axis_rst_n(i_rst_n), .s_axis_tdata(s_axis_tdata), .s_axis_tvalid(s_axis_tvalid), .s_axis_tready(s_axis_tready), .s_axis_tlast(1b0), //-------------------------------------------------- // 输出 //-------------------------------------------------- .m_axis_clk(m_clk), .m_axis_rst_n(m_rst_n), .m_axis_tdata( m_axis_tdata), .m_axis_tvalid(m_axis_tvalid), .m_axis_tready(m_axis_tready), .m_axis_tlast() ); //////////////////////////////////////////////////////// // 下游 AXIS ready //////////////////////////////////////////////////////// // 模拟 DataMover // // 上电先不接收 // 测试FIFO缓存能力 //////////////////////////////////////////////////////// initial begin m_axis_tready 1b0; #400; m_axis_tready 1b1; end //////////////////////////////////////////////////////// // 数据解析 //////////////////////////////////////////////////////// wire [31:0] seq; wire [31:0] ad0; wire [31:0] ad1; wire [31:0] ad2; wire [31:0] ad3; assign seq m_axis_tdata[159:128]; assign ad0 m_axis_tdata[127:96]; assign ad1 m_axis_tdata[95:64]; assign ad2 m_axis_tdata[63:32]; assign ad3 m_axis_tdata[31:0]; //////////////////////////////////////////////////////// // FIFO 写监控 //////////////////////////////////////////////////////// always (posedge i_clk) begin if(s_axis_tvalid s_axis_tready) begin $display( FIFO WRITE time%0t seq%d ad0%d ad1%d ad2%d ad3%d, $time, s_axis_tdata[159:128], s_axis_tdata[127:96], s_axis_tdata[95:64], s_axis_tdata[63:32], s_axis_tdata[31:0] ); end end //////////////////////////////////////////////////////// // FIFO 读监控 //////////////////////////////////////////////////////// integer rx_count; initial begin rx_count 0; end always (posedge m_clk) begin if(m_axis_tvalid m_axis_tready) begin $display(FIFO READ time%0t seq%d ad0%d ad1%d ad2%d ad3%d, $time,seq,ad0,ad1,ad2,ad3); //-------------------------------------------------- // 第一帧检查 //-------------------------------------------------- if(seq0) begin if(ad0!1 ||ad1!2 ||ad2!3 ||ad3!4) begin $display(ERROR first sample); $stop; end end //-------------------------------------------------- // 连续性检查 //-------------------------------------------------- if(seq ! rx_count) begin $display(ERROR sequence expect%d receive%d,rx_count,seq); $stop; end rx_count rx_count 1; end end //////////////////////////////////////////////////////// // Simulation end //////////////////////////////////////////////////////// initial begin #20000; $display(); $display(Simulat finish); $display(); $stop; end endmoduleaxis_data_fifo_0 .vip catalog生成的axis_data_fifo_0//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG axis_data_fifo_0 your_instance_name ( .s_axis_aresetn(s_axis_aresetn), // input wire s_axis_aresetn .s_axis_aclk(s_axis_aclk), // input wire s_axis_aclk .s_axis_tvalid(s_axis_tvalid), // input wire s_axis_tvalid .s_axis_tready(s_axis_tready), // output wire s_axis_tready .s_axis_tdata(s_axis_tdata), // input wire [159 : 0] s_axis_tdata .m_axis_tvalid(m_axis_tvalid), // output wire m_axis_tvalid .m_axis_tready(m_axis_tready), // input wire m_axis_tready .m_axis_tdata(m_axis_tdata) // output wire [159 : 0] m_axis_tdata );axis_data_fifo_0 配置参数配置值Component Nameaxis_data_fifo_0FIFO depth512Memory typeAutoIndependent clocksNoCDC sync stages3Enable packet modeNoACLKEN conversion modeNoneEnable ECCNoInclude ECC error injectionNo参数配置值TDATA width (bytes)20Enable TSTRBNoEnable TKEEPNoEnable TLASTNoTID width (bits)0TDEST width (bits)0TUSER width (bits)0tb_ip_axis_data_fifo.vtimescale 1ns / 1ps module tb_ip_axis_data_fifo; //////////////////////////////////////////////////////// // Clock //////////////////////////////////////////////////////// reg s_axis_aclk; initial begin s_axis_aclk 0; forever #5 s_axis_aclk ~s_axis_aclk; //100MHz end //////////////////////////////////////////////////////// // Reset //////////////////////////////////////////////////////// reg s_axis_aresetn; initial begin s_axis_aresetn 0; #100; s_axis_aresetn 1; end //////////////////////////////////////////////////////// // AXIS input from generator //////////////////////////////////////////////////////// wire [159:0] s_axis_tdata; wire s_axis_tvalid; wire s_axis_tready; //////////////////////////////////////////////////////// // AXIS output //////////////////////////////////////////////////////// wire [159:0] m_axis_tdata; wire m_axis_tvalid; reg m_axis_tready; //////////////////////////////////////////////////////// // AXIS generator //////////////////////////////////////////////////////// axis_generator #( .P_SAMPLE_PERIOD(10), .P_AD_COUNT(4) ) u_axis_generator ( .i_clk(s_axis_aclk), .i_rst_n(s_axis_aresetn), .m_axis_tdata(s_axis_tdata), .m_axis_tvalid(s_axis_tvalid), .m_axis_tready(s_axis_tready) ); //////////////////////////////////////////////////////// // DUT //////////////////////////////////////////////////////// axis_data_fifo_0 u_axis_data_fifo_0 ( .s_axis_aresetn(s_axis_aresetn), .s_axis_aclk(s_axis_aclk), .s_axis_tvalid(s_axis_tvalid), .s_axis_tready(s_axis_tready), .s_axis_tdata(s_axis_tdata), .m_axis_tvalid(m_axis_tvalid), .m_axis_tready(m_axis_tready), .m_axis_tdata(m_axis_tdata) ); //延时读 initial begin m_axis_tready 1b0; #500; m_axis_tready 1b1; end //////////////////////////////////////////////////////// // FIFO WRITE monitor //////////////////////////////////////////////////////// always (posedge s_axis_aclk) begin if(s_axis_tvalid s_axis_tready) begin $display( FIFO WRITE time%0t seq%d ad0%d ad1%d ad2%d ad3%d, $time, s_axis_tdata[159:128], s_axis_tdata[127:96], s_axis_tdata[95:64], s_axis_tdata[63:32], s_axis_tdata[31:0] ); end end //////////////////////////////////////////////////////// // FIFO READ monitor //////////////////////////////////////////////////////// integer rx_count; initial begin rx_count 0; end always (posedge s_axis_aclk) begin if(m_axis_tvalid m_axis_tready) begin $display( FIFO READ time%0t seq%d ad0%d ad1%d ad2%d ad3%d, $time, m_axis_tdata[159:128], m_axis_tdata[127:96], m_axis_tdata[95:64], m_axis_tdata[63:32], m_axis_tdata[31:0]); //----------------------------------------- // seq连续检查 //----------------------------------------- if(m_axis_tdata[159:128] ! rx_count) begin $display( ERROR seq expect%d receive%d, rx_count, m_axis_tdata[159:128] ); $stop; end //----------------------------------------- // AD检查 //----------------------------------------- if(m_axis_tdata[127:96] ! rx_count*41 || m_axis_tdata[95:64] ! rx_count*42 || m_axis_tdata[63:32] ! rx_count*43 || m_axis_tdata[31:0] ! rx_count*44) begin $display(ERROR AD DATA); $stop; end rx_count rx_count 1; end end //////////////////////////////////////////////////////// // Finish //////////////////////////////////////////////////////// initial begin #20000; $display(); $display(Simulation finish); $display(RX COUNT%d,rx_count); $display(); $stop; end endmodule测试tb_axis_generator 输出Vivado Simulator2020.2Time resolution is1pstime205000seq0ad01ad12ad23ad34time315000seq1ad05ad16ad27ad38...time1855000seq15ad061ad162ad263ad364time1965000seq16ad065ad166ad267ad368Simulation finishtb_axis_generator 输出FIFO WRITEtime455000seq0ad01ad12ad23ad34FIFO READtime553000seq0ad01ad12ad23ad34... FIFO READtime19915000seq176ad0705ad1706ad2707ad3708Simulat finishtb_ip_axis_data_fifo.v 输出FIFO WRITEtime205000seq0ad01ad12ad23ad34FIFO WRITEtime315000seq1ad05ad16ad27ad38... FIFO READtime19815000seq178ad0713ad1714ad2715ad3716FIFO WRITEtime19895000seq179ad0717ad1718ad2719ad3720FIFO READtime19925000seq179ad0717ad1718ad2719ad3720Simulation finish RXCOUNT180

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价