AXI4主机测试

前面对AXI4协议进行了比较详细的分析,本篇文章将会写一个主机代码来实现AXI4协议的时序。

设计思路:本次设计的主要目的是验证AXI4_FULL总线的时序,并且提升对AXI4_FULL总线协议的理解,因此可以采用状态机来控制,先向一个地址写入数据,然后读出该地址的数据验证数据的正确性,如果没有错再向下一个地址中写入数据,如此反复执行。

状态转换如下图所示:

状态机初始位于空闲状态,下个时钟跳转到写突发状态,当写应答通道握手成功时,表示写突发完成,跳转到读突发状态,当读出数据与写入数据错误时,跳转到错误状态。当读写数据一致且读突发传输最后一个数据,表示读突发完成,跳转到空闲状态开始下一次读写操作。

  当读、写首地址发送之后,突发地址需要增加突发长度乘以突发字节数,作为下一次突发传输的首地址。

具体实现代码如下:

`timescale 1ns / 1ps

module axi_full_master#(
        parameter       C_M_TARGET_SLAVE_BASE_ADDR          =       32'h40000000        ,       //读写目标从机的基地址
        parameter       C_M_AXI_BURST_LEN                   =       16                  ,       //一次突发读写长度
        parameter       C_M_AXI_ID_WIDTH                    =       1                   ,       //ID长度
        parameter       C_M_AXI_DATA_WIDTH                  =       32                  ,       //读写数据位宽
        parameter       C_M_AXI_ADDR_WIDTH                  =       32                  ,       //读写地址位宽
        parameter       C_M_AXI_AWUSER_WIDTH                =       0                   ,       //用户写地址总线位宽
        parameter       C_M_AXI_ARUSER_WIDTH                =       0                   ,       //用户读地址总线位宽
        parameter       C_M_AXI_WUSER_WIDTH                 =       0                   ,       //用户写数据总线位宽
        parameter       C_M_AXI_RUSER_WIDTH                 =       0                   ,       //用户读数据总线位宽     
        parameter       C_M_AXI_BUSER_WIDTH                 =       0                           //用户写响应总线位宽                                    
    )
    (
        input                                                       M_AXI_ACLK          ,       //AXI时钟时钟
        input                                                       M_AXI_ARESETN       ,       //AXI复位信号
        //AXI写地址通道
        output           reg[C_M_AXI_ADDR_WIDTH-1:0]                M_AXI_AWADDR        ,       //写地址通道地址信号
        output              [C_M_AXI_ID_WIDTH-1:0]                  M_AXI_AWID          ,       //写地址通道ID
        output              [1:0]                                   M_AXI_AWBURST       ,       //写地址通道突发类型
        output              [2:0]                                   M_AXI_AWSIZE        ,       //写地址通道突发大小信号,该信号指示突发传输中每次传输的大小数据
        output              [7:0]                                   M_AXI_AWLEN         ,       //写地址通道突发长度信号
        output                                                      M_AXI_AWLOCK        ,       //写地址通道锁信号
        output              [3:0]                                   M_AXI_AWCACHE       ,       //写地址通道内存类型信号
        output              [2:0]                                   M_AXI_AWPROT        ,       //写地址通道保护类型信号
        output              [3:0]                                   M_AXI_AWQOS         ,       //写地址通道服务质量类型信号
        output              [C_M_AXI_AWUSER_WIDTH-1:0]              M_AXI_AWUSER        ,       //写地址通道用户自定义信号
        output           reg                                        M_AXI_AWVALID       ,       //写地址通道有效指示信号
        input                                                       M_AXI_AWREADY       ,       //写地址通道地址应答信号从机发送给主机                
        //写数据通道
        output           reg[C_M_AXI_DATA_WIDTH-1:0]                M_AXI_WDATA         ,       //写数据通道数据
        output              [C_M_AXI_DATA_WIDTH/8-1:0]              M_AXI_WSTRB         ,       //写数据通道掩码信号
        output           reg                                        M_AXI_WLAST         ,       //写数据通道最后一位数据信号
        output              [C_M_AXI_WUSER_WIDTH-1:0]               M_AXI_WUSER         ,       //写数据通道用户自定义信号
        output           reg                                        M_AXI_WVALID        ,       //写数据通道有效指示信号
        input                                                       M_AXI_WREADY        ,       //写数据通道数据应答信号
        //写响应通道
        input                                                       M_AXI_BVALID        ,       //写响应通道有效指示信号
        input               [C_M_AXI_ID_WIDTH-1:0]                  M_AXI_BID           ,       //写响应通道ID
        input               [1:0]                                   M_AXI_BRESP         ,       //写响应通道回复信号
        input               [C_M_AXI_BUSER_WIDTH-1:0]               M_AXI_BUSER         ,       //写响应通道用户自定义信号
        output           reg                                        M_AXI_BREADY        ,       //写响应通道应答信号
        //读地址通道
        output           reg[C_M_AXI_ADDR_WIDTH-1:0]                M_AXI_ARADDR        ,       //读地址通道地址信号
        output              [C_M_AXI_ID_WIDTH-1:0]                  M_AXI_ARID          ,       //读地址通道ID
        output              [7:0]                                   M_AXI_ARLEN         ,       //读地址通道突发长度
        output              [2:0]                                   M_AXI_ARSIZE        ,       //读地址通道突发大小信号
        output              [1:0]                                   M_AXI_ARBURST       ,       //读地址通道突发类型
        output                                                      M_AXI_ARLOCK        ,       //读地址通道锁信号
        output              [3:0]                                   M_AXI_ARCACHE       ,       //读地址通道内存类型信号
        output              [2:0]                                   M_AXI_ARPROT        ,       //读地址通道保护类型信号
        output              [3:0]                                   M_AXI_ARQOS         ,       //读地址通道服务质量类型信号
        output              [C_M_AXI_ARUSER_WIDTH-1:0]              M_AXI_ARUSER        ,       //读地址用户自定义信号
        output              reg                                     M_AXI_ARVALID       ,       //读地址通道有效指示信号
        input                                                       M_AXI_ARREADY       ,       //读地址通道地址应答信号
        //读数据通道
        input               [C_M_AXI_ID_WIDTH-1:0]                  M_AXI_RID           ,       //读数据通道ID
        input               [C_M_AXI_DATA_WIDTH-1:0]                M_AXI_RDATA         ,       //读数据通道数据
        input               [1:0]                                   M_AXI_RRESP         ,       //读数据通道回复信号
        input                                                       M_AXI_RLAST         ,       //读数据通道最后一位数据信号
        input               [C_M_AXI_RUSER_WIDTH-1:0]               M_AXI_RUSER         ,       //读数据通道用户自定义信号
        input                                                       M_AXI_RVALID        ,       //读数据通道有效指示信号
        output           reg                                        M_AXI_RREADY                //读数据通道数据应答信号        
    );

        parameter               IDLE                =               4'b0001             ;       //空闲状态
        parameter               WRITE               =               4'b0010             ;       //写数据状态
        parameter               READ                =               4'b0100             ;       //读数据状态
        parameter               ERROR               =               4'b1000             ;       //数据错误状态
        parameter               SIZE                =               clogb2(C_M_AXI_DATA_WIDTH/8-1);//突发数据字节位宽数
        parameter               CNT_W               =               clogb2(C_M_AXI_BURST_LEN - 1); //通过突发长度计算计数器位宽

        reg                     [3:0]                               state               ;       //现态
        reg                     [3:0]                               next_state          ;       //次态
        reg                                                         error_flag          ;       //错误指示信号
        reg                     [CNT_W-1:0]                         wr_cnt              ;       //   
        reg                     [CNT_W-1:0]                         rd_cnt              ;       //  
        reg                     [1:0]                               cnt                 ;   

        //写地址通道
        assign  M_AXI_AWID      =   0                                                   ;       //写地址ID
        assign  M_AXI_AWBURST   =   2'b01                                               ;       //该突发类型为递增类型,即读写地址依次递增
        assign  M_AXI_AWSIZE    =   SIZE                                                ;       //突发数据的位宽字节数
        assign  M_AXI_AWLEN     =   C_M_AXI_BURST_LEN - 1                               ;       //写地址突发长度
        assign  M_AXI_AWLOCK    =   0                                                   ;       //写地址通道锁信号
        assign  M_AXI_AWPROT    =   3'd0                                                ;       //写地址端口为0
        assign  M_AXI_AWQOS     =   4'd0                                                ;       //不使用
        assign  M_AXI_AWCACHE   =   4'b0010                                             ;       //不使用缓存
        assign  M_AXI_AWUSER    =   0                                                   ;       //不使用写地址通道用户信号
        //写数据通道
        assign  M_AXI_WSTRB     =   {{C_M_AXI_DATA_WIDTH/8}{1'b1}}                      ;       //将掩码信号拉高,即不使用掩码
        assign  M_AXI_WUSER     =   0                                                   ;       //不使用写数据通道用户信号
        //读地址通道
        assign  M_AXI_ARID      =   0                                                   ;       //写地址ID
        assign  M_AXI_ARBURST   =   2'b01                                               ;       //该突发类型为递增类型,即读写地址依次递增
        assign  M_AXI_ARSIZE    =   SIZE                                                ;       //突发数据的位宽字节数
        assign  M_AXI_ARLEN     =   C_M_AXI_BURST_LEN - 1                               ;       //写地址突发长度
        assign  M_AXI_ARLOCK    =   0                                                   ;       //写地址通道锁信号
        assign  M_AXI_ARPROT    =   3'd0                                                ;       //写地址端口为0
        assign  M_AXI_ARQOS     =   4'd0                                                ;       //不使用
        assign  M_AXI_ARCACHE   =   4'b0010                                             ;       //不使用缓存
        assign  M_AXI_ARUSER    =   0                                                   ;       //不使用写地址通道用户信号  

        //自动计算位宽函数。
        function integer clogb2(input integer depth);begin
            if(depth == 0)
                clogb2 = 1;
            else if(depth != 0)
                for(clogb2=0 ; depth>0 ; clogb2=clogb2+1)
                    depth=depth >> 1;
        end
        endfunction

        always @(negedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                state <= IDLE;
            else
                state <= next_state;
        end

        always @(*) begin
            next_state = IDLE;
            case(state)
                IDLE:   next_state = WRITE;
                WRITE:  begin
                    if(M_AXI_BREADY && M_AXI_BVALID)                    //写响应通道握手成功
                        next_state = READ;
                    else
                        next_state = WRITE;
                end
                READ:   begin
                    if(M_AXI_RLAST && M_AXI_ARVALID)                    //当前数据是最后一位且读地址有效信号拉高
                        next_state = IDLE;
                    else if(error_flag)                                 //错误信号拉高
                        next_state = ERROR;
                    else
                        next_state = READ;
                end 
                ERROR:
                    next_state = ERROR;
                default: next_state = IDLE;
            endcase
        end

        //写地址通道信号
        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_AWADDR <= C_M_TARGET_SLAVE_BASE_ADDR;                                     //复位后为基地址
            else if(M_AXI_BREADY && M_AXI_BVALID)                                               //写响应通道成功响应,注意此处不是写地址通道成功握手
                M_AXI_AWADDR <= M_AXI_AWADDR + (C_M_AXI_BURST_LEN * C_M_AXI_DATA_WIDTH/8);      //跳过被写数据的地址
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_AWVALID <= 1'b0;
            else if(M_AXI_AWREADY)                                                               //当应答信号有效时拉低
                M_AXI_AWVALID <= 1'b0;
            else if(state == IDLE && next_state == WRITE)                                       //进入写状态拉高
                M_AXI_AWVALID <= 1'b1;
        end

        //写数据通道信号
        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                wr_cnt <= 'd0;
            else if(state != WRITE)                                                             //当前状态不处于写状态清零
                wr_cnt <= 'd0;
            else if(M_AXI_WREADY && M_AXI_WVALID)                                               //写入一次数据
                wr_cnt <= wr_cnt + 1'b1;
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_WDATA <= 'd0;
            else if(M_AXI_WREADY && M_AXI_WVALID)                                               //每写入一次数据加一
                M_AXI_WDATA <= M_AXI_WDATA + 1'b1;
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_WVALID <= 1'b0;
            else if(wr_cnt == C_M_AXI_BURST_LEN-1 && M_AXI_WVALID && M_AXI_WREADY)              //写完最后一个数据且写通道握手成功
                M_AXI_WVALID <= 1'b0;
            else if(state == IDLE && next_state == WRITE)                                            //进入写状态拉高
                M_AXI_WVALID <= 1'b1;
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_WLAST <= 1'b0;
            else if(M_AXI_WREADY && M_AXI_WVALID)
                if(wr_cnt == C_M_AXI_BURST_LEN-1)                                               //最后一次数据写入完成后拉低
                    M_AXI_WLAST <= 1'b0;
                else if(wr_cnt == C_M_AXI_BURST_LEN-2)                                          //将要写最后一次数据的时候拉高
                    M_AXI_WLAST <= 1'b1;
            else
            M_AXI_WLAST <= 1'b0;                                                                //否则保持为低
        end

        //写响应通道
        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_BREADY <= 1'b0;
            else if(M_AXI_BVALID)                                                               //与从机握手成功后拉低
                M_AXI_BREADY <= 1'b0;
            else if(M_AXI_WLAST && M_AXI_WREADY && M_AXI_WVALID)                                //写入最后一位数据后拉高
                M_AXI_BREADY <= 1'b1;
        end

        //读地址通道
        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_ARADDR <= 'd0;
            else if(M_AXI_RLAST)                                                                //读完最后一个数据跳过已经读过的地址
                M_AXI_ARADDR <= M_AXI_ARADDR + (C_M_AXI_BURST_LEN * C_M_AXI_DATA_WIDTH/8);
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                cnt <= 2'd0;
            else if(state == READ) 
                if(cnt == 2'd2)
                    cnt <= cnt;
                else 
                    cnt <= cnt + 1'b1;
            else
                cnt <= 2'd0;
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_ARVALID <= 1'b0;
            else if(M_AXI_ARREADY)                                                              //握手成功后拉低
                M_AXI_ARVALID <= 1'b0;        
            else if(cnt == 2'd1)                                                                //进入读状态后拉高
                M_AXI_ARVALID <= 1'b1;
        end 

        //读数据通道
        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                rd_cnt <= 'd0;
            else if(wr_cnt == C_M_AXI_BURST_LEN-1)
                rd_cnt <= 'd0;
            else if(M_AXI_RREADY && M_AXI_RVALID)                                               //每读出一个数据加一
                rd_cnt <= rd_cnt + 1'b1;
        end

        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                M_AXI_RREADY <= 1'b0;
            else if(M_AXI_RLAST)                                                                //读出最后一个数据后拉低
                M_AXI_RREADY <= 1'b0;
            else if(M_AXI_ARVALID && M_AXI_ARREADY)                                             //写地址通道握手成功后拉高,代表可以接受数据
                M_AXI_RREADY <= 1'b1;
        end

        //错误指示信号
        always @(posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
            if(!M_AXI_ARESETN)
                error_flag <= 1'b0;
            else if(M_AXI_WVALID && M_AXI_WREADY && state == READ)
                error_flag <= (M_AXI_ARADDR + C_M_TARGET_SLAVE_BASE_ADDR - rd_cnt != M_AXI_RDATA);//读出的数据不等于写入数据
        end

endmodule

`timescale 1 ns / 1 ps

	module axi_full_slave #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line

		// Width of ID for for write address, write data, read address and read data
		parameter integer C_S_AXI_ID_WIDTH	= 1,
		// Width of S_AXI data bus
		parameter integer C_S_AXI_DATA_WIDTH	= 32,
		// Width of S_AXI address bus
		parameter integer C_S_AXI_ADDR_WIDTH	= 10,
		// Width of optional user defined signal in write address channel
		parameter integer C_S_AXI_AWUSER_WIDTH	= 0,
		// Width of optional user defined signal in read address channel
		parameter integer C_S_AXI_ARUSER_WIDTH	= 0,
		// Width of optional user defined signal in write data channel
		parameter integer C_S_AXI_WUSER_WIDTH	= 0,
		// Width of optional user defined signal in read data channel
		parameter integer C_S_AXI_RUSER_WIDTH	= 0,
		// Width of optional user defined signal in write response channel
		parameter integer C_S_AXI_BUSER_WIDTH	= 0
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line

		// Global Clock Signal
		input wire  S_AXI_ACLK,
		// Global Reset Signal. This Signal is Active LOW
		input wire  S_AXI_ARESETN,
		// Write Address ID
		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
		// Write address
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
		// Burst length. The burst length gives the exact number of transfers in a burst
		input wire [7 : 0] S_AXI_AWLEN,
		// Burst size. This signal indicates the size of each transfer in the burst
		input wire [2 : 0] S_AXI_AWSIZE,
		// Burst type. The burst type and the size information, 
    // determine how the address for each transfer within the burst is calculated.
		input wire [1 : 0] S_AXI_AWBURST,
		// Lock type. Provides additional information about the
    // atomic characteristics of the transfer.
		input wire  S_AXI_AWLOCK,
		// Memory type. This signal indicates how transactions
    // are required to progress through a system.
		input wire [3 : 0] S_AXI_AWCACHE,
		// Protection type. This signal indicates the privilege
    // and security level of the transaction, and whether
    // the transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_AWPROT,
		// Quality of Service, QoS identifier sent for each
    // write transaction.
		input wire [3 : 0] S_AXI_AWQOS,
		// Region identifier. Permits a single physical interface
    // on a slave to be used for multiple logical interfaces.
		input wire [3 : 0] S_AXI_AWREGION,
		// Optional User-defined signal in the write address channel.
		input wire [C_S_AXI_AWUSER_WIDTH-1 : 0] S_AXI_AWUSER,
		// Write address valid. This signal indicates that
    // the channel is signaling valid write address and
    // control information.
		input wire  S_AXI_AWVALID,
		// Write address ready. This signal indicates that
    // the slave is ready to accept an address and associated
    // control signals.
		output wire  S_AXI_AWREADY,
		// Write Data
		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
		// Write strobes. This signal indicates which byte
    // lanes hold valid data. There is one write strobe
    // bit for each eight bits of the write data bus.
		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
		// Write last. This signal indicates the last transfer
    // in a write burst.
		input wire  S_AXI_WLAST,
		// Optional User-defined signal in the write data channel.
		input wire [C_S_AXI_WUSER_WIDTH-1 : 0] S_AXI_WUSER,
		// Write valid. This signal indicates that valid write
    // data and strobes are available.
		input wire  S_AXI_WVALID,
		// Write ready. This signal indicates that the slave
    // can accept the write data.
		output wire  S_AXI_WREADY,
		// Response ID tag. This signal is the ID tag of the
    // write response.
		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
		// Write response. This signal indicates the status
    // of the write transaction.
		output wire [1 : 0] S_AXI_BRESP,
		// Optional User-defined signal in the write response channel.
		output wire [C_S_AXI_BUSER_WIDTH-1 : 0] S_AXI_BUSER,
		// Write response valid. This signal indicates that the
    // channel is signaling a valid write response.
		output wire  S_AXI_BVALID,
		// Response ready. This signal indicates that the master
    // can accept a write response.
		input wire  S_AXI_BREADY,
		// Read address ID. This signal is the identification
    // tag for the read address group of signals.
		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
		// Read address. This signal indicates the initial
    // address of a read burst transaction.
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
		// Burst length. The burst length gives the exact number of transfers in a burst
		input wire [7 : 0] S_AXI_ARLEN,
		// Burst size. This signal indicates the size of each transfer in the burst
		input wire [2 : 0] S_AXI_ARSIZE,
		// Burst type. The burst type and the size information, 
    // determine how the address for each transfer within the burst is calculated.
		input wire [1 : 0] S_AXI_ARBURST,
		// Lock type. Provides additional information about the
    // atomic characteristics of the transfer.
		input wire  S_AXI_ARLOCK,
		// Memory type. This signal indicates how transactions
    // are required to progress through a system.
		input wire [3 : 0] S_AXI_ARCACHE,
		// Protection type. This signal indicates the privilege
    // and security level of the transaction, and whether
    // the transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_ARPROT,
		// Quality of Service, QoS identifier sent for each
    // read transaction.
		input wire [3 : 0] S_AXI_ARQOS,
		// Region identifier. Permits a single physical interface
    // on a slave to be used for multiple logical interfaces.
		input wire [3 : 0] S_AXI_ARREGION,
		// Optional User-defined signal in the read address channel.
		input wire [C_S_AXI_ARUSER_WIDTH-1 : 0] S_AXI_ARUSER,
		// Write address valid. This signal indicates that
    // the channel is signaling valid read address and
    // control information.
		input wire  S_AXI_ARVALID,
		// Read address ready. This signal indicates that
    // the slave is ready to accept an address and associated
    // control signals.
		output wire  S_AXI_ARREADY,
		// Read ID tag. This signal is the identification tag
    // for the read data group of signals generated by the slave.
		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID,
		// Read Data
		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
		// Read response. This signal indicates the status of
    // the read transfer.
		output wire [1 : 0] S_AXI_RRESP,
		// Read last. This signal indicates the last transfer
    // in a read burst.
		output wire  S_AXI_RLAST,
		// Optional User-defined signal in the read address channel.
		output wire [C_S_AXI_RUSER_WIDTH-1 : 0] S_AXI_RUSER,
		// Read valid. This signal indicates that the channel
    // is signaling the required read data.
		output wire  S_AXI_RVALID,
		// Read ready. This signal indicates that the master can
    // accept the read data and response information.
		input wire  S_AXI_RREADY
	);

	// AXI4FULL signals
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
	reg  	axi_awready;
	reg  	axi_wready;
	reg [1 : 0] 	axi_bresp;
	reg [C_S_AXI_BUSER_WIDTH-1 : 0] 	axi_buser;
	reg  	axi_bvalid;
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;
	reg  	axi_arready;
	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
	reg [1 : 0] 	axi_rresp;
	reg  	axi_rlast;
	reg [C_S_AXI_RUSER_WIDTH-1 : 0] 	axi_ruser;
	reg  	axi_rvalid;
	// aw_wrap_en determines wrap boundary and enables wrapping
	wire aw_wrap_en;
	// ar_wrap_en determines wrap boundary and enables wrapping
	wire ar_wrap_en;
	// aw_wrap_size is the size of the write transfer, the
	// write address wraps to a lower address if upper address
	// limit is reached
	wire [31:0]  aw_wrap_size ; 
	// ar_wrap_size is the size of the read transfer, the
	// read address wraps to a lower address if upper address
	// limit is reached
	wire [31:0]  ar_wrap_size ; 
	// The axi_awv_awr_flag flag marks the presence of write address valid
	reg axi_awv_awr_flag;
	//The axi_arv_arr_flag flag marks the presence of read address valid
	reg axi_arv_arr_flag; 
	// The axi_awlen_cntr internal write address counter to keep track of beats in a burst transaction
	reg [7:0] axi_awlen_cntr;
	//The axi_arlen_cntr internal read address counter to keep track of beats in a burst transaction
	reg [7:0] axi_arlen_cntr;
	reg [1:0] axi_arburst;
	reg [1:0] axi_awburst;
	reg [7:0] axi_arlen;
	reg [7:0] axi_awlen;
	//local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
	//ADDR_LSB is used for addressing 32/64 bit registers/memories
	//ADDR_LSB = 2 for 32 bits (n downto 2) 
	//ADDR_LSB = 3 for 42 bits (n downto 3)

	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32)+ 1;
	localparam integer OPT_MEM_ADDR_BITS = 7;
	localparam integer USER_NUM_MEM = 1;
	//----------------------------------------------
	//-- Signals for user logic memory space example
	//------------------------------------------------
	wire [OPT_MEM_ADDR_BITS:0] mem_address;
	wire [USER_NUM_MEM-1:0] mem_select;
	reg [C_S_AXI_DATA_WIDTH-1:0] mem_data_out[0 : USER_NUM_MEM-1];

	genvar i;
	genvar j;
	genvar mem_byte_index;

	// I/O Connections assignments

	assign S_AXI_AWREADY= axi_awready;
	assign S_AXI_WREADY	= axi_wready;
	assign S_AXI_BRESP	= axi_bresp;
	assign S_AXI_BUSER	= axi_buser;
	assign S_AXI_BVALID	= axi_bvalid;
	assign S_AXI_ARREADY	= axi_arready;
	assign S_AXI_RDATA	= axi_rdata;
	assign S_AXI_RRESP	= axi_rresp;
	assign S_AXI_RLAST	= axi_rlast;
	assign S_AXI_RUSER	= axi_ruser;
	assign S_AXI_RVALID	= axi_rvalid;
	assign S_AXI_BID = S_AXI_AWID;
	assign S_AXI_RID = S_AXI_ARID;
	assign  aw_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_awlen)); 
	assign  ar_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_arlen)); 
	assign  aw_wrap_en = ((axi_awaddr & aw_wrap_size) == aw_wrap_size)? 1'b1: 1'b0;
	assign  ar_wrap_en = ((axi_araddr & ar_wrap_size) == ar_wrap_size)? 1'b1: 1'b0;

	// Implement axi_awready generation

	// axi_awready is asserted for one S_AXI_ACLK clock cycle when both
	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
	// de-asserted when reset is low.

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_awready <= 1'b0;
	      axi_awv_awr_flag <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
		  //if (~axi_awready && S_AXI_AWVALID)
	        begin
	          // slave is ready to accept an address and
	          // associated control signals
	          axi_awready <= 1'b1;
	          axi_awv_awr_flag  <= 1'b1;
	          // used for generation of bresp() and bvalid
	        end
	      else if (S_AXI_WLAST && axi_wready)      
	      // preparing to accept next address after current write burst tx completion
	        begin
	          axi_awv_awr_flag  <= 1'b0;
	        end
	      else        
	        begin
	          axi_awready <= 1'b0;
	        end
	    end 
	end       
	// Implement axi_awaddr latching

	// This process is used to latch the address when both 
	// S_AXI_AWVALID and S_AXI_WVALID are valid. 

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_awaddr <= 0;
	      axi_awlen_cntr <= 0;
	      axi_awburst <= 0;
	      axi_awlen <= 0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
	        begin
	          // address latching 
	          axi_awaddr <= S_AXI_AWADDR[C_S_AXI_ADDR_WIDTH - 1:0];  
	           axi_awburst <= S_AXI_AWBURST; 
	           axi_awlen <= S_AXI_AWLEN;     
	          // start address of transfer
	          axi_awlen_cntr <= 0;
	        end   
	      else if((axi_awlen_cntr <= axi_awlen) && axi_wready && S_AXI_WVALID)        
	        begin

	          axi_awlen_cntr <= axi_awlen_cntr + 1;

	          case (axi_awburst)
	            2'b00: // fixed burst
	            // The write address for all the beats in the transaction are fixed
	              begin
	                axi_awaddr <= axi_awaddr;          
	                //for awsize = 4 bytes (010)
	              end   
	            2'b01: //incremental burst
	            // The write address for all the beats in the transaction are increments by awsize
	              begin
	                axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //awaddr aligned to 4 byte boundary
	                axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                //for awsize = 4 bytes (010)
	              end   
	            2'b10: //Wrapping burst
	            // The write address wraps when the address reaches wrap boundary 
	              if (aw_wrap_en)
	                begin
	                  axi_awaddr <= (axi_awaddr - aw_wrap_size); 
	                end
	              else 
	                begin
	                  axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                  axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}}; 
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_awaddr <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //for awsize = 4 bytes (010)
	              end
	          endcase              
	        end
	    end 
	end       
	// Implement axi_wready generation

	// axi_wready is asserted for one S_AXI_ACLK clock cycle when both
	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 
	// de-asserted when reset is low. 

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_wready <= 1'b0;
	    end 
	  else
	    begin    
	      if ( ~axi_wready && S_AXI_WVALID && axi_awv_awr_flag)
	        begin
	          // slave can accept the write data
	          axi_wready <= 1'b1;
	        end
	      //else if (~axi_awv_awr_flag)
	      else if (S_AXI_WLAST && axi_wready)
	        begin
	          axi_wready <= 1'b0;
	        end
	    end 
	end       
	// Implement write response logic generation

	// The write response and response valid signals are asserted by the slave 
	// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
	// This marks the acceptance of address and indicates the status of 
	// write transaction.

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_bvalid <= 0;
	      axi_bresp <= 2'b0;
	      axi_buser <= 0;
	    end 
	  else
	    begin    
	      if (axi_awv_awr_flag && axi_wready && S_AXI_WVALID && ~axi_bvalid && S_AXI_WLAST )
	        begin
	          axi_bvalid <= 1'b1;
	          axi_bresp  <= 2'b0; 
	          // 'OKAY' response 
	        end                   
	      else
	        begin
	          if (S_AXI_BREADY && axi_bvalid) 
	          //check if bready is asserted while bvalid is high) 
	          //(there is a possibility that bready is always asserted high)   
	            begin
	              axi_bvalid <= 1'b0; 
	            end  
	        end
	    end
	 end   
	// Implement axi_arready generation

	// axi_arready is asserted for one S_AXI_ACLK clock cycle when
	// S_AXI_ARVALID is asserted. axi_awready is 
	// de-asserted when reset (active low) is asserted. 
	// The read address is also latched when S_AXI_ARVALID is 
	// asserted. axi_araddr is reset to zero on reset assertion.

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_arready <= 1'b0;
	      axi_arv_arr_flag <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
	        begin
	          axi_arready <= 1'b1;
	          axi_arv_arr_flag <= 1'b1;
	        end
	      else if (axi_rvalid && S_AXI_RREADY && axi_arlen_cntr == axi_arlen)
	      // preparing to accept next address after current read completion
	        begin
	          axi_arv_arr_flag  <= 1'b0;
	        end
	      else        
	        begin
	          axi_arready <= 1'b0;
	        end
	    end 
	end       
	// Implement axi_araddr latching

	//This process is used to latch the address when both 
	//S_AXI_ARVALID and S_AXI_RVALID are valid. 
	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_araddr <= 0;
	      axi_arlen_cntr <= 0;
	      axi_arburst <= 0;
	      axi_arlen <= 0;
	      axi_rlast <= 1'b0;
	      axi_ruser <= 0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID && ~axi_arv_arr_flag)
	        begin
	          // address latching 
	          axi_araddr <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH - 1:0]; 
	          axi_arburst <= S_AXI_ARBURST; 
	          axi_arlen <= S_AXI_ARLEN;     
	          // start address of transfer
	          axi_arlen_cntr <= 0;
	          axi_rlast <= 1'b0;
	        end   
	      else if((axi_arlen_cntr <= axi_arlen) && axi_rvalid && S_AXI_RREADY)        
	        begin
	         
	          axi_arlen_cntr <= axi_arlen_cntr + 1;
	          axi_rlast <= 1'b0;
	        
	          case (axi_arburst)
	            2'b00: // fixed burst
	             // The read address for all the beats in the transaction are fixed
	              begin
	                axi_araddr       <= axi_araddr;        
	                //for arsize = 4 bytes (010)
	              end   
	            2'b01: //incremental burst
	            // The read address for all the beats in the transaction are increments by awsize
	              begin
	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                //for awsize = 4 bytes (010)
	              end   
	            2'b10: //Wrapping burst
	            // The read address wraps when the address reaches wrap boundary 
	              if (ar_wrap_en) 
	                begin
	                  axi_araddr <= (axi_araddr - ar_wrap_size); 
	                end
	              else 
	                begin
	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_araddr <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB]+1;
	                //for arsize = 4 bytes (010)
	              end
	          endcase              
	        end
	      else if((axi_arlen_cntr == axi_arlen) && ~axi_rlast && axi_arv_arr_flag )   
	        begin
	          axi_rlast <= 1'b1;
	        end          
	      else if (S_AXI_RREADY)   
	        begin
	          axi_rlast <= 1'b0;
	        end          
	    end 
	end       
	// Implement axi_arvalid generation

	// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
	// S_AXI_ARVALID and axi_arready are asserted. The slave registers 
	// data are available on the axi_rdata bus at this instance. The 
	// assertion of axi_rvalid marks the validity of read data on the 
	// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	// is deasserted on reset (active low). axi_rresp and axi_rdata are 
	// cleared to zero on reset (active low).  

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_rvalid <= 0;
	      axi_rresp  <= 0;
	    end 
	  else
	    begin    
	      if (axi_arv_arr_flag && ~axi_rvalid)
	        begin
	          axi_rvalid <= 1'b1;
	          axi_rresp  <= 2'b0; 
	          // 'OKAY' response
	        end   
	      else if (axi_rvalid && S_AXI_RREADY)
	        begin
	          axi_rvalid <= 1'b0;
	        end            
	    end
	end    
	// ------------------------------------------
	// -- Example code to access user logic memory region
	// ------------------------------------------

	generate
	  if (USER_NUM_MEM >= 1)
	    begin
	      assign mem_select  = 1;
	      assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
	    end
	endgenerate
	     
	// implement Block RAM(s)
	generate 
	  for(i=0; i<= USER_NUM_MEM-1; i=i+1)
	    begin:BRAM_GEN
	      wire mem_rden;
	      wire mem_wren;
	
	      assign mem_wren = axi_wready && S_AXI_WVALID ;
	
	      assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
	     
	      for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)
	      begin:BYTE_BRAM_GEN
	        wire [8-1:0] data_in ;
	        wire [8-1:0] data_out;
	        reg  [8-1:0] byte_ram [0 : 255];
	        integer  j;
	     
	        //assigning 8 bit data
	        assign data_in  = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
	        assign data_out = byte_ram[mem_address];
	     
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_wren && S_AXI_WSTRB[mem_byte_index])
	            begin
	              byte_ram[mem_address] <= data_in;
	            end   
	        end    
	      
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_rden)
	            begin
	              mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
	            end   
	        end    
	               
	    end
	  end       
	endgenerate
	//Output register or memory read data

	always @( mem_data_out, axi_rvalid)
	begin
	  if (axi_rvalid) 
	    begin
	      // Read address mux
	      axi_rdata <= mem_data_out[0];
	    end   
	  else
	    begin
	      axi_rdata <= 32'h00000000;
	    end       
	end    

	// Add user logic here

	// User logic ends

	endmodule
`timescale  1ns / 1ps

module tb_axi_full_master;
parameter	CYCLE		                =   10              ;//系统时钟周期,单位ns,默认10ns;
parameter	RST_TIME	                =   10              ;//系统复位持续时间,默认10个系统时钟周期;
// axi_full_master Parameters
parameter PERIOD                      = 10                           ;
parameter C_M_TARGET_SLAVE_BASE_ADDR  = 32'h40000000                 ;
parameter C_M_AXI_BURST_LEN           = 16                           ;
parameter C_M_AXI_ID_WIDTH            = 1                            ;
parameter C_M_AXI_DATA_WIDTH          = 32                           ;
parameter C_M_AXI_ADDR_WIDTH          = 32                           ;
parameter C_M_AXI_AWUSER_WIDTH        = 0                            ;
parameter C_M_AXI_ARUSER_WIDTH        = 0                            ;
parameter C_M_AXI_WUSER_WIDTH         = 0                            ;
parameter C_M_AXI_RUSER_WIDTH         = 0                            ;
parameter C_M_AXI_BUSER_WIDTH         = 0                            ;

// axi_full_master Inputs
reg   clk            = 0                     ;
reg   rst_n          = 0                     ;
wire   M_AXI_AWREADY                         ;
wire   M_AXI_WREADY                          ;
wire   M_AXI_BVALID                          ;
wire   [C_M_AXI_ID_WIDTH-1:0]  M_AXI_BID     ;
wire   [1:0]  M_AXI_BRESP                    ;
wire   [C_M_AXI_BUSER_WIDTH-1:0]  M_AXI_BUSER;
wire   M_AXI_ARREADY                         ;
wire   [C_M_AXI_ID_WIDTH-1:0]  M_AXI_RID     ;
wire   [C_M_AXI_DATA_WIDTH-1:0]  M_AXI_RDATA ;
wire   [1:0]  M_AXI_RRESP                    ;
wire   M_AXI_RLAST                           ;
wire   [C_M_AXI_RUSER_WIDTH-1:0]  M_AXI_RUSER;
wire   M_AXI_RVALID                          ;

// axi_full_master Outputs
wire   [C_M_AXI_ADDR_WIDTH-1:0]M_AXI_AWADDR ;
wire  [C_M_AXI_ID_WIDTH-1:0]  M_AXI_AWID   ;
wire  [1:0]  M_AXI_AWBURST                 ;
wire  [2:0]  M_AXI_AWSIZE                  ;
wire  [7:0]  M_AXI_AWLEN                   ;
wire  M_AXI_AWLOCK                         ;
wire  [3:0]  M_AXI_AWCACHE                 ;
wire  [2:0]  M_AXI_AWPROT                  ;
wire  [3:0]  M_AXI_AWQOS                   ;
wire  [C_M_AXI_AWUSER_WIDTH-1:0]  M_AXI_AWUSER ;
wire  M_AXI_AWVALID                        ;
wire  [C_M_AXI_DATA_WIDTH-1:0]    M_AXI_WDATA ;
wire  [C_M_AXI_DATA_WIDTH/8-1:0]  M_AXI_WSTRB ;
wire  M_AXI_WLAST                          ;
wire  [C_M_AXI_WUSER_WIDTH-1:0]  M_AXI_WUSER ;
wire  M_AXI_WVALID                         ;
wire  M_AXI_BREADY                         ;
wire  [C_M_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR ;
wire  [C_M_AXI_ID_WIDTH-1:0]  M_AXI_ARID   ;
wire  [7:0]  M_AXI_ARLEN                   ;
wire  [2:0]  M_AXI_ARSIZE                  ;
wire  [1:0]  M_AXI_ARBURST                 ;
wire  M_AXI_ARLOCK                         ;
wire  [3:0]  M_AXI_ARCACHE                 ;
wire  [2:0]  M_AXI_ARPROT                  ;
wire  [3:0]  M_AXI_ARQOS                   ;
wire  [C_M_AXI_ARUSER_WIDTH-1:0]  M_AXI_ARUSER ;
wire  M_AXI_ARVALID                        ;
wire  M_AXI_RREADY                         ;


initial
begin
    forever #(PERIOD/2)  clk=~clk;
end

axi_full_master #(
    .C_M_TARGET_SLAVE_BASE_ADDR ( C_M_TARGET_SLAVE_BASE_ADDR ),
    .C_M_AXI_BURST_LEN          ( C_M_AXI_BURST_LEN          ),
    .C_M_AXI_ID_WIDTH           ( C_M_AXI_ID_WIDTH           ),
    .C_M_AXI_DATA_WIDTH         ( C_M_AXI_DATA_WIDTH         ),
    .C_M_AXI_ADDR_WIDTH         ( C_M_AXI_ADDR_WIDTH         ),
    .C_M_AXI_AWUSER_WIDTH       ( C_M_AXI_AWUSER_WIDTH       ),
    .C_M_AXI_ARUSER_WIDTH       ( C_M_AXI_ARUSER_WIDTH       ),
    .C_M_AXI_WUSER_WIDTH        ( C_M_AXI_WUSER_WIDTH        ),
    .C_M_AXI_RUSER_WIDTH        ( C_M_AXI_RUSER_WIDTH        ),
    .C_M_AXI_BUSER_WIDTH        ( C_M_AXI_BUSER_WIDTH        )
)
 u_axi_full_master (
    .M_AXI_ACLK                                               ( clk                                                                         ),
    .M_AXI_ARESETN                                            ( rst_n                                                                      ),
    .M_AXI_AWREADY                                            ( M_AXI_AWREADY                                                                       ),
    .M_AXI_WREADY                                             ( M_AXI_WREADY                                                                        ),
    .M_AXI_BVALID                                             ( M_AXI_BVALID                                                                        ),
    .M_AXI_BID                                                ( M_AXI_BID                                                                            ),
    .M_AXI_BRESP                                              ( M_AXI_BRESP                                                                           ),
    .M_AXI_BUSER                                              ( M_AXI_BUSER                                                                           ),
    .M_AXI_ARREADY                                            ( M_AXI_ARREADY                                                                       ),
    .M_AXI_RID                                                ( M_AXI_RID                                                        ),
    .M_AXI_RDATA                                              ( M_AXI_RDATA                                                   ),
    .M_AXI_RRESP                                              ( M_AXI_RRESP                                                                      ),
    .M_AXI_RLAST                                              ( M_AXI_RLAST                                                                         ),
    .M_AXI_RUSER                                              ( M_AXI_RUSER                                                   ),
    .M_AXI_RVALID                                             ( M_AXI_RVALID                                                                        ),

    .M_AXI_AWADDR                                             ( M_AXI_AWADDR                                                                        ),
    .M_AXI_AWID                                               ( M_AXI_AWID                                                       ),
    .M_AXI_AWBURST                                            ( M_AXI_AWBURST                                                                     ),
    .M_AXI_AWSIZE                                             ( M_AXI_AWSIZE                                                                      ),
    .M_AXI_AWLEN                                              ( M_AXI_AWLEN                                                                      ),
    .M_AXI_AWLOCK                                             ( M_AXI_AWLOCK                                                                        ),
    .M_AXI_AWCACHE                                            ( M_AXI_AWCACHE                                                                     ),
    .M_AXI_AWPROT                                             ( M_AXI_AWPROT                                                                     ),
    .M_AXI_AWQOS                                              ( M_AXI_AWQOS                                                                       ),
    .M_AXI_AWUSER                                             ( M_AXI_AWUSER                                                 ),
    .M_AXI_AWVALID                                            ( M_AXI_AWVALID                                                                       ),
    .M_AXI_WDATA                                              (                    M_AXI_WDATA                              ),
    .M_AXI_WSTRB                                              ( M_AXI_WSTRB                                                  ),
    .M_AXI_WLAST                                              ( M_AXI_WLAST                                                                         ),
    .M_AXI_WUSER                                              ( M_AXI_WUSER                                                   ),
    .M_AXI_WVALID                                             ( M_AXI_WVALID                                                                        ),
    .M_AXI_BREADY                                             ( M_AXI_BREADY                                                                        ),
    .M_AXI_ARADDR                                             (                    M_AXI_ARADDR                             ),
    .M_AXI_ARID                                               ( M_AXI_ARID                                                      ),
    .M_AXI_ARLEN                                              ( M_AXI_ARLEN                                                                      ),
    .M_AXI_ARSIZE                                             ( M_AXI_ARSIZE                                                                      ),
    .M_AXI_ARBURST                                            ( M_AXI_ARBURST                                                                    ),
    .M_AXI_ARLOCK                                             ( M_AXI_ARLOCK                                                                        ),
    .M_AXI_ARCACHE                                            ( M_AXI_ARCACHE                                                                     ),
    .M_AXI_ARPROT                                             ( M_AXI_ARPROT                                                                     ),
    .M_AXI_ARQOS                                              ( M_AXI_ARQOS                                                                       ),
    .M_AXI_ARUSER                                             ( M_AXI_ARUSER                                                                        ),
    .M_AXI_ARVALID                                            ( M_AXI_ARVALID                                                                       ),
    .M_AXI_RREADY                                             ( M_AXI_RREADY                                                                        )
);

    //例化AXI从机模块
    axi_full_slave #(
        .C_S_AXI_ID_WIDTH       ( C_M_AXI_ID_WIDTH	    ),
        .C_S_AXI_DATA_WIDTH     ( C_M_AXI_ADDR_WIDTH    ),
        .C_S_AXI_ADDR_WIDTH     ( C_M_AXI_DATA_WIDTH    ),
        .C_S_AXI_AWUSER_WIDTH   ( C_M_AXI_AWUSER_WIDTH  ),
        .C_S_AXI_ARUSER_WIDTH   ( C_M_AXI_ARUSER_WIDTH  ),
        .C_S_AXI_WUSER_WIDTH    ( C_M_AXI_WUSER_WIDTH   ),
        .C_S_AXI_RUSER_WIDTH    ( C_M_AXI_RUSER_WIDTH   ),
        .C_S_AXI_BUSER_WIDTH    ( C_M_AXI_BUSER_WIDTH   )
    )
    u_axi_full_slave (
        .S_AXI_ACLK              ( clk              ),
        .S_AXI_ARESETN           ( rst_n            ),
        //AXI写地址通道
        .S_AXI_AWID              ( M_AXI_AWID       ),
        .S_AXI_AWADDR            ( M_AXI_AWADDR     ),
        .S_AXI_AWLEN             ( M_AXI_AWLEN      ),
        .S_AXI_AWSIZE            ( M_AXI_AWSIZE     ),
        .S_AXI_AWBURST           ( M_AXI_AWBURST    ),
        .S_AXI_AWLOCK            ( M_AXI_AWLOCK     ),
        .S_AXI_AWCACHE           ( M_AXI_AWCACHE    ),
        .S_AXI_AWPROT            ( M_AXI_AWPROT     ),
        .S_AXI_AWQOS             ( M_AXI_AWQOS      ),
        .S_AXI_AWREGION          ( 4'd0             ),
        .S_AXI_AWUSER            ( M_AXI_AWUSER     ),
        .S_AXI_AWVALID           ( M_AXI_AWVALID    ),
        .S_AXI_AWREADY           ( M_AXI_AWREADY    ),
        //AXI写数据通道。
        .S_AXI_WDATA             ( M_AXI_WDATA      ),
        .S_AXI_WSTRB             ( M_AXI_WSTRB      ),
        .S_AXI_WLAST             ( M_AXI_WLAST      ),
        .S_AXI_WUSER             ( M_AXI_WUSER      ),
        .S_AXI_WVALID            ( M_AXI_WVALID     ),
        .S_AXI_WREADY            ( M_AXI_WREADY     ),
        //AXI写应答通道。
        .S_AXI_BREADY            ( M_AXI_BREADY     ),
        .S_AXI_BID               ( M_AXI_BID        ),
        .S_AXI_BRESP             ( M_AXI_BRESP      ),
        .S_AXI_BUSER             ( M_AXI_BUSER      ),
        .S_AXI_BVALID            ( M_AXI_BVALID     ),
        //AXI读地址通道。
        .S_AXI_ARID              ( M_AXI_ARID       ),
        .S_AXI_ARADDR            ( M_AXI_ARADDR     ),
        .S_AXI_ARLEN             ( M_AXI_ARLEN      ),
        .S_AXI_ARSIZE            ( M_AXI_ARSIZE     ),
        .S_AXI_ARBURST           ( M_AXI_ARBURST    ),
        .S_AXI_ARLOCK            ( M_AXI_ARLOCK     ),
        .S_AXI_ARCACHE           ( M_AXI_ARCACHE    ),
        .S_AXI_ARPROT            ( M_AXI_ARPROT     ),
        .S_AXI_ARQOS             ( M_AXI_ARQOS      ),
        .S_AXI_ARREGION          ( 4'd0             ),
        .S_AXI_ARUSER            ( M_AXI_ARUSER     ),
        .S_AXI_ARVALID           ( M_AXI_ARVALID    ),
        .S_AXI_ARREADY           ( M_AXI_ARREADY    ),
        //AXI读数据通道。
        .S_AXI_RID               ( M_AXI_RID        ),
        .S_AXI_RDATA             ( M_AXI_RDATA      ),
        .S_AXI_RRESP             ( M_AXI_RRESP      ),
        .S_AXI_RLAST             ( M_AXI_RLAST      ),
        .S_AXI_RUSER             ( M_AXI_RUSER      ),
        .S_AXI_RVALID            ( M_AXI_RVALID     ),
        .S_AXI_RREADY            ( M_AXI_RREADY     )
    );
    initial begin
        rst_n = 1;
        #2;
        rst_n = 0;//开始时复位10个时钟;
        #(RST_TIME*CYCLE);
        rst_n = 1;
        #10000;
    $stop;
    end

endmodule

仿真结果如下图所示:

首先写地址通道握手,接着写数据通道完成握手,需要注意的是——一旦复位完成,写地址有效信号和写数据有效信号立马拉高,等待从机的准备完成信号。

然后向对应地址中写入数据,当最后一位数据写入时将WLAST信号拉高,表示当前写入数据为最后一位,下一个时钟周期写响应通道完成握手,进入READ状态。

读地址通道首先完成握手,下一个时钟周期读数据通道再完成握手,开始读取数据,需要注意的是,每读出一次数据读数据通道完成一次握手,直到读最后一个数据的时候拉高RLAST,本次验证结束。

问题总结:首先仿真的时候我隔了半个时钟周期就把复位信号拉高了,就得到了如图所示的波形,把复位的时间延长之后写地址有效信号才成功拉高,

但是拉高之后的波形如下图所示,可以看到读地址通道的有效信号在复位结束的时候同时拉高,检查代码后发现是代码的问题,写代码的时候逻辑一定要清晰。

然后代码并未成功,我发现有几个信号在本来应该是高电平的时候却变成了未知态,检查了好久才发现是testbench里面对信号进行了多次赋值,因为我的代码是VScode自动生成的,因此会对所有输入信号进行赋值,上次好像就遇到过相同的问题。

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值