一,摘要
该系统的软件部分使用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;
}