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,再通过突发写将结果写回至原先的地方。
代码已通过仿真测试。