mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
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.
This commit is contained in:
parent
5c67dc3727
commit
010e0c3681
7 changed files with 153 additions and 40 deletions
|
@ -86,7 +86,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class IpNode : public IpCore {
|
||||
class IpNode : public virtual IpCore {
|
||||
public:
|
||||
|
||||
friend class IpNodeFactory;
|
||||
|
|
137
fpga/include/villas/fpga/ips/hls.hpp
Normal file
137
fpga/include/villas/fpga/ips/hls.hpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
|
||||
#include <villas/memory.hpp>
|
||||
#include <villas/fpga/ip_node.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace fpga {
|
||||
namespace ip {
|
||||
|
||||
|
||||
class Hls : public virtual IpCore
|
||||
{
|
||||
public:
|
||||
virtual bool init()
|
||||
{
|
||||
auto& registers = addressTranslations.at(registerMemory);
|
||||
|
||||
controlRegister = reinterpret_cast<ControlRegister*>(registers.getLocalAddr(registerControlAddr));
|
||||
globalIntRegister = reinterpret_cast<GlobalIntRegister*>(registers.getLocalAddr(registerGlobalIntEnableAddr));
|
||||
ipIntEnableRegister = reinterpret_cast<IpIntRegister*>(registers.getLocalAddr(registerIntEnableAddr));
|
||||
ipIntStatusRegister = reinterpret_cast<IpIntRegister*>(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<MemoryBlockName> 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
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <villas/memory.hpp>
|
||||
#include <villas/fpga/ip_node.hpp>
|
||||
#include <villas/fpga/ips/hls.hpp>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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<T*>(translation.getLocalAddr(0));
|
||||
|
|
|
@ -19,7 +19,7 @@ IpNode::streamGraph;
|
|||
bool
|
||||
IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
|
||||
{
|
||||
auto& ipNode = reinterpret_cast<IpNode&>(ip);
|
||||
auto& ipNode = dynamic_cast<IpNode&>(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<ip::AxiStreamSwitch*>(
|
||||
auto axiStreamSwitch = dynamic_cast<ip::AxiStreamSwitch*>(
|
||||
card->lookupIp(portMaster->nodeName));
|
||||
|
||||
if(axiStreamSwitch == nullptr) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -55,12 +55,14 @@ Test(fpga, rtds2gpu, .description = "Rtds2Gpu")
|
|||
|
||||
/* Collect neccessary IPs */
|
||||
|
||||
auto rtds2gpu = reinterpret_cast<villas::fpga::ip::Rtds2Gpu&>(*ip);
|
||||
auto rtds2gpu = dynamic_cast<villas::fpga::ip::Rtds2Gpu&>(*ip);
|
||||
|
||||
auto axiSwitch = reinterpret_cast<villas::fpga::ip::AxiStreamSwitch*>(
|
||||
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<villas::fpga::ip::AxiStreamSwitch*>(axiSwitchPtr);
|
||||
|
||||
auto dma = reinterpret_cast<villas::fpga::ip::Dma*>(
|
||||
cr_assert_not_null(axiSwitchPtr);
|
||||
|
||||
auto dma = dynamic_cast<villas::fpga::ip::Dma*>(
|
||||
state.cards.front()->lookupIp(villas::fpga::Vlnv("xilinx.com:ip:axi_dma:")));
|
||||
|
||||
rtds2gpu.dump(spdlog::level::debug);
|
||||
|
|
Loading…
Add table
Reference in a new issue