自定义的FDMA Brust Length,能够接收比实际Axi Brust Lengtht更多的数据,这是通过这个模块实现的:
即通过设置的Axi总线最大brust len后,通过对比其位宽过一位的数据是否为高,来判断需求的brust长度是否是否超过了max brust len,如果超过了则进行截断。。
FDMA的一次读写操作的分界线是一次FDMA Brust Length的完成,其中可以涵盖多个Axi Brust Length。
- //fdma write data burst len counter----------------------------------
- reg wburst_len_req = 1'b0;
- reg [15:0] fdma_wleft_cnt =16'd0;
-
- // wburst_len_req信号是自动管理每次axi需要burst的长度
- always @(posedge M_AXI_ACLK)
- wburst_len_req <= fdma_wstart|axi_wlast;
-
- // fdma_wleft_cnt用于记录一次FDMA剩余需要传输的数据数量
- always @(posedge M_AXI_ACLK)
- if( fdma_wstart )begin
- wfdma_cnt <= 1'd0;
- fdma_wleft_cnt <= I_fdma_wsize;
- end
- else if(w_next)begin
- wfdma_cnt <= wfdma_cnt + 1'b1;
- fdma_wleft_cnt <= (I_fdma_wsize - 1'b1) - wfdma_cnt;
- end
- //当最后一个数据的时候,产生fdma_wend信号代表本次fdma传输结束
- assign fdma_wend = w_next && (fdma_wleft_cnt == 1 );
- //一次axi最大传输的长度是256因此当大于256,自动拆分多次传输
- always @(posedge M_AXI_ACLK)begin
- if(M_AXI_ARESETN == 1'b0)begin
- wburst_len <= 1;
- end
- else if(wburst_len_req)begin
- if(fdma_wleft_cnt[15:MAX_BURST_LEN_SIZE] >0) //当你希望FDMA提供的Brust长度超过了所配置的Axi brust长度时,brust长度设置为所配置Axi的最大brust长度
- wburst_len <= M_AXI_MAX_BURST_LEN;
- else
- wburst_len <= fdma_wleft_cnt[MAX_BURST_LEN_SIZE-1:0]; //否则按照你配置的来
- end
- else wburst_len <= wburst_len;
- end
-
- `timescale 1ns / 1ns
-
- /*******************************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: 2023/03/23
- *Module Name:
- *File Name:
- *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: 3.1
- *Signal description
- *1) I_ input
- *2) O_ output
- *3) IO_ input output
- *4) S_ system internal signal
- *5) _n activ low
- *6) _dg debug signal
- *7) _r delay or register
- *8) _s state mechine
- *********************************************************************/
-
- /*********uiFDMA(AXI-FAST DMA Controller)基于AXI总线的自定义内存控制器***********
- --版本号3.1
- --1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨,读写对称
- --2.fdma控制信号,简化了AXI总线的控制,根据I_fdma_wsize和I_fdma_rsize可以自动完成AXI总线的控制,完成数据的搬运
- *********************************************************************/
-
- module uiFDMA#
- (
- parameter integer M_AXI_ID_WIDTH = 3 , //ID,demo中没用到
- parameter integer M_AXI_ID = 0 , //ID,demo中没用到
- parameter integer M_AXI_ADDR_WIDTH = 32 ,//内存地址位宽
- parameter integer M_AXI_DATA_WIDTH = 128 ,//AXI总线的数据位宽
- parameter integer M_AXI_MAX_BURST_LEN = 64 //AXI总线的burst 大小,对于AXI4,支持任意长度,对于AXI3以下最大16
- )
- (
- input wire [M_AXI_ADDR_WIDTH-1 : 0] I_fdma_waddr ,//FDMA写通道地址
- input I_fdma_wareq ,//FDMA写通道请求
- input wire [15 : 0] I_fdma_wsize ,//FDMA写通道一次FDMA的传输大小
- output O_fdma_wbusy ,//FDMA处于BUSY状态,AXI总线正在写操作
-
- input wire [M_AXI_DATA_WIDTH-1 :0] I_fdma_wdata ,//FDMA写数据
- output wire O_fdma_wvalid ,//FDMA 写有效
- input wire I_fdma_wready ,//FDMA写准备好,用户可以写数据
-
- input wire [M_AXI_ADDR_WIDTH-1 : 0] I_fdma_raddr ,// FDMA读通道地址
- input I_fdma_rareq ,// FDMA读通道请求
- input wire [15 : 0] I_fdma_rsize ,// FDMA读通道一次FDMA的传输大小
- output O_fdma_rbusy ,// FDMA处于BUSY状态,AXI总线正在读操作
-
- output wire [M_AXI_DATA_WIDTH-1 :0] O_fdma_rdata ,// FDMA读数据
- output wire O_fdma_rvalid ,// FDMA 读有效
- input wire I_fdma_rready ,// FDMA读准备好,用户可以读数据
-
- //以下为AXI总线信号
- input wire M_AXI_ACLK ,
- input wire M_AXI_ARESETN ,
- output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_AWID ,
- output wire [M_AXI_ADDR_WIDTH-1 : 0] M_AXI_AWADDR ,
- output wire [7 : 0] M_AXI_AWLEN ,
- output wire [2 : 0] M_AXI_AWSIZE ,
- output wire [1 : 0] M_AXI_AWBURST ,
- output wire M_AXI_AWLOCK ,
- output wire [3 : 0] M_AXI_AWCACHE ,
- output wire [2 : 0] M_AXI_AWPROT ,
- output wire [3 : 0] M_AXI_AWQOS ,
- output wire M_AXI_AWVALID ,
- input wire M_AXI_AWREADY ,
- output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_WID ,
- output wire [M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA ,
- output wire [M_AXI_DATA_WIDTH/8-1 : 0] M_AXI_WSTRB ,
- output wire M_AXI_WLAST ,
- output wire M_AXI_WVALID ,
- input wire M_AXI_WREADY ,
- input wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_BID ,
- input wire [1 : 0] M_AXI_BRESP ,
- input wire M_AXI_BVALID ,
- output wire M_AXI_BREADY ,
- output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_ARID ,
-
- output wire [M_AXI_ADDR_WIDTH-1 : 0] M_AXI_ARADDR ,
- output wire [7 : 0] M_AXI_ARLEN ,
- output wire [2 : 0] M_AXI_ARSIZE ,
- output wire [1 : 0] M_AXI_ARBURST ,
- output wire M_AXI_ARLOCK ,
- output wire [3 : 0] M_AXI_ARCACHE ,
- output wire [2 : 0] M_AXI_ARPROT ,
- output wire [3 : 0] M_AXI_ARQOS ,
- output wire M_AXI_ARVALID ,
- input wire M_AXI_ARREADY ,
- input wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_RID ,
- input wire [M_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA ,
- input wire [1 : 0] M_AXI_RRESP ,
- input wire M_AXI_RLAST ,
- input wire M_AXI_RVALID ,
- output wire M_AXI_RREADY
- );
-
- //计算数据位宽
- function integer clogb2 (input integer bit_depth);
- begin
- for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
- bit_depth = bit_depth >> 1;
- end
- endfunction
-
- localparam AXI_BYTES = M_AXI_DATA_WIDTH/8;
- localparam [3:0] MAX_BURST_LEN_SIZE = clogb2(M_AXI_MAX_BURST_LEN -1);
-
- //fdma axi write----------------------------------------------
- reg [M_AXI_ADDR_WIDTH-1 : 0] axi_awaddr =0; //AXI4 写地址
- reg axi_awvalid = 1'b0; //AXI4 写地有效
- wire [M_AXI_DATA_WIDTH-1 : 0] axi_wdata ; //AXI4 写数据
- wire axi_wlast ; //AXI4 写LAST信号
- reg axi_wvalid = 1'b0; //AXI4 写数据有效
- wire w_next= (M_AXI_WVALID & M_AXI_WREADY);//当valid ready信号都有效,代表AXI4数据传输有效
- reg [8 :0] wburst_len = 1 ; //写传输的axi burst长度,代码会自动计算每次axi传输的burst 长度
- reg [8 :0] wburst_cnt = 0 ; //每次axi bust的计数器
- reg [15:0] wfdma_cnt = 0 ; //fdma的写数据计数器
- reg axi_wstart_locked =0; //axi 传输进行中,lock住,用于时序控制
- wire [15:0] axi_wburst_size = wburst_len * AXI_BYTES; //axi 传输的地址长度计算
-
- assign M_AXI_AWID = M_AXI_ID; //写地址ID,用来标志一组写信号, M_AXI_ID是通过参数接口定义
- assign M_AXI_AWADDR = axi_awaddr;
- assign M_AXI_AWLEN = wburst_len - 1;//AXI4 burst的长度
- assign M_AXI_AWSIZE = clogb2(AXI_BYTES-1);
- assign M_AXI_AWBURST = 2'b01;//AXI4的busr类型INCR模式,地址递增
- assign M_AXI_AWLOCK = 1'b0;
- assign M_AXI_AWCACHE = 4'b0010;//不使用cache,不使用buffer
- assign M_AXI_AWPROT = 3'h0;
- assign M_AXI_AWQOS = 4'h0;
- assign M_AXI_AWVALID = axi_awvalid;
- assign M_AXI_WDATA = axi_wdata;
- assign M_AXI_WSTRB = {(AXI_BYTES){1'b1}};//设置所有的WSTRB为1代表传输的所有数据有效
- assign M_AXI_WLAST = axi_wlast;
- assign M_AXI_WVALID = axi_wvalid & I_fdma_wready;//写数据有效,这里必须设置I_fdma_wready有效
- assign M_AXI_BREADY = 1'b1;
- //----------------------------------------------------------------------------
- //AXI4 FULL Write
- assign axi_wdata = I_fdma_wdata;
- assign O_fdma_wvalid = w_next;
- reg fdma_wstart_locked = 1'b0;
- wire fdma_wend;
- wire fdma_wstart;
- assign O_fdma_wbusy = fdma_wstart_locked ;
- //在整个写过程中fdma_wstart_locked将保持有效,直到本次FDMA写结束
- always @(posedge M_AXI_ACLK)
- if(M_AXI_ARESETN == 1'b0 || fdma_wend == 1'b1 )
- fdma_wstart_locked <= 1'b0;
- else if(fdma_wstart)
- fdma_wstart_locked <= 1'b1;
- //产生fdma_wstart信号,整个信号保持1个 M_AXI_ACLK时钟周期
- assign fdma_wstart = (fdma_wstart_locked == 1'b0 && I_fdma_wareq == 1'b1);
-
- //AXI4 write burst lenth busrt addr ------------------------------
- //当fdma_wstart信号有效,代表一次新的FDMA传输,首先把地址本次fdma的burst地址寄存到axi_awaddr作为第一次axi burst的地址。如果fdma的数据长度大于256,那么当axi_wlast有效的时候,自动计算下次axi的burst地址
- always @(posedge M_AXI_ACLK)
- if(fdma_wstart)
- axi_awaddr <= I_fdma_waddr;
- else if(axi_wlast == 1'b1)
- axi_awaddr <= axi_awaddr + axi_wburst_size ;
- //AXI4 write cycle -----------------------------------------------
- //axi_wstart_locked_r1, axi_wstart_locked_r2信号是用于时序同步
- reg axi_wstart_locked_r1 = 1'b0, axi_wstart_locked_r2 = 1'b0;
- always @(posedge M_AXI_ACLK)begin
- axi_wstart_locked_r1 <= axi_wstart_locked;
- axi_wstart_locked_r2 <= axi_wstart_locked_r1;
- end
- // axi_wstart_locked的作用代表一次axi写burst操作正在进行中。
- always @(posedge M_AXI_ACLK)
- if((fdma_wstart_locked == 1'b1) && axi_wstart_locked == 1'b0)
- axi_wstart_locked <= 1'b1;
- else if(axi_wlast == 1'b1 || fdma_wstart == 1'b1)
- axi_wstart_locked <= 1'b0;
-
- //AXI4 addr valid and write addr-----------------------------------
- always @(posedge M_AXI_ACLK)
- if((axi_wstart_locked_r1 == 1'b1) && axi_wstart_locked_r2 == 1'b0)
- axi_awvalid <= 1'b1;
- else if((axi_wstart_locked == 1'b1 && M_AXI_AWREADY == 1'b1)|| axi_wstart_locked == 1'b0)
- axi_awvalid <= 1'b0;
- //AXI4 write data---------------------------------------------------
- always @(posedge M_AXI_ACLK)
- if((axi_wstart_locked_r1 == 1'b1) && axi_wstart_locked_r2 == 1'b0)
- axi_wvalid <= 1'b1;
- else if(axi_wlast == 1'b1 || axi_wstart_locked == 1'b0)
- axi_wvalid <= 1'b0;//
- //AXI4 write data burst len counter----------------------------------
- always @(posedge M_AXI_ACLK)
- if(axi_wstart_locked == 1'b0)
- wburst_cnt <= 'd0;
- else if(w_next)
- wburst_cnt <= wburst_cnt + 1'b1;
-
- assign axi_wlast = (w_next == 1'b1) && (wburst_cnt == M_AXI_AWLEN);
- //fdma write data burst len counter----------------------------------
- reg wburst_len_req = 1'b0;
- reg [15:0] fdma_wleft_cnt =16'd0;
-
- // wburst_len_req信号是自动管理每次axi需要burst的长度
- always @(posedge M_AXI_ACLK)
- wburst_len_req <= fdma_wstart|axi_wlast;
-
- // fdma_wleft_cnt用于记录一次FDMA剩余需要传输的数据数量
- always @(posedge M_AXI_ACLK)
- if( fdma_wstart )begin
- wfdma_cnt <= 1'd0;
- fdma_wleft_cnt <= I_fdma_wsize;
- end
- else if(w_next)begin
- wfdma_cnt <= wfdma_cnt + 1'b1;
- fdma_wleft_cnt <= (I_fdma_wsize - 1'b1) - wfdma_cnt;
- end
- //当最后一个数据的时候,产生fdma_wend信号代表本次fdma传输结束
- assign fdma_wend = w_next && (fdma_wleft_cnt == 1 );
- //一次axi最大传输的长度是256因此当大于256,自动拆分多次传输
- always @(posedge M_AXI_ACLK)begin
- if(M_AXI_ARESETN == 1'b0)begin
- wburst_len <= 1;
- end
- else if(wburst_len_req)begin
- if(fdma_wleft_cnt[15:MAX_BURST_LEN_SIZE] >0) //当你希望FDMA提供的Brust长度超过了所配置的Axi brust长度时,brust长度设置为所配置Axi的最大brust长度
- wburst_len <= M_AXI_MAX_BURST_LEN;
- else
- wburst_len <= fdma_wleft_cnt[MAX_BURST_LEN_SIZE-1:0]; //否则按照你配置的来
- end
- else wburst_len <= wburst_len;
- end
-
-
-
- //fdma axi read----------------------------------------------
- reg [M_AXI_ADDR_WIDTH-1 : 0] axi_araddr =0 ; //AXI4 读地址
- reg axi_arvalid =1'b0; //AXI4读地有效
- wire axi_rlast ; //AXI4 读LAST信号
- reg axi_rready = 1'b0;//AXI4读准备好
- wire r_next = (M_AXI_RVALID && M_AXI_RREADY);// 当valid ready信号都有效,代表AXI4数据传输有效
- reg [8 :0] rburst_len = 1 ; //读传输的axi burst长度,代码会自动计算每次axi传输的burst 长度
- reg [8 :0] rburst_cnt = 0 ; //每次axi bust的计数器
- reg [15:0] rfdma_cnt = 0 ; //fdma的读数据计数器
- reg axi_rstart_locked =0; //axi 传输进行中,lock住,用于时序控制
- wire [15:0] axi_rburst_size = rburst_len * AXI_BYTES; //axi 传输的地址长度计算
-
- assign M_AXI_ARID = M_AXI_ID; //读地址ID,用来标志一组写信号, M_AXI_ID是通过参数接口定义
- assign M_AXI_ARADDR = axi_araddr;
- assign M_AXI_ARLEN = rburst_len - 1; //AXI4 burst的长度
- assign M_AXI_ARSIZE = clogb2((AXI_BYTES)-1);
- assign M_AXI_ARBURST = 2'b01; //AXI4的busr类型INCR模式,地址递增
- assign M_AXI_ARLOCK = 1'b0; //不使用cache,不使用buffer
- assign M_AXI_ARCACHE = 4'b0010;
- assign M_AXI_ARPROT = 3'h0;
- assign M_AXI_ARQOS = 4'h0;
- assign M_AXI_ARVALID = axi_arvalid;
- assign M_AXI_RREADY = axi_rready&&I_fdma_rready; //读数据准备好,这里必须设置I_fdma_rready有效
- assign O_fdma_rdata = M_AXI_RDATA;
- assign O_fdma_rvalid = r_next;
-
- //AXI4 FULL Read-----------------------------------------
-
- reg fdma_rstart_locked = 1'b0;
- wire fdma_rend;
- wire fdma_rstart;
- assign O_fdma_rbusy = fdma_rstart_locked ;
- //在整个读过程中fdma_rstart_locked将保持有效,直到本次FDMA写结束
- always @(posedge M_AXI_ACLK)
- if(M_AXI_ARESETN == 1'b0 || fdma_rend == 1'b1)
- fdma_rstart_locked <= 1'b0;
- else if(fdma_rstart)
- fdma_rstart_locked <= 1'b1;
- //产生fdma_rstart信号,整个信号保持1个 M_AXI_ACLK时钟周期
- assign fdma_rstart = (fdma_rstart_locked == 1'b0 && I_fdma_rareq == 1'b1);
- //AXI4 read burst lenth busrt addr ------------------------------
- //当fdma_rstart信号有效,代表一次新的FDMA传输,首先把地址本次fdma的burst地址寄存到axi_araddr作为第一次axi burst的地址。如果fdma的数据长度大于256,那么当axi_rlast有效的时候,自动计算下次axi的burst地址
- always @(posedge M_AXI_ACLK)
- if(fdma_rstart == 1'b1)
- axi_araddr <= I_fdma_raddr;
- else if(axi_rlast == 1'b1)
- axi_araddr <= axi_araddr + axi_rburst_size ;
- //AXI4 r_cycle_flag-------------------------------------
- //axi_rstart_locked_r1, axi_rstart_locked_r2信号是用于时序同步
- reg axi_rstart_locked_r1 = 1'b0, axi_rstart_locked_r2 = 1'b0;
- always @(posedge M_AXI_ACLK)begin
- axi_rstart_locked_r1 <= axi_rstart_locked;
- axi_rstart_locked_r2 <= axi_rstart_locked_r1;
- end
- // axi_rstart_locked的作用代表一次axi读burst操作正在进行中。
- always @(posedge M_AXI_ACLK)
- if((fdma_rstart_locked == 1'b1) && axi_rstart_locked == 1'b0)
- axi_rstart_locked <= 1'b1;
- else if(axi_rlast == 1'b1 || fdma_rstart == 1'b1)
- axi_rstart_locked <= 1'b0;
- //AXI4 addr valid and read addr-----------------------------------
- always @(posedge M_AXI_ACLK)
- if((axi_rstart_locked_r1 == 1'b1) && axi_rstart_locked_r2 == 1'b0)
- axi_arvalid <= 1'b1;
- else if((axi_rstart_locked == 1'b1 && M_AXI_ARREADY == 1'b1)|| axi_rstart_locked == 1'b0)
- axi_arvalid <= 1'b0;
- //AXI4 read data---------------------------------------------------
- always @(posedge M_AXI_ACLK)
- if((axi_rstart_locked_r1 == 1'b1) && axi_rstart_locked_r2 == 1'b0)
- axi_rready <= 1'b1;
- else if(axi_rlast == 1'b1 || axi_rstart_locked == 1'b0)
- axi_rready <= 1'b0;//
- //AXI4 read data burst len counter----------------------------------
- always @(posedge M_AXI_ACLK)
- if(axi_rstart_locked == 1'b0)
- rburst_cnt <= 'd0;
- else if(r_next)
- rburst_cnt <= rburst_cnt + 1'b1;
- assign axi_rlast = (r_next == 1'b1) && (rburst_cnt == M_AXI_ARLEN);
- //fdma read data burst len counter----------------------------------
- reg rburst_len_req = 1'b0;
- reg [15:0] fdma_rleft_cnt =16'd0;
- // rburst_len_req信号是自动管理每次axi需要burst的长度
- always @(posedge M_AXI_ACLK)
- rburst_len_req <= fdma_rstart | axi_rlast;
- // fdma_rleft_cnt用于记录一次FDMA剩余需要传输的数据数量
- always @(posedge M_AXI_ACLK)
- if(fdma_rstart )begin
- rfdma_cnt <= 1'd0;
- fdma_rleft_cnt <= I_fdma_rsize;
- end
- else if(r_next)begin
- rfdma_cnt <= rfdma_cnt + 1'b1;
- fdma_rleft_cnt <= (I_fdma_rsize - 1'b1) - rfdma_cnt;
- end
- //当最后一个数据的时候,产生fdma_rend信号代表本次fdma传输结束
- assign fdma_rend = r_next && (fdma_rleft_cnt == 1 );
- //axi auto burst len caculate-----------------------------------------
- //一次axi最大传输的长度是256因此当大于256,自动拆分多次传输
- always @(posedge M_AXI_ACLK)begin
- if(M_AXI_ARESETN == 1'b0)begin
- rburst_len <= 1;
- end
- else if(rburst_len_req)begin
- if(fdma_rleft_cnt[15:MAX_BURST_LEN_SIZE] >0)
- rburst_len <= M_AXI_MAX_BURST_LEN;
- else
- rburst_len <= fdma_rleft_cnt[MAX_BURST_LEN_SIZE-1:0];
- end
- else rburst_len <= rburst_len;
- end
-
-
-
-
- //dbg_wave dbg_wave_inst
- //(
- // .trig_out_0(),
- // .data_in_0({rburst_len[7:0],rburst_cnt[8:0],fdma_rleft_cnt[15:0],I_fdma_rareq,fdma_rstart,fdma_rstart_locked,axi_rstart_locked,axi_rlast,rburst_len_req,M_AXI_ARVALID,M_AXI_ARREADY,M_AXI_RVALID,M_AXI_RREADY,M_AXI_RLAST,wburst_len[7:0],wburst_cnt[8:0],fdma_wleft_cnt[15:0],I_fdma_wareq,fdma_wstart,fdma_wstart_locked,axi_wstart_locked,axi_wlast,wburst_len_req,M_AXI_AWVALID,M_AXI_AWREADY,M_AXI_WVALID,M_AXI_WREADY,M_AXI_WLAST,M_AXI_ARESETN}),
- // .ref_clk_0(M_AXI_ACLK)
- //);
-
-
- endmodule
-
-