使用ZYNQ实现单LUT内容的动态修改(二)PS端动态修改LUT内容,软件部分,Vitis操作

3 篇文章 0 订阅

一,摘要

该系统的软件部分使用Xilinx Vitis平台进行实现,操作方法类似于之前版本的SDK,不同的是Vitis中的硬件平台要自己手动导入,其余编译调试大体相同。
该篇博客主要记录软件端的整个流程,主要依据官方给出的HW_ICAP驱动库进行开发。具体硬件原理方面的知识不做太多介绍。有需要的话可以参考官方的一些手册。

二,程序流程

程序循环执行以下四种操作,

  1. 输入FAR寄存器值,读取对应地址的数据帧。
  2. 输入要修改的LUT的位置,该位置可通过生成硬件时的Layout找出。
  3. 输入要修改LUT的新数据。将修改过的数据帧写入FPGA内部。
  4. 重新读出数据帧,与写入的数据帧进行对比,完全一致即返回修改成功,返回操作1。

三,工程的建立与调试

主要记录一些关键步骤!

第一步,导入上篇博客生成的硬件平台

导入上篇博客工程目录下的xsa文件。
在这里插入图片描述
接下来编译该硬件平台。
加粗样式

第二步,导入并编译修改单LUT的程序

导入.\src\vitis\目录下的C语言源文件,如下图所示。
在这里插入图片描述

接下来需要注意官方的驱动有个BUG,针对于ZYNQ系列的器件,其DeviceIDCode并没有在7系列里面包含,这就使得在执行XHwIcap_CfgInitialize()函数时出错,所以在此处要将其ID号改成7系列列表中有的ID号,如下图239行所示。
在这里插入图片描述

第三步,调试工程。

右击工程选择Debug As/DebugConfiguration,然后设置如下图,点击调试。
在这里插入图片描述
此时我们把top2.bit文件下载到FPGA部分,可以看到其LUT的输出内容如下图,
在这里插入图片描述
通过串口助手输入FAR地址字段,对FPGA内部该地址的配置帧进行读取。
在这里插入图片描述
截取部分读出的配置数据如下图所示,可在转换过后的rbt文件中找到该配置帧的数据。
我们需要操作的目标LUT的前1/4配置数据为下图中0x55550000这一数据,我们此时要对其进行更改。
在这里插入图片描述
首先我们要输入该LUT数据在该帧数据中的位置08(此位置可以通过layout看出来)。
在这里插入图片描述
进一步输入要修改成的数据,如下图所示,正常情况下返回Success即为写入成功。
在这里插入图片描述
最终我们再来看一下该LUT输出的波形如下,可以看出其内部数据已经被修改了。
在这里插入图片描述

四、中间遇到的问题

  1. 读帧数据时显示不完整,后小部分出现0xfffffffd,此种情况是由于AXI_ICAP ip的读FIFO容量设置太小造成的,中间会有部分数据缺失。解决办法,调大读FIFO的容量。
  2. 写帧数据时写不进去,经排查发现为设置正确的DeviceID号,改正后问题解决。
  3. 配置数据与LUT实际存储内容的映射关系还没来得及整清楚,看后面是否用得到。

五、总结

基本打通了单LUT读写的底层通路,为后面重构控制器的设计打下了基础。考虑通过云端等接口实现远程LUT内容的读写等操作,基于此可实现FPGA内部错误的自修复,高效重构任务的执行等高级功能。

六、附程序代码如下

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "xparameters.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "ff.h"
#include "xdevcfg.h"
#include "xhwicap.h"
#include "xil_io.h"
#include "xil_types.h"

#define PYNQ

#define FRAME_WORDS_NUM	202
// Parameters for Partial Reconfiguration
#ifdef PYNQ

#define READ_FRAME_SIZE 30
#define WRITE_FRAME_SIZE 91
#define PARTIAL_MULT_ADDR   0x200000
#define PARTIAL_ADDER_ADDR   0x300000
#define PARTIAL_BLANK_ADDR   0x400000
#define PARTIAL_MULT_BITFILE_LEN  0xC66F // in number of words
#define PARTIAL_ADDER_BITFILE_LEN  0xC66F // in number of words
#define PARTIAL_BLANK_BITFILE_LEN  0xC66F // in number of words

#endif

// Turn on/off Debug messages
#ifdef DEBUG_PRINT
#define  debug_printf  xil_printf
#else
#define  debug_printf(msg, args...) do {  } while (0)
#endif

// Read function for STDIN
extern char inbyte(void);

// Driver Instantiations
static XDcfg_Config *XDcfg_0;
XDcfg DcfgInstance;
XDcfg *DcfgInstPtr;
static XHwIcap HwIcap;	// The instance of the HWICAP device
XHwIcap *HwIcapInstPtr;
uint32_t read_FrameBuffer[FRAME_WORDS_NUM];
uint32_t read_FrameBuffer_verify[FRAME_WORDS_NUM];
unsigned char uartBuffer[16];
uint32_t addr_word;	//FAR Word.
uint32_t new_word;	//The word to be writen to lut;
uint32_t lut_index;	//



int XHwIcap_DeviceReadFrame1(XHwIcap *InstancePtr, uint32_t far_word , u32 *FrameBuffer)
{

	u32 Packet;
	u32 Data;
	u32 TotalWords;
	int Status;
	u32 WriteBuffer[WRITE_FRAME_SIZE];
	u32 Index = 0;
	u32 NumNoops;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid(FrameBuffer != NULL);

	/*
	 * DUMMY and SYNC
	 */
	WriteBuffer[Index++] = XHI_DUMMY_PACKET;
	WriteBuffer[Index++] = XHI_BUS_WTH_PACKET;
	WriteBuffer[Index++] = XHI_BUS_DET_PACKET;
	WriteBuffer[Index++] = XHI_DUMMY_PACKET;
	WriteBuffer[Index++] = XHI_SYNC_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/*
	 * Reset CRC
	 */
	Packet = XHwIcap_Type1Write(XHI_CMD) | 1;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = XHI_CMD_RCRC;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/*
	 * Setup CMD register to read configuration
	 */
	Packet = XHwIcap_Type1Write(XHI_CMD) | 1;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = XHI_CMD_RCFG;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/*
	 * Setup FAR register.
	 */
	Packet = XHwIcap_Type1Write(XHI_FAR) | 1;
	Data = far_word;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;

	/*
	 * Setup read data packet header.
	 * The frame will be preceeded by a dummy frame, and we need to read one
	 * extra word for V4 and V5 devices.
	 */
	switch (InstancePtr->DeviceFamily) {
		case DEVICE_TYPE_7SERIES :
				TotalWords = InstancePtr->WordsPerFrame << 1;
				NumNoops = 32;
				break;
		case DEVICE_TYPE_ULTRA :
			TotalWords = (InstancePtr->WordsPerFrame << 1) + 10;
			NumNoops = 64;
				break;
		case DEVICE_TYPE_ULTRA_PLUS :
			TotalWords = (InstancePtr->WordsPerFrame << 1) + 25;
			NumNoops = 64;
				break;
		default:
			return XST_FAILURE;
	}

	/*
	 * Create Type one packet
	 */
	Packet = XHwIcap_Type1Read(XHI_FDRO);
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = 0x48000000 | TotalWords;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	for(unsigned int i = 0; i < NumNoops; i++) {
		WriteBuffer[Index++] = XHI_NOOP_PACKET;
	}

	/*
	 * Write the data to the FIFO and initiate the transfer of data
	 * present in the FIFO to the ICAP device
	 */
	Status = XHwIcap_DeviceWrite(InstancePtr, (u32 *)&WriteBuffer[0],
			Index);
	if (Status != XST_SUCCESS)  {
		return XST_FAILURE;
	}

	/*
	 * Wait till the write is done.
	 */
	while (XHwIcap_IsDeviceBusy(InstancePtr) != FALSE);


	/*
	 * Read the frame of the data including the NULL frame.
	 */
	Status = XHwIcap_DeviceRead(InstancePtr, FrameBuffer, TotalWords);
	if (Status != XST_SUCCESS)  {
		return XST_FAILURE;
	}

	/*
	 * Send DESYNC command
	 */
	Status = XHwIcap_CommandDesync(InstancePtr);
	if (Status != XST_SUCCESS)  {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
};

int XHwIcap_DeviceWriteFrame1(XHwIcap *InstancePtr, u32 far_word,
				u32 *FrameData)
{

	u32 Packet;
	u32 Data;
	u32 TotalWords;
	int Status;
	u32 WriteBuffer[READ_FRAME_SIZE];
	u32 Index =0;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid(FrameData != NULL);


	/*
	 * DUMMY and SYNC
	 */
	WriteBuffer[Index++] = XHI_DUMMY_PACKET;
	WriteBuffer[Index++] = XHI_SYNC_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/*
	 * Reset CRC
	 */
	Packet = XHwIcap_Type1Write(XHI_CMD) | 1;
	Data = XHI_CMD_RCRC;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/*
	 * Bypass CRC
	 */

	/*
	 * ID register
	 */
	Packet = XHwIcap_Type1Write(XHI_IDCODE) | 1;
	Data = InstancePtr->DeviceIdCode;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;

	/*
	 * Setup FAR
	 */
	Packet = XHwIcap_Type1Write(XHI_FAR) | 1;

	Data = far_word;

	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;

	/*
	 * Setup CMD register - write configuration
	 */
	Packet = XHwIcap_Type1Write(XHI_CMD) | 1;
	Data = XHI_CMD_WCFG;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/*
	 * Setup Packet header.
	 */
	TotalWords = InstancePtr->WordsPerFrame << 1;
	if (TotalWords < XHI_TYPE_1_PACKET_MAX_WORDS)  {
		/*
		 * Create Type 1 Packet.
		 */
		Packet = XHwIcap_Type1Write(XHI_FDRI) | TotalWords;
		WriteBuffer[Index++] = Packet;
	}
	else {

		/*
		 * Create Type 2 Packet.
		 */
		Packet = XHwIcap_Type1Write(XHI_FDRI);
		WriteBuffer[Index++] = Packet;

		Packet = XHI_TYPE_2_WRITE | TotalWords;
		WriteBuffer[Index++] = Packet;
	}

	/*
	 * Write the Header data into the FIFO and intiate the transfer of
	 * data present in the FIFO to the ICAP device
	 */
	Status = XHwIcap_DeviceWrite(InstancePtr, (u32 *)&WriteBuffer[0], Index);
	if (Status != XST_SUCCESS)  {
		return XST_FAILURE;
	}

	/*
	 * Write the modified frame data.
	 */
	Status = XHwIcap_DeviceWrite(InstancePtr,
				(u32 *) &FrameData[InstancePtr->WordsPerFrame],
				InstancePtr->WordsPerFrame);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Write out the pad frame. The pad frame was read from the device
	 * before the data frame.
	 */
	Status = XHwIcap_DeviceWrite(InstancePtr, (u32 *) &FrameData[0],
				    InstancePtr->WordsPerFrame);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/* Add CRC */
	Index = 0;
	Packet = XHwIcap_Type1Write(XHI_CMD) | 1;
	Data = XHI_CMD_RCRC;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;

	/* Park the FAR */
	Packet = XHwIcap_Type1Write(XHI_FAR) | 1;
	Data = XHwIcap_SetupFar(0, 0, 3, 33, 0);

	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] =  Data;

	/* Add CRC */
	Packet = XHwIcap_Type1Write(XHI_CMD) | 1;
	Data = XHI_CMD_RCRC;
	WriteBuffer[Index++] = Packet;
	WriteBuffer[Index++] = Data;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;
	WriteBuffer[Index++] = XHI_NOOP_PACKET;


	/*
	 * Intiate the transfer of data present in the FIFO to
	 * the ICAP device
	 */
	Status = XHwIcap_DeviceWrite(InstancePtr, &WriteBuffer[0], Index);
	if (Status != XST_SUCCESS)  {
		return XST_FAILURE;
	}

	/*
	 * Send DESYNC command
	 */
	Status = XHwIcap_CommandDesync(InstancePtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
};


u32 getWord (){

	unsigned char byte;

	int digitIndex;
	u32 far_word;

	while(1){
		byte = 0x00;
		digitIndex = 0;

		//get bytes from uart until RETURN is entered

		while(byte != 0x0d){
			byte = inbyte();
			uartBuffer[digitIndex] = byte;
			xil_printf("%x", byte);
			digitIndex++;
		}
		xil_printf("\r\n");

		if(digitIndex==5)
		{
			far_word = uartBuffer[0]<<24 | uartBuffer[1]<<16 |uartBuffer[2]<<8 | uartBuffer[3];
			return far_word;
		}
		else
		{
			digitIndex =0 ;
			break;
		}

	}
}

u32 getByte (){

	unsigned char byte;

	int digitIndex;
	u32 data;

	while(1){
		byte = 0x00;
		digitIndex = 0;

		//get bytes from uart until RETURN is entered

		while(byte != 0x0d){
			byte = inbyte();
			uartBuffer[digitIndex] = byte;
			xil_printf("%x\r\n", byte);
			digitIndex++;
		}

		if(digitIndex==2)
		{
			data = uartBuffer[0];
			return data;
		}

	}
}



int main()
{
	int Status;
	int i;
	int equal_number;
	XHwIcap_Config *ConfigPtr;

	// Flush and disable Data Cache
	Xil_DCacheDisable();

	// Invalidate and enable Data Cache
	Xil_DCacheEnable();

	// Initialize Device Configuration Interface
	DcfgInstPtr = &DcfgInstance;
	XDcfg_0 = XDcfg_LookupConfig(XPAR_XDCFG_0_DEVICE_ID) ;
	Status =  XDcfg_CfgInitialize(DcfgInstPtr, XDcfg_0, XDcfg_0->BaseAddr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Deselect PCAP as the configuration device as we are going to use the ICAP
	XDcfg_ClearControlRegister(DcfgInstPtr, XDCFG_CTRL_PCAP_PR_MASK);

	ConfigPtr = XHwIcap_LookupConfig(XPAR_AXI_HWICAP_0_DEVICE_ID);
	if (ConfigPtr == NULL) {
		return XST_FAILURE;
	}

	HwIcapInstPtr = &HwIcap;
	Status = XHwIcap_CfgInitialize(HwIcapInstPtr, ConfigPtr,
				ConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	HwIcapInstPtr->DeviceIdCode = 0x23727093;
	XHwIcap_Reset(HwIcapInstPtr);

	print("HWICAP Initialized\r\n");

	while(1)
	{
		equal_number=0;
		print("Please input the far words!\r\n");
		addr_word = getWord();
		Status = XHwIcap_DeviceReadFrame1(HwIcapInstPtr, addr_word,&read_FrameBuffer[0]);
		XHwIcap_Reset(HwIcapInstPtr);
		if (Status != XST_SUCCESS) {
			print("Read Lut Failure\r\n");
			return XST_FAILURE;
		}
		else if(Status == XST_SUCCESS)
		{
			for(i=0;i<FRAME_WORDS_NUM;i++)
				xil_printf("%x\r\n",read_FrameBuffer[i]);
		}
		print("Please input the number of the lut:\r\n");
		lut_index = getByte();
		print("Please input the new data of the lut:\r\n");
		new_word = getWord();
		read_FrameBuffer[(101 + lut_index)] = new_word;
		Status = XHwIcap_DeviceWriteFrame1(HwIcapInstPtr, addr_word, &read_FrameBuffer[1]);
		XHwIcap_Reset(HwIcapInstPtr);
		if (Status != XST_SUCCESS) {
			print("Write Lut Failure\r\n");
			return XST_FAILURE;
		}
		Status = XHwIcap_DeviceReadFrame1(HwIcapInstPtr, addr_word,read_FrameBuffer_verify);
		if (Status != XST_SUCCESS) {
			print("Read Lut Failure\r\n");
			return XST_FAILURE;
		}
		for(i=0;i<FRAME_WORDS_NUM;i++)
		{
			if(read_FrameBuffer_verify[i] == read_FrameBuffer[i])
			{
				equal_number ++;
			}
		}
		if(equal_number != 202)
			print("Write Lut Failure!\r\n");
		else
			print("Write Lut Success!\r\n");

	}
    return 0;
}

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值