From bf286568dda73a1bb69fa4770030387e046aa487 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 23 May 2018 20:04:10 +0200 Subject: [PATCH 01/20] rtds2gpu IP works --- fpga/etc/fpga.json | 127 +++++++--- fpga/include/villas/fpga/ips/dma.hpp | 3 + fpga/include/villas/fpga/ips/rtds2gpu.hpp | 59 +++++ .../villas/fpga/ips/rtds2gpu/xrtds2gpu.h | 114 +++++++++ .../villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h | 63 +++++ fpga/lib/CMakeLists.txt | 3 + fpga/lib/ips/dma.cpp | 4 +- fpga/lib/ips/rtds2gpu/rtds2gpu.cpp | 87 +++++++ fpga/lib/ips/rtds2gpu/xrtds2gpu.c | 228 ++++++++++++++++++ fpga/scripts/hwdef-parse.py | 4 +- fpga/tests/CMakeLists.txt | 1 + fpga/tests/rtds2gpu.cpp | 109 +++++++++ 12 files changed, 767 insertions(+), 35 deletions(-) create mode 100644 fpga/include/villas/fpga/ips/rtds2gpu.hpp create mode 100644 fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h create mode 100644 fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h create mode 100644 fpga/lib/ips/rtds2gpu/rtds2gpu.cpp create mode 100644 fpga/lib/ips/rtds2gpu/xrtds2gpu.c create mode 100644 fpga/tests/rtds2gpu.cpp diff --git a/fpga/etc/fpga.json b/fpga/etc/fpga.json index 5f982e2a8..dbf7aaa6f 100644 --- a/fpga/etc/fpga.json +++ b/fpga/etc/fpga.json @@ -33,14 +33,25 @@ "hier_0_axi_dma_axi_dma_0": { "vlnv": "xilinx.com:ip:axi_dma:7.1", "memory-view": { - "M_AXI_SG": { - "bram_0_axi_bram_ctrl_0": { - "Mem0": { + "M_AXI_MM2S": { + "pcie_0_axi_pcie_0": { + "BAR0": { "baseaddr": 0, - "highaddr": 8191, - "size": 8192 + "highaddr": 4294967295, + "size": 4294967296 } - }, + } + }, + "M_AXI_S2MM": { + "pcie_0_axi_pcie_0": { + "BAR0": { + "baseaddr": 0, + "highaddr": 4294967295, + "size": 4294967296 + } + } + }, + "M_AXI_SG": { "hier_0_axi_dma_axi_dma_1": { "Reg": { "baseaddr": 8192, @@ -109,6 +120,27 @@ "size": 4096 } }, + "mem_0": { + "Reg": { + "baseaddr": 57344, + "highaddr": 61439, + "size": 4096 + } + }, + "rtds2gpu_0": { + "Reg": { + "baseaddr": 61440, + "highaddr": 65535, + "size": 4096 + } + }, + "bram_0_axi_bram_ctrl_0": { + "Mem0": { + "baseaddr": 65536, + "highaddr": 73727, + "size": 8192 + } + }, "pcie_0_axi_pcie_0": { "CTL0": { "baseaddr": 268435456, @@ -116,24 +148,6 @@ "size": 268435456 } } - }, - "M_AXI_MM2S": { - "pcie_0_axi_pcie_0": { - "BAR0": { - "baseaddr": 0, - "highaddr": 4294967295, - "size": 4294967296 - } - } - }, - "M_AXI_S2MM": { - "pcie_0_axi_pcie_0": { - "BAR0": { - "baseaddr": 0, - "highaddr": 4294967295, - "size": 4294967296 - } - } } }, "ports": [ @@ -234,7 +248,7 @@ "name": "S04_AXIS" } ], - "num_ports": 7 + "num_ports": 8 }, "hier_0_hls_dft_0": { "vlnv": "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.1", @@ -274,17 +288,24 @@ "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": { "M_AXI": { - "bram_0_axi_bram_ctrl_0": { - "Mem0": { - "baseaddr": 0, - "highaddr": 8191, - "size": 8192 - } - }, "hier_0_axi_dma_axi_dma_1": { "Reg": { "baseaddr": 8192, @@ -353,6 +374,27 @@ "size": 4096 } }, + "mem_0": { + "Reg": { + "baseaddr": 57344, + "highaddr": 61439, + "size": 4096 + } + }, + "rtds2gpu_0": { + "Reg": { + "baseaddr": 61440, + "highaddr": 65535, + "size": 4096 + } + }, + "bram_0_axi_bram_ctrl_0": { + "Mem0": { + "baseaddr": 65536, + "highaddr": 73727, + "size": 8192 + } + }, "pcie_0_axi_pcie_0": { "CTL0": { "baseaddr": 268435456, @@ -382,6 +424,27 @@ "pcie_0_axi_reset_0": { "vlnv": "xilinx.com:ip:axi_gpio:2.0" }, + "rtds2gpu_0": { + "vlnv": "xilinx.com:hls:rtds2gpu:1.0", + "memory-view": { + "m_axi_axi_mm": { + "pcie_0_axi_pcie_0": { + "BAR0": { + "baseaddr": 0, + "highaddr": 4294967295, + "size": 4294967296 + } + } + } + }, + "ports": [ + { + "role": "slave", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:7", + "name": "rtds_input" + } + ] + }, "timer_0_axi_timer_0": { "vlnv": "xilinx.com:ip:axi_timer:2.0", "irqs": { diff --git a/fpga/include/villas/fpga/ips/dma.hpp b/fpga/include/villas/fpga/ips/dma.hpp index 963c20cda..12cf0236a 100644 --- a/fpga/include/villas/fpga/ips/dma.hpp +++ b/fpga/include/villas/fpga/ips/dma.hpp @@ -43,7 +43,10 @@ public: bool init(); bool reset(); + // memory-mapped to stream (MM2S) bool write(const MemoryBlock& mem, size_t len); + + // stream to memory-mapped (S2MM) bool read(const MemoryBlock& mem, size_t len); size_t writeComplete() diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp new file mode 100644 index 000000000..bcca8c069 --- /dev/null +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include "rtds2gpu/xrtds2gpu.h" + +namespace villas { +namespace fpga { +namespace ip { + + +class Rtds2Gpu : public IpNode +{ +public: + friend class Rtds2GpuFactory; + + bool init(); + + void dump(); + + bool startOnce(const MemoryBlock& mem, size_t frameSize); + + bool isDone(); + +private: + static constexpr const char* registerMemory = "Reg"; + static constexpr const char* axiInterface = "m_axi_axi_mm"; + static constexpr const char* streamInterface = "rtds_input"; + + std::list getMemoryBlocks() const + { return { registerMemory }; } + + XRtds2gpu xInstance; +}; + + +class Rtds2GpuFactory : public IpNodeFactory { +public: + Rtds2GpuFactory(); + + IpCore* create() + { return new Rtds2Gpu; } + + std::string + getName() const + { return "Rtds2Gpu"; } + + std::string + getDescription() const + { return "HLS RTDS2GPU IP"; } + + Vlnv getCompatibleVlnv() const + { return {"xilinx.com:hls:rtds2gpu:"}; } +}; + +} // namespace ip +} // namespace fpga +} // namespace villas diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h new file mode 100644 index 000000000..38770aadb --- /dev/null +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h @@ -0,0 +1,114 @@ +// ============================================================== +// 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 XRTDS2GPU_H +#define XRTDS2GPU_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include "xrtds2gpu_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; +} XRtds2gpu_Config; +#endif + +typedef struct { + u32 Ctrl_BaseAddress; + u32 IsReady; +} XRtds2gpu; + +/***************** Macros (Inline Functions) Definitions *********************/ +#ifndef __linux__ +#define XRtds2gpu_WriteReg(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) +#define XRtds2gpu_ReadReg(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) +#else +#define XRtds2gpu_WriteReg(BaseAddress, RegOffset, Data) \ + *(volatile u32*)((BaseAddress) + (RegOffset)) = (u32)(Data) +#define XRtds2gpu_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 XRtds2gpu_Initialize(XRtds2gpu *InstancePtr, u16 DeviceId); +XRtds2gpu_Config* XRtds2gpu_LookupConfig(u16 DeviceId); +int XRtds2gpu_CfgInitialize(XRtds2gpu *InstancePtr, XRtds2gpu_Config *ConfigPtr); +#else +int XRtds2gpu_Initialize(XRtds2gpu *InstancePtr, const char* InstanceName); +int XRtds2gpu_Release(XRtds2gpu *InstancePtr); +#endif + +void XRtds2gpu_Start(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_IsDone(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_IsIdle(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_IsReady(XRtds2gpu *InstancePtr); +void XRtds2gpu_EnableAutoRestart(XRtds2gpu *InstancePtr); +void XRtds2gpu_DisableAutoRestart(XRtds2gpu *InstancePtr); + +void XRtds2gpu_Set_baseaddr(XRtds2gpu *InstancePtr, u32 Data); +u32 XRtds2gpu_Get_baseaddr(XRtds2gpu *InstancePtr); +void XRtds2gpu_Set_data_offset(XRtds2gpu *InstancePtr, u32 Data); +u32 XRtds2gpu_Get_data_offset(XRtds2gpu *InstancePtr); +void XRtds2gpu_Set_doorbell_offset(XRtds2gpu *InstancePtr, u32 Data); +u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr); +void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data); +u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr); +void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data); +u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr); + +void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr); +void XRtds2gpu_InterruptGlobalDisable(XRtds2gpu *InstancePtr); +void XRtds2gpu_InterruptEnable(XRtds2gpu *InstancePtr, u32 Mask); +void XRtds2gpu_InterruptDisable(XRtds2gpu *InstancePtr, u32 Mask); +void XRtds2gpu_InterruptClear(XRtds2gpu *InstancePtr, u32 Mask); +u32 XRtds2gpu_InterruptGetEnabled(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_InterruptGetStatus(XRtds2gpu *InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h new file mode 100644 index 000000000..198963c7e --- /dev/null +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h @@ -0,0 +1,63 @@ +// ============================================================== +// 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 baseaddr +// bit 31~0 - baseaddr[31:0] (Read/Write) +// 0x14 : reserved +// 0x18 : Data signal of data_offset +// bit 31~0 - data_offset[31:0] (Read/Write) +// 0x1c : reserved +// 0x20 : Data signal of doorbell_offset +// bit 31~0 - doorbell_offset[31:0] (Read/Write) +// 0x24 : reserved +// 0x28 : Data signal of status_i +// bit 31~0 - status_i[31:0] (Read/Write) +// 0x2c : reserved +// 0x30 : Data signal of status_o +// bit 31~0 - status_o[31:0] (Read) +// 0x34 : reserved +// 0x38 : Data signal of frame_size +// bit 31~0 - frame_size[31:0] (Read/Write) +// 0x3c : reserved +// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake) + +#define XRTDS2GPU_CTRL_ADDR_AP_CTRL 0x00 +#define XRTDS2GPU_CTRL_ADDR_GIE 0x04 +#define XRTDS2GPU_CTRL_ADDR_IER 0x08 +#define XRTDS2GPU_CTRL_ADDR_ISR 0x0c +#define XRTDS2GPU_CTRL_ADDR_BASEADDR_DATA 0x10 +#define XRTDS2GPU_CTRL_BITS_BASEADDR_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_DATA_OFFSET_DATA 0x18 +#define XRTDS2GPU_CTRL_BITS_DATA_OFFSET_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_DOORBELL_OFFSET_DATA 0x20 +#define XRTDS2GPU_CTRL_BITS_DOORBELL_OFFSET_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA 0x28 +#define XRTDS2GPU_CTRL_BITS_STATUS_I_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_STATUS_O_DATA 0x30 +#define XRTDS2GPU_CTRL_BITS_STATUS_O_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA 0x38 +#define XRTDS2GPU_CTRL_BITS_FRAME_SIZE_DATA 32 + diff --git a/fpga/lib/CMakeLists.txt b/fpga/lib/CMakeLists.txt index eea93a1c9..10165cdd0 100644 --- a/fpga/lib/CMakeLists.txt +++ b/fpga/lib/CMakeLists.txt @@ -15,6 +15,9 @@ set(SOURCES ips/bram.cpp ips/rtds.cpp + ips/rtds2gpu/rtds2gpu.cpp + ips/rtds2gpu/xrtds2gpu.c + kernel/kernel.c kernel/pci.c kernel/vfio.cpp diff --git a/fpga/lib/ips/dma.cpp b/fpga/lib/ips/dma.cpp index 3d8f9a3b6..7408461df 100644 --- a/fpga/lib/ips/dma.cpp +++ b/fpga/lib/ips/dma.cpp @@ -165,7 +165,7 @@ Dma::write(const MemoryBlock& mem, size_t len) mem.getAddrSpaceId()); const void* buf = reinterpret_cast(translation.getLocalAddr(0)); - logger->debug("Write to address: {:p}", buf); + logger->debug("Write to stream from address {:p}", buf); return hasScatterGather() ? writeSG(buf, len) : writeSimple(buf, len); } @@ -180,7 +180,7 @@ Dma::read(const MemoryBlock& mem, size_t len) mem.getAddrSpaceId()); void* buf = reinterpret_cast(translation.getLocalAddr(0)); - logger->debug("Read from address: {:p}", buf); + logger->debug("Read from stream and write to address {:p}", buf); return hasScatterGather() ? readSG(buf, len) : readSimple(buf, len); } diff --git a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp new file mode 100644 index 000000000..50bb34c90 --- /dev/null +++ b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp @@ -0,0 +1,87 @@ +#include +#include + +#include +#include + +#include "log.hpp" + +namespace villas { +namespace fpga { +namespace ip { + +static Rtds2GpuFactory factory; + +bool Rtds2Gpu::init() +{ + xInstance.IsReady = XIL_COMPONENT_IS_READY; + xInstance.Ctrl_BaseAddress = getBaseAddr(registerMemory); + + // make sure IP is stopped for now + XRtds2gpu_DisableAutoRestart(&xInstance); + + dump(); + + return true; +} + +void Rtds2Gpu::dump() +{ + const auto baseaddr = XRtds2gpu_Get_baseaddr(&xInstance); + const auto data_offset = XRtds2gpu_Get_data_offset(&xInstance); + const auto doorbell_offset = XRtds2gpu_Get_doorbell_offset(&xInstance); + const auto frame_size = XRtds2gpu_Get_frame_size(&xInstance); + const auto status = XRtds2gpu_Get_status_o(&xInstance); + + logger->debug("Rtds2Gpu registers (IP base {:#x}):", xInstance.Ctrl_BaseAddress); + logger->debug(" Base address (bytes): {:#x}", baseaddr); + logger->debug(" Doorbell offset (bytes): {:#x}", doorbell_offset); + logger->debug(" Data offset (bytes): {:#x}", data_offset); + logger->debug(" Frame size (words): {:#x}", frame_size); + logger->debug(" Status: {:#x}", status); +} + +bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize) +{ + auto& mm = MemoryManager::get(); + + auto translationFromIp = mm.getTranslation( + getMasterAddrSpaceByInterface(axiInterface), + mem.getAddrSpaceId()); + + // make sure IP is stopped for now + XRtds2gpu_DisableAutoRestart(&xInstance); +// while(not XRtds2gpu_IsIdle(&xInstance) and not XRtds2gpu_IsDone(&xInstance)); + + // set address of memory block in HLS IP + XRtds2gpu_Set_baseaddr(&xInstance, translationFromIp.getLocalAddr(0)); + + XRtds2gpu_Set_doorbell_offset(&xInstance, 0); + XRtds2gpu_Set_data_offset(&xInstance, 4); + XRtds2gpu_Set_frame_size(&xInstance, frameSize); + + // prepare memory with all zeroes + auto translationFromProcess = mm.getTranslationFromProcess(mem.getAddrSpaceId()); + auto memory = reinterpret_cast(translationFromProcess.getLocalAddr(0)); + memset(memory, 0, mem.getSize()); + + // start IP +// XRtds2gpu_EnableAutoRestart(&xInstance); + XRtds2gpu_Start(&xInstance); + + return true; +} + +bool Rtds2Gpu::isDone() +{ + return XRtds2gpu_IsDone(&xInstance); +} + +Rtds2GpuFactory::Rtds2GpuFactory() : + IpNodeFactory(getName()) +{ +} + +} // namespace ip +} // namespace fpga +} // namespace villas diff --git a/fpga/lib/ips/rtds2gpu/xrtds2gpu.c b/fpga/lib/ips/rtds2gpu/xrtds2gpu.c new file mode 100644 index 000000000..f7f1dadb6 --- /dev/null +++ b/fpga/lib/ips/rtds2gpu/xrtds2gpu.c @@ -0,0 +1,228 @@ +// ============================================================== +// 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 + +/************************** Function Implementation *************************/ +#ifndef __linux__ +int XRtds2gpu_CfgInitialize(XRtds2gpu *InstancePtr, XRtds2gpu_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 XRtds2gpu_Start(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL) & 0x80; + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL, Data | 0x01); +} + +u32 XRtds2gpu_IsDone(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL); + return (Data >> 1) & 0x1; +} + +u32 XRtds2gpu_IsIdle(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL); + return (Data >> 2) & 0x1; +} + +u32 XRtds2gpu_IsReady(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL); + // check ap_start to see if the pcore is ready for next input + return !(Data & 0x1); +} + +void XRtds2gpu_EnableAutoRestart(XRtds2gpu *InstancePtr) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL, 0x80); +} + +void XRtds2gpu_DisableAutoRestart(XRtds2gpu *InstancePtr) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_AP_CTRL, 0); +} + +void XRtds2gpu_Set_baseaddr(XRtds2gpu *InstancePtr, u32 Data) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_BASEADDR_DATA, Data); +} + +u32 XRtds2gpu_Get_baseaddr(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_BASEADDR_DATA); + return Data; +} + +void XRtds2gpu_Set_data_offset(XRtds2gpu *InstancePtr, u32 Data) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_DATA_OFFSET_DATA, Data); +} + +u32 XRtds2gpu_Get_data_offset(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_DATA_OFFSET_DATA); + return Data; +} + +void XRtds2gpu_Set_doorbell_offset(XRtds2gpu *InstancePtr, u32 Data) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_DOORBELL_OFFSET_DATA, Data); +} + +u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_DOORBELL_OFFSET_DATA); + return Data; +} + +void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA, Data); +} + +u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA); + return Data; +} + +u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_O_DATA); + return Data; +} + +void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA, Data); +} + +u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA); + return Data; +} + +void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_GIE, 1); +} + +void XRtds2gpu_InterruptGlobalDisable(XRtds2gpu *InstancePtr) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_GIE, 0); +} + +void XRtds2gpu_InterruptEnable(XRtds2gpu *InstancePtr, u32 Mask) { + u32 Register; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Register = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_IER); + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_IER, Register | Mask); +} + +void XRtds2gpu_InterruptDisable(XRtds2gpu *InstancePtr, u32 Mask) { + u32 Register; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Register = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_IER); + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_IER, Register & (~Mask)); +} + +void XRtds2gpu_InterruptClear(XRtds2gpu *InstancePtr, u32 Mask) { + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_ISR, Mask); +} + +u32 XRtds2gpu_InterruptGetEnabled(XRtds2gpu *InstancePtr) { + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + return XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_IER); +} + +u32 XRtds2gpu_InterruptGetStatus(XRtds2gpu *InstancePtr) { + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + return XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_ISR); +} + diff --git a/fpga/scripts/hwdef-parse.py b/fpga/scripts/hwdef-parse.py index 09abe905a..d93cd77af 100755 --- a/fpga/scripts/hwdef-parse.py +++ b/fpga/scripts/hwdef-parse.py @@ -36,7 +36,9 @@ whitelist = [ [ 'xilinx.com', 'ip', 'axi_gpio' ], [ 'xilinx.com', 'ip', 'axi_bram_ctrl' ], [ 'xilinx.com', 'ip', 'axis_data_fifo' ], - [ 'xilinx.com', 'ip', 'axi_pcie' ] + [ 'xilinx.com', 'ip', 'axi_pcie' ], + [ 'xilinx.com', 'hls', 'rtds2gpu' ], + [ 'xilinx.com', 'hls', 'mem' ] ] # List of VLNI ids of AXI4-Stream infrastructure IP cores which do not alter data diff --git a/fpga/tests/CMakeLists.txt b/fpga/tests/CMakeLists.txt index 00d80dcfa..6eb34491a 100644 --- a/fpga/tests/CMakeLists.txt +++ b/fpga/tests/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES dma.cpp fifo.cpp rtds.cpp + rtds2gpu.cpp timer.cpp graph.cpp ) diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp new file mode 100644 index 000000000..adc2603ae --- /dev/null +++ b/fpga/tests/rtds2gpu.cpp @@ -0,0 +1,109 @@ +/** FIFO unit test. + * + * @file + * @author Steffen Vogel + * @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 . + *********************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "global.hpp" + + +static constexpr size_t SAMPLE_SIZE = 4; +static constexpr size_t SAMPLE_COUNT = 8; +static constexpr size_t FRAME_SIZE = SAMPLE_COUNT * SAMPLE_SIZE; + + +Test(fpga, rtds2gpu, .description = "Rtds2Gpu") +{ + auto logger = loggerGetOrCreate("unittest:rtds2gpu"); + + for(auto& ip : state.cards.front()->ips) { + if(*ip != villas::fpga::Vlnv("xilinx.com:hls:rtds2gpu:")) + continue; + + logger->info("Testing {}", *ip); + + auto rtds2gpu = reinterpret_cast(*ip); + + auto dmaMem0 = villas::HostDmaRam::getAllocator(0).allocate(FRAME_SIZE + 4); + auto dmaMem1 = villas::HostDmaRam::getAllocator(0).allocate(FRAME_SIZE + 4); + +// continue; + + + + auto axiSwitch = reinterpret_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:"))); + cr_assert_not_null(axiSwitch); + + auto dma = reinterpret_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axi_dma:"))); + cr_assert_not_null(dma); + + memset(&dmaMem0, 0x55, dmaMem0.getMemoryBlock().getSize()); + memset(&dmaMem1, 0x11, dmaMem1.getMemoryBlock().getSize()); + + puts("Before:"); + for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) { + printf("0x%02x ", dmaMem0[i]); + } + puts(""); + + rtds2gpu.dump(); + + cr_assert(axiSwitch->connect(7, 6)); + cr_assert(axiSwitch->connect(6, 7)); + + + + cr_assert(rtds2gpu.startOnce(dmaMem0.getMemoryBlock(), SAMPLE_COUNT), + "Preparing Rtds2Gpu IP failed"); + + cr_assert(dma->write(dmaMem1.getMemoryBlock(), FRAME_SIZE)); + +// cr_assert(axiSwitch->connect(6, 6)); // loopback +// cr_assert(dma->read(dmaMem1.getMemoryBlock(), FRAME_SIZE)); +// cr_assert(dma->readComplete()); + + cr_assert(dma->writeComplete()); + + puts("After:"); + for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) { + printf("0x%02x ", dmaMem0[i]); + } + puts(""); + + + rtds2gpu.dump(); + + cr_assert(rtds2gpu.isDone()); + + logger->info(TXT_GREEN("Passed")); + } +} From 28458fdf8a00cded997f3b9a0f18440b950bcdab Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Tue, 29 May 2018 12:28:09 +0200 Subject: [PATCH 02/20] update rtds2gpu HLS IP to v1.1 - better tested IP (testbenches) - detect invalid frame sizes - more status reporting --- fpga/include/villas/fpga/ips/rtds2gpu.hpp | 23 +++- .../fpga/ips/rtds2gpu/register_types.hpp | 30 +++++ .../villas/fpga/ips/rtds2gpu/xrtds2gpu.h | 5 +- .../villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h | 24 ++-- fpga/lib/CMakeLists.txt | 4 + fpga/lib/ips/rtds2gpu/rtds2gpu.cpp | 106 ++++++++++++++---- fpga/lib/ips/rtds2gpu/xrtds2gpu.c | 47 ++++---- fpga/tests/rtds2gpu.cpp | 70 ++++++------ 8 files changed, 207 insertions(+), 102 deletions(-) create mode 100644 fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index bcca8c069..2867b28de 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -4,6 +4,7 @@ #include #include "rtds2gpu/xrtds2gpu.h" +#include "rtds2gpu/register_types.hpp" namespace villas { namespace fpga { @@ -17,11 +18,22 @@ public: bool init(); - void dump(); + bool start(); - bool startOnce(const MemoryBlock& mem, size_t frameSize); + void dump(spdlog::level::level_enum logLevel = spdlog::level::info); - bool isDone(); + bool startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOffset, size_t doorbellOffset); + + bool isFinished(); + + bool isReady(); + + size_t getMaxFrameSize(); + + void dumpDoorbell(uint32_t doorbellRegister) const; + +private: + bool updateStatus(); private: static constexpr const char* registerMemory = "Reg"; @@ -32,6 +44,11 @@ private: { return { registerMemory }; } XRtds2gpu xInstance; + + axilite_reg_status_t status; + size_t maxFrameSize; + + bool started; }; diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp new file mode 100644 index 000000000..b59a297c9 --- /dev/null +++ b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp @@ -0,0 +1,30 @@ +#ifndef REGISTER_TYPES_H +#define REGISTER_TYPES_H + +#include + +union axilite_reg_status_t { + uint32_t value; + struct { + uint32_t + last_seq_nr : 16, + last_count : 6, + max_frame_size : 6, + invalid_frame_size : 1, + frame_too_short : 1, + frame_too_long : 1, + is_running : 1; + }; +}; + +union reg_doorbell_t { + uint32_t value; + struct { + uint32_t + seq_nr : 16, + count : 6, + is_valid : 1; + }; +}; + +#endif // REGISTER_TYPES_H diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h index 38770aadb..87cb2b70a 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu.h @@ -93,11 +93,10 @@ void XRtds2gpu_Set_data_offset(XRtds2gpu *InstancePtr, u32 Data); u32 XRtds2gpu_Get_data_offset(XRtds2gpu *InstancePtr); void XRtds2gpu_Set_doorbell_offset(XRtds2gpu *InstancePtr, u32 Data); u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr); -void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data); -u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr); -u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr); void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data); u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_Get_status(XRtds2gpu *InstancePtr); +u32 XRtds2gpu_Get_status_vld(XRtds2gpu *InstancePtr); void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr); void XRtds2gpu_InterruptGlobalDisable(XRtds2gpu *InstancePtr); diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h index 198963c7e..73bf1bce2 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xrtds2gpu_hw.h @@ -33,15 +33,14 @@ // 0x20 : Data signal of doorbell_offset // bit 31~0 - doorbell_offset[31:0] (Read/Write) // 0x24 : reserved -// 0x28 : Data signal of status_i -// bit 31~0 - status_i[31:0] (Read/Write) -// 0x2c : reserved -// 0x30 : Data signal of status_o -// bit 31~0 - status_o[31:0] (Read) -// 0x34 : reserved -// 0x38 : Data signal of frame_size +// 0x28 : Data signal of frame_size // bit 31~0 - frame_size[31:0] (Read/Write) -// 0x3c : reserved +// 0x2c : reserved +// 0x30 : Data signal of status +// bit 31~0 - status[31:0] (Read) +// 0x34 : Control signal of status +// bit 0 - status_ap_vld (Read/COR) +// others - reserved // (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake) #define XRTDS2GPU_CTRL_ADDR_AP_CTRL 0x00 @@ -54,10 +53,9 @@ #define XRTDS2GPU_CTRL_BITS_DATA_OFFSET_DATA 32 #define XRTDS2GPU_CTRL_ADDR_DOORBELL_OFFSET_DATA 0x20 #define XRTDS2GPU_CTRL_BITS_DOORBELL_OFFSET_DATA 32 -#define XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA 0x28 -#define XRTDS2GPU_CTRL_BITS_STATUS_I_DATA 32 -#define XRTDS2GPU_CTRL_ADDR_STATUS_O_DATA 0x30 -#define XRTDS2GPU_CTRL_BITS_STATUS_O_DATA 32 -#define XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA 0x38 +#define XRTDS2GPU_CTRL_ADDR_FRAME_SIZE_DATA 0x28 #define XRTDS2GPU_CTRL_BITS_FRAME_SIZE_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_STATUS_DATA 0x30 +#define XRTDS2GPU_CTRL_BITS_STATUS_DATA 32 +#define XRTDS2GPU_CTRL_ADDR_STATUS_CTRL 0x34 diff --git a/fpga/lib/CMakeLists.txt b/fpga/lib/CMakeLists.txt index 10165cdd0..7159a63a9 100644 --- a/fpga/lib/CMakeLists.txt +++ b/fpga/lib/CMakeLists.txt @@ -29,6 +29,10 @@ set(SOURCES log_helper.c ) +# we don't have much influence on drivers generated by Xilinx, so ignore warnings +set_source_files_properties(ips/rtds2gpu/xrtds2gpu.c + PROPERTIES COMPILE_FLAGS -Wno-int-to-pointer-cast) + include(FindPkgConfig) pkg_check_modules(JANSSON jansson) diff --git a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp index 50bb34c90..b9ce32d13 100644 --- a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp +++ b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp @@ -20,44 +20,64 @@ bool Rtds2Gpu::init() // make sure IP is stopped for now XRtds2gpu_DisableAutoRestart(&xInstance); - dump(); + status.value = 0; + started = false; + + maxFrameSize = getMaxFrameSize(); + logger->info("Max. frame size supported: {}", maxFrameSize); return true; } -void Rtds2Gpu::dump() +bool Rtds2Gpu::start() +{ + XRtds2gpu_Start(&xInstance); + started = true; + + return true; +} + +void Rtds2Gpu::dump(spdlog::level::level_enum logLevel) { const auto baseaddr = XRtds2gpu_Get_baseaddr(&xInstance); const auto data_offset = XRtds2gpu_Get_data_offset(&xInstance); const auto doorbell_offset = XRtds2gpu_Get_doorbell_offset(&xInstance); const auto frame_size = XRtds2gpu_Get_frame_size(&xInstance); - const auto status = XRtds2gpu_Get_status_o(&xInstance); - logger->debug("Rtds2Gpu registers (IP base {:#x}):", xInstance.Ctrl_BaseAddress); - logger->debug(" Base address (bytes): {:#x}", baseaddr); - logger->debug(" Doorbell offset (bytes): {:#x}", doorbell_offset); - logger->debug(" Data offset (bytes): {:#x}", data_offset); - logger->debug(" Frame size (words): {:#x}", frame_size); - logger->debug(" Status: {:#x}", status); + logger->log(logLevel, "Rtds2Gpu registers (IP base {:#x}):", xInstance.Ctrl_BaseAddress); + logger->log(logLevel, " Base address (bytes): {:#x}", baseaddr); + logger->log(logLevel, " Doorbell offset (bytes): {:#x}", doorbell_offset); + logger->log(logLevel, " Data offset (bytes): {:#x}", data_offset); + logger->log(logLevel, " Frame size (words): {:#x}", frame_size); + logger->log(logLevel, " Status: {:#x}", status.value); + logger->log(logLevel, " Running: {}", (status.is_running ? "yes" : "no")); + logger->log(logLevel, " Frame too short: {}", (status.frame_too_short ? "yes" : "no")); + logger->log(logLevel, " Frame too long: {}", (status.frame_too_long ? "yes" : "no")); + logger->log(logLevel, " Frame size invalid: {}", (status.invalid_frame_size ? "yes" : "no")); + logger->log(logLevel, " Last count: {}", status.last_count); + logger->log(logLevel, " Last seq. number: {}", status.last_seq_nr); + logger->log(logLevel, " Max. frame size: {}", status.max_frame_size); } -bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize) +bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOffset, size_t doorbellOffset) { auto& mm = MemoryManager::get(); + if(frameSize > maxFrameSize) { + logger->error("Requested frame size of {} exceeds max. frame size of {}", + frameSize, maxFrameSize); + return false; + } + auto translationFromIp = mm.getTranslation( getMasterAddrSpaceByInterface(axiInterface), mem.getAddrSpaceId()); - // make sure IP is stopped for now - XRtds2gpu_DisableAutoRestart(&xInstance); -// while(not XRtds2gpu_IsIdle(&xInstance) and not XRtds2gpu_IsDone(&xInstance)); - // set address of memory block in HLS IP XRtds2gpu_Set_baseaddr(&xInstance, translationFromIp.getLocalAddr(0)); - XRtds2gpu_Set_doorbell_offset(&xInstance, 0); - XRtds2gpu_Set_data_offset(&xInstance, 4); + XRtds2gpu_Set_doorbell_offset(&xInstance, doorbellOffset); + XRtds2gpu_Set_data_offset(&xInstance, dataOffset); XRtds2gpu_Set_frame_size(&xInstance, frameSize); // prepare memory with all zeroes @@ -66,15 +86,61 @@ bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize) memset(memory, 0, mem.getSize()); // start IP -// XRtds2gpu_EnableAutoRestart(&xInstance); - XRtds2gpu_Start(&xInstance); + return start(); +} + +bool Rtds2Gpu::isFinished() +{ + if(started and isReady()) { + started = false; + + if(not updateStatus()) { + throw "IP is finished but status register invalid"; + } + } + + return !started; +} + +bool +Rtds2Gpu::isReady() +{ + // use the idle bit to indicate readiness, we don't care about the difference + // here + return XRtds2gpu_IsIdle(&xInstance); +} + +bool +Rtds2Gpu::updateStatus() +{ + if(not XRtds2gpu_Get_status_vld(&xInstance)) + return false; + + status.value = XRtds2gpu_Get_status(&xInstance); return true; } -bool Rtds2Gpu::isDone() +size_t +Rtds2Gpu::getMaxFrameSize() { - return XRtds2gpu_IsDone(&xInstance); + XRtds2gpu_Set_frame_size(&xInstance, 0); + + start(); + while(not isFinished()); + + return status.max_frame_size; +} + +void +Rtds2Gpu::dumpDoorbell(uint32_t doorbellRegister) const +{ + auto& doorbell = reinterpret_cast(doorbellRegister); + + logger->info("Doorbell register: {:#08x}", doorbell.value); + logger->info(" Valid: {}", (doorbell.is_valid ? "yes" : "no")); + logger->info(" Count: {}", doorbell.count); + logger->info(" Seq. number: {}", doorbell.seq_nr); } Rtds2GpuFactory::Rtds2GpuFactory() : diff --git a/fpga/lib/ips/rtds2gpu/xrtds2gpu.c b/fpga/lib/ips/rtds2gpu/xrtds2gpu.c index f7f1dadb6..26a5e4f34 100644 --- a/fpga/lib/ips/rtds2gpu/xrtds2gpu.c +++ b/fpga/lib/ips/rtds2gpu/xrtds2gpu.c @@ -127,33 +127,6 @@ u32 XRtds2gpu_Get_doorbell_offset(XRtds2gpu *InstancePtr) { return Data; } -void XRtds2gpu_Set_status_i(XRtds2gpu *InstancePtr, u32 Data) { - Xil_AssertVoid(InstancePtr != NULL); - Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); - - XRtds2gpu_WriteReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA, Data); -} - -u32 XRtds2gpu_Get_status_i(XRtds2gpu *InstancePtr) { - u32 Data; - - Xil_AssertNonvoid(InstancePtr != NULL); - Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); - - Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_I_DATA); - return Data; -} - -u32 XRtds2gpu_Get_status_o(XRtds2gpu *InstancePtr) { - u32 Data; - - Xil_AssertNonvoid(InstancePtr != NULL); - Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); - - Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_O_DATA); - return Data; -} - void XRtds2gpu_Set_frame_size(XRtds2gpu *InstancePtr, u32 Data) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); @@ -171,6 +144,26 @@ u32 XRtds2gpu_Get_frame_size(XRtds2gpu *InstancePtr) { return Data; } +u32 XRtds2gpu_Get_status(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_DATA); + return Data; +} + +u32 XRtds2gpu_Get_status_vld(XRtds2gpu *InstancePtr) { + u32 Data; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Data = XRtds2gpu_ReadReg(InstancePtr->Ctrl_BaseAddress, XRTDS2GPU_CTRL_ADDR_STATUS_CTRL); + return Data & 0x1; +} + void XRtds2gpu_InterruptGlobalEnable(XRtds2gpu *InstancePtr) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index adc2603ae..a9bfe8400 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -35,9 +35,12 @@ static constexpr size_t SAMPLE_SIZE = 4; -static constexpr size_t SAMPLE_COUNT = 8; +static constexpr size_t SAMPLE_COUNT = 16; static constexpr size_t FRAME_SIZE = SAMPLE_COUNT * SAMPLE_SIZE; +static constexpr size_t DOORBELL_OFFSET = SAMPLE_COUNT; +static constexpr size_t DATA_OFFSET = 0; + Test(fpga, rtds2gpu, .description = "Rtds2Gpu") { @@ -49,60 +52,55 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") logger->info("Testing {}", *ip); + + /* Collect neccessary IPs */ + auto rtds2gpu = reinterpret_cast(*ip); - auto dmaMem0 = villas::HostDmaRam::getAllocator(0).allocate(FRAME_SIZE + 4); - auto dmaMem1 = villas::HostDmaRam::getAllocator(0).allocate(FRAME_SIZE + 4); - -// continue; - - - auto axiSwitch = reinterpret_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:"))); - cr_assert_not_null(axiSwitch); auto dma = reinterpret_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axi_dma:"))); - cr_assert_not_null(dma); - memset(&dmaMem0, 0x55, dmaMem0.getMemoryBlock().getSize()); - memset(&dmaMem1, 0x11, dmaMem1.getMemoryBlock().getSize()); + rtds2gpu.dump(spdlog::level::debug); - puts("Before:"); - for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) { - printf("0x%02x ", dmaMem0[i]); - } - puts(""); + cr_assert_not_null(axiSwitch, "No AXI switch IP found"); + cr_assert_not_null(dma, "No DMA IP found"); - rtds2gpu.dump(); - cr_assert(axiSwitch->connect(7, 6)); + /* Allocate and prepare memory */ + + // allocate space for all samples and doorbell register + auto dmaMemSrc = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); + auto dmaMemDst = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); + + memset(&dmaMemSrc, 0x11, dmaMemSrc.getMemoryBlock().getSize()); + memset(&dmaMemDst, 0x55, dmaMemDst.getMemoryBlock().getSize()); + + const uint32_t* dataSrc = &dmaMemSrc[DATA_OFFSET]; + const uint32_t* dataDst = &dmaMemDst[DATA_OFFSET]; + + // connect DMA to Rtds2Gpu IP + // TODO: this should be done automatically cr_assert(axiSwitch->connect(6, 7)); - - - cr_assert(rtds2gpu.startOnce(dmaMem0.getMemoryBlock(), SAMPLE_COUNT), + cr_assert(rtds2gpu.startOnce(dmaMemDst.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET*4, DOORBELL_OFFSET*4), "Preparing Rtds2Gpu IP failed"); - cr_assert(dma->write(dmaMem1.getMemoryBlock(), FRAME_SIZE)); + cr_assert(dma->write(dmaMemSrc.getMemoryBlock(), FRAME_SIZE), + "Starting DMA MM2S transfer failed"); -// cr_assert(axiSwitch->connect(6, 6)); // loopback -// cr_assert(dma->read(dmaMem1.getMemoryBlock(), FRAME_SIZE)); -// cr_assert(dma->readComplete()); + cr_assert(dma->writeComplete(), + "DMA failed"); - cr_assert(dma->writeComplete()); + while(not rtds2gpu.isFinished()); - puts("After:"); - for(size_t i = 0; i < dmaMem0.getMemoryBlock().getSize(); i++) { - printf("0x%02x ", dmaMem0[i]); - } - puts(""); + const uint32_t* doorbellDst = &dmaMemDst[DOORBELL_OFFSET]; + rtds2gpu.dump(spdlog::level::info); + rtds2gpu.dumpDoorbell(*doorbellDst); - - rtds2gpu.dump(); - - cr_assert(rtds2gpu.isDone()); + cr_assert(memcmp(dataSrc, dataDst, FRAME_SIZE) == 0, "Memory not equal"); logger->info(TXT_GREEN("Passed")); } From 5c67dc37274405917780a45f7c127b8c1839dbbc Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 30 May 2018 09:46:26 +0200 Subject: [PATCH 03/20] rtds2gpu: update vlnv to match v1.1 and adapt config to new bitstream --- fpga/etc/fpga.json | 198 +++++++++++----------- fpga/include/villas/fpga/ips/rtds2gpu.hpp | 2 +- fpga/tests/rtds2gpu.cpp | 2 +- 3 files changed, 99 insertions(+), 103 deletions(-) diff --git a/fpga/etc/fpga.json b/fpga/etc/fpga.json index dbf7aaa6f..c6e4d892e 100644 --- a/fpga/etc/fpga.json +++ b/fpga/etc/fpga.json @@ -52,6 +52,13 @@ } }, "M_AXI_SG": { + "hier_0_axi_dma_axi_dma_0": { + "Reg": { + "baseaddr": 4096, + "highaddr": 8191, + "size": 4096 + } + }, "hier_0_axi_dma_axi_dma_1": { "Reg": { "baseaddr": 8192, @@ -59,37 +66,23 @@ "size": 4096 } }, - "hier_0_axi_dma_axi_dma_0": { - "Reg": { + "hier_0_axi_fifo_mm_s_0": { + "Mem0": { "baseaddr": 12288, "highaddr": 16383, "size": 4096 - } - }, - "timer_0_axi_timer_0": { - "Reg": { + }, + "Mem1": { "baseaddr": 16384, - "highaddr": 20479, - "size": 4096 - } - }, - "hier_0_axis_interconnect_0_axis_interconnect_0_xbar": { - "Reg": { - "baseaddr": 20480, "highaddr": 24575, - "size": 4096 + "size": 8192 } }, - "hier_0_axi_fifo_mm_s_0": { - "Mem0": { + "pcie_0_axi_pcie_intc_0": { + "Reg": { "baseaddr": 24576, "highaddr": 28671, "size": 4096 - }, - "Mem1": { - "baseaddr": 49152, - "highaddr": 57343, - "size": 8192 } }, "pcie_0_axi_reset_0": { @@ -99,8 +92,8 @@ "size": 4096 } }, - "hier_0_rtds_axis_0": { - "reg0": { + "timer_0_axi_timer_0": { + "Reg": { "baseaddr": 32768, "highaddr": 36863, "size": 4096 @@ -113,34 +106,41 @@ "size": 4096 } }, - "pcie_0_axi_pcie_intc_0": { + "hier_0_rtds_axis_0": { + "reg0": { + "baseaddr": 40960, + "highaddr": 45055, + "size": 4096 + } + }, + "hier_0_axis_interconnect_0_axis_interconnect_0_xbar": { "Reg": { "baseaddr": 45056, "highaddr": 49151, "size": 4096 } }, - "mem_0": { + "bram_0_axi_bram_ctrl_0": { + "Mem0": { + "baseaddr": 49152, + "highaddr": 57343, + "size": 8192 + } + }, + "hier_0_rtds2gpu_0": { "Reg": { "baseaddr": 57344, "highaddr": 61439, "size": 4096 } }, - "rtds2gpu_0": { + "hier_0_gpu2rtds_0": { "Reg": { "baseaddr": 61440, "highaddr": 65535, "size": 4096 } }, - "bram_0_axi_bram_ctrl_0": { - "Mem0": { - "baseaddr": 65536, - "highaddr": 73727, - "size": 8192 - } - }, "pcie_0_axi_pcie_0": { "CTL0": { "baseaddr": 268435456, @@ -250,6 +250,16 @@ ], "num_ports": 8 }, + "hier_0_gpu2rtds_0": { + "vlnv": "acs.eonerc.rwth-aachen.de:hls:gpu2rtds:1.0", + "ports": [ + { + "role": "master", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:7", + "name": "rtds_output" + } + ] + }, "hier_0_hls_dft_0": { "vlnv": "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.1", "ports": [ @@ -268,6 +278,27 @@ "interrupt": "pcie_0_axi_pcie_intc_0:1" } }, + "hier_0_rtds2gpu_0": { + "vlnv": "acs.eonerc.rwth-aachen.de:hls:rtds2gpu:1.1", + "memory-view": { + "m_axi_axi_mm": { + "pcie_0_axi_pcie_0": { + "BAR0": { + "baseaddr": 0, + "highaddr": 4294967295, + "size": 4294967296 + } + } + } + }, + "ports": [ + { + "role": "slave", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:7", + "name": "rtds_input" + } + ] + }, "hier_0_rtds_axis_0": { "vlnv": "acs.eonerc.rwth-aachen.de:user:rtds_axis:1.0", "ports": [ @@ -288,24 +319,17 @@ "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": { "M_AXI": { + "hier_0_axi_dma_axi_dma_0": { + "Reg": { + "baseaddr": 4096, + "highaddr": 8191, + "size": 4096 + } + }, "hier_0_axi_dma_axi_dma_1": { "Reg": { "baseaddr": 8192, @@ -313,37 +337,23 @@ "size": 4096 } }, - "hier_0_axi_dma_axi_dma_0": { - "Reg": { + "hier_0_axi_fifo_mm_s_0": { + "Mem0": { "baseaddr": 12288, "highaddr": 16383, "size": 4096 - } - }, - "timer_0_axi_timer_0": { - "Reg": { + }, + "Mem1": { "baseaddr": 16384, - "highaddr": 20479, - "size": 4096 - } - }, - "hier_0_axis_interconnect_0_axis_interconnect_0_xbar": { - "Reg": { - "baseaddr": 20480, "highaddr": 24575, - "size": 4096 + "size": 8192 } }, - "hier_0_axi_fifo_mm_s_0": { - "Mem0": { + "pcie_0_axi_pcie_intc_0": { + "Reg": { "baseaddr": 24576, "highaddr": 28671, "size": 4096 - }, - "Mem1": { - "baseaddr": 49152, - "highaddr": 57343, - "size": 8192 } }, "pcie_0_axi_reset_0": { @@ -353,8 +363,8 @@ "size": 4096 } }, - "hier_0_rtds_axis_0": { - "reg0": { + "timer_0_axi_timer_0": { + "Reg": { "baseaddr": 32768, "highaddr": 36863, "size": 4096 @@ -367,34 +377,41 @@ "size": 4096 } }, - "pcie_0_axi_pcie_intc_0": { + "hier_0_rtds_axis_0": { + "reg0": { + "baseaddr": 40960, + "highaddr": 45055, + "size": 4096 + } + }, + "hier_0_axis_interconnect_0_axis_interconnect_0_xbar": { "Reg": { "baseaddr": 45056, "highaddr": 49151, "size": 4096 } }, - "mem_0": { + "bram_0_axi_bram_ctrl_0": { + "Mem0": { + "baseaddr": 49152, + "highaddr": 57343, + "size": 8192 + } + }, + "hier_0_rtds2gpu_0": { "Reg": { "baseaddr": 57344, "highaddr": 61439, "size": 4096 } }, - "rtds2gpu_0": { + "hier_0_gpu2rtds_0": { "Reg": { "baseaddr": 61440, "highaddr": 65535, "size": 4096 } }, - "bram_0_axi_bram_ctrl_0": { - "Mem0": { - "baseaddr": 65536, - "highaddr": 73727, - "size": 8192 - } - }, "pcie_0_axi_pcie_0": { "CTL0": { "baseaddr": 268435456, @@ -424,27 +441,6 @@ "pcie_0_axi_reset_0": { "vlnv": "xilinx.com:ip:axi_gpio:2.0" }, - "rtds2gpu_0": { - "vlnv": "xilinx.com:hls:rtds2gpu:1.0", - "memory-view": { - "m_axi_axi_mm": { - "pcie_0_axi_pcie_0": { - "BAR0": { - "baseaddr": 0, - "highaddr": 4294967295, - "size": 4294967296 - } - } - } - }, - "ports": [ - { - "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:7", - "name": "rtds_input" - } - ] - }, "timer_0_axi_timer_0": { "vlnv": "xilinx.com:ip:axi_timer:2.0", "irqs": { diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index 2867b28de..9c5b24bb3 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -68,7 +68,7 @@ public: { return "HLS RTDS2GPU IP"; } Vlnv getCompatibleVlnv() const - { return {"xilinx.com:hls:rtds2gpu:"}; } + { return {"acs.eonerc.rwth-aachen.de:hls:rtds2gpu:"}; } }; } // namespace ip diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index a9bfe8400..59cb6a415 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -47,7 +47,7 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") auto logger = loggerGetOrCreate("unittest:rtds2gpu"); for(auto& ip : state.cards.front()->ips) { - if(*ip != villas::fpga::Vlnv("xilinx.com:hls:rtds2gpu:")) + if(*ip != villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:rtds2gpu:")) continue; logger->info("Testing {}", *ip); From 010e0c3681729bc4beef140a50175171006081ed Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 30 May 2018 13:58:26 +0200 Subject: [PATCH 04/20] hls: add base HLS IP and enable virtual multi-inheritance Virtual inheritance is required because (for example) the Rtds2Gpu IP inherits from Hls and IpNode who both inherit from IpCore. --- fpga/include/villas/fpga/ip_node.hpp | 2 +- fpga/include/villas/fpga/ips/hls.hpp | 137 ++++++++++++++++++++++ fpga/include/villas/fpga/ips/rtds2gpu.hpp | 9 +- fpga/include/villas/memory.hpp | 2 + fpga/lib/ip_node.cpp | 4 +- fpga/lib/ips/rtds2gpu/rtds2gpu.cpp | 29 +---- fpga/tests/rtds2gpu.cpp | 10 +- 7 files changed, 153 insertions(+), 40 deletions(-) create mode 100644 fpga/include/villas/fpga/ips/hls.hpp diff --git a/fpga/include/villas/fpga/ip_node.hpp b/fpga/include/villas/fpga/ip_node.hpp index 964070991..1257529c2 100644 --- a/fpga/include/villas/fpga/ip_node.hpp +++ b/fpga/include/villas/fpga/ip_node.hpp @@ -86,7 +86,7 @@ public: }; -class IpNode : public IpCore { +class IpNode : public virtual IpCore { public: friend class IpNodeFactory; diff --git a/fpga/include/villas/fpga/ips/hls.hpp b/fpga/include/villas/fpga/ips/hls.hpp new file mode 100644 index 000000000..685af9050 --- /dev/null +++ b/fpga/include/villas/fpga/ips/hls.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include +#include + +namespace villas { +namespace fpga { +namespace ip { + + +class Hls : public virtual IpCore +{ +public: + virtual bool init() + { + auto& registers = addressTranslations.at(registerMemory); + + controlRegister = reinterpret_cast(registers.getLocalAddr(registerControlAddr)); + globalIntRegister = reinterpret_cast(registers.getLocalAddr(registerGlobalIntEnableAddr)); + ipIntEnableRegister = reinterpret_cast(registers.getLocalAddr(registerIntEnableAddr)); + ipIntStatusRegister = reinterpret_cast(registers.getLocalAddr(registerIntStatusAddr)); + + setAutoRestart(false); + setGlobalInterrupt(false); + + return true; + } + + bool start() + { + controlRegister->ap_start = true; + running = true; + + return true; + } + + virtual bool isFinished() + { updateRunningStatus(); return !running; } + + + bool isRunning() + { updateRunningStatus(); return running; } + + + void setAutoRestart(bool enabled) const + { controlRegister->auto_restart = enabled; } + + + void setGlobalInterrupt(bool enabled) const + { globalIntRegister->globalInterruptEnable = enabled; } + + + void setReadyInterrupt(bool enabled) const + { ipIntEnableRegister->ap_ready = enabled; } + + + void setDoneInterrupt(bool enabled) const + { ipIntEnableRegister->ap_done = enabled; } + + + bool isIdleBit() const + { return controlRegister->ap_idle; } + + + bool isReadyBit() const + { return controlRegister->ap_ready; } + + + /// Warning: the corresponding bit is cleared on read of the register, so if + /// not used correctly, this function may never return true. Only use this + /// function if you really know what you are doing! + bool isDoneBit() const + { return controlRegister->ap_done; } + + + bool isAutoRestartBit() const + { return controlRegister->auto_restart; } + +private: + void updateRunningStatus() + { + if(running and isIdleBit()) + running = false; + } + +protected: + /* Memory block handling */ + + static constexpr const char* registerMemory = "Reg"; + + virtual std::list getMemoryBlocks() const + { return { registerMemory }; } + + +private: + /* Register definitions */ + + static constexpr uintptr_t registerControlAddr = 0x00; + static constexpr uintptr_t registerGlobalIntEnableAddr = 0x04; + static constexpr uintptr_t registerIntEnableAddr = 0x08; + static constexpr uintptr_t registerIntStatusAddr = 0x0c; + + union ControlRegister { + uint32_t value; + struct { uint32_t + ap_start : 1, + ap_done : 1, + ap_idle : 1, + ap_ready : 1, + _res1 : 3, + auto_restart : 1, + _res2 : 24; + }; + }; + + struct GlobalIntRegister { uint32_t + globalInterruptEnable : 1, + _res : 31; + }; + + struct IpIntRegister { uint32_t + ap_done : 1, + ap_ready : 1, + _res : 30; + }; +protected: + ControlRegister* controlRegister; + GlobalIntRegister* globalIntRegister; + IpIntRegister* ipIntEnableRegister; + IpIntRegister* ipIntStatusRegister; + + bool running; +}; + +} // namespace ip +} // namespace fpga +} // namespace villas diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index 9c5b24bb3..8a64d44a3 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "rtds2gpu/xrtds2gpu.h" #include "rtds2gpu/register_types.hpp" @@ -11,23 +12,17 @@ namespace fpga { namespace ip { -class Rtds2Gpu : public IpNode +class Rtds2Gpu : public IpNode, public Hls { public: friend class Rtds2GpuFactory; bool init(); - bool start(); - void dump(spdlog::level::level_enum logLevel = spdlog::level::info); bool startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOffset, size_t doorbellOffset); - bool isFinished(); - - bool isReady(); - size_t getMaxFrameSize(); void dumpDoorbell(uint32_t doorbellRegister) const; diff --git a/fpga/include/villas/memory.hpp b/fpga/include/villas/memory.hpp index ce7a9190c..d06e3c1d6 100644 --- a/fpga/include/villas/memory.hpp +++ b/fpga/include/villas/memory.hpp @@ -62,6 +62,8 @@ public: MemoryAccessor(const MemoryBlock& mem) : translation(MemoryManager::get().getTranslationFromProcess(mem.getAddrSpaceId())) {} + MemoryAccessor(const MemoryTranslation& translation) : + translation(translation) {} T& operator*() const { return *reinterpret_cast(translation.getLocalAddr(0)); diff --git a/fpga/lib/ip_node.cpp b/fpga/lib/ip_node.cpp index 9435e24a3..016bdf784 100644 --- a/fpga/lib/ip_node.cpp +++ b/fpga/lib/ip_node.cpp @@ -19,7 +19,7 @@ IpNode::streamGraph; bool IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip) { - auto& ipNode = reinterpret_cast(ip); + auto& ipNode = dynamic_cast(ip); auto logger = getLogger(); json_t* json_ports = json_object_get(json_ip, "ports"); @@ -194,7 +194,7 @@ IpNode::connectLoopback() logger->debug("switch at: {}", portMaster->nodeName); // TODO: verify this is really a switch! - auto axiStreamSwitch = reinterpret_cast( + auto axiStreamSwitch = dynamic_cast( card->lookupIp(portMaster->nodeName)); if(axiStreamSwitch == nullptr) { diff --git a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp index b9ce32d13..a39d45061 100644 --- a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp +++ b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp @@ -14,12 +14,11 @@ static Rtds2GpuFactory factory; bool Rtds2Gpu::init() { + Hls::init(); + xInstance.IsReady = XIL_COMPONENT_IS_READY; xInstance.Ctrl_BaseAddress = getBaseAddr(registerMemory); - // make sure IP is stopped for now - XRtds2gpu_DisableAutoRestart(&xInstance); - status.value = 0; started = false; @@ -29,13 +28,7 @@ bool Rtds2Gpu::init() return true; } -bool Rtds2Gpu::start() -{ - XRtds2gpu_Start(&xInstance); - started = true; - return true; -} void Rtds2Gpu::dump(spdlog::level::level_enum logLevel) { @@ -89,26 +82,9 @@ bool Rtds2Gpu::startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOf return start(); } -bool Rtds2Gpu::isFinished() -{ - if(started and isReady()) { - started = false; - if(not updateStatus()) { - throw "IP is finished but status register invalid"; - } - } - return !started; -} -bool -Rtds2Gpu::isReady() -{ - // use the idle bit to indicate readiness, we don't care about the difference - // here - return XRtds2gpu_IsIdle(&xInstance); -} bool Rtds2Gpu::updateStatus() @@ -128,6 +104,7 @@ Rtds2Gpu::getMaxFrameSize() start(); while(not isFinished()); + updateStatus(); return status.max_frame_size; } diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index 59cb6a415..4c5e301c5 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -55,12 +55,14 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") /* Collect neccessary IPs */ - auto rtds2gpu = reinterpret_cast(*ip); + auto rtds2gpu = dynamic_cast(*ip); - auto axiSwitch = reinterpret_cast( - state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:"))); + auto axiSwitchPtr = state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:")); + auto axiSwitch = dynamic_cast(axiSwitchPtr); - auto dma = reinterpret_cast( + cr_assert_not_null(axiSwitchPtr); + + auto dma = dynamic_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axi_dma:"))); rtds2gpu.dump(spdlog::level::debug); From 93fe1390d6ad19e3ef64f239fdd35561a53f9a43 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 30 May 2018 14:02:25 +0200 Subject: [PATCH 05/20] fix wrong usage of reinterpret_cast in ips and tests --- fpga/lib/ips/bram.cpp | 2 +- fpga/lib/ips/pcie.cpp | 2 +- fpga/lib/ips/switch.cpp | 2 +- fpga/tests/dma.cpp | 2 +- fpga/tests/fifo.cpp | 2 +- fpga/tests/gpu.cpp | 2 +- fpga/tests/timer.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fpga/lib/ips/bram.cpp b/fpga/lib/ips/bram.cpp index 11dda7f67..003e7083f 100644 --- a/fpga/lib/ips/bram.cpp +++ b/fpga/lib/ips/bram.cpp @@ -9,7 +9,7 @@ static BramFactory factory; bool BramFactory::configureJson(IpCore& ip, json_t* json_ip) { - auto& bram = reinterpret_cast(ip); + auto& bram = dynamic_cast(ip); if(json_unpack(json_ip, "{ s: i }", "size", &bram.size) != 0) { getLogger()->error("Cannot parse 'size'"); diff --git a/fpga/lib/ips/pcie.cpp b/fpga/lib/ips/pcie.cpp index d8294469e..ea5675b7d 100644 --- a/fpga/lib/ips/pcie.cpp +++ b/fpga/lib/ips/pcie.cpp @@ -125,7 +125,7 @@ bool AxiPciExpressBridgeFactory::configureJson(IpCore& ip, json_t* json_ip) { auto logger = getLogger(); - auto& pcie = reinterpret_cast(ip); + auto& pcie = dynamic_cast(ip); for(auto barType : std::list{"axi_bars", "pcie_bars"}) { json_t* json_bars = json_object_get(json_ip, barType.c_str()); diff --git a/fpga/lib/ips/switch.cpp b/fpga/lib/ips/switch.cpp index bb0ba0cbc..a06ebbc72 100644 --- a/fpga/lib/ips/switch.cpp +++ b/fpga/lib/ips/switch.cpp @@ -143,7 +143,7 @@ AxiStreamSwitchFactory::configureJson(IpCore& ip, json_t* json_ip) auto logger = getLogger(); - auto& axiSwitch = reinterpret_cast(ip); + auto& axiSwitch = dynamic_cast(ip); if(json_unpack(json_ip, "{ s: i }", "num_ports", &axiSwitch.num_ports) != 0) { logger->error("Cannot parse 'num_ports'"); diff --git a/fpga/tests/dma.cpp b/fpga/tests/dma.cpp index e7c462b26..aa43f12a2 100644 --- a/fpga/tests/dma.cpp +++ b/fpga/tests/dma.cpp @@ -24,7 +24,7 @@ Test(fpga, dma, .description = "DMA") logger->info("Testing {}", *ip); - auto dma = reinterpret_cast(*ip); + auto dma = dynamic_cast(*ip); if(not dma.loopbackPossible()) { logger->info("Loopback test not possible for {}", *ip); diff --git a/fpga/tests/fifo.cpp b/fpga/tests/fifo.cpp index 17cfd3dde..515a5fdac 100644 --- a/fpga/tests/fifo.cpp +++ b/fpga/tests/fifo.cpp @@ -47,7 +47,7 @@ Test(fpga, fifo, .description = "FIFO") logger->info("Testing {}", *ip); - auto fifo = reinterpret_cast(*ip); + auto fifo = dynamic_cast(*ip); if(not fifo.connectLoopback()) { continue; diff --git a/fpga/tests/gpu.cpp b/fpga/tests/gpu.cpp index bdc3aba92..489f86b8c 100644 --- a/fpga/tests/gpu.cpp +++ b/fpga/tests/gpu.cpp @@ -40,7 +40,7 @@ Test(fpga, gpu_dma, .description = "GPU DMA tests") logger->info("Testing {}", *ip); - auto bram = reinterpret_cast(ip.get()); + auto bram = dynamic_cast(ip.get()); cr_assert_not_null(bram, "Couldn't find BRAM"); count++; diff --git a/fpga/tests/timer.cpp b/fpga/tests/timer.cpp index 66cc71d41..2eb0cfba5 100644 --- a/fpga/tests/timer.cpp +++ b/fpga/tests/timer.cpp @@ -46,7 +46,7 @@ Test(fpga, timer, .description = "Timer Counter") count++; - auto timer = reinterpret_cast(*ip); + auto timer = dynamic_cast(*ip); logger->info("Test simple waiting"); timer.start(timer.getFrequency() / 10); From f413712b86f37623fe396f3cc61b48756ee355ff Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 30 May 2018 17:24:51 +0200 Subject: [PATCH 06/20] gpu2rtds: unit test working --- fpga/include/villas/fpga/ips/gpu2rtds.hpp | 79 ++++++++++ fpga/include/villas/fpga/ips/rtds2gpu.hpp | 9 +- .../villas/fpga/ips/rtds2gpu/xgpu2rtds_hw.h | 53 +++++++ fpga/lib/CMakeLists.txt | 1 + fpga/lib/ips/rtds2gpu/gpu2rtds.cpp | 142 ++++++++++++++++++ fpga/lib/ips/rtds2gpu/rtds2gpu.cpp | 2 + fpga/tests/rtds2gpu.cpp | 72 ++++++++- 7 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 fpga/include/villas/fpga/ips/gpu2rtds.hpp create mode 100644 fpga/include/villas/fpga/ips/rtds2gpu/xgpu2rtds_hw.h create mode 100644 fpga/lib/ips/rtds2gpu/gpu2rtds.cpp diff --git a/fpga/include/villas/fpga/ips/gpu2rtds.hpp b/fpga/include/villas/fpga/ips/gpu2rtds.hpp new file mode 100644 index 000000000..6e9a14b40 --- /dev/null +++ b/fpga/include/villas/fpga/ips/gpu2rtds.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace villas { +namespace fpga { +namespace ip { + + +class Gpu2Rtds : public IpNode, public Hls +{ +public: + friend class Gpu2RtdsFactory; + + bool init(); + + void dump(spdlog::level::level_enum logLevel = spdlog::level::info); + bool startOnce(size_t frameSize); + + size_t getMaxFrameSize(); + +// void dumpDoorbell(uint32_t doorbellRegister) const; + +private: + bool updateStatus(); + +private: + struct StatusControlRegister { uint32_t + status_ap_vld : 1, + _res : 31; + }; + + using StatusRegister = axilite_reg_status_t; + + static constexpr uintptr_t registerStatusOffset = XGPU2RTDS_CTRL_ADDR_STATUS_DATA; + static constexpr uintptr_t registerStatusCtrlOffset = XGPU2RTDS_CTRL_ADDR_STATUS_CTRL; + static constexpr uintptr_t registerFrameSizeOffset = XGPU2RTDS_CTRL_ADDR_FRAME_SIZE_DATA; + static constexpr uintptr_t registerFrameOffset = XGPU2RTDS_CTRL_ADDR_FRAME_BASE; + static constexpr uintptr_t registerFrameLength = XGPU2RTDS_CTRL_DEPTH_FRAME; + +public: + StatusRegister* registerStatus; + StatusControlRegister* registerStatusCtrl; + uint32_t* registerFrameSize; + uint32_t* registerFrames; + + size_t maxFrameSize; + + bool started; +}; + + +class Gpu2RtdsFactory : public IpNodeFactory { +public: + Gpu2RtdsFactory(); + + IpCore* create() + { return new Gpu2Rtds; } + + std::string + getName() const + { return "Gpu2Rtds"; } + + std::string + getDescription() const + { return "HLS Gpu2Rtds IP"; } + + Vlnv getCompatibleVlnv() const + { return {"acs.eonerc.rwth-aachen.de:hls:gpu2rtds:"}; } +}; + +} // namespace ip +} // namespace fpga +} // namespace villas diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index 8a64d44a3..bc0e2b94b 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -27,17 +27,18 @@ public: void dumpDoorbell(uint32_t doorbellRegister) const; + static constexpr const char* registerMemory = "Reg"; + std::list getMemoryBlocks() const + { return { registerMemory }; } + + private: bool updateStatus(); private: - static constexpr const char* registerMemory = "Reg"; static constexpr const char* axiInterface = "m_axi_axi_mm"; static constexpr const char* streamInterface = "rtds_input"; - std::list getMemoryBlocks() const - { return { registerMemory }; } - XRtds2gpu xInstance; axilite_reg_status_t status; diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/xgpu2rtds_hw.h b/fpga/include/villas/fpga/ips/rtds2gpu/xgpu2rtds_hw.h new file mode 100644 index 000000000..8ea61f0f1 --- /dev/null +++ b/fpga/include/villas/fpga/ips/rtds2gpu/xgpu2rtds_hw.h @@ -0,0 +1,53 @@ +// ============================================================== +// 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 frame_size +// bit 31~0 - frame_size[31:0] (Read/Write) +// 0x14 : reserved +// 0x80 : Data signal of status +// bit 31~0 - status[31:0] (Read) +// 0x84 : Control signal of status +// bit 0 - status_ap_vld (Read/COR) +// others - reserved +// 0x40 ~ +// 0x7f : Memory 'frame' (16 * 32b) +// Word n : bit [31:0] - frame[n] +// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake) + +#define XGPU2RTDS_CTRL_ADDR_AP_CTRL 0x00 +#define XGPU2RTDS_CTRL_ADDR_GIE 0x04 +#define XGPU2RTDS_CTRL_ADDR_IER 0x08 +#define XGPU2RTDS_CTRL_ADDR_ISR 0x0c +#define XGPU2RTDS_CTRL_ADDR_FRAME_SIZE_DATA 0x10 +#define XGPU2RTDS_CTRL_BITS_FRAME_SIZE_DATA 32 +#define XGPU2RTDS_CTRL_ADDR_STATUS_DATA 0x80 +#define XGPU2RTDS_CTRL_BITS_STATUS_DATA 32 +#define XGPU2RTDS_CTRL_ADDR_STATUS_CTRL 0x84 +#define XGPU2RTDS_CTRL_ADDR_FRAME_BASE 0x40 +#define XGPU2RTDS_CTRL_ADDR_FRAME_HIGH 0x7f +#define XGPU2RTDS_CTRL_WIDTH_FRAME 32 +#define XGPU2RTDS_CTRL_DEPTH_FRAME 16 + diff --git a/fpga/lib/CMakeLists.txt b/fpga/lib/CMakeLists.txt index 7159a63a9..4d0d555e8 100644 --- a/fpga/lib/CMakeLists.txt +++ b/fpga/lib/CMakeLists.txt @@ -17,6 +17,7 @@ set(SOURCES ips/rtds2gpu/rtds2gpu.cpp ips/rtds2gpu/xrtds2gpu.c + ips/rtds2gpu/gpu2rtds.cpp kernel/kernel.c kernel/pci.c diff --git a/fpga/lib/ips/rtds2gpu/gpu2rtds.cpp b/fpga/lib/ips/rtds2gpu/gpu2rtds.cpp new file mode 100644 index 000000000..563d9da63 --- /dev/null +++ b/fpga/lib/ips/rtds2gpu/gpu2rtds.cpp @@ -0,0 +1,142 @@ +#include +#include + +#include +#include + +#include "log.hpp" + +namespace villas { +namespace fpga { +namespace ip { + +static Gpu2RtdsFactory factory; + +bool Gpu2Rtds::init() +{ + Hls::init(); + + auto& registers = addressTranslations.at(registerMemory); + + registerStatus = reinterpret_cast(registers.getLocalAddr(registerStatusOffset)); + registerStatusCtrl = reinterpret_cast(registers.getLocalAddr(registerStatusCtrlOffset)); + registerFrameSize = reinterpret_cast(registers.getLocalAddr(registerFrameSizeOffset)); + registerFrames = reinterpret_cast(registers.getLocalAddr(registerFrameOffset)); + + maxFrameSize = getMaxFrameSize(); + logger->info("Max. frame size supported: {}", maxFrameSize); + + return true; +} + +bool +Gpu2Rtds::startOnce(size_t frameSize) +{ + *registerFrameSize = frameSize; + + start(); + + return true; +} + +void Gpu2Rtds::dump(spdlog::level::level_enum logLevel) +{ + const auto frame_size = *registerFrameSize; + auto status = *registerStatus; + + logger->log(logLevel, "Gpu2Rtds registers:"); + logger->log(logLevel, " Frame size (words): {:#x}", frame_size); + logger->log(logLevel, " Status: {:#x}", status.value); + logger->log(logLevel, " Running: {}", (status.is_running ? "yes" : "no")); + logger->log(logLevel, " Frame too short: {}", (status.frame_too_short ? "yes" : "no")); + logger->log(logLevel, " Frame too long: {}", (status.frame_too_long ? "yes" : "no")); + logger->log(logLevel, " Frame size invalid: {}", (status.invalid_frame_size ? "yes" : "no")); + logger->log(logLevel, " Last count: {}", status.last_count); + logger->log(logLevel, " Last seq. number: {}", status.last_seq_nr); + logger->log(logLevel, " Max. frame size: {}", status.max_frame_size); +} + +//bool Gpu2Rtds::startOnce(const MemoryBlock& mem, size_t frameSize, size_t dataOffset, size_t doorbellOffset) +//{ +// auto& mm = MemoryManager::get(); + +// if(frameSize > maxFrameSize) { +// logger->error("Requested frame size of {} exceeds max. frame size of {}", +// frameSize, maxFrameSize); +// return false; +// } + +// auto translationFromIp = mm.getTranslation( +// getMasterAddrSpaceByInterface(axiInterface), +// mem.getAddrSpaceId()); + +// // set address of memory block in HLS IP +// XGpu2Rtds_Set_baseaddr(&xInstance, translationFromIp.getLocalAddr(0)); + +// XGpu2Rtds_Set_doorbell_offset(&xInstance, doorbellOffset); +// XGpu2Rtds_Set_data_offset(&xInstance, dataOffset); +// XGpu2Rtds_Set_frame_size(&xInstance, frameSize); + +// // prepare memory with all zeroes +// auto translationFromProcess = mm.getTranslationFromProcess(mem.getAddrSpaceId()); +// auto memory = reinterpret_cast(translationFromProcess.getLocalAddr(0)); +// memset(memory, 0, mem.getSize()); + +// // start IP +// return start(); +//} + + + + + +//bool +//Gpu2Rtds::updateStatus() +//{ +// if(not XGpu2Rtds_Get_status_vld(&xInstance)) +// return false; + +// status.value = XGpu2Rtds_Get_status(&xInstance); + +// return true; +//} + +size_t +Gpu2Rtds::getMaxFrameSize() +{ + *registerFrameSize = 0; + + start(); + while(not isFinished()); + + while(not registerStatusCtrl->status_ap_vld); + + axilite_reg_status_t status = *registerStatus; + +// logger->debug("(*registerStatus).max_frame_size: {}", (*registerStatus).max_frame_size); +// logger->debug("status.max_frame_size: {}", status.max_frame_size); + +// assert(status.max_frame_size == (*registerStatus).max_frame_size); + + return status.max_frame_size; +} + +//void +//Gpu2Rtds::dumpDoorbell(uint32_t doorbellRegister) const +//{ +// auto& doorbell = reinterpret_cast(doorbellRegister); + +// logger->info("Doorbell register: {:#08x}", doorbell.value); +// logger->info(" Valid: {}", (doorbell.is_valid ? "yes" : "no")); +// logger->info(" Count: {}", doorbell.count); +// logger->info(" Seq. number: {}", doorbell.seq_nr); +//} + +Gpu2RtdsFactory::Gpu2RtdsFactory() : + IpNodeFactory(getName()) +{ +} + +} // namespace ip +} // namespace fpga +} // namespace villas diff --git a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp index a39d45061..1fa271764 100644 --- a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp +++ b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp @@ -25,6 +25,8 @@ bool Rtds2Gpu::init() maxFrameSize = getMaxFrameSize(); logger->info("Max. frame size supported: {}", maxFrameSize); +// maxFrameSize = 16; + return true; } diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index 4c5e301c5..5d751ce99 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -35,12 +36,31 @@ static constexpr size_t SAMPLE_SIZE = 4; -static constexpr size_t SAMPLE_COUNT = 16; +static constexpr size_t SAMPLE_COUNT = 8; static constexpr size_t FRAME_SIZE = SAMPLE_COUNT * SAMPLE_SIZE; static constexpr size_t DOORBELL_OFFSET = SAMPLE_COUNT; static constexpr size_t DATA_OFFSET = 0; +static void dumpMem(const uint32_t* addr, size_t len) +{ + const size_t bytesPerLine = 16; + const size_t lines = (len) / bytesPerLine + 1; + const uint8_t* buf = reinterpret_cast(addr); + + size_t bytesRead = 0; + + for(size_t line = 0; line < lines; line++) { + const unsigned base = line * bytesPerLine; + printf("0x%04x: ", base); + + for(size_t i = 0; i < bytesPerLine && bytesRead < len; i++) { + printf("0x%02x ", buf[base + i]); + bytesRead++; + } + puts(""); + } +} Test(fpga, rtds2gpu, .description = "Rtds2Gpu") { @@ -57,18 +77,23 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") auto rtds2gpu = dynamic_cast(*ip); - auto axiSwitchPtr = state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:")); - auto axiSwitch = dynamic_cast(axiSwitchPtr); - - cr_assert_not_null(axiSwitchPtr); + auto axiSwitch = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axis_switch:"))); auto dma = dynamic_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axi_dma:"))); - rtds2gpu.dump(spdlog::level::debug); + auto gpu2rtds = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:gpu2rtds:"))); + + cr_assert_not_null(axiSwitch, "No AXI switch IP found"); cr_assert_not_null(dma, "No DMA IP found"); + cr_assert_not_null(gpu2rtds, "No Gpu2Rtds IP found"); + + rtds2gpu.dump(spdlog::level::debug); + gpu2rtds->dump(spdlog::level::debug); /* Allocate and prepare memory */ @@ -76,12 +101,21 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") // allocate space for all samples and doorbell register auto dmaMemSrc = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); auto dmaMemDst = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); + auto dmaMemDst2 = villas::HostDmaRam::getAllocator(0).allocate(SAMPLE_COUNT + 1); + memset(&dmaMemSrc, 0x11, dmaMemSrc.getMemoryBlock().getSize()); memset(&dmaMemDst, 0x55, dmaMemDst.getMemoryBlock().getSize()); + memset(&dmaMemDst2, 0x77, dmaMemDst2.getMemoryBlock().getSize()); const uint32_t* dataSrc = &dmaMemSrc[DATA_OFFSET]; const uint32_t* dataDst = &dmaMemDst[DATA_OFFSET]; + const uint32_t* dataDst2 = &dmaMemDst2[0]; + + dumpMem(dataSrc, dmaMemSrc.getMemoryBlock().getSize()); + dumpMem(dataDst, dmaMemDst.getMemoryBlock().getSize()); + dumpMem(dataDst2, dmaMemDst2.getMemoryBlock().getSize()); + // connect DMA to Rtds2Gpu IP // TODO: this should be done automatically @@ -96,6 +130,7 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") cr_assert(dma->writeComplete(), "DMA failed"); + while(not rtds2gpu.isFinished()); const uint32_t* doorbellDst = &dmaMemDst[DOORBELL_OFFSET]; @@ -104,6 +139,31 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") cr_assert(memcmp(dataSrc, dataDst, FRAME_SIZE) == 0, "Memory not equal"); + (void) dmaMemDst2; + (void) dataDst2; + + for(size_t i = 0; i < SAMPLE_COUNT; i++) { + gpu2rtds->registerFrames[i] = dmaMemDst[i]; + } + cr_assert(axiSwitch->connect(7, 6)); + + cr_assert(dma->read(dmaMemDst2.getMemoryBlock(), FRAME_SIZE), + "Starting DMA S2MM transfer failed"); + + cr_assert(gpu2rtds->startOnce(SAMPLE_COUNT), + "Preparing Gpu2Rtds IP failed"); + + cr_assert(dma->readComplete(), + "DMA failed"); + + while(not rtds2gpu.isFinished()); + + cr_assert(memcmp(dataSrc, dataDst2, FRAME_SIZE) == 0, "Memory not equal"); + + dumpMem(dataSrc, dmaMemSrc.getMemoryBlock().getSize()); + dumpMem(dataDst, dmaMemDst.getMemoryBlock().getSize()); + dumpMem(dataDst2, dmaMemDst2.getMemoryBlock().getSize()); + logger->info(TXT_GREEN("Passed")); } } From 194c4e3eef46f1fe925b26d626fce0f342098c74 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Mon, 4 Jun 2018 13:19:33 +0200 Subject: [PATCH 07/20] etc: update fpga.json with changes related to stream routing --- fpga/etc/fpga.json | 126 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 108 insertions(+), 18 deletions(-) diff --git a/fpga/etc/fpga.json b/fpga/etc/fpga.json index c6e4d892e..2beee4407 100644 --- a/fpga/etc/fpga.json +++ b/fpga/etc/fpga.json @@ -153,12 +153,12 @@ "ports": [ { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:1", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S01_AXIS", "name": "MM2S" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:1", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M01_AXIS", "name": "S2MM" } ], @@ -192,12 +192,12 @@ "ports": [ { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:6", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S06_AXIS", "name": "MM2S" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:6", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M06_AXIS", "name": "S2MM" } ], @@ -211,12 +211,12 @@ "ports": [ { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:2", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S02_AXIS", "name": "STR_TXD" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:2", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M02_AXIS", "name": "STR_RXD" } ], @@ -224,28 +224,118 @@ "interrupt": "pcie_0_axi_pcie_intc_0:2" } }, + "hier_0_axis_data_fifo_0": { + "vlnv": "xilinx.com:ip:axis_data_fifo:1.1", + "ports": [ + { + "role": "master", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S03_AXIS", + "name": "AXIS" + }, + { + "role": "slave", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M03_AXIS", + "name": "AXIS" + } + ] + }, + "hier_0_axis_data_fifo_1": { + "vlnv": "xilinx.com:ip:axis_data_fifo:1.1", + "ports": [ + { + "role": "master", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S04_AXIS", + "name": "AXIS" + }, + { + "role": "slave", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M04_AXIS", + "name": "AXIS" + } + ] + }, "hier_0_axis_interconnect_0_axis_interconnect_0_xbar": { "vlnv": "xilinx.com:ip:axis_switch:1.1", "ports": [ + { + "role": "slave", + "target": "hier_0_rtds_axis_0:m_axis", + "name": "S00_AXIS" + }, { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:3", - "name": "M03_AXIS" + "target": "hier_0_rtds_axis_0:s_axis", + "name": "M00_AXIS" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:3", + "target": "hier_0_axi_dma_axi_dma_0:MM2S", + "name": "S01_AXIS" + }, + { + "role": "master", + "target": "hier_0_axi_dma_axi_dma_0:S2MM", + "name": "M01_AXIS" + }, + { + "role": "slave", + "target": "hier_0_axi_fifo_mm_s_0:STR_TXD", + "name": "S02_AXIS" + }, + { + "role": "master", + "target": "hier_0_axi_fifo_mm_s_0:STR_RXD", + "name": "M02_AXIS" + }, + { + "role": "slave", + "target": "hier_0_axis_data_fifo_0:AXIS", "name": "S03_AXIS" }, { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:4", + "target": "hier_0_axis_data_fifo_0:AXIS", + "name": "M03_AXIS" + }, + { + "role": "slave", + "target": "hier_0_axis_data_fifo_1:AXIS", + "name": "S04_AXIS" + }, + { + "role": "master", + "target": "hier_0_axis_data_fifo_1:AXIS", "name": "M04_AXIS" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:4", - "name": "S04_AXIS" + "target": "hier_0_hls_dft_0:output_r", + "name": "S05_AXIS" + }, + { + "role": "master", + "target": "hier_0_hls_dft_0:input_r", + "name": "M05_AXIS" + }, + { + "role": "slave", + "target": "hier_0_axi_dma_axi_dma_1:MM2S", + "name": "S06_AXIS" + }, + { + "role": "master", + "target": "hier_0_axi_dma_axi_dma_1:S2MM", + "name": "M06_AXIS" + }, + { + "role": "slave", + "target": "hier_0_gpu2rtds_0:rtds_output", + "name": "S07_AXIS" + }, + { + "role": "master", + "target": "hier_0_rtds2gpu_0:rtds_input", + "name": "M07_AXIS" } ], "num_ports": 8 @@ -255,7 +345,7 @@ "ports": [ { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:7", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S07_AXIS", "name": "rtds_output" } ] @@ -265,12 +355,12 @@ "ports": [ { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:5", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S05_AXIS", "name": "output_r" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:5", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M05_AXIS", "name": "input_r" } ], @@ -294,7 +384,7 @@ "ports": [ { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:7", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M07_AXIS", "name": "rtds_input" } ] @@ -304,12 +394,12 @@ "ports": [ { "role": "master", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:0", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:S00_AXIS", "name": "m_axis" }, { "role": "slave", - "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:0", + "target": "hier_0_axis_interconnect_0_axis_interconnect_0_xbar:M00_AXIS", "name": "s_axis" } ], From 92bfe849b47d5d1b8d291c2aa0d5ce540a16ef84 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Mon, 4 Jun 2018 17:29:36 +0200 Subject: [PATCH 08/20] ips/rtds2gpu: use new connect interface --- fpga/include/villas/fpga/ips/gpu2rtds.hpp | 6 +++++- fpga/include/villas/fpga/ips/rtds2gpu.hpp | 6 +++++- fpga/tests/rtds2gpu.cpp | 15 +++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/fpga/include/villas/fpga/ips/gpu2rtds.hpp b/fpga/include/villas/fpga/ips/gpu2rtds.hpp index 6e9a14b40..b19702bef 100644 --- a/fpga/include/villas/fpga/ips/gpu2rtds.hpp +++ b/fpga/include/villas/fpga/ips/gpu2rtds.hpp @@ -24,12 +24,16 @@ public: size_t getMaxFrameSize(); -// void dumpDoorbell(uint32_t doorbellRegister) const; + const StreamVertex& + getDefaultMasterPort() const + { return getMasterPort(rtdsOutputStreamPort); } private: bool updateStatus(); private: + static constexpr const char* rtdsOutputStreamPort = "rtds_output"; + struct StatusControlRegister { uint32_t status_ap_vld : 1, _res : 31; diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index bc0e2b94b..64904d630 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -32,12 +32,16 @@ public: { return { registerMemory }; } + const StreamVertex& + getDefaultSlavePort() const + { return getSlavePort(rtdsInputStreamPort); } + private: bool updateStatus(); private: static constexpr const char* axiInterface = "m_axi_axi_mm"; - static constexpr const char* streamInterface = "rtds_input"; + static constexpr const char* rtdsInputStreamPort = "rtds_input"; XRtds2gpu xInstance; diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index 5d751ce99..b9ddd62af 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -117,9 +117,8 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") dumpMem(dataDst2, dmaMemDst2.getMemoryBlock().getSize()); - // connect DMA to Rtds2Gpu IP - // TODO: this should be done automatically - cr_assert(axiSwitch->connect(6, 7)); + // connect AXI Stream from DMA to Rtds2Gpu IP + cr_assert(dma->connect(rtds2gpu)); cr_assert(rtds2gpu.startOnce(dmaMemDst.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET*4, DOORBELL_OFFSET*4), "Preparing Rtds2Gpu IP failed"); @@ -130,7 +129,6 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") cr_assert(dma->writeComplete(), "DMA failed"); - while(not rtds2gpu.isFinished()); const uint32_t* doorbellDst = &dmaMemDst[DOORBELL_OFFSET]; @@ -139,13 +137,14 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") cr_assert(memcmp(dataSrc, dataDst, FRAME_SIZE) == 0, "Memory not equal"); - (void) dmaMemDst2; - (void) dataDst2; for(size_t i = 0; i < SAMPLE_COUNT; i++) { gpu2rtds->registerFrames[i] = dmaMemDst[i]; } - cr_assert(axiSwitch->connect(7, 6)); + + + // connect AXI Stream from Gpu2Rtds IP to DMA + cr_assert(gpu2rtds->connect(*dma)); cr_assert(dma->read(dmaMemDst2.getMemoryBlock(), FRAME_SIZE), "Starting DMA S2MM transfer failed"); @@ -156,7 +155,7 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") cr_assert(dma->readComplete(), "DMA failed"); - while(not rtds2gpu.isFinished()); + while(not gpu2rtds->isFinished()); cr_assert(memcmp(dataSrc, dataDst2, FRAME_SIZE) == 0, "Memory not equal"); From 49f0c2e0c485e80279711733ca00603b5334db40 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Mon, 4 Jun 2018 19:06:36 +0200 Subject: [PATCH 09/20] unit test RTT via CPU to/from RTDS works! --- fpga/include/villas/fpga/ips/rtds.hpp | 8 +++ fpga/include/villas/fpga/ips/rtds2gpu.hpp | 11 +++- fpga/tests/rtds.cpp | 8 ++- fpga/tests/rtds2gpu.cpp | 70 ++++++++++++++++++++++- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/fpga/include/villas/fpga/ips/rtds.hpp b/fpga/include/villas/fpga/ips/rtds.hpp index aff27601c..5f4b2e6fe 100644 --- a/fpga/include/villas/fpga/ips/rtds.hpp +++ b/fpga/include/villas/fpga/ips/rtds.hpp @@ -44,6 +44,14 @@ public: std::list getMemoryBlocks() const { return { registerMemory }; } + const StreamVertex& + getDefaultSlavePort() const + { return getSlavePort(slavePort); } + + const StreamVertex& + getDefaultMasterPort() const + { return getMasterPort(masterPort); } + private: static constexpr const char registerMemory[] = "reg0"; static constexpr const char* irqTs = "irq_ts"; diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index 64904d630..0b35848cf 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -27,9 +27,16 @@ public: void dumpDoorbell(uint32_t doorbellRegister) const; - static constexpr const char* registerMemory = "Reg"; + bool doorbellIsValid(const uint32_t& doorbellRegister) const + { return reinterpret_cast(doorbellRegister).is_valid; } + + void doorbellReset(uint32_t& doorbellRegister) const + { doorbellRegister = 0; } + + static constexpr const char* registerMemory = "Reg"; + std::list getMemoryBlocks() const - { return { registerMemory }; } + { return { registerMemory }; } const StreamVertex& diff --git a/fpga/tests/rtds.cpp b/fpga/tests/rtds.cpp index fd6de2baf..c60b70fb6 100644 --- a/fpga/tests/rtds.cpp +++ b/fpga/tests/rtds.cpp @@ -81,8 +81,12 @@ Test(fpga, rtds, .description = "RTDS") auto dmaMaster = dma->getMasterPort(dma->mm2sPort); auto dmaSlave = dma->getSlavePort(dma->s2mmPort); - rtds->connect(rtdsMaster, dmaSlave); - dma->connect(dmaMaster, rtdsSlave); +// rtds->connect(*rtds); +// logger->info("loopback"); +// while(1); + +// rtds->connect(rtdsMaster, dmaSlave); +// dma->connect(dmaMaster, rtdsSlave); auto mem = villas::HostRam::getAllocator().allocate(0x100 / sizeof(int32_t)); diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index b9ddd62af..a4c839bfc 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -31,15 +31,16 @@ #include #include #include +#include #include "global.hpp" static constexpr size_t SAMPLE_SIZE = 4; -static constexpr size_t SAMPLE_COUNT = 8; +static constexpr size_t SAMPLE_COUNT = 1; static constexpr size_t FRAME_SIZE = SAMPLE_COUNT * SAMPLE_SIZE; -static constexpr size_t DOORBELL_OFFSET = SAMPLE_COUNT; +static constexpr size_t DOORBELL_OFFSET = FRAME_SIZE; static constexpr size_t DATA_OFFSET = 0; static void dumpMem(const uint32_t* addr, size_t len) @@ -86,11 +87,14 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") auto gpu2rtds = dynamic_cast( state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:gpu2rtds:"))); + auto rtds = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:user:rtds_axis:"))); cr_assert_not_null(axiSwitch, "No AXI switch IP found"); cr_assert_not_null(dma, "No DMA IP found"); cr_assert_not_null(gpu2rtds, "No Gpu2Rtds IP found"); + cr_assert_not_null(rtds, "RTDS IP not found"); rtds2gpu.dump(spdlog::level::debug); gpu2rtds->dump(spdlog::level::debug); @@ -166,3 +170,65 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") logger->info(TXT_GREEN("Passed")); } } + +Test(fpga, rtds2gpu_rtt_cpu, .description = "Rtds2Gpu RTT via CPU") +{ + auto logger = loggerGetOrCreate("unittest:rtds2gpu"); + + /* Collect neccessary IPs */ + + auto gpu2rtds = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:gpu2rtds:"))); + + auto rtds2gpu = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:rtds2gpu:"))); + + cr_assert_not_null(gpu2rtds, "No Gpu2Rtds IP found"); + cr_assert_not_null(rtds2gpu, "No Rtds2Gpu IP not found"); + + for(auto& ip : state.cards.front()->ips) { + if(*ip != villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:user:rtds_axis:")) + continue; + + auto& rtds = dynamic_cast(*ip); + logger->info("Testing {}", rtds); + + auto dmaRam = villas::HostDmaRam::getAllocator().allocate(SAMPLE_COUNT + 1); + uint32_t* data = &dmaRam[DATA_OFFSET]; + uint32_t* doorbell = &dmaRam[DOORBELL_OFFSET / SAMPLE_SIZE]; + + // TEST: rtds loopback via switch +// cr_assert(rtds.connect(rtds)); +// logger->info("loopback"); +// while(1); + + cr_assert(rtds.connect(*rtds2gpu)); + cr_assert(gpu2rtds->connect(rtds)); + + + size_t count = 0; + while(true) { + rtds2gpu->doorbellReset(*doorbell); + rtds2gpu->startOnce(dmaRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET, DOORBELL_OFFSET); + + // while(not rtds2gpu->isFinished()); + while(not rtds2gpu->doorbellIsValid(*doorbell)); + +// rtds2gpu->dump(); +// rtds2gpu->dumpDoorbell(data[1]); +// dumpMem(data, FRAME_SIZE + SAMPLE_SIZE); + + // copy samples to gpu2rtds IP + for(size_t i = 0; i < SAMPLE_COUNT; i++) { + gpu2rtds->registerFrames[i] = data[i]; + } + + gpu2rtds->startOnce(SAMPLE_COUNT); +// while(not gpu2rtds->isFinished()); + + + count++; +// logger->debug("Successful iterations {}, data {}", count, data[0]); + } + } +} From 2a56f5ff13ffedee465ca9b8188f60869b2575b0 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Tue, 5 Jun 2018 14:48:35 +0200 Subject: [PATCH 10/20] tests/rtds2gpu: fix doorbell offset --- fpga/tests/rtds2gpu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index a4c839bfc..b6206da5b 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -40,7 +40,7 @@ static constexpr size_t SAMPLE_SIZE = 4; static constexpr size_t SAMPLE_COUNT = 1; static constexpr size_t FRAME_SIZE = SAMPLE_COUNT * SAMPLE_SIZE; -static constexpr size_t DOORBELL_OFFSET = FRAME_SIZE; +static constexpr size_t DOORBELL_OFFSET = SAMPLE_COUNT; static constexpr size_t DATA_OFFSET = 0; static void dumpMem(const uint32_t* addr, size_t len) @@ -124,7 +124,7 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu") // connect AXI Stream from DMA to Rtds2Gpu IP cr_assert(dma->connect(rtds2gpu)); - cr_assert(rtds2gpu.startOnce(dmaMemDst.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET*4, DOORBELL_OFFSET*4), + cr_assert(rtds2gpu.startOnce(dmaMemDst.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET * 4, DOORBELL_OFFSET * 4), "Preparing Rtds2Gpu IP failed"); cr_assert(dma->write(dmaMemSrc.getMemoryBlock(), FRAME_SIZE), @@ -195,7 +195,7 @@ Test(fpga, rtds2gpu_rtt_cpu, .description = "Rtds2Gpu RTT via CPU") auto dmaRam = villas::HostDmaRam::getAllocator().allocate(SAMPLE_COUNT + 1); uint32_t* data = &dmaRam[DATA_OFFSET]; - uint32_t* doorbell = &dmaRam[DOORBELL_OFFSET / SAMPLE_SIZE]; + uint32_t* doorbell = &dmaRam[DOORBELL_OFFSET]; // TEST: rtds loopback via switch // cr_assert(rtds.connect(rtds)); @@ -209,7 +209,7 @@ Test(fpga, rtds2gpu_rtt_cpu, .description = "Rtds2Gpu RTT via CPU") size_t count = 0; while(true) { rtds2gpu->doorbellReset(*doorbell); - rtds2gpu->startOnce(dmaRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET, DOORBELL_OFFSET); + rtds2gpu->startOnce(dmaRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET * 4, DOORBELL_OFFSET * 4); // while(not rtds2gpu->isFinished()); while(not rtds2gpu->doorbellIsValid(*doorbell)); From f7781d47af24746d77498e2ad245f846987e5e4f Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Tue, 5 Jun 2018 14:56:43 +0200 Subject: [PATCH 11/20] tests/rtds2gpu: cleanup --- fpga/tests/rtds2gpu.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index b6206da5b..a453572d9 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -63,7 +63,7 @@ static void dumpMem(const uint32_t* addr, size_t len) } } -Test(fpga, rtds2gpu, .description = "Rtds2Gpu") +Test(fpga, rtds2gpu_loopback_dma, .description = "Rtds2Gpu") { auto logger = loggerGetOrCreate("unittest:rtds2gpu"); @@ -197,38 +197,42 @@ Test(fpga, rtds2gpu_rtt_cpu, .description = "Rtds2Gpu RTT via CPU") uint32_t* data = &dmaRam[DATA_OFFSET]; uint32_t* doorbell = &dmaRam[DOORBELL_OFFSET]; - // TEST: rtds loopback via switch -// cr_assert(rtds.connect(rtds)); -// logger->info("loopback"); -// while(1); + // TEST: rtds loopback via switch, this should always work and have RTT=1 + //cr_assert(rtds.connect(rtds)); + //logger->info("loopback"); + //while(1); cr_assert(rtds.connect(*rtds2gpu)); cr_assert(gpu2rtds->connect(rtds)); - size_t count = 0; - while(true) { + for(size_t i = 1; i <= 10000; i++) { rtds2gpu->doorbellReset(*doorbell); rtds2gpu->startOnce(dmaRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET * 4, DOORBELL_OFFSET * 4); - // while(not rtds2gpu->isFinished()); + // Wait by polling rtds2gpu IP or ... + // while(not rtds2gpu->isFinished()); + + // Wait by polling (local) doorbell register (= just memory) while(not rtds2gpu->doorbellIsValid(*doorbell)); -// rtds2gpu->dump(); -// rtds2gpu->dumpDoorbell(data[1]); -// dumpMem(data, FRAME_SIZE + SAMPLE_SIZE); // copy samples to gpu2rtds IP for(size_t i = 0; i < SAMPLE_COUNT; i++) { gpu2rtds->registerFrames[i] = data[i]; } + // Waiting for gpu2rtds is not strictly required gpu2rtds->startOnce(SAMPLE_COUNT); -// while(not gpu2rtds->isFinished()); + //while(not gpu2rtds->isFinished()); - - count++; -// logger->debug("Successful iterations {}, data {}", count, data[0]); + if(i % 1000 == 0) { + logger->info("Successful iterations {}, data {}", i, data[0]); + rtds2gpu->dump(); + rtds2gpu->dumpDoorbell(data[1]); + } } + + logger->info(TXT_GREEN("Passed")); } } From d853d5e0d3accacf99dfab768501cde9d0932c78 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 6 Jun 2018 09:55:14 +0200 Subject: [PATCH 12/20] wip GPU RTT --- fpga/include/villas/fpga/ip_node.hpp | 4 +- fpga/include/villas/fpga/ips/gpu2rtds.hpp | 6 +- fpga/include/villas/fpga/ips/hls.hpp | 2 +- fpga/include/villas/fpga/ips/rtds2gpu.hpp | 13 +++ fpga/lib/gpu/gpu.cpp | 7 ++ fpga/lib/gpu/include/villas/gpu.hpp | 3 + fpga/lib/ips/rtds2gpu/rtds2gpu.cpp | 5 +- fpga/lib/kernel/vfio.cpp | 1 + fpga/tests/CMakeLists.txt | 3 +- fpga/tests/rtds2gpu.cpp | 113 +++++++++++++++++++++- 10 files changed, 148 insertions(+), 9 deletions(-) diff --git a/fpga/include/villas/fpga/ip_node.hpp b/fpga/include/villas/fpga/ip_node.hpp index 1257529c2..a89e9842f 100644 --- a/fpga/include/villas/fpga/ip_node.hpp +++ b/fpga/include/villas/fpga/ip_node.hpp @@ -71,8 +71,8 @@ public: const std::string& port, bool isMaster) { - for(auto& [vertexId, vertex] : vertices) { - (void) vertexId; + for(auto& vertexEntry : vertices) { + auto& vertex = vertexEntry.second; if(vertex->nodeName == node and vertex->portName == port and vertex->isMaster == isMaster) return vertex; } diff --git a/fpga/include/villas/fpga/ips/gpu2rtds.hpp b/fpga/include/villas/fpga/ips/gpu2rtds.hpp index b19702bef..1aab1a2aa 100644 --- a/fpga/include/villas/fpga/ips/gpu2rtds.hpp +++ b/fpga/include/villas/fpga/ips/gpu2rtds.hpp @@ -28,10 +28,14 @@ public: getDefaultMasterPort() const { return getMasterPort(rtdsOutputStreamPort); } + MemoryBlock + getRegisterMemory() const + { return MemoryBlock(0, 1 << 10, getAddressSpaceId(registerMemory)); } + private: bool updateStatus(); -private: +public: static constexpr const char* rtdsOutputStreamPort = "rtds_output"; struct StatusControlRegister { uint32_t diff --git a/fpga/include/villas/fpga/ips/hls.hpp b/fpga/include/villas/fpga/ips/hls.hpp index 685af9050..1184fdfd9 100644 --- a/fpga/include/villas/fpga/ips/hls.hpp +++ b/fpga/include/villas/fpga/ips/hls.hpp @@ -92,7 +92,7 @@ protected: { return { registerMemory }; } -private: +public: /* Register definitions */ static constexpr uintptr_t registerControlAddr = 0x00; diff --git a/fpga/include/villas/fpga/ips/rtds2gpu.hpp b/fpga/include/villas/fpga/ips/rtds2gpu.hpp index 0b35848cf..b956805c3 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu.hpp @@ -11,6 +11,19 @@ namespace villas { namespace fpga { namespace ip { +union ControlRegister { + uint32_t value; + struct { uint32_t + ap_start : 1, + ap_done : 1, + ap_idle : 1, + ap_ready : 1, + _res1 : 3, + auto_restart : 1, + _res2 : 24; + }; +}; + class Rtds2Gpu : public IpNode, public Hls { diff --git a/fpga/lib/gpu/gpu.cpp b/fpga/lib/gpu/gpu.cpp index e8f7d58ec..ffb7b7ad3 100644 --- a/fpga/lib/gpu/gpu.cpp +++ b/fpga/lib/gpu/gpu.cpp @@ -351,6 +351,13 @@ void Gpu::memcpyKernel(const MemoryBlock& src, const MemoryBlock& dst, size_t si cudaDeviceSynchronize(); } +MemoryTranslation +Gpu::translate(const MemoryBlock& dst) +{ + auto& mm = MemoryManager::get(); + return mm.getTranslation(masterPciEAddrSpaceId, dst.getAddrSpaceId()); +} + std::unique_ptr GpuAllocator::allocateBlock(size_t size) diff --git a/fpga/lib/gpu/include/villas/gpu.hpp b/fpga/lib/gpu/include/villas/gpu.hpp index 88b316815..00f1464ca 100644 --- a/fpga/lib/gpu/include/villas/gpu.hpp +++ b/fpga/lib/gpu/include/villas/gpu.hpp @@ -36,6 +36,9 @@ public: void memcpyKernel(const MemoryBlock& src, const MemoryBlock& dst, size_t size); + MemoryTranslation + translate(const MemoryBlock& dst); + private: bool registerIoMemory(const MemoryBlock& mem); bool registerHostMemory(const MemoryBlock& mem); diff --git a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp index 1fa271764..e89574efa 100644 --- a/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp +++ b/fpga/lib/ips/rtds2gpu/rtds2gpu.cpp @@ -22,11 +22,10 @@ bool Rtds2Gpu::init() status.value = 0; started = false; - maxFrameSize = getMaxFrameSize(); +// maxFrameSize = getMaxFrameSize(); + maxFrameSize = 16; logger->info("Max. frame size supported: {}", maxFrameSize); -// maxFrameSize = 16; - return true; } diff --git a/fpga/lib/kernel/vfio.cpp b/fpga/lib/kernel/vfio.cpp index b9639c1de..b04d172ce 100644 --- a/fpga/lib/kernel/vfio.cpp +++ b/fpga/lib/kernel/vfio.cpp @@ -754,6 +754,7 @@ VfioGroup::attach(VfioContainer& container, int groupIndex) << (container.isIommuEnabled() ? "" : "noiommu-") << groupIndex; + logger->debug("path: {}", groupPath.str().c_str()); group->fd = open(groupPath.str().c_str(), O_RDWR); if (group->fd < 0) { logger->error("Failed to open VFIO group {}", group->index); diff --git a/fpga/tests/CMakeLists.txt b/fpga/tests/CMakeLists.txt index 6eb34491a..36aacf045 100644 --- a/fpga/tests/CMakeLists.txt +++ b/fpga/tests/CMakeLists.txt @@ -11,7 +11,8 @@ set(SOURCES ) if(CMAKE_CUDA_COMPILER) - list(APPEND SOURCES gpu.cpp) + enable_language(CUDA) + list(APPEND SOURCES gpu.cpp gpu_kernels.cu) endif() add_executable(unit-tests ${SOURCES}) diff --git a/fpga/tests/rtds2gpu.cpp b/fpga/tests/rtds2gpu.cpp index a453572d9..cc3def8ce 100644 --- a/fpga/tests/rtds2gpu.cpp +++ b/fpga/tests/rtds2gpu.cpp @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -32,6 +34,7 @@ #include #include #include +#include #include "global.hpp" @@ -206,7 +209,7 @@ Test(fpga, rtds2gpu_rtt_cpu, .description = "Rtds2Gpu RTT via CPU") cr_assert(gpu2rtds->connect(rtds)); - for(size_t i = 1; i <= 10000; i++) { + for(size_t i = 1; i <= 10000; ) { rtds2gpu->doorbellReset(*doorbell); rtds2gpu->startOnce(dmaRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET * 4, DOORBELL_OFFSET * 4); @@ -233,6 +236,114 @@ Test(fpga, rtds2gpu_rtt_cpu, .description = "Rtds2Gpu RTT via CPU") } } + logger->info(TXT_GREEN("Passed")); + } +} + +void gpu_rtds_rtt_start(volatile uint32_t* dataIn, volatile reg_doorbell_t* doorbellIn, + volatile uint32_t* dataOut, volatile villas::fpga::ip::ControlRegister* controlRegister); + +void gpu_rtds_rtt_stop(); + +Test(fpga, rtds2gpu_rtt_gpu, .description = "Rtds2Gpu RTT via GPU") +{ + auto logger = loggerGetOrCreate("unittest:rtds2gpu"); + + /* Collect neccessary IPs */ + + auto gpu2rtds = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:gpu2rtds:"))); + + auto rtds2gpu = dynamic_cast( + state.cards.front()->lookupIp(villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:hls:rtds2gpu:"))); + + cr_assert_not_null(gpu2rtds, "No Gpu2Rtds IP found"); + cr_assert_not_null(rtds2gpu, "No Rtds2Gpu IP not found"); + + villas::Plugin* plugin = villas::Plugin::lookup(villas::Plugin::Type::Gpu, ""); + auto gpuPlugin = dynamic_cast(plugin); + cr_assert_not_null(gpuPlugin, "No GPU plugin found"); + + auto gpus = gpuPlugin->make(); + cr_assert(gpus.size() > 0, "No GPUs found"); + + // just get first cpu + auto& gpu = gpus.front(); + + // allocate memory on GPU and make accessible by to PCIe/FPGA + auto gpuRam = gpu->getAllocator().allocate(SAMPLE_COUNT + 1); + cr_assert(gpu->makeAccessibleToPCIeAndVA(gpuRam.getMemoryBlock())); + + // make Gpu2Rtds IP register memory on FPGA accessible to GPU + cr_assert(gpu->makeAccessibleFromPCIeOrHostRam(gpu2rtds->getRegisterMemory())); + + auto tr = gpu->translate(gpuRam.getMemoryBlock()); + + auto dataIn = reinterpret_cast(tr.getLocalAddr(DATA_OFFSET * sizeof(uint32_t))); + auto doorbellIn = reinterpret_cast(tr.getLocalAddr(DOORBELL_OFFSET * sizeof(uint32_t))); + + + auto gpu2rtdsRegisters = gpu->translate(gpu2rtds->getRegisterMemory()); + + auto frameRegister = reinterpret_cast(gpu2rtdsRegisters.getLocalAddr(gpu2rtds->registerFrameOffset)); + auto controlRegister = reinterpret_cast(gpu2rtdsRegisters.getLocalAddr(gpu2rtds->registerControlAddr)); + +// auto doorbellInCpu = reinterpret_cast(&gpuRam[DOORBELL_OFFSET]); + + for(auto& ip : state.cards.front()->ips) { + if(*ip != villas::fpga::Vlnv("acs.eonerc.rwth-aachen.de:user:rtds_axis:")) + continue; + + auto& rtds = dynamic_cast(*ip); + logger->info("Testing {}", rtds); + + + // TEST: rtds loopback via switch, this should always work and have RTT=1 + //cr_assert(rtds.connect(rtds)); + //logger->info("loopback"); + //while(1); + + cr_assert(rtds.connect(*rtds2gpu)); + cr_assert(gpu2rtds->connect(rtds)); + + // launch once so they are configured + cr_assert(rtds2gpu->startOnce(gpuRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET * 4, DOORBELL_OFFSET * 4)); + cr_assert(gpu2rtds->startOnce(SAMPLE_COUNT)); + + rtds2gpu->setAutoRestart(true); + rtds2gpu->start(); + + logger->info("GPU RTT RTDS"); + + std::string dummy; + +// logger->info("Press enter to proceed"); +// std::cin >> dummy; + + gpu_rtds_rtt_start(dataIn, doorbellIn, frameRegister, controlRegister); + +// while(1) { +// cr_assert(rtds2gpu->startOnce(gpuRam.getMemoryBlock(), SAMPLE_COUNT, DATA_OFFSET * 4, DOORBELL_OFFSET * 4)); +// } + +// for(int i = 0; i < 10000; i++) { +// while(not doorbellInCpu->is_valid); +// logger->debug("received data"); +// } + +// logger->info("Press enter to cancel"); +// std::cin >> dummy; + + while(1) { + sleep(1); +// logger->debug("Current sequence number: {}", doorbellInCpu->seq_nr); + logger->debug("Still running"); + } + + gpu_rtds_rtt_stop(); + + + logger->info(TXT_GREEN("Passed")); } } From 98c98b685583856b15aa1466a01d9e9bdbb7b116 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 11 Jul 2018 14:00:20 +0200 Subject: [PATCH 13/20] tests: add missing gpu kernels --- fpga/tests/gpu_kernels.cu | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 fpga/tests/gpu_kernels.cu diff --git a/fpga/tests/gpu_kernels.cu b/fpga/tests/gpu_kernels.cu new file mode 100644 index 000000000..3f5b8b0d4 --- /dev/null +++ b/fpga/tests/gpu_kernels.cu @@ -0,0 +1,75 @@ +#include +#include + +#include +#include + +#include +#include + + + +__global__ void +gpu_rtds_rtt_kernel(volatile uint32_t* dataIn, volatile reg_doorbell_t* doorbellIn, + volatile uint32_t* dataOut, volatile villas::fpga::ip::ControlRegister* controlRegister, + int* run) +{ + printf("[gpu] gpu kernel go\n"); + + printf("dataIn: %p\n", dataIn); + printf("doorbellIn: %p\n", doorbellIn); + printf("dataOut: %p\n", dataOut); + printf("control: %p\n", controlRegister); + printf("run: %p\n", run); + +// *run = reinterpret_cast(malloc(sizeof(bool))); +// **run = true; + + uint32_t last_seq; + while(*run) { + // wait for data +// printf("[gpu] wait for data, last_seq=%u\n", last_seq); + while(not (doorbellIn->is_valid and (last_seq != doorbellIn->seq_nr)) and *run); +// printf("doorbell: 0x%08x\n", doorbellIn->value); + + last_seq = doorbellIn->seq_nr; + +// printf("[gpu] copy data\n"); + for(size_t i = 0; i < doorbellIn->count; i++) { + dataOut[i] = dataIn[i]; + } + + // reset doorbell +// printf("[gpu] reset doorbell\n"); +// doorbellIn->value = 0; + +// printf("[gpu] signal go for gpu2rtds\n"); + controlRegister->ap_start = 1; + } + + printf("kernel done\n"); +} + +static int* run = nullptr; + +void gpu_rtds_rtt_start(volatile uint32_t* dataIn, volatile reg_doorbell_t* doorbellIn, + volatile uint32_t* dataOut, volatile villas::fpga::ip::ControlRegister* controlRegister) +{ + printf("run: %p\n", run); + if(run == nullptr) { + run = (int*)malloc(sizeof(uint32_t)); + cudaHostRegister(run, sizeof(uint32_t), 0); + } + printf("run: %p\n", run); + + + *run = 1; + gpu_rtds_rtt_kernel<<<1, 1>>>(dataIn, doorbellIn, dataOut, controlRegister, run); + printf("[cpu] kernel launched\n"); +} + +void gpu_rtds_rtt_stop() +{ + *run = 0; + cudaDeviceSynchronize(); +} From 0cdc05c3d54bed174e300aca28d4a15c3116cd79 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 11 Jul 2018 16:06:48 +0200 Subject: [PATCH 14/20] rtds2gpu: add struct for memory layout of rtds2gpu buffer --- .../villas/fpga/ips/rtds2gpu/register_types.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp index b59a297c9..01cd68817 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp @@ -2,6 +2,7 @@ #define REGISTER_TYPES_H #include +#include union axilite_reg_status_t { uint32_t value; @@ -27,4 +28,14 @@ union reg_doorbell_t { }; }; +template +struct Rtds2GpuMemoryBuffer { + static constexpr size_t valueCount = N; + static constexpr size_t dataOffset = offsetof(Rtds2GpuMemoryBuffer, data); + static constexpr size_t doorbellOffset = offsetof(Rtds2GpuMemoryBuffer, doorbell); + + T data[N]; + reg_doorbell_t doorbell; +} __attribute__((packed)); + #endif // REGISTER_TYPES_H From 375b6b5cd39ecb6afe0eee3d76ed286e1152c2dc Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Fri, 20 Jul 2018 16:44:28 +0200 Subject: [PATCH 15/20] common/memory: let allocators own a memory block This is useful when we sub-delegate management of a memory block to another allocator. --- fpga/include/villas/memory.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fpga/include/villas/memory.hpp b/fpga/include/villas/memory.hpp index d06e3c1d6..a168dce40 100644 --- a/fpga/include/villas/memory.hpp +++ b/fpga/include/villas/memory.hpp @@ -123,6 +123,12 @@ public: }; } + BaseAllocator(std::unique_ptr mem) : + BaseAllocator(mem->getAddrSpaceId()) + { + memoryBlock = std::move(mem); + } + virtual std::unique_ptr allocateBlock(size_t size) = 0; @@ -174,6 +180,9 @@ protected: MemoryBlock::deallocator_fn free; SpdLogger logger; + // optional, if allocator should own the memory block + std::unique_ptr memoryBlock; + private: MemoryManager::AddressSpaceId memoryAddrSpaceId; DerivedAllocator* derivedAlloc; @@ -195,6 +204,12 @@ public: size_t memorySize, size_t internalOffset = 0); + LinearAllocator(std::unique_ptr mem) : + LinearAllocator(mem->getAddrSpaceId(), mem->getSize()) + { + memoryBlock = std::move(mem); + } + size_t getAvailableMemory() const { return memorySize - nextFreeAddress; } From 8a06e96e9265ee3be8ebfbaa229eaecce4e38dac Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Fri, 20 Jul 2018 16:46:55 +0200 Subject: [PATCH 16/20] gpu: always allocate page-sized chunks, then use LinearAllocator This was neccessary in order to make the memory available via GDRcopy when multiple small allocations were made. cudaMalloc() would return multiple memory chunks located in the same GPU page, which GDRcopy pretty much dislikes (`gdrdrv:offset != 0 is not supported`). As a side effect, this will keep the number of BAR-mappings done via GDRcopy low, because they seem to be quite limited. --- fpga/lib/gpu/gpu.cpp | 56 ++++++++++++++++++++--------- fpga/lib/gpu/include/villas/gpu.hpp | 4 +++ 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/fpga/lib/gpu/gpu.cpp b/fpga/lib/gpu/gpu.cpp index ffb7b7ad3..098ec5310 100644 --- a/fpga/lib/gpu/gpu.cpp +++ b/fpga/lib/gpu/gpu.cpp @@ -365,29 +365,53 @@ GpuAllocator::allocateBlock(size_t size) cudaSetDevice(gpu.gpuId); void* addr; - if(cudaSuccess != cudaMalloc(&addr, size)) { - logger->error("cudaMalloc(..., size={}) failed", size); - throw std::bad_alloc(); - } - auto& mm = MemoryManager::get(); - // assemble name for this block - std::stringstream name; - name << std::showbase << std::hex << reinterpret_cast(addr); + // search for an existing chunk that has enough free memory + auto chunk = std::find_if(chunks.begin(), chunks.end(), [&](const auto& chunk) { + return chunk->getAvailableMemory() >= size; + }); - auto blockName = mm.getSlaveAddrSpaceName(getName(), name.str()); - auto blockAddrSpaceId = mm.getOrCreateAddressSpace(blockName); - const auto localAddr = reinterpret_cast(addr); - std::unique_ptr - mem(new MemoryBlock(localAddr, size, blockAddrSpaceId), this->free); + if(chunk != chunks.end()) { + logger->debug("Found existing chunk that can host the requested block"); - insertMemoryBlock(*mem); + return (*chunk)->allocateBlock(size); - gpu.makeAccessibleToPCIeAndVA(*mem); + } else { + // allocate a new chunk - return mem; + // rounded-up multiple of GPU page size + const size_t chunkSize = size - (size & (GpuPageSize - 1)) + GpuPageSize; + logger->debug("Allocate new chunk of {:#x} bytes", chunkSize); + + if(cudaSuccess != cudaMalloc(&addr, chunkSize)) { + logger->error("cudaMalloc(..., size={}) failed", chunkSize); + throw std::bad_alloc(); + } + + // assemble name for this block + std::stringstream name; + name << std::showbase << std::hex << reinterpret_cast(addr); + + auto blockName = mm.getSlaveAddrSpaceName(getName(), name.str()); + auto blockAddrSpaceId = mm.getOrCreateAddressSpace(blockName); + + const auto localAddr = reinterpret_cast(addr); + std::unique_ptr + mem(new MemoryBlock(localAddr, chunkSize, blockAddrSpaceId), this->free); + + insertMemoryBlock(*mem); + + // already make accessible to CPU + gpu.makeAccessibleToPCIeAndVA(*mem); + + // create a new allocator to manage the chunk and push to chunk list + chunks.push_front(std::make_unique(std::move(mem))); + + // call again, this time there's a large enough chunk + return allocateBlock(size); + } } diff --git a/fpga/lib/gpu/include/villas/gpu.hpp b/fpga/lib/gpu/include/villas/gpu.hpp index 00f1464ca..a2eb78efe 100644 --- a/fpga/lib/gpu/include/villas/gpu.hpp +++ b/fpga/lib/gpu/include/villas/gpu.hpp @@ -62,6 +62,8 @@ private: class GpuAllocator : public BaseAllocator { public: + static constexpr size_t GpuPageSize = 64UL << 10; + GpuAllocator(Gpu& gpu); std::string getName() const; @@ -71,6 +73,8 @@ public: private: Gpu& gpu; + // TODO: replace by multimap (key is available memory) + std::list> chunks; }; class GpuFactory : public Plugin { From 26abf44d2f28031a07105a2d9768d5a57ea1f88f Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Fri, 20 Jul 2018 16:50:54 +0200 Subject: [PATCH 17/20] villas/memory: add sanity check to deny allocating zero-sized memory --- fpga/include/villas/memory.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fpga/include/villas/memory.hpp b/fpga/include/villas/memory.hpp index a168dce40..6f608ae89 100644 --- a/fpga/include/villas/memory.hpp +++ b/fpga/include/villas/memory.hpp @@ -136,6 +136,12 @@ public: MemoryAccessor allocate(size_t num) { + if(num == 0) { + // doesn't make sense to allocate an empty block + logger->error("Trying to allocate empty memory"); + throw std::bad_alloc(); + } + const size_t size = num * sizeof(T); auto mem = allocateBlock(size); From c44aedd6a96858aa32a0efbcfcadf5a28ece0242 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Fri, 20 Jul 2018 16:52:09 +0200 Subject: [PATCH 18/20] gpu: update to recent GDRcopy --- fpga/lib/gpu/gdrcopy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpga/lib/gpu/gdrcopy b/fpga/lib/gpu/gdrcopy index 0441daa44..e36e3bbef 160000 --- a/fpga/lib/gpu/gdrcopy +++ b/fpga/lib/gpu/gdrcopy @@ -1 +1 @@ -Subproject commit 0441daa447b80260c4e11096f03e88f7be08bfa2 +Subproject commit e36e3bbeff6d89603ccc0c7f832938f697ac7fd6 From b2698c8bd58b8be429451dac7ba8c97dc4f9b42b Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Thu, 26 Jul 2018 16:49:06 +0200 Subject: [PATCH 19/20] rtds2gpu: update register type to work for more complex payloads --- .../fpga/ips/rtds2gpu/register_types.hpp | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp index 01cd68817..ce7328417 100644 --- a/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp +++ b/fpga/include/villas/fpga/ips/rtds2gpu/register_types.hpp @@ -3,6 +3,7 @@ #include #include +#include union axilite_reg_status_t { uint32_t value; @@ -26,16 +27,31 @@ union reg_doorbell_t { count : 6, is_valid : 1; }; + + constexpr reg_doorbell_t() : value(0) {} }; template struct Rtds2GpuMemoryBuffer { - static constexpr size_t valueCount = N; - static constexpr size_t dataOffset = offsetof(Rtds2GpuMemoryBuffer, data); - static constexpr size_t doorbellOffset = offsetof(Rtds2GpuMemoryBuffer, doorbell); + // this type is only for memory interpretation, it makes no sense to create + // an instance so it's forbidden + Rtds2GpuMemoryBuffer() = delete; + + // T can be a more complex type that wraps multiple values + static constexpr size_t rawValueCount = N * (sizeof(T) / 4); + + // As of C++14, offsetof() is not working for non-standard layout types (i.e. + // composed of non-POD members). This might work in C++17 though. + // More info: https://gist.github.com/graphitemaster/494f21190bb2c63c5516 + //static constexpr size_t doorbellOffset = offsetof(Rtds2GpuMemoryBuffer, doorbell); + //static constexpr size_t dataOffset = offsetof(Rtds2GpuMemoryBuffer, data); + + // HACK: This might break horribly, let's just hope C++17 will be there soon + static constexpr size_t dataOffset = 0; + static constexpr size_t doorbellOffset = N * sizeof(Rtds2GpuMemoryBuffer::data); T data[N]; reg_doorbell_t doorbell; -} __attribute__((packed)); +}; #endif // REGISTER_TYPES_H From 96cd71a87e646962724b8c56ebb7ce2e4a438fd0 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Tue, 21 Aug 2018 13:10:53 +0200 Subject: [PATCH 20/20] gpu/gdrcopy: rebase on current upstream master and update --- fpga/lib/gpu/gdrcopy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpga/lib/gpu/gdrcopy b/fpga/lib/gpu/gdrcopy index e36e3bbef..fcf4bc566 160000 --- a/fpga/lib/gpu/gdrcopy +++ b/fpga/lib/gpu/gdrcopy @@ -1 +1 @@ -Subproject commit e36e3bbeff6d89603ccc0c7f832938f697ac7fd6 +Subproject commit fcf4bc56687c01e71379c174b6875bd3a99b31c7