AXI和AXI-lite均包含五个不同的通道(允许同时读写、双向通信)。
读交易交互图
写交易交互图
读交易过程如上图,主端发送要读的地址,从端把这些地址的数据反馈给主端。
写交易过程见1-2,主端发送要写的地址和数据,完成之后从端发送完成响应。
具体的实现细节,我们以源码进行分析仿真,结合官方提供的一系列文档进行说明。最终达到深入理解AXI-lite的交互过程。
always @(posedge M_AXI_ACLK) begin //Only VALID signals must be deasserted during reset per AXI spec //Consider inverting then registering active-low reset for higher fmax if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_awvalid <= 1'b0; end //Signal a new address/data command is available by user logic else begin if (start_single_write) begin axi_awvalid <= 1'b1; end //Address accepted by interconnect/slave (issue of M_AXI_AWREADY by slave) else if (M_AXI_AWREADY && axi_awvalid) begin axi_awvalid <= 1'b0; end end end //-------------------- //Write Data Channel //-------------------- //The write data channel is for transfering the actual data. //The data generation is speific to the example design, and //so only the WVALID/WREADY handshake is shown here always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_wvalid <= 1'b0; end //Signal a new address/data command is available by user logic else if (start_single_write) begin axi_wvalid <= 1'b1; end //Data accepted by interconnect/slave (issue of M_AXI_WREADY by slave) else if (M_AXI_WREADY && axi_wvalid) begin axi_wvalid <= 1'b0; end end
注意到主端口的源码中,start_single_write拉高时axi_awvalid和axi_wvalid同时拉高。即写地址和写数据通道有效的信号。
写完之后从端口会反馈响应信号M_AXI_WREADY和M_AXI_AWREADY表示地址写入和数据写入完成。而在从端口源码中也提到了类似的信号S_AXI_WREADY和S_AXI_AWREADY的产生逻辑如下:
// 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; aw_en <= 1'b1; end else begin if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) begin // slave is ready to accept write address when // there is a valid write address and write data // on the write address and data bus. This design // expects no outstanding transactions. axi_awready <= 1'b1; aw_en <= 1'b0; end else if (S_AXI_BREADY && axi_bvalid) begin aw_en <= 1'b1; axi_awready <= 1'b0; end else begin axi_awready <= 1'b0; 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 && S_AXI_AWVALID && aw_en ) begin // slave is ready to accept write data when // there is a valid write address and write data // on the write address and data bus. This design // expects no outstanding transactions. axi_wready <= 1'b1; end else begin axi_wready <= 1'b0; end end end
我们可以在tb中将主从端口全部都输入相同的源信号,然后给与主端口的信号发送开始脉冲,即可启动整个交互过程。
交互的关键tb代码如下:
initial begin sys_clk_i = 1; sys_rst_n = 0; m_axi_init_axi_txn = 0; #40 sys_rst_n = 1'b1; #20 m_axi_init_axi_txn = 1; #20 m_axi_init_axi_txn = 0; end .m00_axi_init_axi_txn(m_axi_init_axi_txn),
注意到我们启动时会需要一个脉冲起始位,连接到主端口来进行启动。使用block_board直观显示如图。
可以很明显的看到主设备端口比从设备端口多出的几个接口设计。也能体现最开始图中出现的AXI读写逻辑。
到此我们再根据tb仿真图可以看到更加清晰的读写逻辑,如下图所示:
可以清晰的看到先写后读的数据交互过程,从而对AXI-Lite总线协议有个更加深刻的理解。
不必再相信不该相信的人,努力前行就好。