【FPGA】 xilinx vivado中AXI4通信协议详解

一.什么是AXI通信协议

AXI是ARM 1996年提出的微控制器总线家族AMBA中的一部分。AXI的第一个版本出现在AMBA3.0,发布于2003年。当前的最新的版本发布于2010年。AXI 4总线和别的总线一样,都用来传输bits信息 (包含了数据或者地址) 。AXI4总线有三种类型,分别是AXI4、AXI4-Lite、AXI4-Stream
AXI4:主要面向高性能地址映射通信的需求,支持突发传输;
AXI4-Lite:是一个简单地吞吐量地址映射性通信总线,不支持突发传输;
AXI4-Stream:不包含地址,面向高速流数据传输;
AXI4 是一种高性能memory-mapped总线,分为主、从两端,两者间可以连续的进行通信。AXI4及AXI4Lite有地址,AX14能够实现burst传输,可以在一个地址后传输多个数据,最多可以达256 字节。AXI4-Lite不支持burst传输。AXI4-Stream 只有一个通道,不需要地址,可以burst 传输无限的数据。假设有master A,和 slave B,A与B通过AXI4或者AXI4Lite连接通讯,A可以把B这个外设看作A上的某个地址。当A向B传输数据时,就等同于A向这个地址传数。
AXI4 和 AXI4-Lite接口包含5个不同的通道:两个读通道和三个写通道。
两个读通道:读地址通道(read addresschannel)、读数据通道(read data channel):
读通道
三个写通道: 写地址通道(write addresschannel)、写数据通道(write data channel)、写响应通道(write response channel);

写通道
相比于 AXI4,AXI4-Stream 不涉及地址。AXI4-Stream传输的数据流包含三种类型: data type、position type、 null type 。data type是最有意义的数据; position type作为占位符使用,可以用来表征date type 的相对位置,null type不包含任何有用的信息。
数据流的结构可以有很多种,例如: 可以只传数据,也即都是data type,不包含position type和null type; 也可以将data type 和 null type 混着传输;还可以将position type 和 data type混着传输。当然,三者混着传输也没有问题。

二.信号描述

AXI与AXI-lite信号描述如下所示,由于AXI-lite不支持突发,所以与突发相关的管教都不具备。

//全局信号
		.M_AXI_ACLK(m00_axi_aclk),//时钟
		.M_AXI_ARESETN(m00_axi_aresetn),//全局复位
		//写地址通道信号
		.M_AXI_AWID(m00_axi_awid),//AXI4-LITE不支持 写地址ID。这个信号用于写地址信号组的标记,用来标识数据传输顺序。详见协议定义。
		.M_AXI_AWADDR(m00_axi_awaddr),//写地址。写地址给出突发数据传输的第一个传输地址。
		.M_AXI_AWLEN(m00_axi_awlen),//AXI4-LITE不支持 突发长度。给出突发传输中准确的传输个数。支持INCR和WRAP传输模式。(长度)突发长度=awlen+1
		.M_AXI_AWSIZE(m00_axi_awsize),//AXI4-LITE不支持 突发大小。这个信号用于确定突发传输中每个传输的大小。(宽度)总线位宽=2^size Betyes
		.M_AXI_AWBURST(m00_axi_awburst),//AXI4-LITE不支持 突发类型。该信息与突发大小信息一起,表示在突发过程中,地址如何应用于每个传输。支持INCR和WRAP传输模式。
		.M_AXI_AWLOCK(m00_axi_awlock),//AXI4-LITE不支持 锁类型。该信号提供了关于传输原子特性的额外信息(普通或互斥访问)。AXI3支持,AXI4不支持
		.M_AXI_AWCACHE(m00_axi_awcache),//缓存类型,建议值为0011。
		.M_AXI_AWPROT(m00_axi_awprot),//保护类型,访问权限,建议值为000。
		.M_AXI_AWQOS(m00_axi_awqos),//QoS标识符,xilinx AXI4不支持
		.M_AXI_AWUSER(m00_axi_awuser),//xilinx AXI4不支持
		.M_AXI_AWVALID(m00_axi_awvalid),//写地址有效信号。为高指示地址有效。
		.M_AXI_AWREADY(m00_axi_awready),//写地址准备信号。为高表示从设备空闲,准备接收地址;为低表示从设备忙。
		//写数据通道信号
		.M_AXI_WDATA(m00_axi_wdata),//写数据,AXI-LITE仅支持32bit,AXI支持32bit-1024bit
		.M_AXI_WSTRB(m00_axi_wstrb),//写字节选通,用于表示更新存储器的字节通道,对于数据总线的每8位数据有一位写选通信号
		.M_AXI_WLAST(m00_axi_wlast),//AXI-LITE不支持 写最后一个数据指示信号。表示突发传输中的最后一个数据。
		.M_AXI_WUSER(m00_axi_wuser),//xilinx AXI4不支持。
		.M_AXI_WVALID(m00_axi_wvalid),//写有效。为高指示数据有效。
		.M_AXI_WREADY(m00_axi_wready),//写准备。为高表示从设备空闲,准备接收数据;为低表示从设备忙。
		//写响应通道
		.M_AXI_BID(m00_axi_bid),//AXI-LITE不支持 响应ID。写响应识别标记,BID值必须匹配AWID值。
		.M_AXI_BRESP(m00_axi_bresp),//写响应。该信号表示写状态,0时候表示没有错误,
		.M_AXI_BUSER(m00_axi_buser),//xilinx AXI4不支持。
		.M_AXI_BVALID(m00_axi_bvalid),//写响应有效。为高指示响应数据有效
		.M_AXI_BREADY(m00_axi_bready),//写响应准备。为高表示主设备空闲,准备接收写响应;为低表示主设备忙。
		//读地址通道
		.M_AXI_ARID(m00_axi_arid),//AXI-LITE不支持 读地址ID。这个信号用于读地址信号组的标记。
		.M_AXI_ARADDR(m00_axi_araddr),//读地址。读地址给出突发数据传输的第一个传输地址。
		.M_AXI_ARLEN(m00_axi_arlen),//AXI-LITE不支持 突发长度。给出突发传输中准确的传输个数。支持INCR和WRAP传输模式。
		.M_AXI_ARSIZE(m00_axi_arsize),//AXI-LITE不支持 突发大小。这个信号用于确定突发传输中每个传输的大小。
		.M_AXI_ARBURST(m00_axi_arburst),//AXI-LITE不支持 突发类型。该信息与突发大小信息一起,表示在突发过程中,地址如何应用于每个传输。支持INCR和WRAP传输模式
		.M_AXI_ARLOCK(m00_axi_arlock),//锁类型。该信号提供了关于传输原子特性的额外信息(普通或互斥访问)
		.M_AXI_ARCACHE(m00_axi_arcache),//缓存类型,建议值为0011。
		.M_AXI_ARPROT(m00_axi_arprot),//保护类型,建议值为000。
		.M_AXI_ARQOS(m00_axi_arqos),//QoS标识符,xilinx AXI4不支持。
		.M_AXI_ARUSER(m00_axi_aruser),//xilinx AXI4不支持
		.M_AXI_ARVALID(m00_axi_arvalid),// 	读地址有效信号。为高指示地址有效
		.M_AXI_ARREADY(m00_axi_arready),//读地址准备信号。为高表示从设备空闲,准备接收地址;为低表示从设备忙
        //读数据通道		
		.M_AXI_RID(m00_axi_rid),//AXI-LITE不支持 读ID标记,该信号是读数据信号组标记,由从设备产生RID,RID必须和读交易中的ARID匹配
		.M_AXI_RDATA(m00_axi_rdata),//读数据。32位到1024位宽 AXI-LITE只支持32位宽
		.M_AXI_RRESP(m00_axi_rresp),//读响应。该信号表示读状态,可允许相应的表示为
		.M_AXI_RLAST(m00_axi_rlast),//AXI-LITE不支持 读最后一个数据指示信号。表示突发传输中的最后一个数据
		.M_AXI_RUSER(m00_axi_ruser),//xilinx AXI4不支持。
		.M_AXI_RVALID(m00_axi_rvalid),//读有效。为高指示数据有效
		.M_AXI_RREADY(m00_axi_rready)//读准备。为高表示主设备空闲,准备接收数据;为低表示主设备忙。

AXI-stream信号描述如下所示,

.M_AXIS_ACLK(m00_axis_aclk),//时钟
		.M_AXIS_ARESETN(m00_axis_aresetn),//复位
		.M_AXIS_TVALID(m00_axis_tvalid),//Stream读写数据有效。为高指示数据有效。
		.M_AXIS_TDATA(m00_axis_tdata),//Stream读写数据,8到4096位宽。
		.M_AXIS_TSTRB(m00_axis_tstrb),//字节选通信号。用于表示更新存储器的字节通道,对于数据总线的每8位数据有一位选通信号。
		.M_AXIS_TLAST(m00_axis_tlast),//表明包的边界,1代表最后数据
		.M_AXIS_TREADY(m00_axis_tready)//Stream读写读准备。为高表示对端设备空闲,准备接收数据;为低表示对端设备忙。

三.工作时序图

AXI4协议主从设备间的读操作使用独立的读地址和读数据通道,只需要一个地址就可以执行最大为256的突发长度的读操作。
读时序如下所示。
读时序

(1)首先Master判断arready的信号是否为高电平,若该信号为高电平时,代表slave已经准备好接收新的地址信息,否则Master不能给Slave发送地址信息。
(2)当判断完成后,Master给Slave发送地址信息,即发送araddr;在进行地址发送时,arvalid为高电平,arvalid为高电平,发送araddr。
(3)当地址发送结束之后,slave就会通过read_data通道返回数据,master必须在rready和rvalid信号同时为高时,将数据读取,否则不能读取数据;当最后一个数据发送时,slave会将rlast信号同时拉高,代表最后一个数据发送完成。

写时序如下所示。
写时序
AXI写事务是在3个写通道上完成多次数据传输(transfers)
(1)MASTER将写地址及相应的控制信息通过写地址通道发送给SLAVE
(2)MASTER将需要写入该地址的数据通过写输入通道发送给SLAVE
(3)SLAVE将写结果通过写反馈通道发送给MASTER,表明写入是否成功

四.时序代码实现

读事务握手信号的关系:
在这里插入图片描述
单箭头指向 可以在前一个信号(本信号)断言之前或之后断言的信号(指向的信号)。
双箭头指向 只有在前一个信号(本信号)断言之后才可以断言的信号(指向的信号)。
所以slave 在断言读取的数据有效信号RVALID之前,必须等到ARVALID与ARREADY断言后。

//----------------------------
	//Read Address Channel
	//----------------------------
	  always @(posedge M_AXI_ACLK)                                 
	  begin                                                              
	                                                                     
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                         
	      begin                                                          
	        axi_arvalid <= 1'b0;                                         
	      end                                                            
	    // If previously not valid , start next transaction              
	    else if (~axi_arvalid && start_single_burst_read)                
	      begin                                                          
	        axi_arvalid <= 1'b1;                                         
	      end                                                            
	    else if (M_AXI_ARREADY && axi_arvalid)                           
	      begin                                                          
	        axi_arvalid <= 1'b0;                                         
	      end                                                            
	    else                                                             
	      axi_arvalid <= axi_arvalid;                                    
	  end                                                                
	                                                                     
	                                                                     
	// Next address after ARREADY indicates previous address acceptance  
	  always @(posedge M_AXI_ACLK)                                       
	  begin                                                              
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                          
	      begin                                                          
	        axi_araddr <= 'b0;                                           
	      end                                                            
	    else if (M_AXI_ARREADY && axi_arvalid)                           
	      begin                                                          
	        axi_araddr <= axi_araddr + burst_size_bytes;                 
	      end                                                            
	    else                                                             
	      axi_araddr <= axi_araddr;                                      
	  end                                                                


	//--------------------------------
	//Read Data (and Response) Channel
	//--------------------------------

	 // Forward movement occurs when the channel is valid and ready   
	  assign rnext = M_AXI_RVALID && axi_rready;                            
	                                                                        
	                                                                        
	// Burst length counter. Uses extra counter register bit to indicate    
	// terminal count to reduce decode logic                                
	  always @(posedge M_AXI_ACLK)                                          
	  begin                                                                 
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 || start_single_burst_read)                  
	      begin                                                             
	        read_index <= 0;                                                
	      end                                                               
	    else if (rnext && (read_index != C_M_AXI_BURST_LEN-1))              
	      begin                                                             
	        read_index <= read_index + 1;                                   
	      end                                                               
	    else                                                                
	      read_index <= read_index;                                         
	  end                                                                   
	                                                                        
	                                                                        
                                                                  
	  always @(posedge M_AXI_ACLK)                                          
	  begin                                                                 
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                  
	      begin                                                             
	        axi_rready <= 1'b0;                                             
	      end                                                               
	    // accept/acknowledge rdata/rresp with axi_rready by the master     
	    // when M_AXI_RVALID is asserted by slave                           
	    else if (M_AXI_RVALID)                       
	      begin                                      
	         if (M_AXI_RLAST && axi_rready)          
	          begin                                  
	            axi_rready <= 1'b0;                  
	          end                                    
	         else                                    
	           begin                                 
	             axi_rready <= 1'b1;                 
	           end                                   
	      end                                        
	    // retain the previous value                 
	  end 

写事务握手信号的关系:
在这里插入图片描述
单箭头指向 可以在前一个信号(本信号)断言之前或之后断言的信号(指向的信号)。
双箭头指向 只有在前一个信号(本信号)断言之后才可以断言的信号(指向的信号)。

//--------------------
	//Write Data Channel
	//--------------------
	  assign wnext = M_AXI_WREADY & axi_wvalid;                                   
	                                                                                    
	// WVALID logic, similar to the axi_awvalid always block above                      
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                                        
	      begin                                                                         
	        axi_wvalid <= 1'b0;                                                         
	      end                                                                           
	    // If previously not valid, start next transaction                              
	    else if (~axi_wvalid && start_single_burst_write)                               
	      begin                                                                         
	        axi_wvalid <= 1'b1;                                                         
	      end                                                                           
	    /* If WREADY and too many writes, throttle WVALID                               
	    Once asserted, VALIDs cannot be deasserted, so WVALID                           
	    must wait until burst is complete with WLAST */                                 
	    else if (wnext && axi_wlast)                                                    
	      axi_wvalid <= 1'b0;                                                           
	    else                                                                            
	      axi_wvalid <= axi_wvalid;                                                     
	  end                                                                               
	                                                                                    
	                                                                                    
	//WLAST generation on the MSB of a counter underflow                                
	// WVALID logic, similar to the axi_awvalid always block above                      
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                                        
	      begin                                                                         
	        axi_wlast <= 1'b0;                                                          
	      end                                                                           

	    else if (((write_index == C_M_AXI_BURST_LEN-2 && C_M_AXI_BURST_LEN >= 2) && wnext) || (C_M_AXI_BURST_LEN == 1 ))
	      begin                                                                         
	        axi_wlast <= 1'b1;                                                          
	      end                                                                           
                               
	    else if (wnext)                                                                 
	      axi_wlast <= 1'b0;                                                            
	    else if (axi_wlast && C_M_AXI_BURST_LEN == 1)                                   
	      axi_wlast <= 1'b0;                                                            
	    else                                                                            
	      axi_wlast <= axi_wlast;                                                       
	  end                                                                               
	                                                                                    
	                                                                                                                                    
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 || start_single_burst_write == 1'b1)    
	      begin                                                                         
	        write_index <= 0;                                                           
	      end                                                                           
	    else if (wnext && (write_index != C_M_AXI_BURST_LEN-1))                         
	      begin                                                                         
	        write_index <= write_index + 1;                                             
	      end                                                                           
	    else                                                                            
	      write_index <= write_index;                                                   
	  end                                                                               
	                                                                                    
	                                                                                    
	/* Write Data Generator                                                             
	 Data pattern is only a simple incrementing count from 0 for each burst  */         
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
	      axi_wdata <= 'b1;                                                             
	    //else if (wnext && axi_wlast)                                                  
	    //  axi_wdata <= 'b0;                                                           
	    else if (wnext)                                                                 
	      axi_wdata <= axi_wdata + 1;                                                   
	    else                                                                            
	      axi_wdata <= axi_wdata;                                                       
	    end                                                                             


	//----------------------------
	//Write Response (B) Channel
	//----------------------------

	  always @(posedge M_AXI_ACLK)                                     
	  begin                                                                 
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                            
	      begin                                                             
	        axi_bready <= 1'b0;                                             
	      end                                                               
	    // accept/acknowledge bresp with axi_bready by the master           
	    // when M_AXI_BVALID is asserted by slave                           
	    else if (M_AXI_BVALID && ~axi_bready)                               
	      begin                                                             
	        axi_bready <= 1'b1;                                             
	      end                                                               
	    // deassert after one clock cycle                                   
	    else if (axi_bready)                                                
	      begin                                                             
	        axi_bready <= 1'b0;                                             
	      end                                                               
	    // retain the previous value                                        
	    else                                                                
	      axi_bready <= axi_bready;                                         
	  end                                                                   
	                                                                        
	                                                                        
	//Flag any write response errors                                        
	  assign write_resp_error = axi_bready & M_AXI_BVALID & M_AXI_BRESP[1];

五.总结

vivado中许多IP核都采用AXI通信协议,理解AXI协议有助于后续开发工作,详细信息推荐官方文件ug1037以及ihi0022c

  • 34
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FPGA与信号

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

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

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

打赏作者

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

抵扣说明:

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

余额充值