AXI Lite协议学习与仿真

AXI4-lite总线协议总共包括21条信号线。每个通道都有其自己的双向握手机制信号线xxVALID和xxREADY,关于双向握手机制,可以参见上一篇博客AXI FULL协议学习与仿真。下面是信号线的详细描述。

全局信号

ACLK:全局时钟信号,在上升沿时对信号采样。所有的输入信号都通过上升沿采集,所有的输出信号都在上升沿时变化。
ARESETn:全局复位信号,低电平有效。在复位期间,所有的xxVALID信号必须复位为低电平。其他的信号可以是任意值。

写地址通道信号

主机(master)控制的信号

AWVALID
AWADDR 地址信号线,传输地址信息。
AWPROT 访问权限信号线,xilinx建议赋值为3’b000.xilinx IP 一般忽略此信号。

从机(slave)控制的信号

AWREADY

写数据通道信号

主机(master)控制的信号

WVALID
WDATA 数据信号线,传输数据信息。
WSTRB 数据总线有效字节控制。比如32位的总线,WSTRB等于4’b0010,那么代表WDATA[15:8]中的数据有效。其他无效。如果要求WDATA[31:0]32位全有效,那么WSTRB就应该等于4’b1111.

从机(slave)控制的信号

WREADY

写应答通道信号

主机(master)控制的信号

BREADY

从机(slave)控制的信号

BVALID
BRESP 应答类型。AXI4-lite不支持EXOKAY类型的响应。
OKEY 0 正常访问成功
SLVERR 2 从机错误
DECERR 3 解码错误,比如没有从机的地址。

读地址通道信号

主机(master)控制的信号

ARVALID
ARADDR 地址信号线,传输地址信息。
ARPROT 访问权限信号线,xilinx建议赋值为3’b000.xilinx IP 一般忽略此信号。

从机(slave)控制的信号

ARREADY

读数据通道信号

主机(master)控制的信号

RREADY

从机(slave)控制的信号

RVALID
RDATA 数据信号线,传输数据信息。
RRESP 同写应答信号BRESP。

代码实现

从机:

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


module axi_lite_slave(   //AXI Lite从机
//全局信号
input logic ACLK,
input logic ARESETn,
//写地址通道
input logic AWVALID,
input logic [31:0]AWADDR, 
input logic [2:0]AWPROT, 
output logic AWREADY,
//写数据通道
input logic WVALID,
input logic [31:0] WDATA, 
input logic [3:0] WSTRB,
output logic WREADY,
//写响应通道
input logic BREADY,
output logic BVALID,
output logic [1:0] BRESP,
//读地址通道
input logic ARVALID,
input logic [31:0] ARADDR, 
input logic [2:0] ARPROT, 
output logic ARREADY,
//读数据通道
input logic RREADY,
output logic RVALID,
output logic [31:0] RDATA, 
output logic [1:0] RRESP,
//其他
output logic busy                      //主机往从机写数据时,busy为高,知道数据被写入寄存器
    );

parameter N=4;                         //四个寄存器

logic [31:0] DataReg [0:N-1];

logic [31:0]rd_addr;             
logic [31:0]wr_addr;
logic [31:0]rd_data;
logic [31:0]wr_data;
logic wr_en;
//wr_en
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_en<=0;
else if(WVALID&&WREADY)
    wr_en<=1;                            //此时写数据地址和写数据均被暂存,可以进行写入
else 
    wr_en<=0;
//busy
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    busy<=0;
else if(AWVALID)
    busy<=1;
else if(wr_en)
    busy<=0;
//响应来自主机的写请求
//写地址通道
//AWREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    AWREADY<=0;
else if(AWVALID&&~AWREADY)                        //写地址通道有有效数据,拉高AWREADY以接收
    AWREADY<=1;
else if(AWVALID&&AWREADY)                         //写地址通道数据传输结束
    AWREADY<=0;
//wr_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_addr<=0;
else if(AWVALID&&AWREADY)
    wr_addr<=AWADDR;
//写数据通道
//wr_data
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_data<=0;
else if(WVALID&&WREADY)
    wr_data<=WDATA;
//WREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    WREADY<=0;
else if(WVALID&&~WREADY)
    WREADY<=1;
else if(WVALID&&WREADY)
    WREADY<=0;
//将数据写入寄存器
always_ff@(posedge ACLK)
if(wr_en)
    DataReg[wr_addr]<=wr_data;
//写响应通道
//BVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    BVALID<=0;
else if(WVALID&&WREADY)
    BVALID<=1;
else if(BVALID&&BREADY&&BRESP==2'b00)
    BVALID<=0;
//BRESP
always_comb 
begin
    BRESP=2'b00;                      //OKEY    
end
//响应来自主机的读请求
//读地址通道
//ARREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARREADY<=0;
else if(ARVALID&&~ARREADY)
    ARREADY<=1;
else if(ARVALID&&ARREADY)         //读地址通道数据接受完毕
    ARREADY<=0;
//rd_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_addr<=0;
else if(ARVALID&&ARREADY)           //数据有效,存储地址
    rd_addr<=ARADDR;
//读数据通道
//RVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    RVALID<=0;
else if(ARREADY&&ARVALID)                //读地址通道结束,拉高RVALID发送数据
    RVALID<=1;
else if(RVALID&&RREADY)                  //数据发送完毕
    RVALID<=0;
//RRESP
always_comb
begin
    RRESP=2'b00;
end
//RDATA
always_comb 
begin
    if(RVALID)
        RDATA=DataReg[rd_addr];
    else
        RDATA=32'd0;    
end
endmodule

主机:

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


module axi_lite_master_test;
//全局信号
logic ACLK;
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;
//其他
logic start_write;
logic start_read;
logic [31:0] rd_data;
logic busy;
//ACLK AND ARESETn
initial begin
    ACLK=0;
    forever begin
        #5 ACLK=~ACLK;
    end
end
initial begin
    ARESETn=0;
    #10
    ARESETn=1;
end
//start_write
initial begin
    start_write=0;
    #50
    start_write=1;                    //拉高一个周期以开始写数据操作
    #10
    start_write=0;
end
//发起写请求
//写地址通道
//AWVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    AWVALID<=0;
else if(start_write)
    AWVALID<=1;
else if(AWVALID&&AWREADY)           //写地址通道传输完毕
    AWVALID<=0;
//AWADDR
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    AWADDR<=32'd0;
else if(start_write)
    AWADDR<=32'd1;
//AWPROT
always_comb 
begin
    AWPROT=3'b000;    
end    
//写数据通道
//WDATA
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   WDATA<=0;
else if(AWVALID&&AWREADY)                   //写地址通道完成
   WDATA<=32'd6;
//WVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
   WVALID<=0;
else if(AWVALID&&AWREADY)                   //写地址通道结束,开始写数据,事实上,写数据和写地址通道可以同时进行
   WVALID<=1;
else if(WVALID&&WREADY)                     //写数据完毕
   WVALID<=0;
//WSTRB
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    WSTRB<=4'b0000;
else if(AWVALID&&AWREADY)
    WSTRB<=4'b1111;
//写响应通道
//BREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    BREADY<=0;
else if(AWVALID&&AWREADY)                      //写地址通道结束后就可以提前拉高
    BREADY<=1;
else if(BREADY&&BVALID&&BRESP==2'b00)           //
    BREADY<=0;
//发起读请求
//start_read
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    start_read<=0;
else if(BRESP==2'b00&&BVALID&&BREADY)
    start_read<=1;
else
    start_read<=0;
//读地址通道
//ARVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARVALID<=0;
else if(start_read)
    ARVALID<=1;
else if(ARVALID&&ARREADY)   //读地址通道结束
    ARVALID<=0;
//ARADDR
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARADDR<=0;
else if(start_read)
    ARADDR<=32'd1;
//ARPROT
always_comb 
begin
    ARPROT=3'b000;    
end
//读数据通道
//RREADY
always_ff @(posedge ACLK,negedge ARESETn) 
if(!ARESETn)
    RREADY<=0;
else if(ARVALID&&ARREADY)                  //读地址通道结束后,拉高RREADY以准备接收数据
    RREADY<=1;
else if(RREADY&&RVALID)                    //读数据完成
    RREADY<=0;
//rd_data
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_data<=0;
else if(RVALID&&RREADY)                    //同时为高,可读取数据
begin
    rd_data<=RDATA;
    $display("%d",rd_data);
end
//例化
axi_lite_slave U(                          //AXI Lite从机
//全局信号
.ACLK(ACLK),
.ARESETn(ARESETn),
//写地址通道
.AWVALID(AWVALID),
.AWADDR(AWADDR), 
.AWPROT(AWPROT), 
.AWREADY(AWREADY),
//写数据通道
.WVALID(WVALID),
.WDATA(WDATA), 
.WSTRB(WSTRB),
.WREADY(WREADY),
//写响应通道
.BREADY(BREADY),
.BVALID(BVALID),
.BRESP(BRESP),
//读地址通道
.ARVALID(ARVALID),
.ARADDR(ARADDR), 
.ARPROT(ARPROT), 
.ARREADY(ARREADY),
//读数据通道
.RREADY(RREADY),
.RVALID(RVALID),
.RDATA(RDATA), 
.RRESP(RRESP),
//其他
.busy(busy)                     
);
endmodule

仿真波形如下:
在这里插入图片描述
实现功能为主机往从机地址为1处写入6,然后再读出,可以看到,读出结果确实为6,代码功能正确。
修改主机代码,使得写地址和写数据同时进行(这对AXI Lite来说是可以的),有如下仿真波形图,结果仍为6,功能正确。
在这里插入图片描述
从机代码未考虑到WVALID比AWVALID先断言的情况,现修正如下(已经上板测试成功):

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


module axi_lite_slave(   //AXI Lite从机
//全局信号
input logic ACLK,
input logic ARESETn,
//写地址通道
input logic AWVALID,
input logic [31:0]AWADDR, 
input logic [2:0]AWPROT, 
output logic AWREADY,
//写数据通道
input logic WVALID,
input logic [31:0] WDATA, 
input logic [3:0] WSTRB,
output logic WREADY,
//写响应通道
input logic BREADY,
output logic BVALID,
output logic [1:0] BRESP,
//读地址通道
input logic ARVALID,
input logic [31:0] ARADDR, 
input logic [2:0] ARPROT, 
output logic ARREADY,
//读数据通道
input logic RREADY,
output logic RVALID,
output logic [31:0] RDATA, 
output logic [1:0] RRESP,
//其他
output logic busy                      //主机往从机写数据时,busy为高,知道数据被写入寄存器
    );

parameter N=4;                         //四个寄存器

logic [31:0] DataReg [0:N-1];

logic [31:0]rd_addr;             
logic [31:0]wr_addr;
logic [31:0]rd_data;
logic [31:0]wr_data;
logic [1:0] wr_reg_sel;
logic [1:0] rd_reg_sel;
logic wr_en;

assign wr_reg_sel=wr_addr[3:2];
assign rd_reg_sel=rd_addr[3:2];

//wr_en
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_en<=0;
else if(WVALID&&WREADY&&AWVALID&&AWREADY)
    wr_en<=1;                            //此时写数据地址和写数据均被暂存,可以进行写入
else 
    wr_en<=0;
//busy
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    busy<=0;
else if(AWVALID||WVALID)
    busy<=1;
else if(wr_en)
    busy<=0;
//响应来自主机的写请求
//写地址通道
//AWREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    AWREADY<=0;
else if(AWVALID&&WVALID&&~AWREADY)                        //写地址和写数据均有效时才拉高
    AWREADY<=1;
else if(AWVALID&&AWREADY&&WVALID)                         //写地址通道数据传输结束
    AWREADY<=0;
//wr_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_addr<=0;
else if(AWVALID&&AWREADY)
    wr_addr<=AWADDR;
//写数据通道
//wr_data
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    wr_data<=0;
else if(WVALID&&WREADY)
    wr_data<=WDATA;
//WREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    WREADY<=0;
else if(WVALID&&AWVALID&&~WREADY)
    WREADY<=1;
else if(WVALID&&WREADY&&AWVALID)
    WREADY<=0;
//将数据写入寄存器
always_ff@(posedge ACLK)
if(wr_en)
    DataReg[wr_reg_sel]<=wr_data;
//写响应通道
//BVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    BVALID<=0;
else if(WVALID&&WREADY)
    BVALID<=1;
else if(BVALID&&BREADY&&BRESP==2'b00)
    BVALID<=0;
//BRESP
always_comb 
begin
    BRESP=2'b00;                      //OKEY    
end
//响应来自主机的读请求
//读地址通道
//ARREADY
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    ARREADY<=0;
else if(ARVALID&&~ARREADY)
    ARREADY<=1;
else if(ARVALID&&ARREADY)         //读地址通道数据接受完毕
    ARREADY<=0;
//rd_addr
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    rd_addr<=0;
else if(ARVALID&&ARREADY)           //数据有效,存储地址
    rd_addr<=ARADDR;
//读数据通道
//RVALID
always_ff@(posedge ACLK,negedge ARESETn)
if(!ARESETn)
    RVALID<=0;
else if(ARREADY&&ARVALID)                //读地址通道结束,拉高RVALID发送数据
    RVALID<=1;
else if(RVALID&&RREADY)                  //数据发送完毕
    RVALID<=0;
//RRESP
always_comb
begin
    RRESP=2'b00;
end
//RDATA
always_comb 
begin
    if(RVALID)
        RDATA=DataReg[rd_reg_sel];
    else
        RDATA=32'd0;    
end
endmodule


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA硅农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值