使用ZYNQ實現單LUT內容的動態修改(二)PS端動態修改LUT內容,軟件部分,Vitis操作

一,摘要

該系統的軟件部分使用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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章