AXI STREAM协议学习

axi stream协议的具体内容可参见从零学习AXI4总线(二):AXI4-Stream 介绍AXI4-Stream协议总结
以下是一个简单的HDL示例,完成的功能是master向slave写入512个数据(1,2,3,…,511,512)
主机代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/06/13 20:42:20
// Design Name: 
// Module Name: axis_master
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module axis_master(
input logic ACLK,
input logic ARESETn,
input logic start,
input logic TREADY,
output logic done,
output logic TVALID,
output logic [31:0] TDATA,
output logic [3:0] TSTRB,
output logic [3:0] TKEEP,
output logic TLAST,
output logic TID,                       
output logic TDEST,                    
output logic TUSER                      //TID,TDEST,TUSER用于多机通信
    );
    
parameter N=512;
logic [31:0] tx_buffer [0:N-1];        //待传输的值
logic [31:0] tx_cnt;
//初始化tx_buffer
always_ff@(posedge ACLK,negedge ARESETn) 
if(~ARESETn)
begin
    for(int i=0;i<N;i++)
        tx_buffer[i]<=i+1;
end
else
begin
    ;
end
//TVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    TVALID<=0;
else if(start)
    TVALID<=1;
else if(TVALID&&TREADY&&TLAST)               //最后一个数据传输完成,拉低TVALID
    TVALID<=0;
//tx_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
   tx_cnt<=0;
else if(start)
   tx_cnt<=0;
else if(TVALID&&TREADY)                //每完成一次数据传输,tx_cnt加1
   tx_cnt<=tx_cnt+1;
//TLAST
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    TLAST<=0;
else if(tx_cnt==N-2&&TVALID&&TREADY)   //倒数第二个数据传输完成,拉高TLAST
    TLAST<=1;
else if(TVALID&&TREADY&&TLAST)         //最后一个数据传输完成后,拉低                           
    TLAST<=0;
//TDATA
always_comb
begin
    TDATA=tx_buffer[tx_cnt];
end
//TSTRB
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    TSTRB<=4'b0000;
else if(start)
    TSTRB<=4'b1111;
//TKEEP
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    TKEEP<=4'b0000;
else if(start)
    TKEEP<=4'b1111;
//done
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    done<=0;
else if(TVALID&&TLAST&&TREADY)          //最后一个数据传输完成
    done<=1;
else 
    done<=0;
endmodule

从机代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/06/13 20:43:04
// Design Name: 
// Module Name: axis_slave
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module axis_slave(
input logic ACLK,
input logic ARESETn,
input logic start,                  //可以开始接收数据
input logic TVALID,
input logic TLAST,
input logic [31:0] TDATA,
input logic [3:0] TSTRB,
input logic [3:0] TKEEP,
input logic TID,
input logic TDEST,
input logic TUSER,
output logic TREADY,
output logic done                   //数据接收完毕
    );

parameter N = 1024;
logic [31:0] rx_buffer [0:N-1];     //接收缓冲区
logic [31:0] rx_cnt;                //接收计数器
logic [3:0] bytemask;

//rx_cnt
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    rx_cnt<=0;
else if(start)
    rx_cnt<=0;
else if(TVALID&&TREADY)              //每完成一次数据传输,rx_cnt加1
    rx_cnt<=rx_cnt+1;
//done
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
    done<=0;
else if(TVALID&&TREADY&&TLAST)              //最后一个数据接收完成,done拉高
    done<=1;
else
    done<=0;
//bytemask
assign bytemask=TSTRB & TKEEP;             //tstrb和tkeep同时为高时才是有效字节
//rx_buffer
always_ff@(posedge ACLK)
if(TVALID&&TREADY)                         //接收数据
begin
    for(int i=0;i<4;i++)
    begin
        rx_buffer[rx_cnt][(8*i+7) -:8]<=((bytemask[i]==1'b1)?TDATA[(8*i+7)-:8]:8'h00);
    end
end
//TREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(~ARESETn)
   TREADY<=0;
else if(start)
   TREADY<=1;
else if(TLAST&&TREADY&&TVALID)        //最后一个数据传输完成
   TREADY<=0;
//
always_ff@(posedge ACLK)
if(done)
begin
    for(int i=0;i<512;i++)
    begin
        $display("%d",rx_buffer[i]);
    end
end       
endmodule

测试文件代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/06/13 21:43:09
// Design Name: 
// Module Name: axis_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module axis_tb;
logic ACLK;
logic ARESETn;
logic TVALID;
logic TREADY;
logic TLAST;
logic [31:0] TDATA;
logic [3:0] TSTRB;
logic [3:0] TKEEP;
logic TID;
logic TUSER;
logic TDEST;
logic master_start;
logic master_done;
logic slave_start;
logic slave_done;
//ACLK
initial 
begin
    ACLK=0;
    forever begin
        #5 ACLK=~ACLK;
    end
end
//ARESETn
initial 
begin
    ARESETn=0;
    #20
    ARESETn=1;
end
//start
initial 
begin
    master_start=0;
    slave_start=0;
    #100
    master_start=1;
    slave_start=1;
    #10
    master_start=0;
    slave_start=0;
end
//instance
axis_master M(
.ACLK(ACLK),
.ARESETn(ARESETn),
.start(master_start),
.TREADY(TREADY),
.done(master_done),
.TVALID(TVALID),
.TDATA(TDATA),
.TSTRB(TSTRB),
.TKEEP(TKEEP),
.TLAST(TLAST),
.TID(TID),                       
.TDEST(TDEST),                    
.TUSER(TUSER)                      //TID,TDEST,TUSER用于多机通信
);

axis_slave S(
.ACLK(ACLK),
.ARESETn(ARESETn),
.start(slave_start),                  //可以开始接收数据
.TVALID(TVALID),
.TLAST(TLAST),
.TDATA(TDATA),
.TSTRB(TSTRB),
.TKEEP(TKEEP),
.TID(TID),
.TDEST(TDEST),
.TUSER(TUSER),
.TREADY(TREADY),
.done(slave_done)                   //数据接收完毕
);
endmodule

上一篇:AXI总线信号含义说明


下一篇:ZYNQ-AXI_VDMA IP简介