HLS生成的模块,在BSP中,会生成对应的driver,
在导出HDF后,SDK中,会生成hardware_platform,
之后,在生成的BSP中,会将driver中的src代码合并进BSP中去。
这些HLS生成的模块,都会有一些共性的操作集。
来看看
1)cfginit
int XBayer_photo_accl_CfgInitialize(XBayer_photo_accl *InstancePtr, XBayer_photo_accl_Config *ConfigPtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ConfigPtr != NULL);
InstancePtr->Control_bus_BaseAddress = ConfigPtr->Control_bus_BaseAddress;
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
return XST_SUCCESS;
}
int XClahe_accl_CfgInitialize(XClahe_accl *InstancePtr, XClahe_accl_Config *ConfigPtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ConfigPtr != NULL);
InstancePtr->Control_bus_BaseAddress = ConfigPtr->Control_bus_BaseAddress;
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
return XST_SUCCESS;
}
这个函数,主要是填充结构体,baseaddress和ready状态。
2)start
void XBayer_photo_accl_Start(XBayer_photo_accl *InstancePtr) {
u32 Data;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL) & 0x80;
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL, Data | 0x01);
}
void XClahe_accl_Start(XClahe_accl *InstancePtr) {
u32 Data;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL) & 0x80;
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL, Data | 0x01);
}
这个函数,设置模块启动,
首先读取ap_auto_restart状态,
然后写入ap_start位,
具体的寄存器位的含义如下。
// CONTROL_BUS
// 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
和0x80相与,提取出ap_auto_restart的状态,
再和0x01相或,设置ap_start的状态。
3)isdone
u32 XBayer_photo_accl_IsDone(XBayer_photo_accl *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL);
return (Data >> 1) & 0x1;
}
u32 XClahe_accl_IsDone(XClahe_accl *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL);
return (Data >> 1) & 0x1;
}
这个函数,读取模块完成状态,
首先读取control寄存器,
然后再右移位到bit0,再和0x01相与,取出ap_done的值,返回。
注意,返回值的bit0携带对应的ap_done的值,其他位全部为0。
4)isidle
u32 XBayer_photo_accl_IsIdle(XBayer_photo_accl *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL);
return (Data >> 2) & 0x1;
}
u32 XClahe_accl_IsIdle(XClahe_accl *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL);
return (Data >> 2) & 0x1;
}
这个函数,读取模块空闲状态,
首先读取control寄存器,
然后再右移位到bit0,再和0x01相与,取出ap_idle的值,返回。
注意,返回值的bit0携带对应的ap_idle的值,其他位全部为0。
5)isready
u32 XBayer_photo_accl_IsReady(XBayer_photo_accl *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL);
// check ap_start to see if the pcore is ready for next input
return !(Data & 0x1);
}
u32 XClahe_accl_IsReady(XClahe_accl *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL);
// check ap_start to see if the pcore is ready for next input
return !(Data & 0x1);
}
这个函数,读取模块ready状态,
首先读取control寄存器,
然后再和0x01相与,取出ap_start的值,
然后取反,返回。
注意,返回值的bit0携带对应的ap_start的值的取反值,其他位全部为0。
6)enable_auto_restart
void XBayer_photo_accl_EnableAutoRestart(XBayer_photo_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL, 0x80);
}
void XClahe_accl_EnableAutoRestart(XClahe_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL, 0x80);
}
这个函数,设置模块的auto_restart状态,
写入control寄存器中的ap_auto_restart位。
7)disable_auto_restart
void XBayer_photo_accl_DisableAutoRestart(XBayer_photo_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_AP_CTRL, 0);
}
void XClahe_accl_DisableAutoRestart(XClahe_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_AP_CTRL, 0);
}
这个函数,禁止模块的auto_restart状态,
写入control寄存器中的ap_auto_restart位。
8)interrupt_global_enable
void XBayer_photo_accl_InterruptGlobalEnable(XBayer_photo_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_GIE, 1);
}
void XClahe_accl_InterruptGlobalEnable(XClahe_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_GIE, 1);
}
这个函数,使能模块的全局中断。
写入gie寄存器的gie位。
寄存器定义如下:
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
9)interrupt_global_disable
void XBayer_photo_accl_InterruptGlobalDisable(XBayer_photo_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_GIE, 0);
}
void XClahe_accl_InterruptGlobalDisable(XClahe_accl *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_GIE, 0);
}
这个函数,禁止模块的全局中断。
写入gie寄存器的gie位。
10)interrupt_enable
void XBayer_photo_accl_InterruptEnable(XBayer_photo_accl *InstancePtr, u32 Mask) {
u32 Register;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Register = XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_IER);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_IER, Register | Mask);
}
void XClahe_accl_InterruptEnable(XClahe_accl *InstancePtr, u32 Mask) {
u32 Register;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Register = XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_IER);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_IER, Register | Mask);
}
这个函数,使能模块的各个独立中断源。
首先读出IER寄存器的值,暂存,
然后,根据MASK中提供的bit位,和暂存的原寄存器值相或,写入IER对应的位置。
寄存器定义如下:
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
有两个可用的中断源 ,ap_done和ap_ready。
当ap_done拉高有效时,模块发出一个中断给CPU,此时CPU可以触发对应的前台ISR来处理,从而实现与模块的交互。
当ap_ready拉高有效时,模块发出一个中断给CPU,此时CPU可以出发对应的前台ISR来处理,从而实现与模块的交互。
从CPU的角度看来,
如果执行进入了前台ISR,那么说明模块产生了对应的event。
11)interrupt_disable
void XBayer_photo_accl_InterruptDisable(XBayer_photo_accl *InstancePtr, u32 Mask) {
u32 Register;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Register = XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_IER);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_IER, Register & (~Mask));
}
void XClahe_accl_InterruptDisable(XClahe_accl *InstancePtr, u32 Mask) {
u32 Register;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Register = XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_IER);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_IER, Register & (~Mask));
}
这个函数,禁止模块的各个独立中断源。
首先读出IER寄存器的值,暂存,
然后,根据MASK中提供的bit位,对MASK取反后,和暂存的原寄存器值相与,写入IER对应的位置。
12)interrupt_get_enable
u32 XBayer_photo_accl_InterruptGetEnabled(XBayer_photo_accl *InstancePtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
return XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_IER);
}
u32 XClahe_accl_InterruptGetEnabled(XClahe_accl *InstancePtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
return XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_IER);
}
这个函数,获取模块的各个独立中断源的使能状态。
读出IER寄存器的值,返回。
13)interrupt_clear
void XBayer_photo_accl_InterruptClear(XBayer_photo_accl *InstancePtr, u32 Mask) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XBayer_photo_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_ISR, Mask);
}
void XClahe_accl_InterruptClear(XClahe_accl *InstancePtr, u32 Mask) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XClahe_accl_WriteReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_ISR, Mask);
}
这个函数,对模块的各个独立中断源的状态清零。
根据MASK中提供的bit位,写入ISR对应的位置。
寄存器定义如下:
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
注意,CPU中的中断清标,一般都是通过写1来清标的。
14)interrupt_get_status
u32 XBayer_photo_accl_InterruptGetStatus(XBayer_photo_accl *InstancePtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
return XBayer_photo_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XBAYER_PHOTO_ACCL_CONTROL_BUS_ADDR_ISR);
}
u32 XClahe_accl_InterruptGetStatus(XClahe_accl *InstancePtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
return XClahe_accl_ReadReg(InstancePtr->Control_bus_BaseAddress, XCLAHE_ACCL_CONTROL_BUS_ADDR_ISR);
}
这个函数,读取模块的各个独立中断源的状态。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
这些共性的部分,我们可以封装成一个基类class,名为xhls_accl。
cfginit函数,主要是填充结构体,所以这个函数可以被移植成构建函数,来完成同样的功能。
每个不同的模块,对应一个不同的AXIMM区域,所以,基类可以封装一个io_mem的对象。
这些共性操作集,可以被移植并封装成基类class的成员函数。
如下:
#include "io_mem.h"
//寄存器偏移
#define XHLS_REG_CTRL_START BIT(0)
#define XHLS_REG_CTRL_DONE BIT(1)
#define XHLS_REG_CTRL_IDLE BIT(2)
#define XHLS_REG_CTRL_READY BIT(3)
#define XHLS_REG_CTRL_AUTO_RESTART BIT(7)
#define XHLS_REG_GIE 0x04
#define XHLS_REG_GIE_GIE BIT(0)
#define XHLS_REG_IER 0x08
#define XHLS_REG_IER_DONE BIT(0)
#define XHLS_REG_IER_READY BIT(1)
#define XHLS_REG_ISR 0x0c
#define XHLS_REG_ISR_DONE BIT(0)
#define XHLS_REG_ISR_READY BIT(1)
#define XHLS_REG_ROWS 0x10
#define XHLS_REG_COLS 0x18
//HLS偏移
#define HLS_LOW16_MASK GENMASK(15, 0)
#define HLS_LOW16_SHIFT 0
#define HLS_HIGH16_MASK GENMASK(31, 16)
#define HLS_HIGH16_SHIFT 16
#define HLS_LOW8_MASK GENMASK(7, 0)
#define HLS_LOW8_SHIFT 0
#define HLS_HIGH8_MASK GENMASK(15, 8)
#define HLS_HIGH8_SHIFT 8
class XhlsAccl
{
public:
XhlsAccl(u32 phy_base, u32 size) {
regs_.phy_base_ = phy_base;
regs_.total_size_ = size;
}
void set_ap_start_value(int value) {
regs_.set_bit_value(0, XHLS_REG_CTRL_START, value);
}
void set_ap_auto_restart_value(int value) {
regs_.set_bit_value(0, XHLS_REG_CTRL_AUTO_RESTART, value);
}
void set_gie_gie_value(int value) {
regs_.set_bit_value(1, XHLS_REG_GIE_GIE, value);
}
void set_ier_use_done_value(int value) {
regs_.set_bit_value(2, XHLS_REG_IER_DONE, value);
}
void set_ier_use_ready_value(int value) {
regs_.set_bit_value(2, XHLS_REG_IER_READY, value);
}
void set_isr(u32 value) {
regs_.set_value(3, value);
}
u32 get_ap() {
return regs_.get_value(0);
}
u32 get_isr() {
return regs_.get_value(3);
}
void set_u16_with_en(u32 offset, u32 value, u8 en, int flag = 1) {
en = en & 1;
u32 mask = (en == 0) ? HLS_LOW16_MASK : HLS_HIGH16_MASK;
u32 shift = (en == 0) ? HLS_LOW16_SHIFT : HLS_HIGH16_SHIFT;
regs_.set_value(offset, value, mask, shift, flag);
}
void set_u8_with_en(u32 offset, u32 value, u8 en, int flag = 1) {
en = en & 1;
u32 mask = (en == 0) ? HLS_LOW8_MASK : HLS_HIGH8_MASK;
u32 shift = (en == 0) ? HLS_LOW8_SHIFT : HLS_HIGH8_SHIFT;
regs_.set_value(offset, value, mask, shift, flag);
}
protected:
IoMem regs_;
};