FPGA Partial Reconfiguration 部分重配置(二)——PS重配置PL

目录

1. 背景介绍

ZYNQ平台启动与配置

PS重配置PL

2. 实现思路

3. 实现过程

3.1 PL工程搭建

3.2 bin文件准备

3.3 PS重配置整体PL

3.4 PS重配置局部PL

4. 问题

5. 分析

6. Reference


  系列文章:

1. FPGA Partial Reconfiguration 部分重配置(一)-CSDN博客

2. FPGA Partial Reconfiguration 部分重配置(二)——PS重配置PL-CSDN博客 

 

1. 背景介绍

        由于PCIe掉电后上位机需重启才能识别。当上位机不便关机时,需保持XDMA上位机通信模块持续运行,并替换系统中局部的数据分析等模块。

        基于 ZYNQ 7100  平台,实现远程配置数据分析模块的重构。本节为PS控制PL加载重构文件。

        软件:Vivado 2018.3

ZYNQ平台启动与配置

Ref: ZYNQ PS动态配置PL动态加载_ps加载pl代码-CSDN博客

PS重配置PL

Ref:ZYNQ 实现PL动态重构_zynq动态重构demo-CSDN博客

        所谓重配置,即在当前硬件比特运行期间,有一份新的比特通过网络、串口等等其他方式传输到平台,平台将其存储在Falsh、DDR等外部存储介质中,随后将硬件在不断电的情况下配置成新的比特流。
对bitstream可以大致分为以下几种情况:

  • Vivado下载:Program and debug –> Open Hardware Manager -> open target -> auto connect -> program device 在弹出界面选择bit文件下载即可
  • 固定启动,来自外部存储设备,将比特流固化到存储介质,并选择相应的启动方式。
  • 动态配置,即上述所说的不断电更新。数据来源一般是下图中的DRAM。

  • 在搭建好硬件及软件环境后,要实现PS重配置PL我们需要2个条件,其一是两份不同表现的PL实现的Bin文件,其二是软件部分DEVC 的正确配置使用。

Ref: Zynq使用PCAP实现PL完全重配置 - 知乎 (zhihu.com)

        在Zynq FPGA硬件中使用xdevcfg实现AXI-PCAP桥的控制,通过XDcfgtransfer函数将DRAM内准备好的Bitstream流文件从DRAM传送到PCAP,优点是应用简单且不使用PL任何资源,可实现高速数据传输速率28-130MB/s,但存在问题是重构时挂起处理器。

2. 实现思路

  • PL工程搭建。
  • bin文件准备。
  • PS工程搭建。
  • 下板验证。

3. 实现过程

3.1 PL工程搭建

        见 FPGA Partial Reconfiguration 部分重配置(一)-CSDN博客

3.2 bin文件准备

bin文件

加载需要的文件不支持.bit文件,需要将.bit 文件转换成.bin 文件
在生成bit stream 时直接生成的.bin 文件不能配置成功,需要用tcl 语言将.bit 文件转换成.bin文件:

// write_cfgmem -force -format BIN -interface SMAPx32 -disablebitswap -loadbit ”up 0x0 path” “path”

write_cfgmem -format bin -loadbit "up 0x0 比特文件名.bit" -file 生成的bin文件名.bin -size 128 -force -interface SMAPx32 -disablebitswap


//例如:

write_cfgmem -format bin -loadbit "up 0x0 D:/impl_1/top.bit" -file D:/impl_1/top1.bin -force -interface SMAPx32 -disablebitswap

Ref:Xilinx平台远程更新中FPGA读写Flash设计的讨论 - 知乎 (zhihu.com)

        Xilinx常用的配置文件格式有三个(大部分情况下知道这三个就足够了):bit/bin/mcs。

直接写入Flash的数据,对应的是bin文件。bin文件和bit文件都是二进制格式,bin文件直接对应Flash中的二进制数据。

        用A7 100T为例子,生成一个bit文件作为基准。分析一下三种文件。

  • 默认的情况下没有任何约束,生成的bit文件作为基准,取名为 original.bit 。这是原始文件。
  • 在Vivado工程生成bit的同时,可以同时生成一个bin文件,取名 original.bin 。这是原始文件直接转换而来,不包含针对Flash的配置。
  • 当获取bit文件之后,可以使用 write_cfgmem 命令来生成bin文件和MCS文件。这种方法默认生成的bin文件,取名 g.bin,可以发现g.bin和original.bin两个文件不太一样。 g.bin 可用于Flash。

        如果在使用write_cfgmem命令时添加参数 -interface SPIx1,生成文件spix1.bin,会发现spix1.bin和original.bin两个文件几乎一样。这个原因就是,write_cfgmem这个命令生成的文件是给Flash使用的。所以生成的文件内容会随着Flash配置的改变而改变。

        而write_cfgmem生成的bin文件,默认情况下认为Flash接口格式为SMAPX8(TBD)(可以参考同时生成的.prm文件),所以生成的bin文件g.bin做了相关处理(一般是位序和大小端的转换)。而SPI模式下,不需要额外的转换,所以生成的bin文件spix1.bin和original.bin几乎一样。类似,如果选择BPIx8模式生成BPIx8.bin,可以发现和SMAPX8模式下的g.bin文件几乎一样。

        所以可以明确,生成bit文件时生成的bin文件并不含有配置的相关信息。如果需要使用bin文件,那么用write_cfgmem,并同时提供相关配置接口信息,是更好的方案。上文提到的使用bin文件时可能会犯错,就在于此。

3.3 PS整体重配置PL

        此部分实现PS对PL整体的重配置。

Ref:

1. ZYNQ 实现PL动态重构_zynq动态重构demo-CSDN博客

2. Zynq使用PCAP实现PL完全重配置 - 知乎 (zhihu.com) 

3. Zynq-7000 PS重配置PL_pl重配置通道-CSDN博客

4. Zynq SDK 驱动探求(五)软件动态重配置硬件比特流 - 知乎 (zhihu.com)

Zynq-7000的结构分为PS(ARM)和PL(FPGA),当然也可以理解为PL作为一种外设挂载在PS端。在正常的系统加载顺序(FALSH \ SD -> FSBL -> PL ->BITSTRAM ->PS ELF)完成后重新配置PL程序,可以利用XLINX官方BSP逻辑 xdecfg_polled_example 的Demo例程实现PS配置PL比特流,将指定DDR空间的数据配置到FPGA
原文链接:Zynq-7000 PS重配置PL_pl重配置通道-CSDN博客 

1. 点击<File>、<New>、<Application Project>来创建一个Empty Application SDK工程。

2. 导入xdecfg_polled_example  demo。

在demo中添加 PL_Reset 函数后如下:



/***************************** Include Files *********************************/

#include "xparameters.h"
#include "xdevcfg.h"

/************************** Constant Definitions *****************************/
/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are only defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define DCFG_DEVICE_ID		XPAR_XDCFG_0_DEVICE_ID

/*
 * The BIT_STREAM_LOCATION is a dummy address and BIT_STREAM_SIZE_WORDS is a
 * dummy size. This has to replaced with the actual location/size of the bitstream.
 *
 * The 2 LSBs of the Source/Destination address when equal to 2锟絙01 indicate
 * the last DMA command of an overall transfer.
 * The 2 LSBs of the BIT_STREAM_LOCATION in this example is set to 2b01
 * indicating that this is the last DMA transfer (and the only one).
 */
#define BIT_STREAM_LOCATION	0x20000001	/* Bitstream location */
#define BIT_STREAM_SIZE_WORDS	0x4270270 //0xF6EC0		/* Size in Words (32 bit)*/
/* top.bin 0x4270270 w 17416348 Byte; part1 5169356 Byte */

/*
 * SLCR registers
 */
#define SLCR_LOCK	0xF8000004 /**< SLCR Write Protection Lock */
#define SLCR_UNLOCK	0xF8000008 /**< SLCR Write Protection Unlock */
#define SLCR_LVL_SHFTR_EN 0xF8000900 /**< SLCR Level Shifters Enable */
#define SLCR_PCAP_CLK_CTRL XPAR_PS7_SLCR_0_S_AXI_BASEADDR + 0x168 /**< SLCR
					* PCAP clock control register address
					*/

#define SLCR_PCAP_CLK_CTRL_EN_MASK 0x1
#define SLCR_LOCK_VAL	0x767B
#define SLCR_UNLOCK_VAL	0xDF0D

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

int XDcfgPolledExample(XDcfg * DcfgInstance, u16 DeviceId);
void Pl_Reset(XDcfg *_DcfgInstancePtr);

/************************** Variable Definitions *****************************/

XDcfg DcfgInstance;		/* Device Configuration Interface Instance */

/*****************************************************************************/
/**
*
* Main function to call the polled mode example.
*
* @param	None.
*
* @return
*		- XST_SUCCESS if successful
*		- XST_FAILURE if unsuccessful
*
* @note		None.
*
******************************************************************************/
int main(void)
{
	int Status;

//	int   value1 = 0;
//	value1 =  BIT_STREAM_LOCATION ;
	/*
	 * Call the example , specify the device ID that is generated in
	 * xparameters.h.
	 */
	Pl_Reset(&DcfgInstance); //此行或许可以去掉

	Status = XDcfgPolledExample(&DcfgInstance, DCFG_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("Dcfg Polled Example Test Failed\r\n");
		return XST_FAILURE;
	}

	xil_printf("Successfully ran Dcfg Polled Example Test\r\n");
	return XST_SUCCESS;
}

/*****************************************************************************/
/**
* This function downloads the Non secure bit stream to the FPGA fabric
* using the Device Configuration Interface.
*
* @param	DcfgInstPtr is a pointer to the instance of XDcfg driver.
* @param	DeviceId is the unique device id of the device.
*
* @return
*		- XST_SUCCESS if successful
*		- XST_FAILURE if unsuccessful
*
* @note		None
*
****************************************************************************/
int XDcfgPolledExample(XDcfg *DcfgInstPtr, u16 DeviceId)
{
	int Status;
	u32 IntrStsReg = 0;
	u32 StatusReg;
	u32 PartialCfg = 0;

	XDcfg_Config *ConfigPtr;

	/*
	 * Initialize the Device Configuration Interface driver.
	 */
	ConfigPtr = XDcfg_LookupConfig(DeviceId);

	/*
	 * This is where the virtual address would be used, this example
	 * uses physical address.
	 */
	Status = XDcfg_CfgInitialize(DcfgInstPtr, ConfigPtr,
					ConfigPtr->BaseAddr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}


	Status = XDcfg_SelfTest(DcfgInstPtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Check first time configuration or partial reconfiguration
	 */
	IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
	if (IntrStsReg & XDCFG_IXR_DMA_DONE_MASK) {
		PartialCfg = 1;
	}

	/*
	 * Enable the pcap clock.
	 */
	StatusReg = Xil_In32(SLCR_PCAP_CLK_CTRL);
	if (!(StatusReg & SLCR_PCAP_CLK_CTRL_EN_MASK)) {
		Xil_Out32(SLCR_UNLOCK, SLCR_UNLOCK_VAL);
		Xil_Out32(SLCR_PCAP_CLK_CTRL,
				(StatusReg | SLCR_PCAP_CLK_CTRL_EN_MASK));
		Xil_Out32(SLCR_UNLOCK, SLCR_LOCK_VAL);
	}

	/*
	 * Disable the level-shifters from PS to PL.
	 */
	if (!PartialCfg) {
		Xil_Out32(SLCR_UNLOCK, SLCR_UNLOCK_VAL);
		Xil_Out32(SLCR_LVL_SHFTR_EN, 0xA);
		Xil_Out32(SLCR_LOCK, SLCR_LOCK_VAL);
	}

	/*
	 * Select PCAP interface for partial reconfiguration
	 */
	if (PartialCfg) {
		XDcfg_EnablePCAP(DcfgInstPtr);
		XDcfg_SetControlRegister(DcfgInstPtr, XDCFG_CTRL_PCAP_PR_MASK);
	}

	/*
	 * Clear the interrupt status bits
	 */
	XDcfg_IntrClear(DcfgInstPtr, (XDCFG_IXR_PCFG_DONE_MASK |
					XDCFG_IXR_D_P_DONE_MASK |
					XDCFG_IXR_DMA_DONE_MASK));

	/* Check if DMA command queue is full */
	StatusReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
				XDCFG_STATUS_OFFSET);
	if ((StatusReg & XDCFG_STATUS_DMA_CMD_Q_F_MASK) ==
			XDCFG_STATUS_DMA_CMD_Q_F_MASK) {
		return XST_FAILURE;
	}

	/*
	 * Download bitstream in non secure mode
	 */
	Pl_Reset(DcfgInstPtr);
	XDcfg_Transfer(DcfgInstPtr, (u8 *)BIT_STREAM_LOCATION,
			BIT_STREAM_SIZE_WORDS,
			(u8 *)XDCFG_DMA_INVALID_ADDRESS,
			0, XDCFG_NON_SECURE_PCAP_WRITE);

	/* Poll IXR_DMA_DONE */
	IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
	while ((IntrStsReg & XDCFG_IXR_DMA_DONE_MASK) !=
			XDCFG_IXR_DMA_DONE_MASK) {
		IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
	}

	if (PartialCfg) {
		/* Poll IXR_D_P_DONE */
		while ((IntrStsReg & XDCFG_IXR_D_P_DONE_MASK) !=
				XDCFG_IXR_D_P_DONE_MASK) {
			IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
		}
	} else {
		/* Poll IXR_PCFG_DONE */
		while ((IntrStsReg & XDCFG_IXR_PCFG_DONE_MASK) !=
				XDCFG_IXR_PCFG_DONE_MASK) {
			IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
		}
		/*
		 * Enable the level-shifters from PS to PL.
		 */
		Xil_Out32(SLCR_UNLOCK, SLCR_UNLOCK_VAL);
		Xil_Out32(SLCR_LVL_SHFTR_EN, 0xF);
		Xil_Out32(SLCR_LOCK, SLCR_LOCK_VAL);
	}

	return XST_SUCCESS;
}

void Pl_Reset(XDcfg *_DcfgInstancePtr)
{
	u32 CtrlReg;
		CtrlReg = XDcfg_ReadReg(_DcfgInstancePtr->Config.BaseAddr,
				XDCFG_CTRL_OFFSET);
		XDcfg_WriteReg(_DcfgInstancePtr->Config.BaseAddr,
				XDCFG_CTRL_OFFSET, (CtrlReg |
						XDCFG_CTRL_PCFG_PROG_B_MASK));

		//@lf reset prog
		CtrlReg = XDcfg_ReadReg(_DcfgInstancePtr->Config.BaseAddr,
				XDCFG_CTRL_OFFSET);
		XDcfg_WriteReg(_DcfgInstancePtr->Config.BaseAddr,
				XDCFG_CTRL_OFFSET, (CtrlReg &
						(~XDCFG_CTRL_PCFG_PROG_B_MASK)));

		//@lf wait for reset
		while((XDcfg_ReadReg(_DcfgInstancePtr->Config.BaseAddr, XDCFG_STATUS_OFFSET)
					& XDCFG_STATUS_PCFG_INIT_MASK) == 1);

		//@lf set prog
		CtrlReg = XDcfg_ReadReg(_DcfgInstancePtr->Config.BaseAddr,
					XDCFG_CTRL_OFFSET);
			XDcfg_WriteReg(_DcfgInstancePtr->Config.BaseAddr,
					XDCFG_CTRL_OFFSET, (CtrlReg |
							XDCFG_CTRL_PCFG_PROG_B_MASK));
		//@lf wait for set
		while((XDcfg_ReadReg(_DcfgInstancePtr->Config.BaseAddr, XDCFG_STATUS_OFFSET)
					& XDCFG_STATUS_PCFG_INIT_MASK) == 0);

}

3. 将准备好的bin文件通过 Xlinx -> Dump/Restore Date File 方式导入DDR。

  • start address 对应demo代码中的 BIT_STREAM_LOCATION - 1 ,BIT_STREAM_LOCATION地址实际上是GP-AXI MASTER地址空间的,并不是DDR里面的,;
    • size 对应导入bin文件的字节大小(右键属性可查看),demo代码中相关变量:BIT_STREAM_SIZE_WORDS = size * 4  ;

对于函数中的两个关键宏定义,BIT_STREAM_LOCATION 为读取DDR的起始地址。读取时从DDR地址0x3000001 开始读取,这是因为最低 2bit == 2’b01 用来表示此时为最后一次 DMA 传输。BIT_STREAM_SIZE_WORD 的大小为bin文件字节数*4。
————————————————

4. 下板debug或run,注意不用 Reset system 和 Program FPGA。

 PL 部分没有比特流,下载时会提醒硬件还未就绪,忽略继续即可。

小结:

  •         此部分函数功能仅可以实现 PL整体 top.bin 的重配置,不能实现PL 局部重构。即上面第3步如果在DDR中加载 partial.bin,最终是无法正常运行的。
    •         查看 Dump/Restore Date File 方式是否成功将bin文件导入DDR,可以添加地址数据监控:

3.4 PS局部重配置PL

PL部分重构同样可以使用PCAP实现,软件部分一样可以采用xdevcfg_polled_example例程实现。与之前完全重配置的流程基本是一样,也需要使用write_cfgmem将部分流文件转换为bin文件,也需要将bin文件加载到DRAM中,最后通过xdevcfg设备实现部分重构。有一点需要注意,在完全重构的时候为了清除PL内原有配置,在例程中添加了PL_Reset函数,在部分重构中需要去掉此函数。

Zynq使用PCAP实现PL部分重配置 - 知乎 (zhihu.com)

        先下载了整体 top.bin 文件运行,然后去掉代码中的 Pl_Reset(DcfgInstPtr); 下载 partial.bin,确实可以实现PL 局部重构。但是代码疑似有复位机制,下载运行几秒会回到 top.bin 的状态。应该与 XDcfg_Transfer 函数细节有关,待研究。

	/*
	 * Download bitstream in non secure mode
	 */
//	Pl_Reset(DcfgInstPtr);
	XDcfg_Transfer(DcfgInstPtr, (u8 *)BIT_STREAM_LOCATION,
			BIT_STREAM_SIZE_WORDS,
			(u8 *)XDCFG_DMA_INVALID_ADDRESS,
			0, XDCFG_NON_SECURE_PCAP_WRITE);

关于 XDcfg_Transfer 函数:

//
u32 XDcfg_Transfer	(	
    XDcfg * 	InstancePtr, 	// XDcfg 实例指针
    void * 	SourcePtr,			// bit Stream 地址
    u32 	SrcWordLength,		// bit stream 长度÷4(Size in Words,32bit)
    void * 	DestPtr,			// 目标指针
    u32 	DestWordLength,			// 待传输到目标地址的数据长度(Size in Words)
    u32 	TransferType 		// 传输类型,参考xdevcfg.h中宏定义
)

4. 问题

5. 分析

6. Reference

1. ZYNQ 实现PL动态重构_zynq动态重构demo-CSDN博客

2. Zynq使用PCAP实现PL部分重配置 - 知乎 (zhihu.com)

3. Xilinx平台远程更新中FPGA读写Flash设计的讨论 - 知乎 (zhihu.com)

4. Zynq-7000 PS重配置PL_pl重配置通道-CSDN博客

5. ZYNQ PS动态配置PL动态加载_ps加载pl代码-CSDN博客

6. ZYNQ学习笔记(3)-局部重构Partial Reconfiguration_动态和部分重构-CSDN博客

7. ZYNQ linux通过xdevcfg在线更新PL BIT-CSDN博客

8. zynq实现动态加载(Partial Reconfiguration)_zynq partial reconfiguration-CSDN博客

9. ZYNQ | 可重构技术PCAP(1)——例程学习 - ZoroGH's Blog

10. ZYNQ | 可重构技术PCAP(2)——Flash启动 - ZoroGH's Blog

11. 

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值