Commit 4840eaa5 authored by Daniel Krebs's avatar Daniel Krebs

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.
parent 291cc9d0
......@@ -86,7 +86,7 @@ public:
};
class IpNode : public IpCore {
class IpNode : public virtual IpCore {
public:
friend class IpNodeFactory;
......
#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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment