From 010e0c3681729bc4beef140a50175171006081ed Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Wed, 30 May 2018 13:58:26 +0200 Subject: [PATCH] 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);