在fpga ip设计里面,中断是不可缺少的。一般来说,ip处理结束之后,要么用轮询的方法获得结果,要么用中断的方法获取结果。两种方式都是可以拿来使用,只是一般来说,轮询的方式效率会比较低。今天可以看下,hls里面中断是怎么处理的。不失一般性,可以把之前求平均值的hls代码拿出来分析,
1、hls代码
#include <ap_cint.h>
uint32 _average_int(uint32* array, int num)
{
uint32 sum = 0;
int i;
for(i = 0; i < num; i++)
{
sum += array[i];
}
return sum / num;
}
extern "C" uint32 average_int(uint32* array, int num)
{
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=num
#pragma HLS INTERFACE m_axi depth=1024 offset=slave port=array
uint32 result = _average_int(array, num);
return result;
}
这段代码只是完成基本功能,大家可以忽略它的性能设计,这部分不做考虑。
2、综合、export
利用vivado hls软件进行综合和导出。
3、查看生成的驱动代码,
主要的接口都在xaverage_int.h里面。
4、查看xaverage_int.h文件
// ==============================================================
// File generated on Sun May 08 06:30:23 +0800 2022
// Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC v2018.3 (64-bit)
// SW Build 2405991 on Thu Dec 6 23:38:27 MST 2018
// IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018
// Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.
// ==============================================================
#ifndef XAVERAGE_INT_H
#define XAVERAGE_INT_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files *********************************/
#ifndef __linux__
#include "xil_types.h"
#include "xil_assert.h"
#include "xstatus.h"
#include "xil_io.h"
#else
#include <stdint.h>
#include <assert.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#endif
#include "xaverage_int_hw.h"
/**************************** Type Definitions ******************************/
#ifdef __linux__
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
#else
typedef struct {
u16 DeviceId;
u32 Axilites_BaseAddress;
} XAverage_int_Config;
#endif
typedef struct {
u32 Axilites_BaseAddress;
u32 IsReady;
} XAverage_int;
/***************** Macros (Inline Functions) Definitions *********************/
#ifndef __linux__
#define XAverage_int_WriteReg(BaseAddress, RegOffset, Data) \
Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data))
#define XAverage_int_ReadReg(BaseAddress, RegOffset) \
Xil_In32((BaseAddress) + (RegOffset))
#else
#define XAverage_int_WriteReg(BaseAddress, RegOffset, Data) \
*(volatile u32*)((BaseAddress) + (RegOffset)) = (u32)(Data)
#define XAverage_int_ReadReg(BaseAddress, RegOffset) \
*(volatile u32*)((BaseAddress) + (RegOffset))
#define Xil_AssertVoid(expr) assert(expr)
#define Xil_AssertNonvoid(expr) assert(expr)
#define XST_SUCCESS 0
#define XST_DEVICE_NOT_FOUND 2
#define XST_OPEN_DEVICE_FAILED 3
#define XIL_COMPONENT_IS_READY 1
#endif
/************************** Function Prototypes *****************************/
#ifndef __linux__
int XAverage_int_Initialize(XAverage_int *InstancePtr, u16 DeviceId);
XAverage_int_Config* XAverage_int_LookupConfig(u16 DeviceId);
int XAverage_int_CfgInitialize(XAverage_int *InstancePtr, XAverage_int_Config *ConfigPtr);
#else
int XAverage_int_Initialize(XAverage_int *InstancePtr, const char* InstanceName);
int XAverage_int_Release(XAverage_int *InstancePtr);
#endif
void XAverage_int_Start(XAverage_int *InstancePtr);
u32 XAverage_int_IsDone(XAverage_int *InstancePtr);
u32 XAverage_int_IsIdle(XAverage_int *InstancePtr);
u32 XAverage_int_IsReady(XAverage_int *InstancePtr);
void XAverage_int_EnableAutoRestart(XAverage_int *InstancePtr);
void XAverage_int_DisableAutoRestart(XAverage_int *InstancePtr);
u32 XAverage_int_Get_return(XAverage_int *InstancePtr);
void XAverage_int_Set_array_r(XAverage_int *InstancePtr, u32 Data);
u32 XAverage_int_Get_array_r(XAverage_int *InstancePtr);
void XAverage_int_Set_num(XAverage_int *InstancePtr, u32 Data);
u32 XAverage_int_Get_num(XAverage_int *InstancePtr);
void XAverage_int_InterruptGlobalEnable(XAverage_int *InstancePtr);
void XAverage_int_InterruptGlobalDisable(XAverage_int *InstancePtr);
void XAverage_int_InterruptEnable(XAverage_int *InstancePtr, u32 Mask);
void XAverage_int_InterruptDisable(XAverage_int *InstancePtr, u32 Mask);
void XAverage_int_InterruptClear(XAverage_int *InstancePtr, u32 Mask);
u32 XAverage_int_InterruptGetEnabled(XAverage_int *InstancePtr);
u32 XAverage_int_InterruptGetStatus(XAverage_int *InstancePtr);
#ifdef __cplusplus
}
#endif
#endif
5、分析xaverage_int.h文件
主要的驱动接口分成这么几个部分,
初始化函数,XAverage_int_Initialize等
状态检查函数,XAverage_int_Start、XAverage_int_IsDone等
获取返回值函数,XAverage_int_Get_return
参数设置函数,XAverage_int_Set_array_r、XAverage_int_Set_num等
中断处理函数,XAverage_int_InterruptEnable、XAverage_int_InterruptClear等
6、关于中断和查询
在5中提到的中断函数都可以使用。其实如果不需要中断,仅仅利用状态检查函数,也是可以获取计算结果的,这里面的取舍取决于具体的应用场景。
7、寄存器的布局
关于寄存器的相关信息,主要来自于xaverage_int_hw.h文件,
// ==============================================================
// File generated on Sun May 08 06:30:23 +0800 2022
// Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC v2018.3 (64-bit)
// SW Build 2405991 on Thu Dec 6 23:38:27 MST 2018
// IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018
// Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.
// ==============================================================
// AXILiteS
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Data signal of ap_return
// bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of array_r
// bit 31~0 - array_r[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of num
// bit 31~0 - num[31:0] (Read/Write)
// 0x24 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
#define XAVERAGE_INT_AXILITES_ADDR_AP_CTRL 0x00
#define XAVERAGE_INT_AXILITES_ADDR_GIE 0x04
#define XAVERAGE_INT_AXILITES_ADDR_IER 0x08
#define XAVERAGE_INT_AXILITES_ADDR_ISR 0x0c
#define XAVERAGE_INT_AXILITES_ADDR_AP_RETURN 0x10
#define XAVERAGE_INT_AXILITES_BITS_AP_RETURN 32
#define XAVERAGE_INT_AXILITES_ADDR_ARRAY_R_DATA 0x18
#define XAVERAGE_INT_AXILITES_BITS_ARRAY_R_DATA 32
#define XAVERAGE_INT_AXILITES_ADDR_NUM_DATA 0x20
#define XAVERAGE_INT_AXILITES_BITS_NUM_DATA 32
8、ip、驱动和中断
利用fpga设计好ip,这只是第一步。后面还需要移植好驱动函数,如果是裸机系统可能不需要手动移植驱动代码了,当os变成linux的时候,还需要转成kernel driver。当然,变成kernel driver之后,后面就是具体的调用了。这中间,ip如果有中断,还需要把中断反馈到zynq cpu上面。