FPGA実践教程(七)IPcoreを用いてDDRを呼び出す


目的:IPcoreを直接運用してDDRを呼び出す
参考資料:
1. Using the DDR memory independently of the Processor:
http://zedboard.org/content/using-ddr-memory-independently-processor
2.UG 873 Chaptet 6では、AXI CDMA coreがDDR 3を呼び出す可能性があるが、実際に見てもPS対DDRの呼び出しである.
3.axi-liteルーチン:D:xilinxSDx2016.4Vivado_HLS\examples\design\axi_lite
4.他の人とDDR 3を呼び出すプロセス:
https://forums.xilinx.com/t5/Vivado-High-Level-Synthesis-HLS/Axi-Master-DDR-MIG-tester/td-p/641990
5.FPGA実践教程(五)PS用MIG呼び出しDDRhttps://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が伝わる.
ポインタはマスターの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
",size,mode); result = memDDR3Tester(0,size,mode,0,memPtr,&expectedVal,&failedAddr,&numErrors); printf("Result mode 0: %d Expected: %d failedAddr:%d numErrors:%d
",result,expectedVal,failedAddr,numErrors); printf("Results:
"); //Output the values in array(DDR3) for (int idx = 0; idx < size; idx++) { printf("address:%x DDR3[%d]=%x
",&memPtr[idx],idx,memPtr[idx]); } return 0; }

testBenchは簡単で、対応する値をIPcoreに直接入力します.
ここでDDRはTestBenchにおいて大きな配列volatile unsigned int memPtr[5200000]を用いて実現され、そのポインタはDDRポインタとして扱われる.その後、HLSを直接運転すると、対応する値が読み出されます.
FPGA实践教程(七)运用IPcore调用DDR_第1张图片
二、システム構築と駆動生成
2.1参考のシステム構築
MicroBlazeで構築されたシステムの運用
FPGA实践教程(七)运用IPcore调用DDR_第2张图片
FPGA实践教程(七)运用IPcore调用DDR_第3张图片
2.2デルが構築したシステム
7 z 035で構築したシステム:(余分な接続のexternalが現れないでください.そうしないと、ビットストリームの生成はいつも成功しません)
ここでmigのパラメータは以下のパラメータに従って行う:FPGA実践教程(五)PSはMIGでDDRを呼び出すhttps://blog.csdn.net/weixin_36474809/article/details/80997945#%E4%BA%94%E3%80%81SDK
1回目:
FPGA实践教程(七)运用IPcore调用DDR_第4张图片
FPGA实践教程(七)运用IPcore调用DDR_第5张图片
2回目:
FPGA实践教程(七)运用IPcore调用DDR_第6张图片
FPGA实践教程(七)运用IPcore调用DDR_第7张图片
1回目は1つのインターコネクトで接続され、PSとIPcoreはいずれもインターコネクトで接続されているため、両者に共通のアドレスがあり、2回目は2つのインターコネクトで接続され、IPcoreはmigにしか接続されていないため、PSにはtesterIPcoreのポインタしかなく、IPcoreにはDDR 3のポインタしかありません.
対応するドライバは、関連するフォルダに生成されました.
三、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
",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:
"); for (idx = 0; idx < size; idx++) { printf("address:%x DDR3[%d]=%d
",&migPtr[idx],idx,migPtr[idx]); } return 0; }

対応するドライバを生成するなど、SDK側のプログラムは以下のようになり、migPtrの値はvivadoでシステムを構築した後のmigのアドレスオフセット量であることに注意する.
#include 
#include 
#include 
#include 

XMigtester XMigtesterCore;

int main()
{
	printf("
Program start SUCCESS!
"); int statue,result,testIdx; int size=5000; int migPtr=0x80000000; printf(" Testsize is %d......
",size); //Init IPcore statue=XMigtester_Initialize(&XMigtesterCore, XPAR_MIGTESTER_0_DEVICE_ID); if (statue==XST_DEVICE_NOT_FOUND){ printf(" IPcore find FAILURE!
"); return 1; } printf(" IP core init SUCCESS!
"); //Running IPcore printf(" Running IP core......
"); //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.......
",totalNumDDR); //PS run total int totalNumPS=0; for (testIdx = 0; testIdx < size; testIdx++){ totalNumPS+=testIdx; } printf(" Get from PS totalNumPS=%d.......
",totalNumPS); //IPcore result if(result==0) printf(" Result=0,IPcore test DDR3 SUCCESS!
"); else printf("FAILURE!
"); return 0; }

SDKプログラムの作成はこのように行われる.