mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-30 00:00:11 +01:00
168 lines
4.7 KiB
C++
168 lines
4.7 KiB
C++
/* Interlectual Property component.
|
|
*
|
|
* This class represents a module within the FPGA.
|
|
*
|
|
* Author: Steffen Vogel <post@steffenvogel.de>
|
|
* Author: Daniel Krebs <github@daniel-krebs.net>
|
|
* SPDX-FileCopyrightText: 2017 Institute for Automation of Complex Power Systems, RWTH Aachen University
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <fmt/ostream.h>
|
|
#include <jansson.h>
|
|
#include <map>
|
|
#include <string>
|
|
#include <villas/config.hpp>
|
|
#include <villas/fpga/core.hpp>
|
|
#include <villas/graph/directed.hpp>
|
|
|
|
namespace villas {
|
|
namespace fpga {
|
|
namespace ip {
|
|
|
|
class StreamVertex : public graph::Vertex {
|
|
public:
|
|
StreamVertex(const std::string &node, const std::string &port, bool isMaster)
|
|
: graph::Vertex(), nodeName(node), portName(port), isMaster(isMaster) {}
|
|
|
|
std::string getName() const {
|
|
return nodeName + "/" + portName + "(" + (isMaster ? "M" : "S") + ")";
|
|
}
|
|
|
|
friend std::ostream &operator<<(std::ostream &stream,
|
|
const StreamVertex &vertex) {
|
|
return stream << vertex.getIdentifier() << ": " << vertex.getName();
|
|
}
|
|
|
|
public:
|
|
std::string nodeName;
|
|
std::string portName;
|
|
bool isMaster;
|
|
};
|
|
|
|
class StreamGraph : public graph::DirectedGraph<StreamVertex> {
|
|
public:
|
|
StreamGraph() : graph::DirectedGraph<StreamVertex>("stream:graph") {}
|
|
|
|
std::shared_ptr<StreamVertex> getOrCreateStreamVertex(const std::string &node,
|
|
const std::string &port,
|
|
bool isMaster) {
|
|
for (auto &vertexEntry : vertices) {
|
|
auto &vertex = vertexEntry.second;
|
|
if (vertex->nodeName == node and vertex->portName == port and
|
|
vertex->isMaster == isMaster)
|
|
return vertex;
|
|
}
|
|
|
|
// Vertex not found, create new one
|
|
auto vertex = std::make_shared<StreamVertex>(node, port, isMaster);
|
|
addVertex(vertex);
|
|
|
|
return vertex;
|
|
}
|
|
};
|
|
|
|
class Node : public virtual Core {
|
|
public:
|
|
using Ptr = std::shared_ptr<Node>;
|
|
|
|
friend class NodeFactory;
|
|
|
|
const StreamVertex &getMasterPort(const std::string &name) const {
|
|
return *portsMaster.at(name);
|
|
}
|
|
|
|
const std::map<std::string, std::shared_ptr<StreamVertex>> &
|
|
getMasterPorts() const {
|
|
return portsMaster;
|
|
}
|
|
|
|
const StreamVertex &getSlavePort(const std::string &name) const {
|
|
return *portsSlave.at(name);
|
|
}
|
|
|
|
const std::map<std::string, std::shared_ptr<StreamVertex>> &
|
|
getSlavePorts() const {
|
|
return portsSlave;
|
|
}
|
|
|
|
bool connect(const StreamVertex &from, const StreamVertex &to);
|
|
bool connect(const StreamVertex &from, const StreamVertex &to, bool reverse) {
|
|
bool ret;
|
|
|
|
ret = connect(from, to);
|
|
|
|
if (reverse)
|
|
ret &= connect(to, from);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Easy-usage assuming that the slave IP to connect to only has one slave
|
|
// port and implements the getDefaultSlavePort() function
|
|
bool connect(const Node &slaveNode, bool reverse = false) {
|
|
return this->connect(this->getDefaultMasterPort(),
|
|
slaveNode.getDefaultSlavePort(), reverse);
|
|
}
|
|
|
|
// Used by easy-usage connect, will throw if not implemented by derived node
|
|
virtual const StreamVertex &getDefaultSlavePort() const;
|
|
|
|
// Used by easy-usage connect, will throw if not implemented by derived node
|
|
virtual const StreamVertex &getDefaultMasterPort() const;
|
|
|
|
static const StreamGraph &getGraph() { return streamGraph; }
|
|
|
|
bool loopbackPossible() const;
|
|
bool connectLoopback();
|
|
|
|
protected:
|
|
virtual bool connectInternal(const std::string &slavePort,
|
|
const std::string &masterPort);
|
|
|
|
private:
|
|
std::pair<std::string, std::string> getLoopbackPorts() const;
|
|
|
|
protected:
|
|
std::map<std::string, std::shared_ptr<StreamVertex>> portsMaster;
|
|
std::map<std::string, std::shared_ptr<StreamVertex>> portsSlave;
|
|
|
|
static StreamGraph streamGraph;
|
|
};
|
|
|
|
class NodeFactory : public CoreFactory {
|
|
public:
|
|
using CoreFactory::CoreFactory;
|
|
|
|
virtual void parse(Core &, json_t *);
|
|
};
|
|
|
|
template <typename T, const char *name, const char *desc, const char *vlnv>
|
|
class NodePlugin : public NodeFactory {
|
|
|
|
public:
|
|
virtual std::string getName() const { return name; }
|
|
|
|
virtual std::string getDescription() const { return desc; }
|
|
|
|
private:
|
|
// Get a VLNV identifier for which this IP / Node type can be used.
|
|
virtual Vlnv getCompatibleVlnv() const { return Vlnv(vlnv); }
|
|
|
|
// Create a concrete IP instance
|
|
Core *make() const { return new T; }
|
|
};
|
|
|
|
} // namespace ip
|
|
} // namespace fpga
|
|
} // namespace villas
|
|
|
|
#ifndef FMT_LEGACY_OSTREAM_FORMATTER
|
|
template <>
|
|
class fmt::formatter<villas::fpga::ip::StreamVertex>
|
|
: public fmt::ostream_formatter {};
|
|
template <>
|
|
class fmt::formatter<villas::fpga::ip::Node> : public fmt::ostream_formatter {};
|
|
#endif
|