背景:PS与PL的通信方式有AXI4,AXI-Lite,AXI-Stream。之前实现的为AXI-Stream s(side channel),并且编译环境为linux编译环境。现在改为基础的AXI-Lite的通信方式,编译环境变为SDK环境。
目的:实现AXI-Lite的通信。
AXI-lite的实现过程中,设计流程中三点至关重要,一是编写什么样的c程序并如何用HLS综合,二是系统如何搭建,三是PS端的SDK的c程序如何编写。
目录
一、C程序HLS为IPcore
1.1 接口
//Ipcore
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void AxiLiteTest(int * tenNum, int * oneNum, int * outNum)
{
#pragma HLS INTERFACE s_axilite port=outNum
#pragma HLS INTERFACE s_axilite port=oneNum
#pragma HLS INTERFACE s_axilite port=tenNum
* outNum=10*(*tenNum)+(*oneNum);
}
需要在HLS中将接口综合为s_axi-lite,值既可以为指针,也可以为int或者float,有return的话也可以进行相应的综合,传回return的值,后续HLS会根据接口生成相应的驱动,系统搭建时会传给vivado系统,再传给SDK软件。
1.2 HLS test Bench编写
// IPcore HLS testBench
#include <stdio.h>
void AxiLiteTest(int * tenNum, int * oneNum, int * outNum);
int main()
{
// init value
int tenNum=3;
int oneNum=4;
int outNumPS,outNumIP;
//PS simulate
outNumPS=10*tenNum+oneNum;
printf("PS simulate finished\n");
//AXI-lite and IP core
printf("Test HLS AXI-Lite with mig\n");
AxiLiteTest(&tenNum, &oneNum, &outNumIP);
//compare the results
if(outNumPS==outNumIP)
printf("IP and AXI-lite OK");
else
printf("IP and AXI-lite failed");
return 0;
}
只需将相应的值送入,因为Core为指针,所以在testBench中运用取址。(IPcore的c程序就相当于一个子函数,若不是指针的话就不会更改主函数中的变量值?这点需要实验验证,但目前来看是这样的。如果不是指针形式就需要用return来返回值,但HLS的testBench不是关键,仅仅用于验证IPcore的c代码正确,关键在于SDK的testBench)
二、系统搭建
只需要用PS的master GP端就可以,运用interConnect相连,系统会自动生成相应的连接。
相应的地址分配如上,驱动程序在搭建vivado时就会被综合好。parameter.h即为根据具体的程序生成的头文件。里面有各个IPcore的地址等等信息。我们可以参考例子程序实现相应的功能,如IPcore的使能,通信等等。
系统生成的驱动
在axi-lite接口的时候,HLS会生成一个.h和.c的源文件,路径为\ddrHLS\solution1\impl\ip\drivers\memDDR3Tester_v1_0\src 意思是相关IP的单片机的驱动。以供后续的SDK的单片机使用。
SDK的单片机参考程序D:\xilinx\SDx\2016.4\SDK\data\embeddedsw\XilinxProcessorIPLib\drivers
三、SDK单片机程序
//axi-lite SDK testBench
#include <stdio.h>
#include <xaxilitetest.h>
#include <xparameters.h>
#include <xil_cache.h>
XAxilitetest XAxilitetestCore;
int main()
{
//initialize IP core
XAxilitetest_Initialize(&XAxilitetestCore, XPAR_AXILITETEST_0_DEVICE_ID);
printf("\n Initialize axilitetest IPcore SUCCESSFUL!\n");
//initialize value
int tenNum=0;
int oneNum=0;
int outNumPS, outNumIP,outNumIPVld;
printf(" Initialize param tenNum=%d,oneNum=%d SUCCESSFUL!\n",tenNum,oneNum);
//before set value on IP core
outNumIPVld=XAxilitetest_Get_outNum_vld(&XAxilitetestCore);
printf(" outNumIPVld is %d,outNumIP is %d\n",outNumIPVld,outNumIP);
//simulate on PS
outNumPS=10*tenNum+oneNum;
//test on IPcore
printf(" Test axi-lite IP core\n");
XAxilitetest_Set_tenNum(&XAxilitetestCore,tenNum);
XAxilitetest_Set_oneNum(&XAxilitetestCore,oneNum);
//out
outNumIP=XAxilitetest_Get_outNum(&XAxilitetestCore);
outNumIPVld=XAxilitetest_Get_outNum_vld(&XAxilitetestCore);
printf(" outNumIPVld is %d \n",outNumIPVld);
if(outNumIP==outNumPS)
printf(" outNumIP is %d,Test SUCCESSFUL!\n",outNumIP);
return 0;
}
单片机程序在编写时,可以参考SDK软件中相应的例程,SDK软件中几乎对所有的程序都有例程,只需更改其中的参数即可。对AXI-lite通信,首先我们需要使能IPcore,然后对相应的端口进行值的设定,然后进行IPcore的运算。
四、运行与测试
表明IPcore上的寄存器只要不断电就会保持原来值,如果不初始化IPcore,只变更单片机SDK的程序,则IPcore的值均为上次初始化的值。IPcore_vld函数在运行之后就会变为1值。我们的IPcore正常工作。这里我们发现进行运算之前,只要不断电,IPcore上的寄存器会保持之前的值。
(依然存在疑问:IPcore开始运算的标志是什么?是否为每次Get_outnum时就开始IPcore?然后用vld来标志其是否有效?)