zl程序教程

您现在的位置是:首页 >  工具

当前栏目

AXI FULL协议学习与仿真

学习协议 仿真 full AXI
2023-09-14 09:10:01 时间

AXI FULL采用READY,VALID 握手通信机制,可支持最大256长度的突发传输,详细内容可参考博客
下面是AXI突发传输读和写的时序图。
读时序:
在这里插入图片描述
写时序:
在这里插入图片描述

在AXI协议中,数据传输发生在VALID和 READY信号同时为高的时候,如下图所示:
在这里插入图片描述
根据这三张图,我们就能编写代码进行测试。
verilog代码(主机)

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

/*
本程序功能为:从start_addr地址开始处连续读取32个数据至buffer,然后分别将其加1,写回原地址处
*/

module PL_DDR_Test(
//全局信号
input logic ACLK,
input logic ARESETn,
//写地址通道信号
output logic AWVALID,           
output logic [31:0]AWADDR,
output logic [7:0]AWLEN,
output logic AWID,              //dont care
output logic [2:0]AWSIZE,       //dont care
output logic [1:0]AWBURST,      //dont care
output logic AWLOCK,            //dont care
output logic [3:0]AWCACHE,      //dont care
output logic [2:0]AWPROT,       //dont care
output logic [3:0]AWQOS,        //dont care
output logic AWUSER,            //dont care
input logic AWREADY,
//写数据通道信号
output logic [63:0]WDATA,
output logic [7:0]WSTRB,
output logic WLAST,
output logic WUSER,             //dont care
output logic WVALID,
input logic WREADY,
//写应答通道信号
output logic BREADY,
input logic BID,                //dont care
input logic [1:0]BRESP,
input logic BUSER,              //dont care
input logic BVALID,
//读地址通道信号
output logic ARID,              //dont care
output logic [31:0]ARADDR,
output logic [7:0]ARLEN,
output logic [2:0]ARSIZE,       //dont care
output logic [1:0]ARBURST,      //dont care
output logic [1:0]ARLOCK,       //dont care
output logic [3:0]ARCACHE,      //dont care
output logic [2:0]ARPROT,       //dont care
output logic [3:0]ARQOS,        //dont care
output logic ARUSER,            //done care
output logic ARVALID,       
input logic ARREADY,
//读数据通道
output logic RREADY,
input logic RID,                //dont care
input logic [63:0]RDATA,   
input logic [1:0]RRESP,         //dont care   
input logic RLAST,          
input logic RUSER,              //dont care
input logic RVALID
    );

assign AWID = 1'b0;
assign AWSIZE  = 3'b011;
assign AWBURST = 2'b01;
assign AWLOCK  = 1'b0;
assign AWCACHE = 4'b0011;
assign AWPROT = 3'b000;
assign AWQOS = 4'b0000;
assign AWUSER = 1'b1;
assign WUSER = 1'b1;

assign ARID = 1'b0;
assign ARSIZE = 3'b011;
assign ARBURST = 2'b01;
assign ARLOCK = 1'b0;
assign ARCACHE = 4'b0011;
assign ARPROT = 3'b000;
assign ARQOS = 4'b0000;
assign ARUSER = 1'b1;

logic [9:0]wr_cnt;
logic [9:0]rd_cnt;
logic rd_done;
logic wr_done;
logic read_start;
logic write_start;
logic test_start;
logic test_done;
//
logic [31:0]start_addr;
logic [9:0] test_len;            //=31,即突发传输长度32
logic [63:0] data_buffer [0:31];

enum {IDLE,READ,WRITE,DONE} State,NextState;
//*************************************************************************//
//test_len
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    test_len<=31;
//test_start
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    test_start<=1;
else
    test_start<=0;
//start_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    start_addr<=0;
//FSM
always_ff@(posedge ACLK,negedge ARESETn)
begin
    if(!ARESETn)
        State<=IDLE;
    else
        State<=NextState;
end
//FSM
always@(*)
case(State)
    IDLE:if(test_start)
             NextState=READ;
         else
             NextState=IDLE;
    READ:if(rd_done)
             NextState=WRITE;
         else
             NextState=READ;
    WRITE:if(wr_done)
             NextState=DONE;
          else
             NextState=WRITE;
    DONE:NextState=DONE;
    default:NextState=IDLE;
endcase
//读地址通道
always_comb
   read_start=test_start;
//ARVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARVALID<=1'b0;
else if(NextState==READ&&read_start)                      //read_start为一个宽一个周期的脉冲
    ARVALID<=1'b1;
else if(ARVALID==1'b1&&ARREADY==1'b1)                     //读通道数据传输完成
    ARVALID<=1'b0;
//ARADDR
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARADDR<=32'd0;
else if(NextState==READ&&read_start)
    ARADDR<=start_addr;
//ARLEN
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   ARLEN<=8'd0;
else if(NextState==READ&&read_start)
   ARLEN<=test_len;
//读数据通道
//rd_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_cnt<=10'd0;
else if(RVALID&&RREADY)      //完成一个数据的读取,计数器加1
    if(RLAST)
        rd_cnt<=0;
    else
        rd_cnt<=rd_cnt+1'b1;
//data_buffer
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    for(int i=0;i<32;i++)
        data_buffer[i]<=32'd0;
else if(RVALID&&RREADY)
    data_buffer[rd_cnt]<=RDATA;
//RREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    RREADY<=0;
else if(RVALID&&~RREADY)
    RREADY<=1;
else if(RVALID&&RREADY&&RLAST)                       //最后一个数据读取完成
    RREADY<=0;
//rd_done
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_done<=0;
else if(RLAST)
    rd_done<=1;
else 
    rd_done<=0;
//写地址通道
//write_start
always_comb 
begin
    write_start=rd_done;    
end
//AWVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   AWVALID<=0;
else if(NextState==WRITE&&write_start)
   AWVALID<=1;
else if(AWVALID&&AWREADY)                         //写地址通道传输完成
   AWVALID<=0;
//AWADDR
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   AWADDR<=32'd0;
else if(NextState==WRITE&&write_start)
   AWADDR<=start_addr;
//AWLEN
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   AWLEN<=8'd0;
else if(NextState==WRITE&&write_start)
   AWLEN<=test_len;                                      //写突发传输长度为32
//写数据通道
//wr_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_cnt<=10'd0;
else if(WVALID&&WREADY)                         //完成一个数据的写入,计数器加1
    if(WLAST)
        wr_cnt<=0;
    else
        wr_cnt<=wr_cnt+1;
//WVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    WVALID<=0;
else if(AWVALID&&AWREADY)                      //写地址通道传输完成,开始写数据
    WVALID<=1;
else if(WLAST&&WVALID&&WREADY)                 //最后一个数据传输完成
    WVALID<=0;
//WSTRB
always_ff@(posedge ACLK,negedge ARESETn)                  //
if(!ARESETn)
    WSTRB<=8'd0;
else if(AWVALID&&AWREADY)                
    WSTRB<=8'hff;
//WDATA
always_comb 
begin
   if(WVALID&&WREADY)                                  //此时写入数据有效
       WDATA=data_buffer[wr_cnt]+1;    
   else
       WDATA=0;
end
//WLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   WLAST<=0;
else if(wr_cnt==test_len-1&&WVALID&&WREADY)                           //31-1=30
   WLAST<=1;
else 
   WLAST<=0;
//写响应通道
//BREAY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   BREADY<=0;
else if(AWVALID&&AWREADY)
   BREADY<=1;
else if(BVALID&&BRESP==2'b00)                      //BRESP=OKEY
   BREADY<=0;
//wr_done
always_comb 
begin
    if(BREADY&&BVALID&&BRESP==2'b00)
        wr_done=1;
    else
        wr_done=0;    
end
//test_done
always_comb
    test_done=wr_done;

endmodule

Testbench(从机)

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/03/08 18:32:44
// Design Name: 
// Module Name: test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module test;
//全局信号
logic ACLK;
logic ARESETn;
//写地址通道
logic AWVALID;
logic [31:0]AWADDR;
logic [7:0]AWLEN;                  //突发传输长度,实际长度为AWLEN+1
logic AWREADY;
//写数据通道
logic [63:0] WDATA;
logic WVALID;
logic [7:0] WSTRB;                //dont care
logic WLAST;
logic WREADY;
//写响应通道
logic BVALID;
logic BREADY;
logic [1:0]BRESP;
//读数据通道
logic [63:0]RDATA;
logic RVALID;
logic RREADY;
logic RLAST;
//读地址通道
logic [31:0] ARADDR;
logic [7:0] ARLEN;
logic ARVALID;
logic ARREADY;
//MEM
logic [63:0] mem [0:31];
//other signal
logic [31:0] rd_base_addr;
logic [31:0] wr_base_addr;
logic [9:0] rd_len;
logic [9:0] wr_len;
logic [9:0] rd_cnt;                     //这里的rd是相对与主机来说的,即主机读取,从机发送
logic [9:0] wr_cnt;
//initialize memory
/*initial begin
    for(int i=0;i<32;i++)
       mem[i]=i;
end*/
//ACLK,ARESET
initial begin
    ACLK=0;
    forever begin
        #5 ACLK=~ACLK;
    end
end
initial begin
    ARESETn=0;
    #10
    ARESETn=1;
end
//处理主机发起的读请求
//读地址通道
//ARREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARREADY<=0;
else if(ARVALID&&~ARREADY)                    //ARVALID信号为1,拉高ARREADY以接受信息
    ARREADY<=1;
else if(ARVALID&&ARREADY)                     //读地址通道数据接受完毕
    ARREADY<=0;
//rd_base_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_base_addr<=32'd0;
else if(ARREADY&&ARVALID)
    rd_base_addr<=ARADDR;
//rd_len
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_len<=0;
else if(ARVALID&&ARREADY)
    rd_len<=ARLEN;
//读数据通道
//rd_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_cnt<=0;
else if(RVALID&&RREADY)                  //从机发送一个数据完成
    if(RLAST)                            //所有数据发送完毕
        rd_cnt<=0;
    else                                 //计数器加1
        rd_cnt<=rd_cnt+1;
//RVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    RVALID<=0;
else if(ARREADY&&ARVALID)                    //读地址通道结束,读数据通道开始
    RVALID<=1;
else if(RVALID&&RREADY&&RLAST)               //最后一个数据发送完成
    RVALID<=0;
//RDATA
always_comb                                  //组合逻辑,否则数据相对于发送次数延迟了一个周期
begin
if(RVALID&&RREADY)
    RDATA=mem[rd_cnt];
else
    RDATA=0;
end
//RLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    RLAST<=0;
else if(rd_cnt==rd_len-1&&RVALID&&RREADY)              //rd_len等于实际长度-1
    RLAST<=1;
else
    RLAST<=0;
//处理主机发起的写请求
//写地址通道
//AWREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    AWREADY<=0;
else if(AWVALID&&~AWREADY)
    AWREADY<=1;
else if(AWVALID&&AWREADY)                   //写地址通道接收信息完毕
    AWREADY<=0;
//wr_len
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_len<=0;
else if(AWVALID&&AWREADY)
    wr_len<=AWLEN;
//wr_base_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_base_addr<=0;
else if(AWVALID&&AWREADY)
    wr_base_addr<=AWADDR;
//写数据通道
//WREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   WREADY<=0;
else if(AWVALID&&AWREADY)                  //写地址通道完成之后拉高WREADY以等待数据的到来
   WREADY<=1;
else if(WVALID&&WLAST&&WREADY)             //最后一个数据接收后拉低WREADY
   WREADY<=0;
//wr_cnt                                  //wr是相对于主机来说的,主机写数据,从机接收数据
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_cnt<=0;
else if(WVALID&&WREADY)
    if(WLAST)                            //从机接受数据完成
        wr_cnt<=0;
    else 
        wr_cnt<=wr_cnt+1;
//WDATA
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
begin
    for(int i=0;i<32;i++)
        mem[i]<=i;
end
else if(WVALID&&WREADY)
    mem[wr_cnt]<=WDATA;
//写响应通道
//BVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    BVALID<=0;
else if(WVALID&&WLAST&&WREADY)
    BVALID<=1;
else if(BVALID&&BREADY&&BRESP==2'b00)
    BVALID<=0;
//BRESP
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    BRESP<=2'b11;
else if(WVALID&&WREADY&&WLAST)
    BRESP<=2'b00;
else if(BREADY&&BVALID&&BRESP==2'b00)
    BRESP<=2'b11;
//打印结果
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ;
else if(BREADY&&BVALID&&BRESP==2'b00)
begin
    for(int i=0;i<32;i++)
        $display("%d",mem[i]);
end
//例化主机
PL_DDR_Test U(
//全局信号
.ACLK(ACLK),
.ARESETn(ARESETn),
//写地址通道信号
.AWVALID(AWVALID),           
.AWADDR(AWADDR),
.AWLEN(AWLEN),
.AWID(),              //dont care
.AWSIZE(),       //dont care
.AWBURST(),      //dont care
.AWLOCK(),            //dont care
.AWCACHE(),      //dont care
.AWPROT(),       //dont care
.AWQOS(),        //dont care
.AWUSER(),            //dont care
.AWREADY(AWREADY),
//写数据通道信号
.WDATA(WDATA),
.WSTRB(WSTRB),
.WLAST(WLAST),
.WUSER(),             //dont care
.WVALID(WVALID),
.WREADY(WREADY),
//写应答通道信号
.BREADY(BREADY),
.BID(),                //dont care
.BRESP(BRESP),
.BUSER(),              //dont care
.BVALID(BVALID),
//读地址通道信号
.ARID(),              //dont care
.ARADDR(ARADDR),
.ARLEN(ARLEN),
.ARSIZE(),       //dont care
.ARBURST(),      //dont care
.ARLOCK(),       //dont care
.ARCACHE(),      //dont care
.ARPROT(),       //dont care
.ARQOS(),        //dont care
.ARUSER(),            //done care
.ARVALID(ARVALID),       
.ARREADY(ARREADY),
//读数据通道
.RREADY(RREADY),
.RID(),                //dont care
.RDATA(RDATA),   
.RRESP(RRESP),         //dont care   
.RLAST(RLAST),          
.RUSER(),              //dont care
.RVALID(RVALID)
);
endmodule

代码完成的功能为:主机从从机的0地址起始地址处连续读取32个64位数据,然后分别加1,再通过突发写将结果写回至原先的地方。
代码已通过仿真测试。