PL读写DDR3 实现PS和PL间的数据交互 代码分析

本文是PL读写DDR3 实现PS和PL间的数据交互 的继续,深入分析其代码。

首先分析基本要求,或者需求分析,然后读写流程描述,实测采集的读写过程的波形图,最后分段代码分析,这个代码是上文中利用vivado 2018.2 自动生成的,也许做了一点修改比如注释。然后对代码分段分析,我想使用这些代码,所以必须分析弄懂。在引用中@5表示第5个always 代码段。

还在继续学习中,如果有什么问题,大家一起讨论,若有更明白说法的地方请赐教。

需求分析

要想PL访问板上的DDR3存储器,必须借道Zynq中的“Memory Interfaces----DDR2/3,LPDDR2 Controller”(后文简称“DDR3 Controller”)。根据之前的经验,在Zynq系统中,ARM Core(CPU)能够访问硬核“DDR3 Controller”,根据经验可以确定“DDR3 Controller”一定是一个从设备,而PL要想访问“DDR3 Controller”的话,PL一定要是一个主设备,由PL发起读写操作。

“DDR3 Controller”是封装在Zynq子系统中的,因此,PL必须连接Zynq的从机接口。Zynq有两个从机接口,分别是“32b GP AXI Slave Ports”和“High Performance AXI 32b/64b Slave Ports”根据名称可以看出,一个是高性能的,另一个应该是普通的。之前Zynq作为主机连接AXI4-Lite从设备时,走的是“32b GP AXI Master Ports”,可以辅助证明,对于本节应用,走的接口应该是“32b GP AXI Slave Ports”。

交互数据将会经过Zynq子系统的内部总线控制器“Central Interconnect”转发给Memory Interfaces。

除了读写流程外,本代码也包含了一段测试代码,激发读写过程,代码内容如下:

利用向导生成的PL端AXI4-Lite Master IP 用户用例,在INIT_AXI_TXN负脉冲触发下,主机模块的逻辑是连续4次(次数默认为4,可通过修改参数C_M00_AXI_TRANSACTIONS_NUM的数值改变次数)向递增的地址区间写入4组测试数据,测试数据每次加1。然后主机模块自动读取刚才写入数据的地址内的数据,将读的的数据与写入数据进行比较,如果正确,主机IP的ERROR信号保持低电平,如果错误,ERROR给出高电平。然后触发结束后,TXN_DONE指示运行结束。

写入数据的内容是:C_M_START_DATA_VALUE 决定的,axi_wdata <= C_M_START_DATA_VALUE + write_index; write_index是0,1,2,3

读写的地址内容是  C_M_TARGET_SLAVE_BASE_ADDR决定的。偏置地址是0,4,8,12

这个模块的外部接口是:

input wire  m00_axi_init_axi_txn,
output wire  m00_axi_error,
output wire  m00_axi_txn_done,

此外,除了复位,时钟,就是axi 总线了,我们的是Master 接口。

可以参考我的另一博文:AXI4 Lite 协议分析,可以查看读写时序分析图,信号线总结也一样。

1:写地址通道: AWVALID, AWADDR, AWREADY(O),AWPROT

2:写数据通道: WVALID, WDATA, WSTRB, WREADY(O)

3:写应答通道: BVALID(O), BRESP(O), BREADY

4:读地址通道: ARVALID, ARADDR,ARREADY(O),ARPROT

5:读数据通道: RVALID,RDATA,RREADY, RRESP

6:系统通道: ACLK, ARESETN

读写流程

https://www.realdigital.org/doc/a9fee931f7a172423e1ba73f66ca4081 介绍不错,部分原文引用在此

https://www.realdigital.org/doc/c4d57104000339a55b764e5e5f21e28c 看波形不错。

写流程:

AXI4-Lite Write Transaction

Below, the sequence for an AXI4-Lite write is shown:

A description of the events in figure 4 follows:

  1. The Master puts an address on the Write Address channel and data on the Write data channel. At the same time it asserts AWVALID and WVALID indicating the address and data on the respective channels is valid. BREADY is also asserted by the Master, indicating it is ready to receive a response.
  2. The Slave asserts AWREADY and WREADY on the Write Address and Write Data channels, respectively.
  3. Since Valid and Ready signals are present on both the Write Address and Write Data channels, the handshakes on those channels occur and the associated Valid and Ready signals can be deasserted. (After both handshakes occur, the slave has the write address and data)
  4. The Slave asserts BVALID, indicating there is a valid reponse on the Write response channel. (in this case the response is 2’b00, that being ‘OKAY’).
  5. The next rising clock edge completes the transaction, with both the Ready and Valid signals on the write response channel high.

Master 把地址和数据放通道上,同时拉高AWVALID WVALID,表面地址和数据有效,同时BREADY由Master 拉高,表明准备接收响应。

Slave 拉高AWREADY WREADY

数据和地址都有Valid Ready 信号,开始握手,同时Valid Ready 放低。这2个握手都发生时,Slave 有了地址和数据

Slave 拉高 BVALID,响应是2‘b00 也就是'OKEY'

下个时钟周期,写事务结束写响应的Ready Valid 都拉高

代码中是这样的:

设置写保护级别:assign M_AXI_AWPROT    = 3'b000;

写使能:assign M_AXI_WSTRB    = 4'b1111;

开始写过程时:start_single_write <= 1'b1;                              
                          write_issued  <= 1'b1; 

 

axi_awvalid <= 1'b1; axi_wvalid <= 1'b1;

WDATA,AWADDR准备好写的数据(M_AXI_AWREADY && axi_awvalid) ,和地址数据(M_AXI_WREADY && axi_wvalid)

M_AXI_AWREADY,M_AXI_WREADY,来自slave 的输入

*****我认为地址和数据应该先于awvalid,wvalid 才对,可这里好像后于,不知为什么

axi_awvalid <= 1'b0(M_AXI_AWREADY && axi_awvalid); 

axi_wvalid <= 1'b0;(M_AXI_WREADY && axi_wvalid)

 

axi_bready <= 1'b1;(M_AXI_BVALID && ~axi_bready) 只有一个时钟的上脉冲,M_AXI_BVALID来自Slave

 

last_write 的时候,write_issued  <= 1'b0; (axi_bready),然后start_single_write <= 1'b0;

 

读流程:

AXI4-Lite Read Transaction

Below, the sequence for an AXI4-Lite read is shown:

A description of the events in figure 3 follows:

  1. The Master puts an address on the Read Address channel as well as asserting ARVALID,indicating the address is valid, and RREADY, indicating the master is ready to receive data from the slave.
  2. The Slave asserts ARREADY, indicating that it is ready to receive the address on the bus.
  3. Since both ARVALID and ARREADY are asserted, on the next rising clock edge the handshake occurs, after this the master and slave deassert ARVALID and the ARREADY, respectively. (At this point, the slave has received the requested address).
  4. The Slave puts the requested data on the Read Data channel and asserts RVALID, indicating the data in the channel is valid. The slave can also put a response on RRESP, though this does not occur here.
  5. Since both RREADY and RVALID are asserted, the next rising clock edge completes the transaction. RREADY and RVALID can now be deasserted.

Master 把地址放读地址通道上,ARVALID 拉高,指示地址有效,同时RREADY 也拉高,指示准备好接受数据。

Slave 拉高ARREADY,指示准备接收读地址总线的地址

ARVALID ARREADY都拉高了,下个时钟上升沿,握手发生,这之后,ARVALID ARREADY 放低,这个点,Slave接受地址

Slave 把读数据放读数据通道上,,拉高 RVALID,指示数据有效,Slave 也有RRESP响应,这里图上没有

RREADY RVALID 都拉高了,下一个时钟周期,读事务结束了,RREADY RVALID 放低。

 

读流程开始:start_single_read <= 1'b1;                                     
                       read_issued  <= 1'b1;      (~axi_arvalid && ~M_AXI_RVALID)

axi_arvalid <= 1'b1; (start_single_read)

写读地址:axi_araddr <=..  (M_AXI_ARREADY && axi_arvalid) 

 

axi_rready <= 1'b1;(M_AXI_RVALID && ~axi_rready)  一个时钟脉冲

expected_rdata <= (M_AXI_RVALID && axi_rready)

read_mismatch <= 1'b1;((M_AXI_RVALID && axi_rready) && (M_AXI_RDATA != expected_rdata)) 

并没有读取数据,简单与期望值比较一下。

axi_rready <= 1'b0; (axi_rready)  只有一个时钟高脉冲

 

实测波形图

这2个实测波形图,通过Vivado 下的集成逻辑分析仪ILA在开发板上实际测试获得。其方法请见 Vivado的集成逻辑分析仪ILA 在有sdk 下的应用入门。

axi4 读流程:PL读写DDR3 实现PS和PL间的数据交互 代码分析_第1张图片

 

axi4 写流程: 

这个地址线分成了好几组,只有WDATA[2:0]是变化的,也不知道怎么控制能分成几组。

PL读写DDR3 实现PS和PL间的数据交互 代码分析_第2张图片

AzIP_AXI_Master_v1_0.v 代码分析


这个文件比较小,3kb大小,只是一个接口封装,列出所有接口,然后调用实例

// Instantiation of Axi Bus Interface M00_AXI 

这行开始就是调用实例。

 

AzIP_AXI_Master_v1_0_M00_AXI.v 文件 代码分析

这个是我们分析的重点,代码实现都是在这里。

到 95,96行

       output wire  M_AXI_RREADY
    );

一直是函数的说明,io等。

然后到110行,是2个辅助函数,

	// function called clogb2 that returns an integer which has the
	// value of the ceiling of the log base 2

	 function integer clogb2 (input integer bit_depth);
		 begin
		 for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
			 bit_depth = bit_depth >> 1;
		 end
	 endfunction

	// TRANS_NUM_BITS is the width of the index counter for 
	// number of write or read transaction.
	 localparam integer TRANS_NUM_BITS = clogb2(C_M_TRANSACTIONS_NUM-1);

到128行reg [1:0] mst_exec_state; 定义测试代码状态机,读,写,比较,空闲

这个不是读写的代码,而是测试调用读写的代码

在185行或者 // I/O Connections assignments前,都是寄存器声明

到212行或者 //Generate a pulse to initiate AXI transaction. 行前一组assign,io口对应寄存器变量

	// I/O Connections assignments

	//Adding the offset address to the base addr of the slave
	assign M_AXI_AWADDR	= C_M_TARGET_SLAVE_BASE_ADDR + axi_awaddr;
	//AXI 4 write data
	assign M_AXI_WDATA	= axi_wdata;
	assign M_AXI_AWPROT	= 3'b000;
	assign M_AXI_AWVALID	= axi_awvalid;
	//Write Data(W)
	assign M_AXI_WVALID	= axi_wvalid;
	//Set all byte strobes in this example
	assign M_AXI_WSTRB	= 4'b1111;
	//Write Response (B)
	assign M_AXI_BREADY	= axi_bready;
	//Read Address (AR)
	assign M_AXI_ARADDR	= C_M_TARGET_SLAVE_BASE_ADDR + axi_araddr;
	assign M_AXI_ARVALID	= axi_arvalid;
	assign M_AXI_ARPROT	= 3'b001;
	//Read and Read Response (R)
	assign M_AXI_RREADY	= axi_rready;
	//Example design I/O
	assign TXN_DONE	= compare_done;
	assign init_txn_pulse	= (!init_txn_ff2) && init_txn_ff;

@1: 然后处理: init_txn_ff, init_txn_ff2,init_txn_ff 直接对应INIT_AXI_TXN输入,但init_txn_ff2 需要延后一个时钟

这段代码的作用就是得到一个init_txt_pulse,上升脉冲,作为程序启动的标识。init_txn_ff, init_txn_ff2在其他地方都没有用到,只有一个语句:

assign init_txn_pulse    = (!init_txn_ff2) && init_txn_ff;

这个init_txn_pulse == 1'b1 几乎每个always 都用到,作为初始化,为程序运行做准备。

	//Generate a pulse to initiate AXI transaction.
	always @(posedge M_AXI_ACLK)										      
	  begin                                                                        
	    // Initiates AXI transaction delay    
	    if (M_AXI_ARESETN == 0 )                                                   
	      begin                                                                    
	        init_txn_ff <= 1'b0;                                                   
	        init_txn_ff2 <= 1'b0;                                                   
	      end                                                                               
	    else                                                                       
	      begin  
	        init_txn_ff <= INIT_AXI_TXN;
	        init_txn_ff2 <= init_txn_ff;                                                                 
	      end                                                                      
	  end  

@2: 230行或者//Write Address Channel 开始,处理Write Address 通道的 axi_awvalid

写地址通道有效,由start_single_write启动为1,M_AXI_AWREADY(由slave确认)告知结束,为0。

	//--------------------
	//Write Address Channel
	//--------------------

	// The purpose of the write address channel is to request the address and 
	// command information for the entire transaction.  It is a single beat
	// of information.

	// Note for this example the axi_awvalid/axi_wvalid are asserted at the same
	// time, and then each is deasserted independent from each other.
	// This is a lower-performance, but simplier control scheme.

	// AXI VALID signals must be held active until accepted by the partner.

	// A data transfer is accepted by the slave when a master has
	// VALID data and the slave acknoledges it is also READY. While the master
	// is allowed to generated multiple, back-to-back requests by not 
	// deasserting VALID, this design will add rest cycle for
	// simplicity.

	// Since only one outstanding transaction is issued by the user design,
	// there will not be a collision between a new request and an accepted
	// request on the same clock cycle. 

	  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

@3: 277行或者// start_single_write triggers a new write

write_index,实际上只是0,1,2,3

@4: 297 行或者 //Write Data Channel

axi_wvalid,写数据有效,由start_single_write==1 发起,为1,在M_AXI_WREADY==1 时回落,M_AXI_WREADY是slave发起确定的。

	//--------------------
	//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         

@5: 324行或者 //Write Response (B) Channel

axi_bready:要写的数据,数据地址都到达slave,而且被slave 确认了。M_AXI_BVALID(由slave反馈的)为高,则axi_bready 变高,一个时钟后回低,也就是说一个正脉冲。

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

	//The write response channel provides feedback that the write has committed
	//to memory. BREADY will occur after both the data and the write address
	//has arrived and been accepted by the slave, and can guarantee that no
	//other accesses launched afterwards will be able to be reordered before it.

	//The BRESP bit [1] is used indicate any errors from the interconnect or
	//slave for the entire write burst. This example will capture the error.

	//While not necessary per spec, it is advisable to reset READY signals in
	//case of differing reset latencies between master/slave.

	  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 write errors                                                    
	assign write_resp_error = (axi_bready & M_AXI_BVALID & M_AXI_BRESP[1]);

 

@6: 365行//Read Address Channel

read_index,实际上只是0,1,2,3

@7: 385行开始, 

axi_arvalid:读地址有效,由start_single_read启动,为1,M_AXI_ARREADY(由slave 发起)转为0

	  // A new axi_arvalid is asserted when there is a valid read address              
	  // available by the master. start_single_read triggers a new read                
	  // transaction                                                                   
	  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 

@8: 409行//Read Data (and Response) Channel  

处理 axi_rready :读响应, M_AXI_RVALID 由slave激发读有效后,给一个高脉冲,作为读响应

	  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 && ~axi_rready)                               
	      begin                                                             
	        axi_rready <= 1'b1;                                             
	      end                                                               
	    // deassert after one clock cycle                                   
	    else if (axi_rready)                                                
	      begin                                                             
	        axi_rready <= 1'b0;                                             
	      end                                                               
	    // retain the previous value                                        
	  end  

 440行开始是//user logic  用户逻辑。虽然是用户逻辑,但也很重要,写地址的写,写数据的写,读地址的写,读数据

@9: 450-464:写地址的写,

	  //Write Addresses                                        
	  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 

@10: 466-479:写数据的写:

	  // Write data generation                                      
	  always @(posedge M_AXI_ACLK)                                  
	      begin                                                     
	        if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                
	          begin                                                 
	            axi_wdata <= C_M_START_DATA_VALUE;                  
	          end                                                   
	        // Signals a new write address/ write data is           
	        // available by user logic                              
	        else if (M_AXI_WREADY && axi_wvalid)                    
	          begin                                                 
	            axi_wdata <= C_M_START_DATA_VALUE + write_index;    
	          end                                                   
	        end 

@11: 481-494:读地址的写:

	  //Read Addresses                                              
	  always @(posedge M_AXI_ACLK)                                  
	      begin                                                     
	        if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
	          begin                                                 
	            axi_araddr <= 0;                                    
	          end                                                   
	          // Signals a new write address/ write data is         
	          // available by user logic                            
	        else if (M_AXI_ARREADY && axi_arvalid)                  
	          begin                                                 
	            axi_araddr <= axi_araddr + 32'h00000004;            
	          end                                                   
	      end  

 @12: 498-510:获取期望的读数据,expected保存期望的读数据,用于比较。

	  always @(posedge M_AXI_ACLK)                                  
	      begin                                                     
	        if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
	          begin                                                 
	            expected_rdata <= C_M_START_DATA_VALUE;             
	          end                                                   
	          // Signals a new write address/ write data is         
	          // available by user logic                            
	        else if (M_AXI_RVALID && axi_rready)                    
	          begin                                                 
	            expected_rdata <= C_M_START_DATA_VALUE + read_index;
	          end                                                   
	      end 

 @13: 511-616:测试主程序的状态机转换代码

复位初始状态是IDLE,有外部激发时,转为INIT_WRITE,

在INIT_WRITE状态时,write_done==1,转为INIT_READ

在INIT_READ状态下,read_done==1,转为INIT_COMPARE

在INIT_COMPARE状态下,一个周期转换为IDLE

 

	  //implement master command interface state machine                         
	  always @ ( posedge M_AXI_ACLK)                                                    
	  begin                                                                             
	    if (M_AXI_ARESETN == 1'b0)                                                     
	      begin                                                                         
	      // reset condition                                                            
	      // All the signals are assigned default values under reset condition          
	        mst_exec_state  <= IDLE;                                            
	        start_single_write <= 1'b0;                                                 
	        write_issued  <= 1'b0;                                                      
	        start_single_read  <= 1'b0;                                                 
	        read_issued   <= 1'b0;                                                      
	        compare_done  <= 1'b0;                                                      
	        ERROR <= 1'b0;
	      end                                                                           
	    else                                                                            
	      begin                                                                         
	       // state transition                                                          
	        case (mst_exec_state)                                                       
	                                                                                    
	          IDLE:                                                             
	          // This state is responsible to initiate 
	          // AXI transaction when init_txn_pulse is asserted 
	            if ( init_txn_pulse == 1'b1 )                                     
	              begin                                                                 
	                mst_exec_state  <= INIT_WRITE;                                      
	                ERROR <= 1'b0;
	                compare_done <= 1'b0;
	              end                                                                   
	            else                                                                    
	              begin                                                                 
	                mst_exec_state  <= IDLE;                                    
	              end                                                                   
	                                                                                    
	          INIT_WRITE:                                                               
	            // This state is responsible to issue start_single_write pulse to       
	            // initiate a write transaction. Write transactions will be             
	            // issued until last_write signal is asserted.                          
	            // write controller                                                     
	            if (writes_done)                                                        
	              begin                                                                 
	                mst_exec_state <= INIT_READ;//                                      
	              end                                                                   
	            else                                                                    
	              begin                                                                 
	                mst_exec_state  <= INIT_WRITE;                                      
	                                                                                    
	                  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                                                             
	              end                                                                   
	                                                                                    
	          INIT_READ:                                                                
	            // This state is responsible to issue start_single_read pulse to        
	            // initiate a read transaction. Read transactions will be               
	            // issued until last_read signal is asserted.                           
	             // read controller                                                     
	             if (reads_done)                                                        
	               begin                                                                
	                 mst_exec_state <= INIT_COMPARE;                                    
	               end                                                                  
	             else                                                                   
	               begin                                                                
	                 mst_exec_state  <= INIT_READ;                                      
	                                                                                    
	                 if (~axi_arvalid && ~M_AXI_RVALID && ~last_read && ~start_single_read && ~read_issued)
	                   begin                                                            
	                     start_single_read <= 1'b1;                                     
	                     read_issued  <= 1'b1;                                          
	                   end                                                              
	                 else if (axi_rready)                                               
	                   begin                                                            
	                     read_issued  <= 1'b0;                                          
	                   end                                                              
	                 else                                                               
	                   begin                                                            
	                     start_single_read <= 1'b0; //Negate to generate a pulse        
	                   end                                                              
	               end                                                                  
	                                                                                    
	           INIT_COMPARE:                                                            
	             begin
	                 // This state is responsible to issue the state of comparison          
	                 // of written data with the read data. If no error flags are set,      
	                 // compare_done signal will be asseted to indicate success.            
	                 ERROR <= error_reg; 
	                 mst_exec_state <= IDLE;                                    
	                 compare_done <= 1'b1;                                              
	             end                                                                  
	           default :                                                                
	             begin                                                                  
	               mst_exec_state  <= IDLE;                                     
	             end                                                                    
	        endcase                                                                     
	    end                                                                             
	  end //MASTER_EXECUTION_PROC  

@14: 618-630:测试是否最后一次写

	  //Terminal write count                                                            
	                                                                                    
	  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   

 @15: 632-648:判断写是否完成,write_done

	  //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 

@16: 654-666:判断是否最后一次读

	//Terminal Read Count                                                               
	                                                                                    
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
	      last_read <= 1'b0;                                                            
	                                                                                    
	    //The last read should be associated with a read address ready response         
	    else if ((read_index == C_M_TRANSACTIONS_NUM) && (M_AXI_ARREADY) )              
	      last_read <= 1'b1;                                                            
	    else                                                                            
	      last_read <= last_read;                                                       
	  end  

@17: 668-684:判断读是否完成

	/*                                                                                  
	 Check for last read completion.                                                    
	                                                                                    
	 This logic is to qualify the last read count with the final read                   
	 response/data.                                                                     
	 */                                                                                 
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
	      reads_done <= 1'b0;                                                           
	                                                                                    
	    //The reads_done should be associated with a read ready response                
	    else if (last_read && M_AXI_RVALID && axi_rready)                               
	      reads_done <= 1'b1;                                                           
	    else                                                                            
	      reads_done <= reads_done;                                                     
	    end 

@18: 690-701:数据比较,如果不匹配,则read_mismatch 为1,每一次外部激发清0

	//Data Comparison                                                                   
	  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 

@19: 703-714:错误指示的计算

 读取数据不匹配,读响应错误,或写响应错误都有错误只是,每一次外部激发清0

	// Register and hold any data mismatches, or read/write interface errors            
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                         
	      error_reg <= 1'b0;                                                            
	                                                                                    
	    //Capture any error types                                                       
	    else if (read_mismatch || write_resp_error || read_resp_error)                  
	      error_reg <= 1'b1;                                                            
	    else                                                                            
	      error_reg <= error_reg;                                                       
	  end 

2个文件的代码

我的文件位置在 D:\alinx\ip_repo\AzIP_AXI_Master_1.0\hdl 目录下。

AzIP_AXI_Master_v1_0.v 文件内容 90行

AzIP_AXI_Master_v1_0_M00_AXI.v 文件内容720 行

文件代码太长,不占文章太多内容了。都是PL读写DDR3 实现PS和PL间的数据交互 一文由vivado 产生的,若有需要可以留言联系我。

 

你可能感兴趣的:(fpga,zynq)