本文介紹一個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