FPGA实践教程(七)运用IPcore调用DDR

目的:直接运用IPcore调用DDR

参考资料:

1. Using the DDR memory independently of the Processor:

http://zedboard.org/content/using-ddr-memory-independently-processor

2. UG873 Chaptet 6中,AXI CDMA core有可能调用DDR3,但实际查看后依然是PS对DDR的调用。

3. axi-lite例程:D:\xilinx\SDx\2016.4\Vivado_HLS\examples\design\axi_lite

4. 与其他人调用DDR3的流程:

https://forums.xilinx.com/t5/Vivado-High-Level-Synthesis-HLS/Axi-Master-DDR-MIG-tester/td-p/641990

5. FPGA实践教程(五)PS用MIG调用DDR https://blog.csdn.net/weixin_36474809/article/details/80997945#%E4%BA%94%E3%80%81SDK

6. FPGA实践教程(六)AXI-Lite实现PS与PL通信 https://blog.csdn.net/weixin_36474809/article/details/81206660

目录

一、IPcore与TestBench

1.1 IPcore程序的编写

1.2 TestBench的编写

  二、系统搭建与驱动生成

2.1 参考的系统搭建

2.2 我们搭建的系统

三、SDK程序的编写


一、IPcore与TestBench

1.1 IPcore程序的编写

// HLS IP Core
#include 
#include 
#include 

unsigned int memDDR3Tester(unsigned int start, unsigned int size,
		unsigned int mode, unsigned int data, 
		volatile unsigned int *memPtr, unsigned int *expectedVal, 
		unsigned int *failedAddr, unsigned int *numErrors)
{
#pragma HLS INTERFACE s_axilite port=numErrors bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=failedAddr bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=expectedVal bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=start bundle=CRTL_BUS
#pragma HLS INTERFACE m_axi depth=512 port=memPtr offset=slave
#pragma HLS INTERFACE s_axilite port=data bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=mode bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=size bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS
	unsigned int result = 0;
	unsigned int idxMemAddr = 0;
	unsigned int errorCounter = 0;
	*numErrors = 0;
	*expectedVal = 0;
	*failedAddr = 0;

	switch (mode){
	case 0:{
		// Write
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned char isOdd = (idxMemAddr % 2);
			unsigned int value = (isOdd)?0x55AA:0xAA55;
			memPtr[idxMemAddr] = value;
		}
		// Read
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned char isOdd = (idxMemAddr % 2);
			unsigned int value = (isOdd)?0x55AA:0xAA55;
			if (memPtr[idxMemAddr] != value)
			{
				result = 1;
				*expectedVal = value;
				*failedAddr = idxMemAddr;
				// Bail out on the first error
				*numErrors = 1;
				break;
			}
		}
		break;
	}
	/*
	 * Send an incremental value but don't stop if some error occured and return the number of errors
	 * */
	case 1:{
		// Write
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned int value = idxMemAddr;
			memPtr[idxMemAddr] = value;
		}
		// Read
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned int value = idxMemAddr;
			if (memPtr[idxMemAddr] != value)
			{
				result = 1;
				errorCounter++;
			}
		}
		*numErrors = errorCounter;
		break;
	}
	}
	return result;
}

程序除了主题的接口部分就是后续的执行部分,执行根据memPtr的指针来进行对读写,以实现对DDR的读写。

注意相应的接口:

unsigned int memDDR3Tester(unsigned int start, unsigned int size,
		unsigned int mode, unsigned int data, 
		volatile unsigned int *memPtr, unsigned int *expectedVal, 
		unsigned int *failedAddr, unsigned int *numErrors)
{
#pragma HLS INTERFACE s_axilite port=numErrors bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=failedAddr bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=expectedVal bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=start bundle=CRTL_BUS
#pragma HLS INTERFACE m_axi depth=512 port=memPtr offset=slave
#pragma HLS INTERFACE s_axilite port=data bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=mode bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=size bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS

参数运用接口的s_axilite协议,运用CTRL_BUS来传递。

指针作为master的axi总线,端口设为memPtr。运用memptr传入指针,然后IPcore对指针所指的内容进行读写。offset设为slave

1.2 TestBench的编写

// HLS test Bench
#include 
unsigned int memDDR3Tester(unsigned start, unsigned int size, 
		unsigned int mode, unsigned int data, 
		//Use arrays to simulate DDR3 in HLS testBench
		volatile unsigned int memPtr[512000000], unsigned int *expectedVal, 
		unsigned int *failedAddr, unsigned int *numErrors);
int main()
{
	unsigned int memPtr[10];
	unsigned int expectedVal;
	unsigned int failedAddr;
	unsigned int numErrors;
	unsigned int result;
	unsigned int size=10;
	unsigned int mode=0;
	//Test the IPcore
	printf("	Test Size:%d, Test mode %d\n",size,mode);
	result = memDDR3Tester(0,size,mode,0,memPtr,&expectedVal,&failedAddr,&numErrors);
	printf("Result mode 0: %d Expected: %d failedAddr:%d numErrors:%d\n",result,expectedVal,failedAddr,numErrors);
	printf("Results:\n");
	//Output the values in array(DDR3)
	for (int idx = 0; idx < size; idx++)
	{
		printf("address:%x DDR3[%d]=%x\n",&memPtr[idx],idx,memPtr[idx]);
	}
	return 0;
}

testBench较为简单,直接将相应的值传入IPcore。

其中DDR在TestBench之中运用一个大的数组volatile unsigned int memPtr[512000000]来实现,其指针当作DDR指针。然后直接运行HLS就能读出相应的值。

FPGA实践教程(七)运用IPcore调用DDR_第1张图片

  二、系统搭建与驱动生成

2.1 参考的系统搭建

运用MicroBlaze搭建的系统

FPGA实践教程(七)运用IPcore调用DDR_第2张图片

FPGA实践教程(七)运用IPcore调用DDR_第3张图片

2.2 我们搭建的系统

我们用7z035搭建的系统:(不要出现多余的连接的external,不然生成比特流总是不成功)

这里mig的参数按照下面的参数进行: FPGA实践教程(五)PS用MIG调用DDR https://blog.csdn.net/weixin_36474809/article/details/80997945#%E4%BA%94%E3%80%81SDK

第一次:

FPGA实践教程(七)运用IPcore调用DDR_第4张图片

FPGA实践教程(七)运用IPcore调用DDR_第5张图片

第二次:

FPGA实践教程(七)运用IPcore调用DDR_第6张图片

FPGA实践教程(七)运用IPcore调用DDR_第7张图片

第一次通过一个interconnect连接,PS与IPcore均与interconnect相连,所以两者有共同的地址,第二次通过两个interconnect相连,IPcore只与mig相连,所以PS只能有testerIPcore的指针,IPcore只有DDR3的指针。

相应驱动已经生成,在相关的文件夹之中。

三、SDK程序的编写

 E:\FPGAdocuments\7z035\DDR3TestProject

上面文档缺失。下面重新开始(运行时要及时保存步骤,免得后期不好整理):

与之对应的IPcore程序为下面,相应DDR为m_axi接口,并且offset=slave

#include 
#include 
#include 

int migTester(int size, volatile int *migPtr ,int totalNumDDR){
#pragma HLS INTERFACE s_axilite port=totalNumDDR
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=512 port=migPtr offset=slave
#pragma HLS INTERFACE s_axilite port=size	
	int testIdx=0;
	int result=1;  //1 means FAILURE,0 means SUCCESS!
	int value;
	totalNumDDR=0;
	int totalNumIdx=0;
	// Write Mig DDR
	for (testIdx = 0; testIdx < size; testIdx++){
		migPtr[testIdx] = testIdx;
		totalNumIdx+=testIdx;
	}
	// Read Mig DDR
	for (testIdx = 0; testIdx < size; testIdx++){
		totalNumDDR+=migPtr[testIdx];
	}
	//compare results
	if(totalNumIdx==totalNumDDR)
		result=0;
	else
		result=1;
	return result;
}

下面为testBench

#include 
int migTester(int size, volatile int *migPtr ,int totalNumDDR);
int main()
{
	int size=100;
	int migPtr[100];
	int totalNumDDR;
	int idx;
	int result;
	//Test IPcore C code
	printf("	Test Size:%d, migAddr %x\n",size,migPtr);
	result = migTester(size,migPtr,totalNumDDR);
	//result
	if (result==0)
		printf("IP core C code test SUCCESS!");
	else
		printf("IP core C code test FAILED!");
	//Test Address using PC PS
	printf("Results:\n");
	for (idx = 0; idx < size; idx++)
	{
		printf("address:%x DDR3[%d]=%d\n",&migPtr[idx],idx,migPtr[idx]);
	}
	return 0;
}

生成相应的驱动,等等,SDK端的程序为下面,注意migPtr的值为vivado之中搭建系统之后mig的地址偏移量。

#include 
#include 
#include 
#include 

XMigtester XMigtesterCore;

int main()
{
	printf("\n	Program start SUCCESS!\n");

	int statue,result,testIdx;
	int size=5000;
	int migPtr=0x80000000;
	
	printf("	Testsize is %d......\n",size);
	
	//Init IPcore
	statue=XMigtester_Initialize(&XMigtesterCore, XPAR_MIGTESTER_0_DEVICE_ID);
	if (statue==XST_DEVICE_NOT_FOUND){
		printf("	IPcore find FAILURE!\n");
		return 1;
	}
	printf("	IP core init SUCCESS!\n");
	
	//Running IPcore
	printf("	Running IP core......\n");
	//set value
	XMigtester_Set_size(&XMigtesterCore, size);
	XMigtester_Set_migPtr(&XMigtesterCore, migPtr);
	//start
	XMigtester_Start(&XMigtesterCore);
	//done
	while (!XMigtester_IsDone(&XMigtesterCore));
	result=XMigtester_Get_return(&XMigtesterCore);
	int totalNumDDR=XMigtester_Get_totalNumDDR(&XMigtesterCore);
	printf("	Get from IP core totalNumDDR=%d.......\n",totalNumDDR);
	
	//PS run total
	int totalNumPS=0;
	for (testIdx = 0; testIdx < size; testIdx++){
		totalNumPS+=testIdx;
	}
	printf("	Get from PS      totalNumPS=%d.......\n",totalNumPS);
	
	//IPcore result
	if(result==0)
		printf("	Result=0,IPcore test DDR3 SUCCESS!\n");
	else
		printf("FAILURE!\n");
	
	return 0;
}

SDK程序的编写按照此套路进行。

你可能感兴趣的:(FPGA,FPGA实践教程)