首页 > 其他分享 >05uifdma_dbuf 3.0 IP介绍

05uifdma_dbuf 3.0 IP介绍

时间:2023-12-30 11:33:27浏览次数:31  
标签:begin end fdma IP cnt FDMA 3.0 integer dbuf

软件版本:vitis2021.1(vivado2021.1)

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA

登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!

5.1概述    

    uifdma_dbuf IP是米联客研发用于配合FDMA完成数据传输控制的IP模块。FDMA-DBUF IP代码采用"对称设计"方法,读写代码对称,好处是代码结构清晰,读写过程一致,代码效率高,更加容易维护。本文只用到了写通道部分,读通道部分没有用到,但是我们还是介绍下。

    uifdma_dbuf的信号接口包含了:

AXI-LITE接口:用于PS端获取当前的中断帧号;

FDMA_M接口:和FDMA相连接的数据接口

ud_wx接口: uifdma_dbuf写数据通路接口

ud_rx接口: uifdma_dbuf读数据通路接口

以下只介绍uifdma_dbuf 的ud写数据通道和ud读数据通道

5.2uifdma_dbuf 的ud信号定义

写数据接口信号定义

信号名称

方向

位宽

功能描述

ud_wclk

input

1

写数据通路时钟

ud_wvs

input

1

写数据帧同步信号,当使能视频功能,每个ud_wvs的上升沿进行帧同步,否则该值设置为1

ud_wde

input

1

写数据数据有效,高电平有效

ud_wdata

input

32~128

写数据

ud_wfull

output

1

写数据FIFO满,当FIFO满,继续写入会导致数据溢出

wbuf_sync_o

output

7

写数据帧同步输出,代表了正在操作的缓存号

wbuf_sync_i

input

7

写数据帧同步输入, 帧同步关系到内部缓存地址切换

fdma_wbuf

output

7

当fdma_wirq中断产生后,代表了当前已经写到DDR完成的帧缓存号

fdma_wirq

output

1

写数据完成中断

读数据接口信号定义

信号名称

方向

位宽

功能描述

ud_rclk

input

1

读数据通路时钟

ud_rvs

input

1

读数据帧同步信号,当使能视频功能,每个ud_rvs的上升沿进行帧同步,否则该值设置为1

ud_rde

input

1

读数据数据有效,高电平有效

ud_rdata

input

32~128

读数据

ud_rempty

output

1

读数据FIFO空,当FIFO非空,可以读出数据,当fdma工作在非视频模式下,可以用该信号去使能ud_rde

rbuf_sync_o

output

7

读数据帧同步输出 ,代表了正在操作的缓存号

rbuf_sync_i

input

7

读数据帧同步输入, 帧同步关系到内部缓存地址切换

fdma_rbuf

output

7

当fdma_rirq中断产生后,代表了当前已经读到DDR完成的帧缓存号

fdma_rirq

output

 

读数据完成中断

5.3FDMA-DBUF IP代码分析

FDMA-DBUF IP代码采用"对称设计"方法,读写代码对称,好处是代码结构清晰,读写过程一致,代码效率高,更加容易维护。

1:FDMA-DBUF写状态机

为了配合AXI-FDMA IP发送数据到PS,我们写了一个uifdmadbuf ip,通过这个IP把用户编写的数据时序,转为AXI-FMDA接口数据流。该IP支持视频格式的帧同步,每一帧都进行同步,也支持没有帧同步的数据流方式传输。

 

2:FDMA的写时序波形图

fdma_wready设置为1,当fdma_wbusy=0的时候代表FDMA的总线非忙,可以进行一次新的FDMA传输,这个时候可以设置fdma_wreq=1,同时设置fdma burst的起始地址和fdma_wsize本次需要传输的数据大小(以bytes为单位)。当fdma_wvalid=1的时候需要给出有效的数据,写入AXI总线。当最后一个数写完后,fdma_wvalid和fdma_wbusy变为0。

AXI4总线最大的burst lenth是256,而经过封装后,用户接口的fdma_size可以任意大小的,fdma ip内部代码控制每次AXI4总线的Burst长度,这样极大简化了AXI4总线协议的使用。

3:FDMA-DBUF写状态机

读数据的过程和写数据的过程是对称的,状态机如下:

为了配合AXI-FDMA IP发送数据到PS,我们写了一个uifdmadbuf ip,通过这个IP把用户编写的数据时序,转为AXI-FMDA接口数据流。该IP支持视频格式的帧同步,每一帧都进行同步,也支持没有帧同步的数据流方式传输。

4:FDMA的读时序波形图

fdma_rready设置为1,当fdma_rbusy=0的时候代表FDMA的总线非忙,可以进行一次新的FDMA传输,这个时候可以设置fdma_rreq=1,同时设置fdma burst的起始地址和fdma_rsize本次需要传输的数据大小(以bytes为单位)。当fdma_rvalid=1的时候需要给出有效的数据,写入AXI总线。当最后一个数写完后,fdma_rvalid和fdma_rbusy变为0。

同样对于AXI4总线的读操作,AXI4总线最大的burst lenth是256,而经过封装后,用户接口的fdma_size可以任意大小的,fdma ip内部代码控制每次AXI4总线的Burst长度,这样极大简化了AXI4总线协议的使用。

5.4源码分析

米联客自定义IP路径在配套的soc_prj/uisrc/03_ip路径下,如下图所示:

代码的层次结构如下:

源码部分一共有包括4个文件:

fs_cap.v该文件用于帧同步信号的抓取,采样边沿抓取方式。

uidbufirq.v文件用来保存一帧数据发送完毕后产生的中断,ps部分可以通过axi-lite接口读取中断值知道哪一个地址完成数据传输。

uidbuf.v文件是完成用户数据到FDMA接口数据转换的关键代码,同时该代码完成了中断控制,帧缓存控制。

uifdma_dbuf.v该文件是该IP的顶层文件

1:uidbuf.v

 

/*******************************MILIANKE*******************************

*Company : MiLianKe Electronic Technology Co., Ltd.

*WebSite:https://www.milianke.com

*TechWeb:https://www.uisrc.com

*tmall-shop:https://milianke.tmall.com

*jd-shop:https://milianke.jd.com

*taobao-shop1: https://milianke.taobao.com

*Create Date: 2021/10/15

*File Name: uidbuf.v

*Description: 

*Declaration:

*The reference demo provided by Milianke is only used for learning. 

*We cannot ensure that the demo itself is free of bugs, so users 

*should be responsible for the technical problems and consequences

*caused by the use of their own products.

*Copyright: Copyright (c) MiLianKe

*All rights reserved.

*Revision: 1.0

*Signal description

*1) _i input

*2) _o output

*3) _n activ low

*4) _dg debug signal 

*5) _r delay or register

*6) _s state mechine

*********************************************************************/

`timescale 1ns / 1ps

 

module uidbuf#(

parameter  integer                   VIDEO_ENABLE   = 1,//使能视频帧支持功能

parameter  integer                   ENABLE_WRITE   = 1,//使能写通道

parameter  integer                   ENABLE_READ    = 1,//使能读通道

 

parameter  integer                   AXI_DATA_WIDTH = 128,//AXI总线数据位宽

parameter  integer                   AXI_ADDR_WIDTH = 32, //AXI总线地址位宽

 

parameter  integer                   W_BUFDEPTH     = 2048, //写通道AXI设置FIFO缓存大小

parameter  integer                   W_DATAWIDTH    = 32, //写通道AXI设置数据位宽大小

parameter  [AXI_ADDR_WIDTH -1'b1: 0] W_BASEADDR     = 0, //写通道设置内存起始地址

parameter  integer                   W_DSIZEBITS    = 24, //写通道设置缓存数据的增量地址大小,用于FDMA DBUF 计算帧缓存起始地址

parameter  integer                   W_XSIZE        = 1920, //写通道设置X方向的数据大小,代表了每次FDMA 传输的数据长度

parameter  integer                   W_XSTRIDE      = 1920, //写通道设置X方向的Stride值,主要用于图形缓存应用

parameter  integer                   W_YSIZE        = 1080, //写通道设置Y方向值,代表了进行了多少次XSIZE传输

parameter  integer                   W_XDIV         = 2, //写通道对X方向数据拆分为XDIV次传输,减少FIFO的使用

parameter  integer                   W_BUFSIZE      = 3, //写通道设置帧缓存大小,目前最大支持128帧,可以修改参数支持更缓存数

 

parameter  integer                   R_BUFDEPTH     = 2048, //读通道AXI设置FIFO缓存大小

parameter  integer                   R_DATAWIDTH    = 32, //读通道AXI设置数据位宽大小

parameter  [AXI_ADDR_WIDTH -1'b1: 0] R_BASEADDR     = 0, //读通道设置内存起始地址

parameter  integer                   R_DSIZEBITS    = 24, //读通道设置缓存数据的增量地址大小,用于FDMA DBUF 计算帧缓存起始地址

parameter  integer                   R_XSIZE        = 1920, //读通道设置X方向的数据大小,代表了每次FDMA 传输的数据长度

parameter  integer                   R_XSTRIDE      = 1920, //读通道设置X方向的Stride值,主要用于图形缓存应用

parameter  integer                   R_YSIZE        = 1080, //读通道设置Y方向值,代表了进行了多少次XSIZE传输

parameter  integer                   R_XDIV         = 2, //读通道对X方向数据拆分为XDIV次传输,减少FIFO的使用

parameter  integer                   R_BUFSIZE      = 3 //读通道设置帧缓存大小,目前最大支持128帧,可以修改参数支持更缓存数

)

(

input wire                                  ui_clk, //和FDMA AXI总线时钟一致

input wire                                  ui_rstn, //和FDMA AXI复位一致

//sensor input -W_FIFO--------------

input wire                                  W_wclk_i, //用户写数据接口时钟

input wire                                  W_FS_i, //用户写数据接口同步信号,对于非视频帧一般设置为1

input wire                                  W_wren_i, //用户写数据使能

input wire     [W_DATAWIDTH-1'b1 : 0]       W_data_i, //用户写数据

output reg     [7   :0]                     W_sync_cnt_o =0, //写通道BUF帧同步输出

input  wire    [7   :0]                     W_buf_i, // 写通道BUF帧同步输入

output wire                                 W_full,

 

//----------fdma signals write-------       

output wire    [AXI_ADDR_WIDTH-1'b1: 0]     fdma_waddr, //FDMA写通道地址

output wire                                 fdma_wareq, //FDMA写通道请求

output wire    [15  :0]                     fdma_wsize, //FDMA写通道一次FDMA的传输大小                                     

input  wire                                 fdma_wbusy, //FDMA处于BUSY状态,AXI总线正在写操作   

output wire    [AXI_DATA_WIDTH-1'b1:0]      fdma_wdata, //FDMA写数据

input  wire                                 fdma_wvalid, //FDMA 写有效

output wire                                 fdma_wready, //FDMA写准备好,用户可以写数据

output reg     [7   :0]                     fmda_wbuf =0, //FDMA的写帧缓存号输出

output wire                                 fdma_wirq, //FDMA一次写完成的数据传输完成后,产生中断。   

//----------fdma signals read-------  

input  wire                                 R_rclk_i, //用户读数据接口时钟

input  wire                                 R_FS_i, //用户读数据接口同步信号,对于非视频帧一般设置1

input  wire                                 R_rden_i, //用户读数据使能

output wire    [R_DATAWIDTH-1'b1 : 0]       R_data_o, //用户读数据

output reg     [7   :0]                     R_sync_cnt_o =0, //读通道BUF帧同步输出

input  wire    [7   :0]                     R_buf_i, //写通道BUF帧同步输入

output wire                                 R_empty,

 

output wire    [AXI_ADDR_WIDTH-1'b1: 0]     fdma_raddr, // FDMA读通道地址

output wire                                 fdma_rareq, // FDMA读通道请求

output wire    [15: 0]                      fdma_rsize, // FDMA读通道一次FDMA的传输大小                                     

input  wire                                 fdma_rbusy, // FDMA处于BUSY状态,AXI总线正在读操作     

input  wire    [AXI_DATA_WIDTH-1'b1:0]      fdma_rdata, // FDMA读数据

input  wire                                 fdma_rvalid, // FDMA 读有效

output wire                                 fdma_rready, // FDMA读准备好,用户可以写数据

output reg     [7  :0]                      fmda_rbuf =0, // FDMA的读帧缓存号输出

output wire                                 fdma_rirq // FDMA一次读完成的数据传输完成后,产生中断

);    

 

// 计算Log2

function integer clog2;

  input integer value;

  begin 

    value = value-1;

    for (clog2=0; value>0; clog2=clog2+1)

      value = value>>1;

    end 

  endfunction

 

//FDMA读写状态机的状态值,一般4个状态值即可 

localparam S_IDLE  =  2'd0;  

localparam S_RST   =  2'd1;  

localparam S_DATA1 =  2'd2;   

localparam S_DATA2 =  2'd3; 

 

// 通过设置通道使能,可以优化代码的利用率

generate  if(ENABLE_WRITE == 1)begin : FDMA_WRITE_ENABLE

 

localparam WFIFO_DEPTH = W_BUFDEPTH; //写通道FIFO深度

localparam W_WR_DATA_COUNT_WIDTH = clog2(WFIFO_DEPTH)+1; //计算FIFO的写通道位宽

localparam W_RD_DATA_COUNT_WIDTH = clog2(WFIFO_DEPTH*W_DATAWIDTH/AXI_DATA_WIDTH)+1;//clog2(WFIFO_DEPTH/(AXI_DATA_WIDTH/W_DATAWIDTH))+1;

 

localparam WYBUF_SIZE           = (W_BUFSIZE - 1'b1); //写通道需要完成多少次XSIZE操作

localparam WY_BURST_TIMES       = (W_YSIZE*W_XDIV); //写通道需要完成的FDMA burst 操作次数,XDIV用于把XSIZE分解多次传输

localparam FDMA_WX_BURST        = (W_XSIZE*W_DATAWIDTH/AXI_DATA_WIDTH)/W_XDIV; //FDMA BURST 一次的大小

localparam WX_BURST_ADDR_INC    = (W_XSIZE*(W_DATAWIDTH/8))/W_XDIV; //FDMA每次burst之后的地址增加

localparam WX_LAST_ADDR_INC     = (W_XSTRIDE-W_XSIZE)*(W_DATAWIDTH/8) + WX_BURST_ADDR_INC; //根据stride值计算出来最后一次地址

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *) wire  W_wren_ri = W_wren_i; 

 

assign                                  fdma_wready = 1'b1;

reg                                     fdma_wareq_r= 1'b0;

reg                                     W_FIFO_Rst=0; 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)wire                                    W_FS;

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg [1 :0]                              W_MS=0; 

reg [W_DSIZEBITS-1'b1:0]                W_addr=0; 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg [15:0]                              W_bcnt=0; 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)wire[W_RD_DATA_COUNT_WIDTH-1'b1 :0]     W_rcnt;

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg                                     W_REQ=0; 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg [5 :0]                              wirq_dly_cnt =0;

reg [3 :0]                              wdiv_cnt =0;

reg [7 :0]                              wrst_cnt =0;

reg [7 :0]                              fmda_wbufn;

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *) wire wirq= fdma_wirq;

 

assign fdma_wsize = FDMA_WX_BURST;

assign fdma_wirq = (wirq_dly_cnt>0);

 

assign fdma_waddr = W_BASEADDR + {fmda_wbufn,W_addr};//由于FPGA逻辑做乘法比较复杂,因此通过设置高位地址实现缓存设置

 

reg [1:0] W_MS_r =0;

always @(posedge ui_clk) W_MS_r <= W_MS;

 

//每次FDMA DBUF 完成一帧数据传输后,产生中断,这个中断持续60个周期的uiclk,这里的延迟必须足够ZYNQ IP核识别到这个中断

always @(posedge ui_clk) begin

    if(ui_rstn == 1'b0)begin

        wirq_dly_cnt <= 6'd0;

        fmda_wbuf <=0;

    end

    else if((W_MS_r == S_DATA2) && (W_MS == S_IDLE))begin

        wirq_dly_cnt <= 60;

        fmda_wbuf <= fmda_wbufn;

    end

    else if(wirq_dly_cnt >0)

        wirq_dly_cnt <= wirq_dly_cnt - 1'b1;

end

 

//帧同步,对于视频有效

fs_cap #

(

.VIDEO_ENABLE(VIDEO_ENABLE)

)

fs_cap_W0

(

 .clk_i(ui_clk),

 .rstn_i(ui_rstn),

 .vs_i(W_FS_i),

 .fs_cap_o(W_FS)

);

 

assign fdma_wareq = fdma_wareq_r;

 

//写通道状态机,采用4个状态值描述

 always @(posedge ui_clk) begin

    if(!ui_rstn)begin

        W_MS         <= S_IDLE;

        W_FIFO_Rst   <= 0;

        W_addr       <= 0;

        W_sync_cnt_o <= 0;

        W_bcnt       <= 0;

        wrst_cnt     <= 0;

        wdiv_cnt     <= 0;

        fmda_wbufn    <= 0;

        fdma_wareq_r <= 1'd0;

    end   

    else begin

      case(W_MS)

        S_IDLE:begin

          W_addr <= 0;

          W_bcnt <= 0;

          wrst_cnt <= 0;

          wdiv_cnt <=0;

          if(W_FS) begin //帧同步,对于非视频数据一般常量为1

            W_MS <= S_RST;

            if(W_sync_cnt_o < WYBUF_SIZE) //输出帧同步计数器

                W_sync_cnt_o <= W_sync_cnt_o + 1'b1; 

            else 

                W_sync_cnt_o <= 0;  

          end

       end

       S_RST:begin//帧同步,对于非视频数据直接跳过,对于视频数据,会同步每一帧,并且复位数据FIFO

           fmda_wbufn <= W_buf_i;

           wrst_cnt <= wrst_cnt + 1'b1;

           if((VIDEO_ENABLE == 1) && (wrst_cnt < 40))

                W_FIFO_Rst <= 1;

           else if((VIDEO_ENABLE == 1) && (wrst_cnt < 100))

                W_FIFO_Rst <= 0;

           else if(fdma_wirq == 1'b0) begin

                W_MS <= S_DATA1;

           end

       end

        S_DATA1:begin //发送写FDMA请求

          if(fdma_wbusy == 1'b0 && W_REQ )begin

             fdma_wareq_r  <= 1'b1; 

          end 

          else if(fdma_wbusy == 1'b1) begin

             fdma_wareq_r  <= 1'b0;

             W_MS    <= S_DATA2;

          end          

         end

        S_DATA2:begin //写有效数据

            if(fdma_wbusy == 1'b0)begin

                if(W_bcnt == WY_BURST_TIMES - 1'b1) //判断是否传输完毕

                    W_MS <= S_IDLE;

                else begin

                    if(wdiv_cnt < W_XDIV - 1'b1)begin//如果对XSIZE做了分次传输,一个XSIZE也需要XDIV次FDMA完成传输

                        W_addr <= W_addr +  WX_BURST_ADDR_INC;  //计算地址增量

                        wdiv_cnt <= wdiv_cnt + 1'b1;

                     end

                    else begin

                        W_addr <= W_addr + WX_LAST_ADDR_INC; //计算最后一次地址增量,最后一次地址根据stride 计算

                        wdiv_cnt <= 0;

                    end

                    W_bcnt <= W_bcnt + 1'b1;

                    W_MS    <= S_DATA1;

                end 

            end

         end

         default: W_MS <= S_IDLE; 

       endcase

    end

 end 

 

//写通道的数据FIFO,采用了原语调用xpm_fifo_async fifo,当FIFO存储的数据阈值达到一定量,一般满足一次FDMA的burst即可发出请求

wire W_rbusy;

always@(posedge ui_clk)     

     W_REQ  <= (W_rcnt > FDMA_WX_BURST - 2)&&(~W_rbusy); 

       

xpm_fifo_async # (

  .FIFO_MEMORY_TYPE          ("auto"),           //string; "auto", "block", or "distributed";

  .ECC_MODE                  ("no_ecc"),         //string; "no_ecc" or "en_ecc";

  .RELATED_CLOCKS            (0),                //positive integer; 0 or 1

  .FIFO_WRITE_DEPTH          (WFIFO_DEPTH),     //positive integer

  .WRITE_DATA_WIDTH          (W_DATAWIDTH),               //positive integer

  .WR_DATA_COUNT_WIDTH       (W_WR_DATA_COUNT_WIDTH),               //positive integer

  .PROG_FULL_THRESH          (20),               //positive integer

  .FULL_RESET_VALUE          (0),                //positive integer; 0 or 1

  .USE_ADV_FEATURES          ("0707"),           //string; "0000" to "1F1F"; 

  .READ_MODE                 ("fwft"),            //string; "std" or "fwft";

  .FIFO_READ_LATENCY         (0),                //positive integer;

  .READ_DATA_WIDTH           (AXI_DATA_WIDTH),               //positive integer

  .RD_DATA_COUNT_WIDTH       (W_RD_DATA_COUNT_WIDTH),               //positive integer

  .PROG_EMPTY_THRESH         (10),               //positive integer

  .DOUT_RESET_VALUE          ("0"),              //string

  .CDC_SYNC_STAGES           (2),                //positive integer

  .WAKEUP_TIME               (0)                 //positive integer; 0 or 2;

) xpm_fifo_W_inst (

      .rst              ((ui_rstn == 1'b0) || (W_FIFO_Rst == 1'b1)),

      .wr_clk           (W_wclk_i),

      .wr_en            (W_wren_i),

      .din              (W_data_i),

      .full             (W_full),

      .overflow         (),

      .prog_full        (),

      .wr_data_count    (),

      .almost_full      (),

      .wr_ack           (),

      .wr_rst_busy      (),

      .rd_clk           (ui_clk),

      .rd_en            (fdma_wvalid),

      .dout             (fdma_wdata),

      .empty            (),

      .underflow        (),

      .rd_rst_busy      (W_rbusy),

      .prog_empty       (),

      .rd_data_count    (W_rcnt),

      .almost_empty     (),

      .data_valid       (W_dvalid),

      .sleep            (1'b0),

      .injectsbiterr    (1'b0),

      .injectdbiterr    (1'b0),

      .sbiterr          (),

      .dbiterr          ()

 

);

end

else begin : FDMA_WRITE_DISABLE

 

//----------fdma signals write-------       

assign fdma_waddr = 0;

assign fdma_wareq = 0;

assign fdma_wsize = 0;                                    

assign fdma_wdata = 0;

assign fdma_wready = 0;

assign fdma_wirq = 0; 

assign W_full = 0;

 

end

endgenerate

 

generate  if(ENABLE_READ == 1)begin : FDMA_READ// 通过设置通道使能,可以优化代码的利用率

localparam RYBUF_SIZE           = (R_BUFSIZE - 1'b1); //读通道需要完成多少次XSIZE操作

localparam RY_BURST_TIMES       = (R_YSIZE*R_XDIV); //读通道需要完成的FDMA burst 操作次数,XDIV用于把XSIZE分解多次传输

localparam FDMA_RX_BURST        = (R_XSIZE*R_DATAWIDTH/AXI_DATA_WIDTH)/R_XDIV; //FDMA BURST 一次的大小

localparam RX_BURST_ADDR_INC    = (R_XSIZE*(R_DATAWIDTH/8))/R_XDIV; //FDMA每次burst之后的地址增加

localparam RX_LAST_ADDR_INC     = (R_XSTRIDE-R_XSIZE)*(R_DATAWIDTH/8) + RX_BURST_ADDR_INC; //根据stride值计算出来最后一次地址

 

localparam RFIFO_DEPTH = R_BUFDEPTH*R_DATAWIDTH/AXI_DATA_WIDTH;//R_BUFDEPTH/(AXI_DATA_WIDTH/R_DATAWIDTH);

localparam R_WR_DATA_COUNT_WIDTH = clog2(RFIFO_DEPTH)+1; //读通道FIFO 输入部分深度

localparam R_RD_DATA_COUNT_WIDTH = clog2(R_BUFDEPTH)+1; //写通道FIFO输出部分深度

 

assign                                  fdma_rready = 1'b1;

reg                                     fdma_rareq_r= 1'b0;

reg                                     R_FIFO_Rst=0; 

wire                                    R_FS;

reg [1 :0]                              R_MS=0; 

reg [R_DSIZEBITS-1'b1:0]                R_addr=0; 

reg [15:0]                              R_bcnt=0; 

wire[R_WR_DATA_COUNT_WIDTH-1'b1 :0]     R_wcnt;

reg                                     R_REQ=0; 

reg [5 :0]                              rirq_dly_cnt =0;

reg [3 :0]                              rdiv_cnt =0;

reg [7 :0]                              rrst_cnt =0;

reg [7 :0]                              fmda_rbufn;

assign fdma_rsize = FDMA_RX_BURST;

assign fdma_rirq = (rirq_dly_cnt>0);

 

assign fdma_raddr = R_BASEADDR + {fmda_rbufn,R_addr};//由于FPGA逻辑做乘法比较复杂,因此通过设置高位地址实现缓存设置

 

reg [1:0] R_MS_r =0;

always @(posedge ui_clk) R_MS_r <= R_MS;

 

//每次FDMA DBUF 完成一帧数据传输后,产生中断,这个中断持续60个周期的uiclk,这里的延迟必须足够ZYNQ IP核识别到这个中断

always @(posedge ui_clk) begin

    if(ui_rstn == 1'b0)begin

        rirq_dly_cnt <= 6'd0;

        fmda_rbuf <=0;

    end

    else if((R_MS_r == S_DATA2) && (R_MS == S_IDLE))begin

        rirq_dly_cnt <= 60;

        fmda_rbuf <= fmda_rbufn;

    end

    else if(rirq_dly_cnt >0)

        rirq_dly_cnt <= rirq_dly_cnt - 1'b1;

end

 

//帧同步,对于视频有效

fs_cap #

(

.VIDEO_ENABLE(VIDEO_ENABLE)

)

fs_cap_R0

(

  .clk_i(ui_clk),

  .rstn_i(ui_rstn),

  .vs_i(R_FS_i),

  .fs_cap_o(R_FS)

);

 

assign fdma_rareq = fdma_rareq_r;

 

//读通道状态机,采用4个状态值描述

 always @(posedge ui_clk) begin

   if(!ui_rstn)begin

        R_MS          <= S_IDLE;

        R_FIFO_Rst   <= 0;

        R_addr       <= 0;

        R_sync_cnt_o <= 0;

        R_bcnt       <= 0;

        rrst_cnt     <= 0;

        rdiv_cnt      <= 0;

        fmda_rbufn    <= 0;

        fdma_rareq_r  <= 1'd0;

    end   

    else begin

      case(R_MS) //帧同步,对于非视频数据一般常量为1

        S_IDLE:begin

          R_addr <= 0;

          R_bcnt <= 0;

          rrst_cnt <= 0;

          rdiv_cnt <=0;

          if(R_FS) begin

            R_MS <= S_RST;

            if(R_sync_cnt_o < RYBUF_SIZE) //输出帧同步计数器,当需要用读通道做帧同步的时候使用

                R_sync_cnt_o <= R_sync_cnt_o + 1'b1; 

            else 

                R_sync_cnt_o <= 0;  

          end

       end

       S_RST:begin//帧同步,对于非视频数据直接跳过,对于视频数据,会同步每一帧,并且复位数据FIFO

           fmda_rbufn <= R_buf_i;

           rrst_cnt <= rrst_cnt + 1'b1;

           if((VIDEO_ENABLE == 1) && (rrst_cnt < 40))

                R_FIFO_Rst <= 1;

           else if((VIDEO_ENABLE == 1) && (rrst_cnt < 100))

                R_FIFO_Rst <= 0;

           else if(fdma_rirq == 1'b0) begin

                R_MS <= S_DATA1;

           end

       end

       S_DATA1:begin 

         if(fdma_rbusy == 1'b0 && R_REQ)begin

            fdma_rareq_r  <= 1'b1;  

         end

         else if(fdma_rbusy == 1'b1) begin

            fdma_rareq_r  <= 1'b0;

            R_MS    <= S_DATA2;

         end         

        end

        S_DATA2:begin //写有效数据

            if(fdma_rbusy == 1'b0)begin

                if(R_bcnt == RY_BURST_TIMES - 1'b1) //判断是否传输完毕

                    R_MS <= S_IDLE;

                else begin

                    if(rdiv_cnt < R_XDIV - 1'b1)begin//如果对XSIZE做了分次传输,一个XSIZE也需要XDIV次FDMA完成传输

                        R_addr <= R_addr +  RX_BURST_ADDR_INC;  //计算地址增量

                        rdiv_cnt <= rdiv_cnt + 1'b1;

                     end

                    else begin

                        R_addr <= R_addr + RX_LAST_ADDR_INC; //计算最后一次地址增量,最后一次地址根据stride 计算

                        rdiv_cnt <= 0;

                    end

                    R_bcnt <= R_bcnt + 1'b1;

                    R_MS    <= S_DATA1;

                end 

            end

         end

         default:R_MS <= S_IDLE;

      endcase

   end

end 

 

//写通道的数据FIFO,采用了原语调用xpm_fifo_async fifo,当FIFO存储的数据阈值达到一定量,一般满足一次FDMA的burst即可发出请求

wire R_wbusy;

always@(posedge ui_clk)      

     R_REQ  <= (R_wcnt < FDMA_RX_BURST - 2)&&(~R_wbusy);

 

xpm_fifo_async # (

  .FIFO_MEMORY_TYPE          ("auto"),           //string; "auto", "block", or "distributed";

  .ECC_MODE                  ("no_ecc"),         //string; "no_ecc" or "en_ecc";

  .RELATED_CLOCKS            (0),                //positive integer; 0 or 1

  .FIFO_WRITE_DEPTH          (RFIFO_DEPTH),     //positive integer

  .WRITE_DATA_WIDTH          (AXI_DATA_WIDTH),               //positive integer

  .WR_DATA_COUNT_WIDTH       (R_WR_DATA_COUNT_WIDTH),               //positive integer

  .PROG_FULL_THRESH          (20),               //positive integer

  .FULL_RESET_VALUE          (0),                //positive integer; 0 or 1

  .USE_ADV_FEATURES          ("0707"),           //string; "0000" to "1F1F"; 

  .READ_MODE                 ("fwft"),            //string; "std" or "fwft";

  .FIFO_READ_LATENCY         (0),                //positive integer;

  .READ_DATA_WIDTH           (R_DATAWIDTH),               //positive integer

  .RD_DATA_COUNT_WIDTH       (R_RD_DATA_COUNT_WIDTH),               //positive integer

  .PROG_EMPTY_THRESH         (10),               //positive integer

  .DOUT_RESET_VALUE          ("0"),              //string

  .CDC_SYNC_STAGES           (2),                //positive integer

  .WAKEUP_TIME               (0)                 //positive integer; 0 or 2;

) xpm_fifo_R_inst (

      .rst              ((ui_rstn == 1'b0) || (W_FIFO_Rst == 1'b1)),

      .wr_clk           (ui_clk),

      .wr_en            (fdma_rvalid),

      .din              (fdma_rdata),

      .full             (),

      .overflow         (),

      .prog_full        (),

      .wr_data_count    (R_wcnt),

      .almost_full      (),

      .wr_ack           (),

      .wr_rst_busy      (R_wbusy),

      .rd_clk           (R_rclk_i),

      .rd_en            (R_rden_i),

      .dout             (R_data_o),

      .empty            (R_empty),

      .underflow        (),

      .rd_rst_busy      (),

      .prog_empty       (),

      .rd_data_count    (),

      .almost_empty     (),

      .data_valid       (),

      .sleep            (1'b0),

      .injectsbiterr    (1'b0),

      .injectdbiterr    (1'b0),

      .sbiterr          (),

      .dbiterr          ()

 

);

end

else begin : FDMA_READ_DISABLE

     

assign fdma_raddr = 0;

assign fdma_rareq = 0;

assign fdma_rsize = 0;                                    

assign fdma_rdata = 0;

assign fdma_rready = 0;

assign fdma_rirq = 0; 

assign R_empty = 1'b0;

 

end

endgenerate

 

endmodule

2:fs_cap.v

/*******************************MILIANKE*******************************

*Company : MiLianKe Electronic Technology Co., Ltd.

*WebSite:https://www.milianke.com

*TechWeb:https://www.uisrc.com

*tmall-shop:https://milianke.tmall.com

*jd-shop:https://milianke.jd.com

*taobao-shop1: https://milianke.taobao.com

*Create Date: 2021/10/15

*Module Name:fs_cap

*File Name:fs_cap.v

*Description: 

*The reference demo provided by Milianke is only used for learning. 

*We cannot ensure that the demo itself is free of bugs, so users 

*should be responsible for the technical problems and consequences

*caused by the use of their own products.

*Copyright: Copyright (c) MiLianKe

*All rights reserved.

*Revision: 1.0

*Signal description

*1) _i input

*2) _o output

*3) _n activ low

*4) _dg debug signal 

*5) _r delay or register

*6) _s state mechine

*********************************************************************/

`timescale 1ns / 1ps

 

module fs_cap#(

parameter  integer  VIDEO_ENABLE   = 1

)

(

input  clk_i,

input  rstn_i,

input  vs_i,

output reg fs_cap_o

);

      

reg[4:0]CNT_FS   = 6'b0;

reg[4:0]CNT_FS_n = 6'b0;

reg     FS       = 1'b0;

//异步信号定义,告诉工具异步信号不用分析时序

(* ASYNC_REG = "TRUE" *)   reg vs_i_r1;

(* ASYNC_REG = "TRUE" *)   reg vs_i_r2;

(* ASYNC_REG = "TRUE" *)   reg vs_i_r3;

(* ASYNC_REG = "TRUE" *)   reg vs_i_r4;

//异步转同步

always@(posedge clk_i) begin

      vs_i_r1 <= vs_i;

      vs_i_r2 <= vs_i_r1;

      vs_i_r3 <= vs_i_r2;

      vs_i_r4 <= vs_i_r3;

end

 

//同步vs信号,只有当使能了VIDEO_ENABLE才会启作用

always@(posedge clk_i) begin

   if(!rstn_i)begin

      fs_cap_o <= 1'd0;

   end

   else if(VIDEO_ENABLE == 1)begin //当VIDEO_ENABLE=1,vs的上升沿有效,用于视频同步

      if({vs_i_r4,vs_i_r3} == 2'b01)begin

         fs_cap_o <= 1'b1;

      end

      else begin

         fs_cap_o <= 1'b0;

      end

   end 

   else begin//当VIDEO_ENABLE=0,直接寄存一次vs_i_r4

         fs_cap_o <= vs_i_r4;

   end

end

          

endmodule

3:uidbufirq.v

这个部分的功能只有在PS需要获取中断后的帧缓存通道才会用到,PS通过axi-lite接口可以读取到寄存器的值。

关于更多AXI4总线相关知识可以阅读"3-2-02_axi_bus_7035fa.pdf" 这个章节,这个章节专讲AXI4总线,其中也详细讲解了FDMA的代码分析。(注意: 7035fa代表了zynq系列中MZ7035FA这个子型号)

    这里主要看代码的最后,根据中断信号寄存内存的中断号

// 当写中断产生的时候,寄存当前的帧缓存号到fdma_wbfu_irq寄存器

always @(posedge S_AXI_ACLK) fdma_wirq_r <= fdma_wirq;

 

always @(posedge S_AXI_ACLK)begin

if( S_AXI_ARESETN == 1'b0)

    fdma_wbuf_irq <= 0;

else if(fdma_wirq_r == 1'b0 & fdma_wirq == 1'b1) 

    fdma_wbuf_irq <= fdma_wbuf; 

end

 

// 当读中断产生的时候,寄存当前的帧缓存号到fdma_wbfu_irq寄存器

always @(posedge S_AXI_ACLK) fdma_rirq_r <= fdma_rirq;

 

always @(posedge S_AXI_ACLK)begin

if( S_AXI_ARESETN == 1'b0)

    fdma_rbuf_irq <= 0;

else if(fdma_rirq_r == 1'b0 & fdma_rirq == 1'b1) 

    fdma_rbuf_irq <= fdma_rbuf; 

end

 

// User logic ends

endmodule

标签:begin,end,fdma,IP,cnt,FDMA,3.0,integer,dbuf
From: https://www.cnblogs.com/milianke/p/17936187.html

相关文章

  • 3-1-02AXI4-FULL-uiFDMA IP仿真验证
    软件版本:vitis2021.1(vivado2021.1)操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!2.1概述本文试验中对前面编写的FDMAIP进行仿真验证。2.2saxi_full_memIP介绍这个IP的源码可以基于XILINX提供的ax......
  • 3-1-01 AXI4-FULL-MASTER IP FDMA介绍
    件版本:vitis2021.1(vivado2021.1)操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!1.1概述    FDMA是米联客的基于AXI4总线协议定制的一个DMA控制器。本文对AXI4-FULL总线接口进行了封装,同时定义了简......
  • IP: dns-lookup : 查询域名的公网IP地址 解决 DNS域名解析绑架的问题例如访问 raw.git
    示例:https://github.com/orgs/community/discussions/42655https://github.com/mwaskom/seaborn-data/blob/2b29313169bf8dfa77d8dc930f7bd3eba559a906/dataset_names.txthttps://www.ip-lookup.org/dns-lookup/raw.githubusercontent.comIPDetailsDomain:Raw.githubuser......
  • IPTV SQM的项目总结
    本文于2015年底完成,发布在个人博客网站上,标题为《项目总结--纪念我参与过的IPTVSQM项目》。考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。时间很快,离开SQM团队已接近10个月,对于参与了5年的项目,很早就想写些什么来纪念;现在终于找到了时间,用自己......
  • JavaScript的apply、call、bind方法
    JavaScript的apply、call、bind方法概述简述这三个方法存在一定的迷惑性,而且对于刚看ES6的人来说,十分难理解,这里为了以后我可能会复习到这个知识点,做出详解。总的来说,这三个方法都是将某某某(某01)绑定在某某某(某02)上,然后执行这个被绑定的某某某(某01),或者单纯就是绑定不执行。详......
  • 饭卡(容器)3.0
    #include<iostream>#include<vector>usingnamespacestd;#definelist1000structa{stringname;intid;intage;stringClass;}index;voidMAIN(){cout<<"欢迎使用学生管理系统"<<endl<<"1.......
  • Apipost一键压测参数化功能详解
    最近更新中Apipost对UI页面进行了一些调整,另外一键压测功能支持参数化!本篇文章将详细介绍这些改动!API调试页面的细节改动在请求区填入请求参数或脚本时会有相应的标识如在Query中填入多个参数时上方会展示数量在预、后执行脚本中写入脚本上方会有绿色小点标识一键压测参数化一键压......
  • Juniper日常维护命令
    关闭1、日常show操作#show查看所有配置#show|displayset查看set格式的所有配置#showsystem|displayset查看set格式的system层级配置#showsystemlogin|displayset查看set格式的system层级下的login层级配置#runshowversion#runshowroute......
  • 35 VIVADO用户IP软件总线接口封装
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述使用VIVADO基于图形化创新编程FPGA的方式可以大大提高FPGA编程效率,但是前提是把代码打包成图形化的IP......
  • Apipost一键压测参数化功能详解
    最近更新中Apipost对UI页面进行了一些调整,另外一键压测功能支持参数化!本篇文章将详细介绍这些改动!API调试页面的细节改动在请求区填入请求参数或脚本时会有相应的标识如在Query中填入多个参数时上方会展示数量在预、后执行脚本中写入脚本上方会有绿色小点标识 一键压测参......