AXI4主机测试

news2024/9/20 14:40:26

前面对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自动生成的,因此会对所有输入信号进行赋值,上次好像就遇到过相同的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2118529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

孩子用的台灯哪个牌子好?挑选护眼台灯先了解护眼台灯十大排名

孩子们的日常生活中有高达80%的时间是在阅读、做作业或面对电脑屏幕中度过的&#xff0c;因此对良好照明的需求显得尤为严格和精确。一些家长可能认为&#xff0c;只要孩子使用的是纸质材料&#xff0c;不像电子产品那样对眼睛有害&#xff0c;使用普通的台灯照明就足够了&…

mysql快速定位cpu 占比过高的sql语句

mysql快速定位cpu 占比过高的sql语句 当MySQL数据库的CPU使用率异常升高时&#xff0c;定位导致问题的SQL语句可以通过以下步骤进行 1、使用top命令找出mysl进程中占用CPU靠前的线程 #找出mysql 的进程号 ps -ef | grep mysql#根据进程号&#xff0c;找出占用CPU靠前的线程号…

【QT】文件读写,文件对话框

一.QFile类 QFile提供了从文件中读取和写入数据的能力。 我们通常会将文件路径作为参数传给QFile的构造函数。不过也可以在创建好对象最后&#xff0c;使用setFileName()来修改。 QFile是QIODevice的子类&#xff0c;利用QFile可以对文件进行打开&#xff0c;读取&#xff0c…

Bootstrap 5.3版本创建常用页面

你可以根据自己的主题需求来自定义样式。Bootstrap提供了丰富的CSS类和组件&#xff0c;使得创建响应式、移动优先的网站变得简单。下面我将指导你如何基于Bootstrap 5.3来编写一个简单但自定义主题的页面。 引入Bootstrap 首先&#xff0c;确保你的HTML文件中已经正确引入了B…

Vue学习:v-model绑定文本框、单选按钮、下拉菜单、复选框等

v-model指令可以在组件上使用以实现双向绑定&#xff0c;之前学习过v-model绑定文本框和下拉菜单&#xff0c;今天把表单的几个控件单选按钮radio、复选框checkbox、多行文本框textarea都试着绑定了一下。 一、单行文本框和多行文本框 <p>1.单行文本框</p> 用户名…

程序员日志之DNF编年史

目录 传送门正文日志1、概要2、超高度总结概括3、详细编年史3.1、大背景3.2、冒险家 传送门 SpringMVC的源码解析&#xff08;精品&#xff09; Spring6的源码解析&#xff08;精品&#xff09; SpringBoot3框架&#xff08;精品&#xff09; MyBatis框架&#xff08;精品&…

YOLOv5改进 | 模块缝合 | C3 融合RFCAConv增强感受野空间特征 【二次融合 小白必备】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv5入门 改…

飞牛fnOS安装KDE桌面

飞牛fnOS安装KDE桌面 这段时间新出的nas系统飞牛os真不错&#xff0c;基于debian的可折腾性又高了不少&#xff0c;今天就来给这个系统装个桌面&#xff0c;插上显示器也能当个电脑自己进自己的管理界面&#xff0c;播放下视频&#xff0c;上上网啥的。 文章目录 飞牛fnOS安装…

问卷调查,动静IP应该如何选择?

在探讨问卷调查这一领域时&#xff0c;选择使用动态IP还是静态IP&#xff0c;成为了许多从业者及市场研究者面临的重要决策&#xff0c;它不仅关乎数据收集的效率与质量&#xff0c;还直接影响到问卷调查的合法性与安全性。本文将从多个维度深入分析这两种IP类型的优劣&#xf…

python-网页自动化(三)

如果遇到使用 ajax 加载的网页&#xff0c;页面元素可能不是同时加载出来的&#xff0c;这个时候尝试在 get 方法执行完 成时获取网页源代码可能并非浏览器完全加载完成的页面。所以&#xff0c;这种情况下需要设置延时等待一定时间&#xff0c;确保全部节点都加载出来。 那么&…

每日一练8:dd爱框框(含链接)

1.链接 登录—专业IT笔试面试备考平台_牛客网 2.题目 3.代码 #include<iostream> #include<vector>using namespace std;const int N 1e7 5;int n,x;vector<int> v(N);int main() {cin >> n >> x;for(int i 0; i < n;i) cin >> v…

服务端性能测试:行业流行性能监控工具介绍

行业流行性能监控工具有哪些 Linux 自带命令 Vmstat&#xff0c;Top 等 Nmon Collectd InfluxDB Grafana Prometheus Grafana 行业流行性能监控工具的介绍 Linux 自带命令 Vmstat&#xff0c;Top 等 vmstat 和 top 都是 Linux 系统自带的命令&#xff0c;提供了实时的…

每日一练:轮转数组

一、题目要求 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: …

hive时间函数

一、随机示例&#xff08;想到哪里写哪里&#xff09; 1.系统时间函数 查询 select current_timestamp --当前格式化时间,current_date --当前格式化日期,unix_timestamp() --当前unix时间戳 结果&#xff1a; 2.时间函数转换 查询 --将时间戳转化为格式化时间 sel…

微片水凝胶如何用于4D生物打印?快来了解一下!

大家好&#xff0c;今天我们来聊聊一项4D 活细胞生物打印技术——《Jammed Micro-Flake Hydrogel for 4D Living Cell Bioprinting》发表于《Advanced Materials》。在组织器官再生应用中&#xff0c;构建具有复杂几何形状和功能的载细胞结构至关重要。而水凝胶基4D生物墨水的发…

免费 U 盘数据恢复 - 用 4 种免费方法从随身U 盘恢复文件

如何在不使用软件的情况下从 USB 驱动器恢复已删除的文件&#xff1f;如何取消删除 USB 闪存驱动器&#xff1f;首先&#xff0c;不要对拇指驱动器进行任何进一步的更改。然后下载奇客数据恢复&#xff0c;这是一款免费的U 盘恢复工具&#xff0c;能够从各种问题中恢复笔式驱动…

网络层协议-ARP协议

网络层协议-ARP协议 1&#xff09;概述 ARP&#xff1a;地址解析协议&#xff0c;作用&#xff1a;根据IP地址查询MAC地址 数据包发送前需要进行封包&#xff0c;在数据链路层需要封装源mac地址是自己的mac&#xff0c;目的mac地址是别人&#xff0c;但是不知道别人的mac地址…

西门子WinCC开发笔记(一):winCC西门子组态软件介绍、安装

文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/142060535 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、Op…

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

&#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系列 &#x1f308;Linux学习专栏&#xff1a; 南桥谈Linux &#x1f308;数据结构学习专栏&#xff1a; 数据结构杂谈 &#x1f308;数据…

为什么RAG对下一代AI开发至关重要

RAG&#xff08;检索增强生成&#xff09;是一种突破性技术&#xff0c;它将信息检索与文本生成相结合&#xff0c;以提高人工智能系统的知识和准确性。利用 RAG 可以帮助开发人员确保应用程序响应具有最丰富的上下文和准确性&#xff0c;因为它可以访问原始模型训练之外的精选…