Aufgrund eines Versionsupdates wird GitLab am 17.12. zwischen 9:00 und 9:30 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to a version upgrade, GitLab won't be accessible at 17.12. between 9 and 9:30 a.m.

Commit b509e870 authored by Daniel Krebs's avatar Daniel Krebs

ip-node: add implementation of StreamGraph for automatic routing

parent b8dc8fd7
......@@ -29,6 +29,10 @@ class Vertex {
public:
using Identifier = std::size_t;
const Identifier&
getIdentifier() const
{ return id; }
friend std::ostream&
operator<< (std::ostream& stream, const Vertex& vertex)
{ return stream << vertex.id; }
......@@ -314,7 +318,7 @@ public:
}
}
private:
protected:
VertexIdentifier lastVertexId;
EdgeIdentifier lastEdgeId;
......
......@@ -43,6 +43,52 @@ namespace villas {
namespace fpga {
namespace ip {
class StreamVertex : public graph::Vertex {
public:
StreamVertex(const std::string& node, const std::string& port, bool isMaster) :
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>("StreamGraph") {}
std::shared_ptr<StreamVertex>
getOrCreateStreamVertex(const std::string& node,
const std::string& port,
bool isMaster)
{
for(auto& [vertexId, vertex] : vertices) {
(void) vertexId;
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;
}
};
extern StreamGraph streamGraph;
// TODO: reflect on interface that an IpNode exposes and how to design it to
// blend in with VILLASnode software nodes
class IpNode : public IpCore {
......@@ -58,6 +104,14 @@ public:
bool connect(std::string portName, const StreamPort& to);
bool disconnect(std::string portName);
const StreamVertex&
getMasterPort(const std::string& name) const
{ return *portsMaster.at(name); }
const StreamVertex&
getSlavePort(const std::string& name) const
{ return *portsSlave.at(name); }
bool loopbackPossible() const;
bool connectLoopback();
......@@ -65,8 +119,8 @@ private:
std::pair<std::string, std::string> getLoopbackPorts() const;
protected:
std::map<std::string, StreamPort> portsMaster;
std::map<std::string, StreamPort> portsSlave;
std::map<std::string, std::shared_ptr<StreamVertex>> portsMaster;
std::map<std::string, std::shared_ptr<StreamVertex>> portsSlave;
};
class IpNodeFactory : public IpCoreFactory {
......
......@@ -13,6 +13,8 @@ namespace fpga {
namespace ip {
StreamGraph streamGraph;
bool
IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
{
......@@ -49,25 +51,28 @@ IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
return false;
}
int port_num;
try {
port_num = std::stoi(tokens[1]);
} catch(const std::invalid_argument&) {
logger->error("Target port number is not an integer: '{}'", target_raw);
return false;
}
const std::string role(role_raw);
const bool isMaster = (role == "master" or role == "initiator");
IpNode::StreamPort port;
port.nodeName = tokens[0];
port.portNumber = port_num;
const std::string role(role_raw);
if(role == "master" or role == "initiator") {
ipNode.portsMaster[name_raw] = port;
auto thisVertex = streamGraph.getOrCreateStreamVertex(
ip.getInstanceName(),
name_raw,
isMaster);
auto connectedVertex = streamGraph.getOrCreateStreamVertex(
tokens[0],
tokens[1],
not isMaster);
if(isMaster) {
streamGraph.addDefaultEdge(thisVertex->getIdentifier(),
connectedVertex->getIdentifier());
ipNode.portsMaster[name_raw] = thisVertex;
} else /* slave */ {
ipNode.portsSlave[name_raw] = port;
ipNode.portsSlave[name_raw] = thisVertex;
}
}
return true;
......@@ -79,7 +84,7 @@ IpNode::getLoopbackPorts() const
for(auto& [masterName, masterTo] : portsMaster) {
for(auto& [slaveName, slaveTo] : portsSlave) {
// TODO: should we also check which IP both ports are connected to?
if(masterTo.nodeName == slaveTo.nodeName) {
if(masterTo->nodeName == slaveTo->nodeName) {
return { masterName, slaveName };
}
}
......@@ -105,11 +110,11 @@ IpNode::connectLoopback()
logger->debug("master port: {}", ports.first);
logger->debug("slave port: {}", ports.second);
logger->debug("switch at: {}", portMaster.nodeName);
logger->debug("switch at: {}", portMaster->nodeName);
// TODO: verify this is really a switch!
auto axiStreamSwitch = reinterpret_cast<ip::AxiStreamSwitch*>(
card->lookupIp(portMaster.nodeName));
card->lookupIp(portMaster->nodeName));
if(axiStreamSwitch == nullptr) {
logger->error("Cannot find switch");
......@@ -117,7 +122,7 @@ IpNode::connectLoopback()
}
// switch's slave port is our master port and vice versa
return axiStreamSwitch->connect(portMaster.portNumber, portSlave.portNumber);
return axiStreamSwitch->connect(*portMaster, *portSlave);
}
} // namespace ip
......
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