一,摘要
該系統的軟件部分使用Xilinx Vitis平臺進行實現,操作方法類似於之前版本的SDK,不同的是Vitis中的硬件平臺要自己手動導入,其餘編譯調試大體相同。
該篇博客主要記錄軟件端的整個流程,主要依據官方給出的HW_ICAP驅動庫進行開發。具體硬件原理方面的知識不做太多介紹。有需要的話可以參考官方的一些手冊。
二,程序流程
程序循環執行以下四種操作,
- 輸入FAR寄存器值,讀取對應地址的數據幀。
- 輸入要修改的LUT的位置,該位置可通過生成硬件時的Layout找出。
- 輸入要修改LUT的新數據。將修改過的數據幀寫入FPGA內部。
- 重新讀出數據幀,與寫入的數據幀進行對比,完全一致即返回修改成功,返回操作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輸出的波形如下,可以看出其內部數據已經被修改了。
四、中間遇到的問題
- 讀幀數據時顯示不完整,後小部分出現0xfffffffd,此種情況是由於AXI_ICAP ip的讀FIFO容量設置太小造成的,中間會有部分數據缺失。解決辦法,調大讀FIFO的容量。
- 寫幀數據時寫不進去,經排查發現爲設置正確的DeviceID號,改正後問題解決。
- 配置數據與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;
}