PL讀寫DDR3 實現PS和PL間的數據交互 查表程序

本文介紹一個PL讀取DDR3 的實用程序,查表程序。這個可能也可叫RAM 程序吧,把數據表格放置在固定的一段RAM 中, PL就可以查表,用於計算。其實也可以放置代碼在這段空間裏,你的ip 就可以像cpu一樣執行代碼。

PL讀寫DDR3 實現PS和PL間的數據交互 爲基礎,修改而成。也可參考PL讀寫DDR3 實現PS和PL間的數據交互 代碼分析 

MasterIP 代碼修改

1: 添加端口

		//input original
		input wire [15 : 0] IN_ADDR,
		//out results
		output wire [15 : 0] OUT_DATA,
		//output cycle for search
		output wire [7 : 0] OUT_TIM,

2 讀地址段:

	  //Read Addresses                                              
	  always @(posedge M_AXI_ACLK)                                  
	      begin                                                     
	        if (M_AXI_ARESETN == 0)                                
	          begin                                                 
	            axi_araddr <= 0;                                    
	          end                                                   
	          // Signals a new write address/ write data is         
	          // available by user logic                            
	        else                 
	          begin                                                 
	            axi_araddr <= IN_ADDR;            
	          end                                                   
	      end  

3:狀態機代碼,只有讀,控制read_issued, start_single_read

	  //implement master command interface state machine   only read                      
	  always @ ( posedge M_AXI_ACLK)                                                    
	  begin                                                                             
	    if (M_AXI_ARESETN == 1'b0)                                                     
	      begin                                                                         
	      // reset condition                                                                                                  
	        start_single_write <= 1'b0;                                                 
	        write_issued  <= 1'b0;                                                      
	        start_single_read  <= 1'b0;                                                 
	        read_issued   <= 1'b0;                                                      
	      end                                                                           
	    else                                                                                                                                                                
			 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 //MASTER_EXECUTION_PROC  

4 last read

	  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    

5 讀取數據放在輸出上:

	//Data read and put on outport                                                                   
	  always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0)                                                         
	    out_data<=0;                                                        
	                                                                                    
	    //The read data when available (on axi_rready) 
	    else if (M_AXI_RVALID && axi_rready)          
	      out_data<=M_AXI_RDATA;                                                       
	    else                                                                            
	      out_data<=out_data;                                               
	  end   

6 評估讀一次的時間週期數:

	//escapecycle
	always @(posedge M_AXI_ACLK)                                                      
	  begin                                                                             
	    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
	      escapecycle <= 1'b0;                                                            
	                                                                                    
	    //The last read should be associated with a read address ready response         
	    else if ((~last_read)  &&(escapecycle<100000))              
	      escapecycle <= escapecycle+1'b1;                                                            
	    else  if  (escapecycle == 100000)    
			escapecycle[15]<=1;
		else
	      escapecycle <= escapecycle;                                                       
	  end  

輸出查表數據,除了查表數據,還統計查表時間,15位是溢出位,14位爲查表結束標誌。

	assign OUT_DATA=out_data;
	assign OUT_TIM[13:0]=escapecycle[13:0];
	assign OUT_TIM[15]=escapecycle[15];
	assign OUT_TIM[14]=last_read;

驗證接口ip

可以用gpio 連接相應接口,完成測試。但我直接加axi_gpio 做測試,連接不上,自定義一個。方法見:zynq 7000 自定義IP 實驗

在2個文件中都添加io

		// Users to add ports here
		output wire [31:0]out_addr,
        output wire start,
        input  wire [31:0]in_data,
        input wire [15:0]in_cycles_last,
		// User ports ends

在接口代碼中添加函數調用的接口: 

.out_addr(out_addr),
.start(start),
.in_data(in_data),
.in_cycles_last(in_cycles_last),

實現代碼中添加

讀取部分:16‘h0003是32位的高位。

2'h2   : reg_data_out <= in_data;
2'h3   : reg_data_out <= { 16'h0003, in_cycles_last };

寫保持不變,但用戶邏輯修改如下:

	// Add user logic here
    assign out_addr=slv_reg0;
    assign start=slv_reg1[0];
 	// User logic ends

驗證工程

驗證工程可以以PL讀寫DDR3 實現PS和PL間的數據交互 爲基礎,注意我們的測試ip 是Slave Axi IP, 原理圖如下:

除了基本的axi 總線連接外,

axi_gpio的 start =>SearchTable 的 init_axi_txn

out_addr=>in_addr

in_data <=out_data

in_cycles_last <=out_tim

這個是數據控制的基本流程,axi_gpio 輸出地址,發出啓動信號,然後接收in_cycles_last數據,完成了就接收in_data

在這裏處理器設置是這樣的,注意這裏的2個勾選:

 產生比特流,輸出,然後啓動SDK

驗證程序

驗證代碼的流程是先寫入數據,這裏有3種方式寫入數據:test_ram(), setram(),setram2()

searchi(addr) 則是查數據,驗證。

這裏程序有點問題,test_ram() 寫的數據比較多,幾乎所有的數據都寫了,先運行這個,然後setram()或setram2(), 寫的數據量不多的時候,比如2000, 結果是pl 讀取的數據還是原來的,沒有被覆蓋,驗證讀取的數據是更新了的。後面寫的數據很多的時候,比如200000,pl讀取的數據就是更新了的。是不是ddr3 有緩存問題。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h"

#define MY_IP	0x44A00000
#define DDRAM	0x04000000


#define MAXLENTH	512000000
unsigned char lasercmd[MAXLENTH];
u32 ok=0;
//int ip_data;

void test_ram(void)
{
	int i;
	int* ip=(int*)lasercmd;
	printf("ip=%x\n",(int)ip);
	for(i=0;i<512000000/4;i++)
	{
		ip[i]=i;
	}
	for(i=0;i<51;i++)
	{
		//printf("%d=%d\n",i,ip[i*1000000]);
	}
}

void setram(u32 count)
{
	u32* comp_addr=DDRAM;
	u32 i;
	for(i=0;i<count;i++)
	{
		*(comp_addr+i)=i*2;
	}
}

void setram2(u32 count)
{
	u32 comp_addr=DDRAM;
	u32 i;
	for(i=0;i<count;i+=4)
	{
		Xil_Out32(comp_addr+i,i);
	}
}


void searchi(u32 addr)
{
	u16 state=0;
	u32 result,result2;
	int delay=0;
	unsigned int comp;
	unsigned char* comp_addr=addr+DDRAM;
	int* ip=(int*)lasercmd;
	comp=*((u32*)comp_addr);

	Xil_Out32(MY_IP+4,0);

	Xil_Out32(MY_IP,addr);
	Xil_Out32(MY_IP+4,1);
	state=Xil_In32(MY_IP+12);
	while((state&0x4000)==0)
	{
		delay++;
		if(delay>1000)
			break;
		state=Xil_In32(MY_IP+12);
	}
	result=Xil_In32(MY_IP+8);
	result2=ip[result];
	if(result!=comp)
		printf("addr=%d:result=%x,ccomp=%x cycles=%x delay=%d \n",addr,result,comp,state&0xfff,delay);

	else { ok++;printf("------addr=%d rusult=%x\n",addr,result);}
}


int main()
{
	u32 i;
	u32 counts;
	u32 setNo;
    init_platform();

    counts=800;
    setNo=60000;
    test_ram();
    setram2(setNo);
    ok=0;
    for(i=0;i<counts;i+=4)
    	searchi(i);

    printf("counts=%d,ok=%d,setNo=%d\n",(int)counts,(int)ok,(int)setNo);

    cleanup_platform();
    return 0;
 }

運行結果

下面是更改參數運行2次的結果。SetNo =70000, pl讀取的數據沒有更新,而SetNo =80000的時候pl 讀取的數據更新了。

ip=114324
addr=0:result=fbaf37,ccomp=0 cycles=4f delay=3 
addr=4:result=fbaf38,ccomp=4 cycles=51 delay=4 
addr=8:result=fbaf39,ccomp=8 cycles=4a delay=3 
addr=12:result=fbaf3a,ccomp=c cycles=4b delay=3 
addr=16:result=fbaf3b,ccomp=10 cycles=49 delay=3 
...
addr=788:result=fbaffc,ccomp=314 cycles=4a delay=3 
addr=792:result=fbaffd,ccomp=318 cycles=4b delay=3 
addr=796:result=fbaffe,ccomp=31c cycles=4b delay=3 
counts=800,ok=0,setNo=60000
ip=114324
------addr=0 rusult=0
------addr=4 rusult=4
------addr=8 rusult=8
------addr=12 rusult=c
------addr=16 rusult=10
...
------addr=788 rusult=314
------addr=792 rusult=318
------addr=796 rusult=31c
counts=800,ok=200,setNo=70000
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章