Commit 04e6b289 authored by Daniel Krebs's avatar Daniel Krebs
Browse files

ips/hla-mem: playing around with HLS AXI master

The HLS IP has an AXI master interface that reads a value from
memory (PCIe bus), returns it via an AXI Lite register and then
modifies the memory to a fixed value.
parent 69437338
Pipeline #49588 failed with stages
in 49 seconds
......@@ -274,6 +274,20 @@
"irq_case": "pcie_0_axi_pcie_intc_0:7"
}
},
"mem_0": {
"vlnv": "xilinx.com:hls:mem:1.6",
"memory-view": {
"m_axi_gmem": {
"pcie_0_axi_pcie_0": {
"BAR0": {
"baseaddr": 0,
"highaddr": 4294967295,
"size": 4294967296
}
}
}
}
},
"pcie_0_axi_pcie_0": {
"vlnv": "xilinx.com:ip:axi_pcie:2.8",
"memory-view": {
......@@ -353,6 +367,13 @@
"size": 4096
}
},
"mem_0": {
"Reg": {
"baseaddr": 57344,
"highaddr": 61439,
"size": 4096
}
},
"pcie_0_axi_pcie_0": {
"CTL0": {
"baseaddr": 268435456,
......
#pragma once
#include <villas/memory.hpp>
#include <villas/fpga/ips/xmem.h>
#include "fpga/ip.hpp"
namespace villas {
namespace fpga {
namespace ip {
class HlsMem : public IpCore
{
public:
friend class HlsMemFactory;
bool init();
bool testMemory(const MemoryBlock& mem);
private:
static constexpr const char* registerMemory = "Reg";
static constexpr const char* axiInterface = "m_axi_gmem";
std::list<MemoryBlockName> getMemoryBlocks() const
{ return { registerMemory }; }
XMem xmem;
};
class HlsMemFactory : public IpCoreFactory {
public:
HlsMemFactory();
IpCore* create()
{ return new HlsMem; }
std::string
getName() const
{ return "HlsMem"; }
std::string
getDescription() const
{ return "HLS memory test"; }
Vlnv getCompatibleVlnv() const
{ return {"xilinx.com:hls:mem:"}; }
};
} // namespace ip
} // namespace fpga
} // namespace villas
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2017.3
// Copyright (C) 1986-2017 Xilinx, Inc. All Rights Reserved.
//
// ==============================================================
#ifndef XMEM_H
#define XMEM_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 "xmem_hw.h"
/**************************** Type Definitions ******************************/
#ifdef __linux__
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
#else
typedef struct {
u16 DeviceId;
u32 Ctrl_BaseAddress;
} XMem_Config;
#endif
typedef struct {
u32 Ctrl_BaseAddress;
u32 IsReady;
} XMem;
/***************** Macros (Inline Functions) Definitions *********************/
#ifndef __linux__
#define XMem_WriteReg(BaseAddress, RegOffset, Data) \
Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data))
#define XMem_ReadReg(BaseAddress, RegOffset) \
Xil_In32((BaseAddress) + (RegOffset))
#else
#define XMem_WriteReg(BaseAddress, RegOffset, Data) \
*(volatile u32*)((BaseAddress) + (RegOffset)) = (u32)(Data)
#define XMem_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 XMem_Initialize(XMem *InstancePtr, u16 DeviceId);
XMem_Config* XMem_LookupConfig(u16 DeviceId);
int XMem_CfgInitialize(XMem *InstancePtr, XMem_Config *ConfigPtr);
#else
int XMem_Initialize(XMem *InstancePtr, const char* InstanceName);
int XMem_Release(XMem *InstancePtr);
#endif
void XMem_Start(XMem *InstancePtr);
u32 XMem_IsDone(XMem *InstancePtr);
u32 XMem_IsIdle(XMem *InstancePtr);
u32 XMem_IsReady(XMem *InstancePtr);
void XMem_EnableAutoRestart(XMem *InstancePtr);
void XMem_DisableAutoRestart(XMem *InstancePtr);
void XMem_Set_axi_master(XMem *InstancePtr, u32 Data);
u32 XMem_Get_axi_master(XMem *InstancePtr);
u32 XMem_Get_value_r(XMem *InstancePtr);
u32 XMem_Get_value_r_vld(XMem *InstancePtr);
void XMem_InterruptGlobalEnable(XMem *InstancePtr);
void XMem_InterruptGlobalDisable(XMem *InstancePtr);
void XMem_InterruptEnable(XMem *InstancePtr, u32 Mask);
void XMem_InterruptDisable(XMem *InstancePtr, u32 Mask);
void XMem_InterruptClear(XMem *InstancePtr, u32 Mask);
u32 XMem_InterruptGetEnabled(XMem *InstancePtr);
u32 XMem_InterruptGetStatus(XMem *InstancePtr);
#ifdef __cplusplus
}
#endif
#endif
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2017.3
// Copyright (C) 1986-2017 Xilinx, Inc. All Rights Reserved.
//
// ==============================================================
// CTRL
// 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 axi_master
// bit 31~0 - axi_master[31:0] (Read/Write)
// 0x14 : reserved
// 0x18 : Data signal of value_r
// bit 31~0 - value_r[31:0] (Read)
// 0x1c : Control signal of value_r
// bit 0 - value_r_ap_vld (Read/COR)
// others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
#define XMEM_CTRL_ADDR_AP_CTRL 0x00
#define XMEM_CTRL_ADDR_GIE 0x04
#define XMEM_CTRL_ADDR_IER 0x08
#define XMEM_CTRL_ADDR_ISR 0x0c
#define XMEM_CTRL_ADDR_AXI_MASTER_DATA 0x10
#define XMEM_CTRL_BITS_AXI_MASTER_DATA 32
#define XMEM_CTRL_ADDR_VALUE_R_DATA 0x18
#define XMEM_CTRL_BITS_VALUE_R_DATA 32
#define XMEM_CTRL_ADDR_VALUE_R_CTRL 0x1c
......@@ -14,6 +14,9 @@ set(SOURCES
ips/dma.cpp
ips/bram.cpp
ips/hls-mem.cpp
ips/src/xmem.c
kernel/kernel.c
kernel/pci.c
kernel/vfio.cpp
......
#include <unistd.h>
#include <villas/memory_manager.hpp>
#include <villas/fpga/ips/hls-mem.hpp>
#include <villas/fpga/ips/xmem.h>
#include "log.hpp"
namespace villas {
namespace fpga {
namespace ip {
static HlsMemFactory factory;
bool HlsMem::init()
{
xmem.IsReady = XIL_COMPONENT_IS_READY;
xmem.Ctrl_BaseAddress = getBaseAddr(registerMemory);
return true;
}
bool HlsMem::testMemory(const MemoryBlock& mem)
{
static constexpr uint8_t testValue = 42;
auto& mm = MemoryManager::get();
auto translationFromXMem = mm.getTranslation(
getMasterAddrSpaceByInterface(axiInterface),
mem.getAddrSpaceId());
// set address of memory block in HLS IP
XMem_Set_axi_master(&xmem, translationFromXMem.getLocalAddr(0));
// prepare memory with a known value
auto translationFromProcess = mm.getTranslationFromProcess(mem.getAddrSpaceId());
auto memory = reinterpret_cast<volatile uint8_t*>(translationFromProcess.getLocalAddr(0));
memory[0] = testValue;
logger->debug("Memory before: {}", memory[0]);
// start and wait until it is done
XMem_Start(&xmem);
while(!XMem_IsDone(&xmem));
logger->debug("Memory after: {}", memory[0]);
const auto valueReadBack = XMem_Get_value_r(&xmem);
if(valueReadBack != testValue) {
logger->error("Read-back value is not equal to written value ({} != {})",
valueReadBack, testValue);
return false;
}
const auto currentMemoryValue = memory[0];
if(currentMemoryValue != 0x55) {
logger->error("Memory value should have been overwritten to 0x55, but it is {}",
currentMemoryValue);
return false;
}
return true;
}
HlsMemFactory::HlsMemFactory() :
IpCoreFactory(getName())
{
}
} // namespace ip
} // namespace fpga
} // namespace villas
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2017.3
// Copyright (C) 1986-2017 Xilinx, Inc. All Rights Reserved.
//
// ==============================================================
/***************************** Include Files *********************************/
#include <villas/fpga/ips/xmem.h>
/************************** Function Implementation *************************/
#ifndef __linux__
int XMem_CfgInitialize(XMem *InstancePtr, XMem_Config *ConfigPtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ConfigPtr != NULL);
InstancePtr->Ctrl_BaseAddress = ConfigPtr->Ctrl_BaseAddress;
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
return XST_SUCCESS;
}
#endif
void XMem_Start(XMem *InstancePtr) {
u32 Data;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL) & 0x80;
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL, Data | 0x01);
}
u32 XMem_IsDone(XMem *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL);
return (Data >> 1) & 0x1;
}
u32 XMem_IsIdle(XMem *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL);
return (Data >> 2) & 0x1;
}
u32 XMem_IsReady(XMem *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL);
// check ap_start to see if the pcore is ready for next input
return !(Data & 0x1);
}
void XMem_EnableAutoRestart(XMem *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL, 0x80);
}
void XMem_DisableAutoRestart(XMem *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AP_CTRL, 0);
}
void XMem_Set_axi_master(XMem *InstancePtr, u32 Data) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AXI_MASTER_DATA, Data);
}
u32 XMem_Get_axi_master(XMem *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_AXI_MASTER_DATA);
return Data;
}
u32 XMem_Get_value_r(XMem *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_VALUE_R_DATA);
return Data;
}
u32 XMem_Get_value_r_vld(XMem *InstancePtr) {
u32 Data;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Data = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_VALUE_R_CTRL);
return Data & 0x1;
}
void XMem_InterruptGlobalEnable(XMem *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_GIE, 1);
}
void XMem_InterruptGlobalDisable(XMem *InstancePtr) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_GIE, 0);
}
void XMem_InterruptEnable(XMem *InstancePtr, u32 Mask) {
u32 Register;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Register = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_IER);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_IER, Register | Mask);
}
void XMem_InterruptDisable(XMem *InstancePtr, u32 Mask) {
u32 Register;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Register = XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_IER);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_IER, Register & (~Mask));
}
void XMem_InterruptClear(XMem *InstancePtr, u32 Mask) {
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
XMem_WriteReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_ISR, Mask);
}
u32 XMem_InterruptGetEnabled(XMem *InstancePtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
return XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_IER);
}
u32 XMem_InterruptGetStatus(XMem *InstancePtr) {
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
return XMem_ReadReg(InstancePtr->Ctrl_BaseAddress, XMEM_CTRL_ADDR_ISR);
}
......@@ -35,7 +35,8 @@ whitelist = [
[ 'acs.eonerc.rwth-aachen.de', 'sysgen' ],
[ 'xilinx.com', 'ip', 'axi_gpio' ],
[ 'xilinx.com', 'ip', 'axi_bram_ctrl' ],
[ 'xilinx.com', 'ip', 'axi_pcie' ]
[ 'xilinx.com', 'ip', 'axi_pcie' ],
[ 'xilinx.com', 'hls', 'mem' ]
]
# List of VLNI ids of AXI4-Stream infrastructure IP cores which do not alter data
......
......@@ -4,6 +4,7 @@ set(SOURCES
logging.cpp
dma.cpp
fifo.cpp
hls-mem.cpp
# hls.c
# intc.c
# rtds_rtt.c
......
/** FIFO unit test.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Steffen Vogel
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <criterion/criterion.h>
#include <villas/log.hpp>
#include <villas/memory.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/ips/hls-mem.hpp>
#include "global.hpp"
Test(fpga, hls_mem, .description = "HlsMem")
{
auto logger = loggerGetOrCreate("unittest:hls-mem");
for(auto& ip : state.cards.front()->ips) {
if(*ip != villas::fpga::Vlnv("xilinx.com:hls:mem:"))
continue;
logger->info("Testing {}", *ip);
auto hlsMem = reinterpret_cast<villas::fpga::ip::HlsMem&>(*ip);
auto dmaMem = villas::HostDmaRam::getAllocator(0).allocate<char>(4);
cr_assert(hlsMem.testMemory(dmaMem.getMemoryBlock()), "Testing HlsMem failed");
logger->info(TXT_GREEN("Passed"));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment