米联客FDMA及其控制器代码逐行讲解,全网最细,不接受反驳 对于做图像处理的兄弟来说,图像缓存是基本操作,一般是图像三帧缓存于DDR3,然后再读出显示,DDR3操作很复杂,所以Xilinx官方出了个MIG 的IP核供开发者使用,但对于像我这样的little_white来说,操作MIG 的用户接口还是不方便,所以又有了挂载AXI4总线的AXI4_MIG,这下不就简单了,直接操作AXI不就完了吗?不再需要关心底层怎么搞了。 基于此,米联客搞了一个叫做FDMA的东西,实质就是一个AXI4_FULL的主机总线,即使有了FDMA还不行,还得有控制图像读写发热控制器,米联客都给出了源码,也给了文档,但无奈,米联客的代码虽然写得精简漂亮,但文档写得确实一般,加之代码的有些变量命名也不太恰当,使得像我这样的little_white有些云雾缭绕 所以我对FDMA及其控制器的源码进行了优化,现在逐行解读: FDMA部分:
module uiFDMA#
(
parameter integer C_M_AXI_BURST_LEN = 64 , //AXI的一次读写突发长度
parameter integer C_M_AXI_ID_WIDTH = 1 ,
parameter integer C_M_AXI_ID = 0 ,
parameter integer C_M_AXI_ADDR_WIDTH = 32 ,
parameter integer C_M_AXI_DATA_WIDTH = 32 //AXI的数据位宽
)
(
//user logic
input wire pkg_wr_areq , //FDMS包写请求,一个时钟脉冲
output wire pkg_wr_last , //FDMS包写数据结尾
input wire [C_M_AXI_DATA_WIDTH-1 :0] pkg_wr_data , //FDMS包写数据包
output wire pkg_wr_en , //指示FDMS正在写数据,高有效
input wire [C_M_AXI_ADDR_WIDTH-1 :0] pkg_wr_addr , //FDMS包写数据包地址
input wire [C_M_AXI_ADDR_WIDTH-1 :0] pkg_wr_size , //FDMS包写数据包长度,应为
//C_M_AXI_BURST_LEN的整数倍
input wire pkg_rd_areq ,
output wire pkg_rd_last ,
output wire [C_M_AXI_DATA_WIDTH-1 :0] pkg_rd_data ,
output wire pkg_rd_en ,
input wire [C_M_AXI_ADDR_WIDTH-1 :0] pkg_rd_addr ,
input wire [C_M_AXI_ADDR_WIDTH-1 :0] pkg_rd_size ,
//input wire INIT_AXI_TXN ,
input wire M_AXI_ACLK ,
input wire M_AXI_ARESETN ,
output wire [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_AWID ,
output wire [C_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 [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA ,
output wire [C_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 [C_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 [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_ARID ,
output wire [C_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 [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_RID ,
input wire [C_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 integer C_TRANSACTIONS_NUM = clogb2(C_M_AXI_BURST_LEN-1);
localparam integer BURST_SIZE = C_M_AXI_BURST_LEN * C_M_AXI_DATA_WIDTH/8; //一包FDMA数据包所占的字节数(或理解为一包数据的总地址)
// AXI4LITE signals
//AXI4 internal temp signals
//write
reg [C_M_AXI_ADDR_WIDTH-1 : 0] axi_awaddr ; //写地址
reg axi_awvalid ; //写地址有效
wire [C_M_AXI_DATA_WIDTH-1 : 0] axi_wdata ; //写数据
reg axi_wlast ; //写数据结尾
reg axi_wvalid ; //写数据有效
//read
reg [C_M_AXI_ADDR_WIDTH-1 : 0] axi_araddr ; //读地址
reg axi_arvalid ; //读地址有效
reg axi_rready ; //读数据准备
// wire [C_TRANSACTIONS_NUM+2 : 0] burst_size_bytes;
assign M_AXI_AWID = C_M_AXI_ID;
assign M_AXI_AWADDR = axi_awaddr;
assign M_AXI_AWLEN = C_M_AXI_BURST_LEN - 1;
assign M_AXI_AWSIZE = clogb2((C_M_AXI_DATA_WIDTH/8)-1);
assign M_AXI_AWBURST = 2'b01;
assign M_AXI_AWLOCK = 1'b0;
assign M_AXI_AWCACHE = 4'b0010;
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 = {(C_M_AXI_DATA_WIDTH/8){1'b1}}; //每个字节都选通,都有效
assign M_AXI_WLAST = axi_wlast;
assign M_AXI_WVALID = axi_wvalid;
assign M_AXI_BREADY = axi_bready;
assign M_AXI_ARID = C_M_AXI_ID;
assign M_AXI_ARADDR = axi_araddr;
assign M_AXI_ARLEN = C_M_AXI_BURST_LEN - 1;
assign M_AXI_ARSIZE = clogb2((C_M_AXI_DATA_WIDTH/8)-1);
assign M_AXI_ARBURST = 2'b01;
assign M_AXI_ARLOCK = 1'b0;
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;
reg [7 :0 ] w_axi4_cnt ;
reg [C_M_AXI_ADDR_WIDTH-1 : 0] WR_BASE_ADDR ;
reg [C_M_AXI_ADDR_WIDTH-1 : 0] RD_BASE_ADDR ;
reg [C_M_AXI_ADDR_WIDTH-1 : 0] w_fdma_cnt ;
reg [C_M_AXI_ADDR_WIDTH-1 : 0] r_fdma_cnt ;
reg w_axi4_flag ;
reg r_axi4_addr_flag ;
reg r_axi4_data_flag;
wire w_next = (axi_wvalid && M_AXI_WREADY);
wire r_next = (M_AXI_RVALID && axi_rready);
assign pkg_wr_en = w_next; //写一包FDMAMA数据标志
assign pkg_wr_last = (w_next && w_fdma_cnt==pkg_wr_size-1); //写一包FDMAMA数据结尾
assign axi_wdata = pkg_wr_data;
assign pkg_rd_en = r_next; //读一包FDMAMA数据标志
assign pkg_rd_last = (r_next && r_fdma_cnt==pkg_rd_size-1); //读一包FDMAMA数据结尾
assign pkg_rd_data = M_AXI_RDATA;
//----------------------------------------------------------------------------
//AXI4 FULL Write
//AXI4 data is ready for axi master write to slave
reg w_fdma_flag; //这里原来不叫这个名字,由于命名不直观,我改了
//标志fdma传输过程
always @(posedge M_AXI_ACLK) begin
if(M_AXI_ARESETN == 1'b0) w_fdma_flag
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?