AXI总线

news2024/11/24 20:20:08

目录

  • 一、AXI接口特点
  • 二、AXI接口的握手机制
    • 2.1 握手原理
    • 2.2 握手机制的三种情形
  • 三、AXI接口的通道
    • 3.1 AXI4-Stream
      • 3.1.1 通道信号
      • 3.1.2 数据字节类型
      • 3.1.3 流格式
    • 3.2 AXI4-Lite和AXI4-Full
      • 3.1.1 读地址通道
      • 3.1.2 读数据通道
      • 3.1.3 写地址通道
      • 3.1.4 写数据通道
      • 3.1.5 写响应通道
      • 3.1.6 通道信号的编码
  • 四、时序
  • 五、源码分析
    • AXI4-Stream
      • 主机模块
      • 从机模块
    • AXI4-Lite
      • 主机模块
      • 从机模块
    • AXI-Full
      • 主机模块
      • 从机模块
  • 六、功能仿真
    • AXI4-Stream
    • AXI4-Lite
    • AXI-Full

参考:IHI0022D_amba_axi_protocol_spec、IHI0051A_amba4_axi4_stream_v1_0_protocol_spec、ug1037-vivado-axi-reference-guide

一、AXI接口特点

AXI-Full:高性能存储映射接口,用于需要指定地址的高速数据传输,支持最大256长度的突发传输;

AXI-Lite:轻量级存储映射接口,用于访问一些低速外设中的寄存器(如读写控制和状态寄存器等),不支持突发传输;

AXI-Stream:流接口,用于高速数据流通信,不需要地址,允许无限制长度的突发传输;

  • 存储映射:如果一个协议是存储映射的,那么主机所发出的会话(无论读或写)就会指定一个地址。这个地址对应于系统存储空间中的一个地址,表明是针对该存储空间的读写操作。
  • 流传输:向某一方向,以固定的速度,连续不断地输出。

突发传输:在一次事务中进行连续的数据传输而无需在每次传输之间重新设置地址和控制信号,AXI-Full的突发传输过程只需要首地址。

二、AXI接口的握手机制

2.1 握手原理

valid:由源端产生,表示当前地址或数据线上的信息是有效的;

ready:由目的端产生,表示已经准备好接收地址、数据以及控制信息;

握手:只有检测到valid和ready同时为高时,才能进行数据传输。这种机制使得主、从机都可以控制信息的传输。

valid和ready需要完全独立,不能相互依赖,避免二者相互等待而造成锁死

2.2 握手机制的三种情形


1.源端在T1之后将VALID拉高,表明INFORMATION信号线上传输的是有效信息;

2.目的端在T2之后将READY拉高,表明已准备好接收数据;

3.此时源端必须保持数据稳定,直到T3时刻进行数据传输;

  • 一旦VALID拉高,源端必须保持其有效状态,直到成功握手
  • 源端不允许等待READY拉高后才拉高VALID(简单来说就是VALID信号是由主机自主产生的);

在这里插入图片描述

  • 允许目的端等待VALID拉高后再拉高READY;
  • 如果拉高了READY,可以在拉高VALID之前取消拉高READY;

在这里插入图片描述

在这里插入图片描述

三、AXI接口的通道

3.1 AXI4-Stream

3.1.1 通道信号

信号含义
TVALIDM置1表示主机发出的数据有效
TREADYS置1表示从机准备好接收数据
TDATA[(8x-1):0]M流数据,宽度是1个整数字节
TLASTM置1表示此时传输的是数据流的最后一个数据,用于指示传输的结束
TSTRB[(x-1):0]M指示TDATA的相关字节是数据字节还是位置字节
TKEEP[(x-1):0]M指示TDATA的相关字节是否可以作为数据流的一部分处理(是否为空字节)
TID[(i-1):0]M区分同一接口上传输的多个数据流(源),用于多机通信
TDEST[(d-1):0]M指示数据流粗略路由信息(目的),用于多机通信
TUSER[(u-1):0]M用户自定义信号,用于多机通信
  • 具有相同TID和TDEST值的传输来自同一流。

3.1.2 数据字节类型

  1. 数据字节:包含在源和目的之间传输的有效信息的一个字节数据;
  2. 占位字节:指示流中数据字节相对位置的字节,是一个占位符,不包含传输的任何相关数据值;
  3. 空字节:不包含任何数据信息或相对位置信息的字节;
  • TKEEP置1表示传输的是数据字节或位置字节,必须传输到目的端;TKEEP置0表示传输的是可以从流中删除的空字节。
  • TKEEP置1后,用TSTRB指示相关字节具体是数据字节还是位置字节。TSTRB置1表示是数据字节,包含有效信息;TSTRB置0表示是位置字节,不包含有效信息。

在这里插入图片描述

3.1.3 流格式

  1. 字节流:传输一些数据字节和空字节,每次握手后可以传输任意数量的数据字节,空字节没有意义,可以从流中插入或删除,如下面两图传输的信息完全相同。
    在这里插入图片描述
  2. 连续对齐流:传输一些数据字节,每个数据包没有空字节或位置字节。
    在这里插入图片描述
  3. 连续不对齐流:数据包的开始和结束位置处有任意数量的位置字节,开始和结束中间全是数据字节。
    在这里插入图片描述
  4. 稀疏流:数据包包含数据字节和位置字节的任意组合,通常大多数字节是数据字节。
    在这里插入图片描述

3.2 AXI4-Lite和AXI4-Full

  • 突发传输不能被提前终止,写突发中可以通过禁用所有写选通来阻止进一步的写,读突发中主机可以丢弃读取的数据,但都必须完成突发中所有的传输。

3.1.1 读地址通道

信号含义AXI-lite是否支持该信号
ARADDR[x:0]M读突发传输中第一次传输的地址(AXI-lite中是每次传输的地址)
ARPROT[2:0]M保护类型,指示传输的安全级别以及传输是数据访问还是指令访问
ARVALIDM置1表明读地址和控制信息有效
ARREADYS置1表示从机可以接收一个读地址和相关控制信息
ARID[x:0]M读地址组信号的标识,指定某些特殊传输任务的顺序
ARLEN[7:0]M突发长度,表示一次突发中与该地址相关的传输数量。实际的突发长度是ARLEN+1,支持 2 n ( n = 0 , 1 , 2...8 ) 2^n(n=0,1,2...8) 2n(n=0,1,2...8)
ARSIZE[2:0]M突发大小,表示一次突发中每次传输的数据大小。SIZE值对应的数据大小为 2 S I Z E 2^{SIZE} 2SIZE字节,该字节数不能超过数据位宽对应的字节数。
ARBURST[1:0]M突发类型,和突发大小共同决定了如何计算突发内每次传输的地址
ARLOCKM锁类型,置0表示正常传输,置1表示独有传输
ARCACHE[3:0]M内存类型
ARQOS[3:0]M服务质量,一般直接置0

突发类型AxBURST:

  1. FIXED:突发中每次传输的地址相同,该类型用于重复访问同一位置;
  2. INCR:突发中每次传输的地址都是前一次传输地址的增量,增量为突发大小,该类型较常用;
  3. WRAP(回环突发):突发传输的最低地址与传输数据的总大小对齐,该最低地址被定义为回环边界。每次传输后,地址以与INCR相同方式增加,但是如果地址增加到(回环边界+传输数据总大小),就会退回到回环边界。该类型突发长度必须是2,4,8,16。

3.1.2 读数据通道

在这里插入图片描述

信号含义AXI-lite中是否支持该信号
RDATA[x:0]S读数据,AXI-Lite的数据宽度是32位或64位,AXI-Full的数据宽度可以是 2 n ( n = 3 , 4...10 ) 2^n(n=3,4...10) 2n(n=3,4...10)
RRESP[1:0]S读响应,指示读传输的状态 ,AXI-Lite不支持EXOKAY状态
RVALIDS置1表示要读的数据有效
RREADYM置1表示主机可以接收读数据
RID[x:0]S读数据传输标识,RID值必须与正在响应的读传输的ARID值匹配
RLASTS置1表示一次读突发中的最后一次传输

响应类型xRESP:

  1. OKAY:正常访问成功;
  2. EXOKAY:独有访问成功;
  3. SLVERR:从机错误,访问已到达从机,但从机希望向主机返回错误时使用 ;
  4. DECERR:解码错误,指示该传输地址上没有从机;

3.1.3 写地址通道

信号含义AXI-lite中是否支持该信号
AWADDR[x:0]M写突发传输中第一次传输的地址(AXI-lite中是每次传输的地址)
AWPROT[2:0]M保护类型,指示传输的安全级别以及传输是数据访问还是指令访问
AWVALIDM置1表示写地址和控制信息有效
AWREADYS置1表示从机可接收一个地址和相关控制信号
AWID[x:0]M写地址组信号的标识,指定某些特殊传输任务的顺序
AWLEN[7:0]M突发长度,表示一次突发中与该地址相关的传输数量。实际的突发长度是AWLEN+1,支持 2 n ( n = 0 , 1 , 2...8 ) 2^n(n=0,1,2...8) 2n(n=0,1,2...8)
AWSIZE[2:0]M突发大小,表示一次突发中每次传输的数据大小。SIZE值对应的数据大小为 2 S I Z E 2^{SIZE} 2SIZE字节,该字节数不能超过数据位宽对应的字节数。
AWBURST[1:0]M突发类型,和突发大小共同决定了如何计算突发内每次传输的地址
AWLOCKM锁类型,置0表示正常传输,置1表示独有传输;
AWCACHE[3:0]M内存类型
AWQOS[3:0]M服务质量,一般直接置0

AXI-Lite所有传输的宽度必须为32位或64位,并且不可修改、不可缓冲,不支持独有传输。

3.1.4 写数据通道

在这里插入图片描述

信号含义AXI-lite中是否支持该信号
WID[x:0]M写数据传输标识,WID值必须与AWID值匹配
WDATA[x:0]M写数据,AXI-Lite的数据宽度是32位或64位,AXI-Full的数据宽度可以是 2 n ( n = 3 , 4...10 ) 2^n(n=3,4...10) 2n(n=3,4...10)
WSTRB[x:0]M写选通,指示内存中要更新的字节的位置,写数据总线每8位有一个选通位,即WSTRB[x]对应于WDATA[(8x+7):8x]
WVALIDM置1表示写数据有效且WSTRB可用
WREADYS置1表示从机可以接收写数据
WLASTM置1表示一次写突发中的最后一次传输
  • WSTRB:主机需确保写选通只对包含有效数据的字节通道为高,当WVALID为低时,写选通可以取任何值;

3.1.5 写响应通道

信号含义AXI-lite中是否支持该信号
BRESP[1:0]S写响应,指示写传输的状态,AXI-Lite不支持EXOKAY状态
BVALIDS置1表示写响应有效
BREADYM置1表示主机可以接收写响应信息。
BID[x:0]S写响应标识,BID值必须与正在响应的写传输的AWID值匹配

3.1.6 通道信号的编码

  • AxSIZE:
    在这里插入图片描述
  • AxBURST:
    在这里插入图片描述
  • AxPROT:
    在这里插入图片描述
  • AxCACHE:
    在这里插入图片描述
  • xRESP:
    在这里插入图片描述

四、时序

突发读:
在这里插入图片描述
重叠突发读:
在这里插入图片描述
突发写:
在这里插入图片描述

五、源码分析

AXI4-Stream

流接口的源码是在AXI-Stream时序的基础上以读写FIFO的场景来描述传输过程。

主机模块

  1. 初始化计数状态:主机在开始传输前会等待一定的时钟周期,等待过后进入发送数据状态;
INIT_COUNTER:                                                       
	        // The slave starts accepting tdata when                          
	        // there tvalid is asserted to mark the                           
	        // presence of valid streaming data                               
	        if ( count == C_M_START_COUNT - 1 )                               
	          begin                                                           
	            mst_exec_state  <= SEND_STREAM;                               
	          end                                                             
	        else                                                              
	          begin                                                           
	            count <= count + 1;                                           
	            mst_exec_state  <= INIT_COUNTER;                              
	          end
  1. 发送数据状态:将数据有效信号置1,表示将要发送有效的数据。主从机握手后,将发送使能信号置1,开始连续发送自增数据。发送NUMBER_OF_OUTPUT_WORDS个数据后,将tlast置1;
assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);
assign tx_en = M_AXIS_TREADY && axis_tvalid;   
assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
	    // Streaming output data is read from FIFO       
	    always @( posedge M_AXIS_ACLK )                  
	    begin                                            
	      if(!M_AXIS_ARESETN)                            
	        begin                                        
	          stream_data_out <= 1;                      
	        end                                          
	      else if (tx_en)// && M_AXIS_TSTRB[byte_index]  
	        begin                                        
	          stream_data_out <= read_pointer + 32'b1;   
	        end                                          
	    end
  1. 数据开始发送滞后于tvalid拉高1周期,tlast拉高提前于发送最后一个数据1周期。last信号要与最后一个数据对齐,将tvalid和tlast信号延迟一拍;
always @(posedge M_AXIS_ACLK)                                                                  
	begin                                                                                          
	  if (!M_AXIS_ARESETN)                                                                         
	    begin                                                                                      
	      axis_tvalid_delay <= 1'b0;                                                               
	      axis_tlast_delay <= 1'b0;                                                                
	    end                                                                                        
	  else                                                                                         
	    begin                                                                                      
	      axis_tvalid_delay <= axis_tvalid;                                                        
	      axis_tlast_delay <= axis_tlast;                                                          
	    end                                                                                        
	end
  1. clogb2函数是用移位的方式来计算数据位宽,输入参数是原数据减1
function integer clogb2 (input integer bit_depth);                                   
	  begin                                                                              
	    for(clogb2=0; bit_depth>0; clogb2=clogb2+1)                                      
	      bit_depth = bit_depth >> 1;                                                    
	  end                                                                                
	endfunction 

从机模块

  1. 检测到数据有效后,进入到写FIFO状态;
if (S_AXIS_TVALID)
	            begin
	              mst_exec_state <= WRITE_FIFO;
	            end
	          else
	            begin
	              mst_exec_state <= IDLE;
	            end
  1. 写FIFO状态:将tready信号置1,表示准备好接收数据,主从机握手后,将FIFO写使能置1,然后写指针自增;写入NUMBER_OF_INPUT_WORDS个数据后,将done置1。
assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1));

	always@(posedge S_AXIS_ACLK)
	begin
	  if(!S_AXIS_ARESETN)
	    begin
	      write_pointer <= 0;
	      writes_done <= 1'b0;
	    end  
	  else
	    if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
	      begin
	        if (fifo_wren)
	          begin
	            // write pointer is incremented after every write to the FIFO
	            // when FIFO write signal is enabled.
	            write_pointer <= write_pointer + 1;
	            writes_done <= 1'b0;
	          end
	          if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
	            begin
	              // reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data 
	              // has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
	              writes_done <= 1'b1;
	            end
	      end  
	end
  1. AXIS数据总线宽度为4字节,使用generate-for语句生成4FIFO块,每个块写入AXIS发送数据的1个字节;
assign fifo_wren = S_AXIS_TVALID && axis_tready;

	// FIFO Implementation
	generate 
	  for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
	  begin:FIFO_GEN

	    reg  [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];

	    // Streaming input data is stored in FIFO

	    always @( posedge S_AXIS_ACLK )
	    begin
	      if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
	        begin
	          stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
	        end  
	    end  
	  end		
	endgenerate

S_AXIS_TDATA[7 -: 8]表示S_AXIS_TDATA[7:0]。

AXI4-Lite

主机模块

  1. 在读写状态,链路上无有效信号时,产生start_single脉冲,开始一次读写传输;issued信号指示当前正在进行一次传输,只有issued为0即没有正在进行的传输时,才会产生start_single脉冲;
if (~axi_awvalid && ~axi_wvalid && ~M_AXI_BVALID && ~last_write && ~start_single_write && ~write_issued)
	                    begin                                                           
	                      start_single_write <= 1'b1;                                   
	                      write_issued  <= 1'b1;                                        
	                    end                                                             
	                  else if (axi_bready)                                              
	                    begin                                                           
	                      write_issued  <= 1'b0;                                        
	                    end                                                             
	                  else                                                              
	                    begin                                                           
	                      start_single_write <= 1'b0; //Negate to generate a pulse      
	                    end 
  1. 每次传输开始后读写索引变量加1,最后一次传输握手后产生last信号,与最后一次传输的数据对齐。最后一次传输响应后,产生读/写完成信号,表示传输过程结束,随后进入下个过程;
always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
	      last_write <= 1'b0;                                                           
	                                                                                    
	    //The last write should be associated with a write address ready response       
	    else if ((write_index == C_M_TRANSACTIONS_NUM) && M_AXI_AWREADY)                
	      last_write <= 1'b1;                                                           
	    else                                                                            
	      last_write <= last_write;                                                     
	  end                                                                               
	                                                                                    
	  //Check for last write completion.                                                
	                                                                                    
	  //This logic is to qualify the last write count with the final write              
	  //response. This demonstrates how to confirm that a write has been                
	  //committed.                                                                      
	                                                                                    
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
	      writes_done <= 1'b0;                                                          
	                                                                                    
	      //The writes_done should be associated with a bready response                 
	    else if (last_write && M_AXI_BVALID && axi_bready)                              
	      writes_done <= 1'b1;                                                          
	    else                                                                            
	      writes_done <= writes_done;                                                   
	  end 
  1. 检测到start_single脉冲后,将主机发出的valid或ready拉高,握手后就拉低,由于lite接口每次传输1个数据,握手信号持续1周期即可; 主机ready信号是等待从机valid信号拉高后才置1;
always @(posedge M_AXI_ACLK)                                                     
	  begin                                                                            
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                       
	      begin                                                                        
	        axi_arvalid <= 1'b0;                                                       
	      end                                                                          
	    //Signal a new read address command is available by user logic                 
	    else if (start_single_read)                                                    
	      begin                                                                        
	        axi_arvalid <= 1'b1;                                                       
	      end                                                                          
	    //RAddress accepted by interconnect/slave (issue of M_AXI_ARREADY by slave)    
	    else if (M_AXI_ARREADY && axi_arvalid)                                         
	      begin                                                                        
	        axi_arvalid <= 1'b0;                                                       
	      end                                                                          
	    // retain the previous value                                                   
	  end 
  1. 每个valid都和数据对应,从机检测到valid就会接收数据,握手后生成下一次的写数据和读写地址偏移量,最后传输的地址实际是基地址+地址偏移量;内存地址以字节为单位,数据位宽为4字节,所以每次传输的地址偏移量加4;
always @(posedge M_AXI_ACLK)                                  
	      begin                                                     
	        if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
	          begin                                                 
	            axi_awaddr <= 0;                                    
	          end                                                   
	          // Signals a new write address/ write data is         
	          // available by user logic                            
	        else if (M_AXI_AWREADY && axi_awvalid)                  
	          begin                                                 
	            axi_awaddr <= axi_awaddr + 32'h00000004;            
	                                                                
	          end                                                   
	      end
  1. 读写响应xRESP[1]置1说明读写传输错误,产生错误标志resp_error;读写数据不一致时,产生错误标志read_mismatch;

assign read_resp_error = (axi_rready & M_AXI_RVALID & M_AXI_RRESP[1]);

always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                         
	    read_mismatch <= 1'b0;                                                          
	                                                                                    
	    //The read data when available (on axi_rready) is compared with the expected data
	    else if ((M_AXI_RVALID && axi_rready) && (M_AXI_RDATA != expected_rdata))         
	      read_mismatch <= 1'b1;                                                        
	    else                                                                            
	      read_mismatch <= read_mismatch;                                               
	  end 

从机模块

  1. 复位后写地址使能为1,这表示从机可以接收写地址。检测到写地址和写数据通道有效信号后,axi_awready置1,同时写地址使能置0,此时正在进行一次有效传输,不再接收写地址。读写地址通道握手后,发出写响应有效信号,写响应通道握手后,写地址使能置1,axi_awready置0,此时已完成一次传输,又可以重新接收写地址;
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
  1. 写地址通道和写数据通道握手后会向AXI-lite从机写数据,模块会将数据接收到存储映射寄存器slv_reg;ar/awaddr的高位是选择位,用于选择将数据接收到哪个slv_reg。

ADDR_LSB表示选择位的最低位,对于32位数据总线,最低位是2,对于64位数据总线,最低位是3。
OPT_MEM_ADDR_BITS表示有几个选择位,当添加多个存储映射寄存器时,写地址宽度和选择位都会增加

在向AXI-lite模块某地址中写时会指定地址偏移量,偏移量之间相差1个数据字节宽度,偏移量的值和选择位的值大小相等。当指定偏移量为0时,写地址的选择位就是0,数据将被接收到slv_reg0;在接收数据时是按字节接收,只有写选通为1的字节才能被接收到slv_reg

slv_reg0[(byte_index * 8) + : 8] <= S_AXI_WDATA[(byte_index * 8) + : 8] 等价于slv_reg[7:0]<=S_AXI_WDATA[7:0],slv_reg[15:8]<=S_AXI_WDATA[15:8]…;

assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;

case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	          2'h0:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 0
	                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h1:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 1
	                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end 
  1. 按选择位将slv_reg赋值给reg_data_out,读地址通道握手后再赋值给读数据;
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
	always @(*)
	begin
	      // Address decoding for reading registers
	      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	        2'h0   : reg_data_out <= slv_reg0;
	        2'h1   : reg_data_out <= slv_reg1;
	        2'h2   : reg_data_out <= slv_reg2;
	        2'h3   : reg_data_out <= slv_reg3;
	        default : reg_data_out <= 0;
	      endcase
	end

若要读取PS写到AXI-lite的数据,只需读取存储映射寄存器slv_reg;
若要将数据写到PS端,只需将reg_data_out <=右端替换为要写的数据

AXI-Full

主机模块

  1. 整体过程由状态机控制,当没有有效的读/写地址并且当前没有正在进行的突发传输时,产生开始一次读/写突发传输脉冲。
if (~axi_awvalid && ~start_single_burst_write && ~burst_write_active)
  	begin                                                              
   	 	start_single_burst_write <= 1'b1;                                
  	end                                                                
else                                                                 
  	begin                                                              
    	start_single_burst_write <= 1'b0; //Negate to generate a pulse   
  	end                                                                
  1. 检测到读/写脉冲后,拉高读/写地址有效信号,握手后就拉低,每次突发传输只需要传输一个地址,握手信号只需持续1个周期。
always @(posedge M_AXI_ACLK)                                   
	  begin                                                                
	                                                                       
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                           
	      begin                                                            
	        axi_awvalid <= 1'b0;                                           
	      end                                                              
	    // If previously not valid , start next transaction                
	    else if (~axi_awvalid && start_single_burst_write)                 
	      begin                                                            
	        axi_awvalid <= 1'b1;                                           
	      end                                                              
	    /* Once asserted, VALIDs cannot be deasserted, so axi_awvalid      
	    must wait until transaction is accepted */                         
	    else if (M_AXI_AWREADY && axi_awvalid)                             
	      begin                                                            
	        axi_awvalid <= 1'b0;                                           
	      end                                                              
	    else                                                               
	      axi_awvalid <= axi_awvalid;                                      
	    end
  1. 读/写地址通道握手后,产生下一次突发的地址。读/写数据通道握手后,产生下一次传输的数据。

assign burst_size_bytes = C_M_AXI_BURST_LEN * C_M_AXI_DATA_WIDTH/8;//一次突发传输64字节

always @(posedge M_AXI_ACLK)                                         
	  begin                                                                
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                            
	      begin                                                            
	        axi_awaddr <= 'b0;                                             
	      end                                                              
	    else if (M_AXI_AWREADY && axi_awvalid)                             
	      begin                                                            
	        axi_awaddr <= axi_awaddr + burst_size_bytes;                   
	      end                                                              
	    else                                                               
	      axi_awaddr <= axi_awaddr;                                        
	    end
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 
  1. 每进行突发中的1次读/写数据传输,index计1次数,直到完成C_M_AXI_BURST_LEN次数据传输。
    assign wnext = M_AXI_WREADY & axi_wvalid; //握手信号
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
  1. 如果只有1次突发传输,直接拉高last信号,持续1个时钟周期;如果突发传输超过2次,直到完成(C_M_AXI_BURST_LEN-1)次突发传输后拉高tlast信号,持续1个时钟周期。这里计数到C_M_AXI_BURST_LEN-2是因为last信号要和最后一个数据对齐。
always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                                        
	      begin                                                                         
	        axi_wlast <= 1'b0;                                                          
	      end                                                                           
	    // axi_wlast is asserted when the write index                                   
	    // count reaches the penultimate count to synchronize                           
	    // with the last write data when write_index is b1111                           
	    // else if (&(write_index[C_TRANSACTIONS_NUM-1:1])&& ~write_index[0] && wnext)  
	    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                                                                           
	    // Deassrt axi_wlast when the last write data has been                          
	    // accepted by the slave with a valid response                                  
	    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
  1. 每进行1次突发传输,burst_counter计1次数,当burst_counter最高位是1时,就计到了最大值64,停止计数。
    源码中给出的是在4K地址范围进行突发传输,每次突发传输64字节,故最大计到4K/64=64,位宽为12-6+1=7。
     localparam integer C_MASTER_LENGTH	= 12;//主机传输地址范围的宽度
	 localparam integer C_NO_BURSTS_REQ = C_MASTER_LENGTH-clogb2((C_M_AXI_BURST_LEN*C_M_AXI_DATA_WIDTH/8)-1);//突发计数器位宽-1
always @(posedge M_AXI_ACLK)                                                                              
	  begin                                                                                                     
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                                                                 
	      begin                                                                                                 
	        write_burst_counter <= 'b0;                                                                         
	      end                                                                                                   
	    else if (M_AXI_AWREADY && axi_awvalid)                                                                  
	      begin                                                                                                 
	        if (write_burst_counter[C_NO_BURSTS_REQ] == 1'b0)                                                   
	          begin                                                                                             
	            write_burst_counter <= write_burst_counter + 1'b1;                                              
	            //write_burst_counter[C_NO_BURSTS_REQ] <= 1'b1;                                                 
	          end                                                                                               
	      end                                                                                                   
	    else                                                                                                    
	      write_burst_counter <= write_burst_counter;                                                           
	  end  
  1. burst_active信号指示当前正在进行1次突发读/写传输,检测到写响应握手信号后burst_active置0,每开启1次传输置1。
always @(posedge M_AXI_ACLK)                                                                              
	  begin                                                                                                     
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                                                 
	      burst_write_active <= 1'b0;                                                                           
	                                                                                                            
	    //The burst_write_active is asserted when a write burst transaction is initiated                        
	    else if (start_single_burst_write)                                                                      
	      burst_write_active <= 1'b1;                                                                           
	    else if (M_AXI_BVALID && axi_bready)                                                                    
	      burst_write_active <= 0;                                                                              
	  end
  1. done信号用于指示所有突发传输都已经完成,当burst_counter计到最大且收到最后一次数据响应时done置1.
always @(posedge M_AXI_ACLK)                                                                              
	  begin                                                                                                     
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                                                 
	      writes_done <= 1'b0;                                                                                  
	                                                                                                            
	    //The writes_done should be associated with a bready response                                           
	    //else if (M_AXI_BVALID && axi_bready && (write_burst_counter == {(C_NO_BURSTS_REQ-1){1}}) && axi_wlast)
	    else if (M_AXI_BVALID && (write_burst_counter[C_NO_BURSTS_REQ]) && axi_bready)                          
	      writes_done <= 1'b1;                                                                                  
	    else                                                                                                    
	      writes_done <= writes_done;                                                                           
	    end

从机模块

  1. axi_awv_awr_flag是当前正在进行1次写传输的状态标志,检测到写地址有效后axi_awv_awr_flag置1,检测到写数据的last后置0.读写地址通道握手后,W/RREADY信号才拉高,
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)
	        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
  1. 检测到读/写地址有效后将读/写地址锁存,axi_awlen_cntr用于计数1次突发的每次传输,根据突发类型产生相应的读/写地址。

突发传输中起始地址要和AxSIZE对应的传输数据大小对齐,即起始地址的[ADDR_LSB-1:0]应该为0,而ADDR_LSB由AxSIZE决定。如源码中AxSIZE值是2,对应的突发大小是4(3’b100)个字节,4的[1:0]位是0,ADDR_LSB就是2,即起始地址的[1:0]位是0。

aw_wrap_en :这里是利用进位判断到达回环边界,如起始axi_awaddr =6’b011001,到达回环边界时axi_awaddr=6‘b011001+7’b1000000=7’b1011001,7’b1011001&7’b1000000=7’b1000000,也就是说当地址增加了64字节后最高位变成了1.

assign  aw_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_awlen));//回环突发数据总大小64字节
assign  aw_wrap_en = ((axi_awaddr & aw_wrap_size) == aw_wrap_size)? 1'b1: 1'b0;//回环使能,表示到达回环边界
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
  1. 这里和AXI-lite从机接口将数据接收到寄存器中类似,只不过由于传输多个数据,变为根据WSTRB将一次突发传输的全部数据按字节分别存储到4个RAM中。写通道握手后,RAM写使能,然后根据写选通将数据字节存储到byte_ram中。进入到读状态后,RAM读使能,将byte_ram的数据读出。
byte_ram:用数组定义的存储数据字节的RAM
OPT_MEM_ADDR_BITS:RAM地址的位宽-1,和burst_length有关
USER_NUM_MEM :用户需要多少组这样的RAM
mem_address :按读写状态标志获取RAM地址,范围是0~burst_length

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 : 15];
	        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    

六、功能仿真

AXI4-Stream

直接使用官方的主从、机IP核进行连接,并在testbench中给出时钟和复位信号。
在这里插入图片描述
在这里插入图片描述

AXI4-Lite

AXI-lite主从机对地址的处理不同,不能直接相连,需要添加互联模块。
在这里插入图片描述
在这里插入图片描述

AXI-Full

在这里插入图片描述

写通道:
在这里插入图片描述
读通道:
在这里插入图片描述

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

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

相关文章

MybatisPlus分页插件

分页查询是一个很常见的需求&#xff0c;故Mybatis-Plus提供了一个分页插件&#xff0c;使用它可以十分方便的完成分页查询。下面介绍Mybatis-Plus分页插件的用法&#xff0c;详细信息可参考官方链接。 配置分页插件 创建com.atguigu.hellomp.config.MPConfiguration配置类&a…

奇异值分解(SVD)时间复杂度分析与优化

奇异值分解是一种矩阵分解的方法&#xff0c;大学线性代数里面也讲过奇异值分解的方法&#xff0c;因此这是一个为大家所熟知的算法。 1 SVD 时间复杂度分析 给定一个 m n m \times n mn 的矩阵 a \boldsymbol{a} a&#xff0c;按照下面公式做分解&#xff0c;其中 Σ \S…

python语言利用Tkinter实现GUI计算器|(二)优化计算器:过滤用户不合理的输入

python语言利用Tkinter实现GUI计算器 python语言利用Tkinter实现GUI计算器|&#xff08;一&#xff09;计算器基本功能设计 python语言利用Tkinter实现GUI计算器|&#xff08;二&#xff09;优化计算器 python语言利用Tkinter实现GUI计算器|&#xff08;三&#xff09;pyinstal…

python在类中手动定义标准化输出函数

在深度学习等训练框架中&#xff0c;有时候需要对模型的名称、参数量、训练进度、中间结果等进行标准化输出&#xff0c;从而方便实时查看代码运行情况&#xff0c;这时&#xff0c;可以在类中手动定义如下标准化的输出函数&#xff0c;然后在需要输出的地方进行调用即可。 首…

免费【2024】springboot 超市货品信息管理系统

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

修复SteamUI.dll加载失败的指南,快速修复failed to load steamui.dll

在使用Steam平台进行游戏下载、安装和运行时&#xff0c;可能会遇到一些系统错误&#xff0c;比如“failed to load steamui.dll”。这个错误通常意味着Steam的用户界面库文件steamui.dll出现了问题。本文将详细介绍steamui.dll文件的相关信息以及如何修复这一问题。 一.什么是…

vue 开发环境配置

1. nvm 安装 在 github上下载 最新的 nvm 包 https://github.com/coreybutler/nvm-windows/releases或者在 csdn 上下载&#xff08;从github上迁移&#xff0c;方便下载&#xff09;https://download.csdn.net/download/u011171506/89585197 下载后不用修改任何配置&#x…

Opencv学习项目4——手部跟踪

上一篇博客我们介绍了mediapipe库和对手部进行了检测&#xff0c;这次我们进行手部关键点的连线 代码实现 import cv2 import mediapipe as mpcap cv2.VideoCapture(1) mpHands mp.solutions.hands hands mpHands.Hands() mpDraw mp.solutions.drawing_utilswhile True:…

树莓派智能家居中枢

一个先进的枢纽&#xff0c;使智能家居系统更智能、更可定制、更易于控制 Homey Pro由树莓派 Compute Module 4 供电,Homey Pro 为用户提供了一个单一界面,用于控制和监控来自不同品牌的所有智能家居设备。它完全在本地网络上运行,而不是依赖云端,从而实现了最低的延迟、最高的…

对Linux目录结构的补充

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…

【数据结构】哈希表的模拟实现

文章目录 1. 哈希的概念2. 哈希表与哈希函数2.1 哈希冲突2.2 哈希函数2.3 哈希冲突的解决2.3.1 闭散列&#xff08;线性探测&#xff09;2.3.2 闭散列的实现2.3.3 开散列(哈希桶)2.3.4 开散列的实现 2.4 开散列与闭散列比较 1. 哈希的概念 在我们之前所接触到的所有的数据结构…

【C语言项目】 以链表实现的管理系统(注册、登录、对表进行数据操作)

第一次编辑这么长的文章&#xff0c;如果对你有帮助&#xff0c;可以点赞收藏一下一起学习&#xff01;一起进步&#xff01; 目录 一、项目介绍 二、代码介绍 三、小记 四、完整代码 五、输出结果展示 1、成功将终端输入的用户姓名和密码分别存入到.txt文件中 2、登陆成…

cpp学习记录03

结构体 定义&#xff1a;用户自定义符合数据类型&#xff0c;可以包含不同类型的不同成员。 //声明结构体 struct 结构体类型&#xff08;自己起名&#xff09; {成员1类型 成员1名称&#xff1b;。。。成员N类型 成员N名称&#xff1b;} 基本用法&#xff08;类似class&…

探索 Electron:构建用户友好的登录页面流程

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…

88年汉城奥运追忆:差距尤存,出路何在

&#xff08;35年前的文章&#xff0c;摘自1989年2月1日《大众日报》&#xff09; 差距尤存 出路何在 ——汉城奥运会后的思索 刘伟 一项调查表明&#xff1a;在当今中国中学生最喜爱的十本杂志中&#xff0c;竟没有一本是体育类杂志&#xff1b;在城市工人、干部、科技人员家…

搜索引擎项目(四)

SearchEngine 王宇璇/submit - 码云 - 开源中国 (gitee.com) 基于Servlet完成前后端交互 WebServlet("/searcher") public class DocSearcherServlet extends HttpServlet {private static DocSearcher docSearcher new DocSearcher();private ObjectMapper obje…

【前端/js】使用js读取本地文件(xml、二进制)内容

目录 说在前面FileReaderDOMParser文本文件二进制文件 说在前面 浏览器版本&#xff1a;Microsoft Edge 126.0.2 (正式版本) (64 位) FileReader MDNFileReader 接口允许 Web 应用程序异步读取存储在用户计算机上的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#x…

Golang 高性能 Websocket 库 gws 使用与设计(一)

前言 大家好这里是&#xff0c;白泽&#xff0c;这期分析一下 golang 开源高性能 websocket 库 gws。 视频讲解请关注&#x1f4fa;B站&#xff1a;白泽talk 介绍 gws&#xff1a;https://github.com/lxzan/gws &#xff5c;GitHub &#x1f31f; 1.2k&#xff0c;高性能的 …

STM32(七):STM32指南者-通信实验

目录 一、基本概念通讯基本概念1、串行和并行2、同步通讯与异步通讯3、全双工、半双工、单工4、通讯速率 USART基本概念1、串口通讯基本概念2、物理层3、协议层4、指南者的串口USART I2C基本概念SPI基本概念 二、USART串口实验前期准备1、安装安装 USB 转串口驱动_CH3402、野火…

【中项】系统集成项目管理工程师-第5章 软件工程-5.1软件工程定义与5.2软件需求

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…