System verilog实战----AXI DMA的简单实现

AXI DMA

在FPGA加速器的设计中,往往会涉及到PS和PL之间的数据传输,对于zynq平台来说,最合适的数据传输方式就是通过AXI总线,同时,为了提高CPU的利用率,DMA往往是数据交互的首选。
尽管Xilinx提供了AXI DMA IP核,但是,本着练习system verilog编码的目的,以及进一步加深对AXI DMA的理解,博主打算自己手写一个AXI DMA,(目前仅作仿真用)。

两种工作模式

赛灵思的官方IP一共有两种模式,分别为Direct Register Mode,以及更加高级的Scatter/Gather Mode。
Direct Register Mode具备DMA的基本功能,除了控制寄存器和状态寄存器之外,给出源(目的)地址和传输长度之后就可以开启一次传输了。Direct Register Mode的特点(也是缺点)是配置完一次寄存器之后只能完成存储器连续地址空间的读写,如果有需求往不同地址空间搬运数据的话,那就需要重新配置寄存器开启一次新的传输。
更高级的Scatter/Gather Mode把关于传输的基本参数(比如起始地址、传输长度、包信息等)存储在存储器中,这套参数称之为Buffer Descriptor(简称BD),在工作过程中通过上面提到的SG接口来加载BD并且更新BD中的状态。从下图可以看出,Scatter/Gather Mode下的寄存器列表中没有了Address、Length相关的寄存器了,取而代之的是CURDESC、TAILDESC。
System verilog实战----AXI DMA的简单实现_第1张图片
为了实现上的简单,博主实现的是Direct Register Mode的AXI DMA,主要可配置的寄存器包括:
rd_base_addr:读起始地址
rd_total_len:读数据长度
wr_base_addr:写起始地址
wr_total_len:写数据长度
start:开始信号
done:完成信号
其中,这里的读是指AXI DMA读取DDR中的数据,写则是DMA将数据写回DDR。
在本次设计中,为了方便,还使用了system verilog的interface特性,它可以将一组接口封装为一个整体,大大简化了模块例化时端口的连接。
AXI FULL,AXI LITE以及AXI STREAM的interface定义分别如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/08/10 10:40:29
// Design Name: 
// Module Name: AXI_Interface
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

interface AXI4_FULL #(DATA_WIDTH = 32)(input logic ACLK,input logic ARESETn);
//全局信号
//写地址通道信号
logic AWVALID;
logic [31:0] AWADDR;
logic [7:0] AWLEN;
logic AWID;
logic [2:0] AWSIZE;
logic [1:0] AWBURST;
logic AWLOCK;
logic [3:0]AWCACHE;
logic [2:0]AWPROT;
logic [3:0]AWQOS;
logic AWUSER;
logic AWREADY;
//写数据通道
logic WVALID;
logic WLAST;
logic [DATA_WIDTH-1:0]WDATA;
logic [DATA_WIDTH/8-1:0]WSTRB;
logic WUSER;
logic WREADY;
//写应答通道
logic BREADY;
logic BID;
logic [1:0] BRESP;
logic BUSER;
logic BVALID;
//读地址通道
logic ARID;
logic [31:0] ARADDR;
logic [7:0] ARLEN;
logic [2:0] ARSIZE;
logic [1:0] ARBURST;
logic [1:0] ARLOCK;
logic [3:0] ARCACHE;
logic [2:0] ARPROT;
logic [3:0] ARQOS;
logic ARUSER;
logic ARVALID;
logic ARREADY;
//读数据通道
logic RREADY;
logic RID;
logic [DATA_WIDTH-1:0] RDATA;
logic [1:0] RRESP;
logic RLAST;
logic RUSER;
logic RVALID;
//modport
//master
modport MASTER
(
input ACLK,
input ARESETn,
//写地址通道信号
output AWVALID,
output AWADDR,
output AWLEN,
output AWID,
output AWSIZE,
output AWBURST,
output AWLOCK,
output AWCACHE,
output AWPROT,
output AWQOS,
output AWUSER,
input AWREADY,
//写数据通道
output WVALID,
output WLAST,
output WDATA,
output WSTRB,
output WUSER,
input WREADY,
//写应答通道
output BREADY,
input BID,
input BRESP,
input BUSER,
input BVALID,
//读地址通道
output ARID,
output ARADDR,
output ARLEN,
output ARSIZE,
output ARBURST,
output ARLOCK,
output ARCACHE,
output ARPROT,
output ARQOS,
output ARUSER,
output ARVALID,
input ARREADY,
//读数据通道
output RREADY,
input RID,
input RDATA,
input RRESP,
input RLAST,
input RUSER,
input RVALID          
);
//slave
modport SLAVE
(
input ACLK,
input ARESETn,
//写地址通道信号
input AWVALID,
input AWADDR,
input AWLEN,
input AWID,
input AWSIZE,
input AWBURST,
input AWLOCK,
input AWCACHE,
input AWPROT,
input AWQOS,
input AWUSER,
output AWREADY,
//写数据通道
input WVALID,
input WLAST,
input WDATA,
input WSTRB,
input WUSER,
output WREADY,
//写应答通道
input BREADY,
output BID,
output BRESP,
output BUSER,
output BVALID,
//读地址通道
input ARID,
input ARADDR,
input ARLEN,
input ARSIZE,
input ARBURST,
input ARLOCK,
input ARCACHE,
input ARPROT,
input ARQOS,
input ARUSER,
input ARVALID,
output ARREADY,
//读数据通道
input RREADY,
output RID,
output RDATA,
output RRESP,
output RLAST,
output RUSER,
output RVALID          
);

endinterface




`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/08/10 15:08:51
// Design Name: 
// Module Name: AXI_Lite_Interface
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

interface AXI4_LITE (input logic ACLK,input logic ARESETn);
//写地址通道
logic AWVALID;
logic [31:0]AWADDR; 
logic [2:0]AWPROT; 
logic AWREADY;
//写数据通道
logic WVALID;
logic [31:0] WDATA; 
logic [3:0] WSTRB;
logic WREADY;
//写响应通道
logic BREADY;
logic BVALID;
logic [1:0] BRESP;
//读地址通道
logic ARVALID;
logic [31:0] ARADDR; 
logic [2:0] ARPROT; 
logic ARREADY;
//读数据通道
logic RREADY;
logic RVALID;
logic [31:0] RDATA; 
logic [1:0] RRESP;
modport  MASTER (
input ACLK,ARESETn,AWREADY,WREADY,BVALID,BRESP,ARREADY,RVALID,RDATA,RRESP,
output AWVALID,AWADDR,AWPROT,WVALID,WDATA,WSTRB,BREADY,ARVALID,ARADDR,ARPROT,RREADY
); 
modport SLAVE (
output AWREADY,WREADY,BVALID,BRESP,ARREADY,RVALID,RDATA,RRESP,
input ACLK,ARESETn,AWVALID,AWADDR,AWPROT,WVALID,WDATA,WSTRB,BREADY,ARVALID,ARADDR,ARPROT,RREADY
);
endinterface 
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/08/10 18:22:07
// Design Name: 
// Module Name: AXIS_INTERFACE
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
interface AXIS #(DATA_WIDTH=128) (input logic ACLK,input logic ARESETn);
logic TREADY;
logic TVALID;
logic TLAST;
logic [DATA_WIDTH/8-1:0] TSTRB;
logic [DATA_WIDTH-1:0] TDATA;
logic TUSER;

modport MASTER (
input TREADY,ACLK,ARESETn,
output TVALID,TLAST,TSTRB,TDATA,TUSER
);

modport SLAVE (
input TVALID,TLAST,TSTRB,TDATA,TUSER,ACLK,ARESETn,
output TREADY
);

endinterface

AXI DMA的实现思路如下:
设置一个tx_buffer和rx_buffer,分别缓冲从DDR读取的数据和从PL设备读取的数据,数据的读取长度按256为单位(除了最后一次不到256个数据的),这里256即AXI FULL协议所支持的最大突发传输长度,一旦tx_buffer中有数据,AXI DMA就拉高TVALID信号,等待从设备的接收,最后,一旦rx_buffer中的数据全部收集完毕,则启动AXI FULL总线的写通道,将数据写回DDR内指定位置。
下面是AXI DMA的具体代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/08/10 17:50:21
// Design Name: 
// Module Name: AXI_DMA
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module AXI_DMA(
input logic ACLK,
input logic ARESETn,
AXI4_FULL.MASTER axi_full,                                  //MM
AXI4_LITE.SLAVE s_axilite,                              //LITE
AXIS.MASTER m_axis,                                     //STREAM
AXIS.SLAVE s_axis                                       //STREAM
    );
parameter DEPTH = 1024;
//DMA<--->MM,读
logic [31:0] rd_base_addr;
logic [31:0] rd_base_addr_r;                       //读起始地址
logic [31:0] rd_total_len;
logic [31:0] rd_total_len_r;                       //需要传输的字的个数,字为单位,可大于256
logic [31:0] rd_len;                             //当前突发传输长度
logic [31:0] rd_cnt;                             //一次传输内的计数
logic rd_continue;                               //是否继续突发读
logic [31:0] rd_transfer_num;                    //共需要多少次突发传输
logic [31:0] rd_transfer_cnt;                    //当前完成的突发读的次数
//DMA<--->,写
logic [31:0] wr_base_addr;
logic [31:0] wr_base_addr_r;                       //写起始地址
logic [31:0] wr_total_len;
logic [31:0] wr_total_len_r;                       //需要传输的总次数,可以大于256
logic [31:0] wr_len;                             //当前突发传输长度
logic [31:0] wr_cnt;                             //一次传输内的计数
logic wr_continue;                               //是否继续发起突发写
logic [31:0] wr_transfer_num;                    //共需要多少次突发传输
logic [31:0] wr_transfer_cnt;                    //当前完成的传输事务次数
logic start;
logic [31:0] start_r;
logic [31:0] start_r_ff;
logic writeback;                                 //写回数据标志
logic done;
logic [31:0] done_r;
//DMA<--->STREAM,发送数据
logic [31:0] send_cnt;
//DMA<--->STREAM,接受数据
logic [31:0] recv_cnt;
//缓冲区
(*ram_style = "block"*)logic [31:0] tx_buffer [0:DEPTH-1];               
(*ram_style = "block"*)logic [31:0] rx_buffer [0:DEPTH-1];
logic [31:0] tx_buffer_cnt;                   //记录tx_buffer内数据个数
logic [31:0] rx_buffer_cnt;                   //记录rx_buffer内数据个数

//writeback
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    writeback<=0;
else if(s_axis.TREADY&&s_axis.TVALID&&s_axis.TLAST)
    writeback<=1;
else
    writeback<=0;
//rd_continue
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    rd_continue<=0;
else if(axi_full.RVALID&&axi_full.RREADY&&axi_full.RLAST)
begin
    if(rd_transfer_cnt<rd_transfer_num-1)
        rd_continue<=1;
    else
        rd_continue<=0;
end
else
    rd_continue<=0;
//wr_continue
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    wr_continue<=0;
else if(axi_full.BVALID&&axi_full.BREADY)
begin
    if(wr_transfer_cnt<wr_transfer_num-1)
        wr_continue<=1;
    else
        wr_continue<=0;
end
else
    wr_continue<=0;
//rd_transfer_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    rd_transfer_cnt<=0;
else if(start)
    rd_transfer_cnt<=0;
else if(axi_full.RVALID&&axi_full.RREADY&&axi_full.RLAST)    //完成一次读操作
    rd_transfer_cnt<=rd_transfer_cnt+1;
//wr_transfer_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    wr_transfer_cnt<=0;
else if(start)
    wr_transfer_cnt<=0;
else if(axi_full.BVALID&&axi_full.BREADY)                   //完成一次写操作
    wr_transfer_cnt<=wr_transfer_cnt+1;
//rd_transfer_num
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    rd_transfer_num<=0;
else if(start)
begin
    if(rd_total_len[7:0]==8'd0)
        rd_transfer_num<=rd_total_len[31:8];
    else
        rd_transfer_num<=rd_total_len[31:8]+1;                               //最后一次传输长度为rd_len[7:0]+1
end
//wr_transfer_num
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    wr_transfer_num<=0;
else if(start)
begin
    if(wr_total_len[7:0]==8'd0)
        wr_transfer_num<=wr_total_len[31:8];
    else
        wr_transfer_num<=wr_total_len[31:8]+1;
end    
//最大突发传输长度为256,可能需要分多次进行传输
//读数据
//*************************************************读地址通道*************************************************
//rd_len
always_comb
if(rd_transfer_cnt<rd_transfer_num-1)
    rd_len=8'd255;
else
    rd_len=rd_total_len[7:0];
//ARVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.ARVALID<=0;
else if(start||rd_continue)
    axi_full.ARVALID<=1;
else if(axi_full.ARVALID&&axi_full.ARREADY)
    axi_full.ARVALID<=0;
//ARADDR
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.ARADDR<=0;
else if(start||rd_continue)
    axi_full.ARADDR<=rd_base_addr+rd_transfer_cnt*256;
//ARLEN
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.ARLEN<=0;
else if(start||rd_continue)
    axi_full.ARLEN<=rd_len;               //实际长度-1
//ARSIZE
assign axi_full.ARSIZE=4'b0010;            
//ARBURST
assign axi_full.ARBURST=2'b01;
//ARID
assign axi_full.ARID=0;
//ARPROT
assign axi_full.ARPROT=3'b000;
//ARQOS
assign axi_full.ARQOS=4'b0000;
//ARCACHE
assign axi_full.ARCACHE=4'b0011;
//ARLOCK
assign axi_full.ARLOCK=1'b0;
//ARUSER
assign axi_full.ARUSER=0;
//**********************************************读数据通道***************************************************
//RID
assign axi_full.RID=0;
//RREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.RREADY<=0;
else if(axi_full.ARVALID&&axi_full.ARREADY)
    axi_full.RREADY<=1;
else if(axi_full.RREADY&&axi_full.RVALID&&axi_full.RLAST)
    axi_full.RREADY<=0;
//RDATA寄存
always_ff@(posedge ACLK)
if(axi_full.RVALID&&axi_full.RREADY)
    tx_buffer[tx_buffer_cnt]<=axi_full.RDATA;
//rd_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    rd_cnt<=0;
else if(axi_full.ARVALID&&axi_full.ARREADY)
    rd_cnt<=0;
else if(axi_full.RVALID&&axi_full.RREADY)
    rd_cnt<=rd_cnt+1;
//tx_buffer_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    tx_buffer_cnt<=0;
else if(start)
    tx_buffer_cnt<=0;
else if(axi_full.RVALID&&axi_full.RREADY)
    tx_buffer_cnt<=tx_buffer_cnt+1;
//写数据
//************************************************************写地址通道***********************************************************
//wr_len
always_comb
if(wr_transfer_cnt<wr_transfer_num-1)
    wr_len=8'd255;
else
    wr_len=wr_total_len[7:0];
//AWVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.AWVALID<=0;
else if(writeback||wr_continue)
    axi_full.AWVALID<=1;
else if(axi_full.AWVALID&&axi_full.AWREADY)
    axi_full.AWVALID<=0;
//AWADDR
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.AWADDR<=0;
else if(writeback||wr_continue)
    axi_full.AWADDR<=wr_base_addr+wr_transfer_cnt*256;                      //?
//AWLEN
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.AWLEN<=0;
else if(writeback||wr_continue)
    axi_full.AWLEN<=wr_len;
//AWID
assign axi_full.AWID=0;
//AWSIZE
assign axi_full.AWSIZE=4'b0010;
//AWBURST
assign axi_full.AWBURST=2'b01;
//AWLOCK
assign axi_full.AWLOCK=1'b0;
//AWCACHE
assign axi_full.AWCACHE=4'b0011;
//AWPROT
assign axi_full.AWPROT=0;
//AWQOS
assign axi_full.AWQOS=0;
//AWUSER
assign axi_full.AWUSER=0;
//***********************************************************写数据通道***********************************************************
//wr_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    wr_cnt<=0;
else if(axi_full.AWVALID&&axi_full.AWREADY)
    wr_cnt<=0;
else if(axi_full.WVALID&&axi_full.WREADY)
if(axi_full.WLAST)
    wr_cnt<=0;
else
    wr_cnt<=wr_cnt+1;
//WVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.WVALID<=0;
else if(axi_full.AWVALID&&axi_full.AWREADY)
    axi_full.WVALID<=1;
else if(axi_full.WVALID&&axi_full.WREADY&&axi_full.WLAST)
    axi_full.WVALID<=0;
//WLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.WLAST<=0;
else if(axi_full.WVALID&&axi_full.WREADY&&wr_cnt==wr_len-1)
    axi_full.WLAST<=1;
else if(axi_full.WVALID&&axi_full.WREADY&&axi_full.WLAST)
    axi_full.WLAST<=0;
//WDATA
always_comb
if(axi_full.WVALID&&axi_full.WREADY)
    axi_full.WDATA=rx_buffer[rx_buffer_cnt];
else
    axi_full.WDATA=0;
//rx_buffer_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    rx_buffer_cnt<=0;
else if(writeback)
    rx_buffer_cnt<=0;
else if(axi_full.WVALID&&axi_full.WREADY)                                      //
    rx_buffer_cnt<=rx_buffer_cnt+1;
//
assign axi_full.WSTRB=4'b1111;
assign axi_full.WUSER=0;
//***********************************************************写应答通道***********************************************************
//BREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    axi_full.BREADY<=0;
else if(axi_full.AWVALID&&axi_full.AWREADY)
    axi_full.BREADY<=1;
else if(axi_full.BVALID&&axi_full.BREADY)
    axi_full.BREADY<=0;

//**********************************************AXIS MASTER,DMA向设备写入**********************************************
//TLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    m_axis.TLAST<=0;
else if(m_axis.TVALID&&m_axis.TREADY&&send_cnt==rd_total_len-7)
    m_axis.TLAST<=1;
else if(m_axis.TVALID&&m_axis.TREADY&&m_axis.TLAST)
    m_axis.TLAST<=0;
//TVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    m_axis.TVALID<=0;
else if(m_axis.TVALID&&m_axis.TREADY)                       //前一个周期发生数据传输,send_cnt实际值应加4
begin
    if(m_axis.TLAST)
        m_axis.TVALID<=0;
    else if(send_cnt+8>tx_buffer_cnt)
        m_axis.TVALID<=0;
    else if(send_cnt+8<=tx_buffer_cnt)
        m_axis.TVALID<=1;
end
else if(send_cnt+4>tx_buffer_cnt)                          //前一个周期没有发生数据传输,send_cnt是最新的
    m_axis.TVALID<=0;
else
    m_axis.TVALID<=1;
//TUSER
assign m_axis.TUSER=0;
//TSTRB
assign m_axis.TSTRB=16'hffff;
//TDATA
always_comb
if(m_axis.TVALID&&m_axis.TREADY)
begin
    for(int i=0;i<4;i++)
    begin
        m_axis.TDATA[i*32+:32]=tx_buffer[send_cnt+i];
    end
end
else
    m_axis.TDATA=0;
//send_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    send_cnt<=0;
else if(start)
    send_cnt<=0;
else if(m_axis.TVALID&&m_axis.TREADY)             //成功发送一个数据
    send_cnt<=send_cnt+4;
//*******************************************************AXIS SLAVE,DMA接收来自设备的数据*******************************************************
//TREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    s_axis.TREADY<=0;
else if(start)
    s_axis.TREADY<=1;
else if(s_axis.TREADY&&s_axis.TVALID&&s_axis.TLAST)
    s_axis.TREADY<=0;
//缓存数据
always_ff@(posedge ACLK)
if(s_axis.TVALID&&s_axis.TREADY)
begin
    for(int i=0;i<4;i++)
        rx_buffer[recv_cnt+i]<=s_axis.TDATA[i*32+:32];
end
//recv_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    recv_cnt<=0;
else if(start)
    recv_cnt<=0;
else if(s_axis.TVALID&&s_axis.TREADY)
    recv_cnt<=recv_cnt+4;
//***********************************************************AXI LITE,配置寄存器*************************************************************
//写寄存器
/*
rd_base_addr         0
rd_total_len         4
wr_base_addr         8
wr_total_len         12
start                16
done                 20
*/
//写地址通道
//AWREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    s_axilite.AWREADY<=0;
else if(s_axilite.AWVALID&&s_axilite.WVALID&&~s_axilite.AWREADY)
    s_axilite.AWREADY<=1;
else if(s_axilite.AWVALID&&s_axilite.AWREADY)
    s_axilite.AWREADY<=0;
//************************************************写数据通道************************************************
//WREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    s_axilite.WREADY<=0;
else if(s_axilite.AWVALID&&s_axilite.WVALID&&~s_axilite.WREADY)
    s_axilite.WREADY<=1;
else if(s_axilite.WVALID&&s_axilite.WREADY)
    s_axilite.WREADY<=0;
//将数据写入寄存器
always_ff@(posedge ACLK)
if(s_axilite.WVALID&&s_axilite.AWVALID&&s_axilite.AWREADY&&s_axilite.WREADY)
begin
    case(s_axilite.AWADDR[4:2])
        3'd0:rd_base_addr_r<=s_axilite.WDATA;
        3'd1:rd_total_len_r<=s_axilite.WDATA;
        3'd2:wr_base_addr_r<=s_axilite.WDATA;
        3'd3:wr_total_len_r<=s_axilite.WDATA;
        3'd4:start_r<=s_axilite.WDATA;
        3'd5:done_r<=s_axilite.WDATA;
        default:;
    endcase
end
//**************************************************写响应通道********************************************
//BVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    s_axilite.BVALID<=0;
else if(s_axilite.WVALID&&s_axilite.WREADY)
    s_axilite.BVALID<=1;
else if(s_axilite.BVALID&&s_axilite.BREADY)
    s_axilite.BVALID<=0;
//BRESP
assign s_axilite.BRESP=2'b00;
//***********************************************AXI LITE读地址通道***************************************
//ARREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    s_axilite.ARREADY<=0;
else if(s_axilite.ARVALID&&~s_axilite.ARREADY)
    s_axilite.ARREADY<=1;
else if(s_axilite.ARREADY&&s_axilite.ARVALID)
    s_axilite.ARREADY<=0;
//****************************************************读数据通道***********************************************
//RVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    s_axilite.RVALID<=0;
else if(s_axilite.ARVALID&&s_axilite.ARREADY)
    s_axilite.RVALID<=1;
else if(s_axilite.RVALID&&s_axilite.RREADY)
    s_axilite.RVALID<=0;
//RDATA
always_ff@(posedge ACLK)
if(s_axilite.ARVALID&&s_axilite.ARREADY)
begin
    case(s_axilite.ARADDR[4:2])
        3'd0:s_axilite.RDATA<=rd_base_addr_r;
        3'd1:s_axilite.RDATA<=rd_total_len_r;
        3'd2:s_axilite.RDATA<=wr_base_addr_r;
        3'd3:s_axilite.RDATA<=wr_total_len_r;
        3'd4:s_axilite.RDATA<=start_r;
        3'd5:s_axilite.RDATA<=done_r;
        default:;
    endcase
end
//RRESP
assign s_axilite.RRESP=2'b00;
//start_r_ff
always_ff@(posedge ACLK)
    start_r_ff<=start_r;
//start
assign start=start_r[0]&&(~start_r_ff[0]);
//done
assign done=(rx_buffer_cnt==wr_total_len)?1:0;
//
assign rd_base_addr=rd_base_addr_r;
assign rd_total_len=rd_total_len_r;
assign wr_base_addr=wr_base_addr_r;
assign wr_total_len=wr_total_len_r;
//done_r
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    done_r<=32'd0;
else if(start)
    done_r<=32'd0;
else if(done)
    done_r<=32'd1;
endmodule

此代码仅通过了仿真,进一步综合表明,由于采用了数组,且多端口访问(大于等于2),因此综合出来的电路资源消耗较大,进一步的改进思路就是用FIFO代替缓存,即可有效解决该问题。
最后,完整的工程可以参见链接
System verilog实战----AXI DMA的简单实现_第2张图片

欢迎star!!

你可能感兴趣的:(FPGA)