Commit 7150d3ba authored by Daniel Krebs's avatar Daniel Krebs

lib/ip-node: add IpNode class, IpCore which has streaming ports

parent 07af43a3
......@@ -26,7 +26,6 @@
"slot": "03:00.0",
"do_reset": true,
"ips": {
"axi_reset_0": {
"vlnv": "xilinx.com:ip:axi_gpio:2.0",
"baseaddr": 28672
......@@ -39,7 +38,6 @@
"dma_0": {
"vlnv": "xilinx.com:ip:axi_dma:7.1",
"baseaddr": 12288,
"port": "switch_0:1",
"irq": "axi_pcie_intc_0:3"
},
"axi_pcie_intc_0": {
......@@ -49,26 +47,38 @@
"dma_1": {
"vlnv": "xilinx.com:ip:axi_dma:7.1",
"baseaddr": 8192,
"port": "switch_0:6",
"ports": {
"master": [ { "num": 0, "other": "switch_0:6" } ],
"slave": [ { "num": 0, "other": "switch_0:6" } ]
},
"irq": "axi_pcie_intc_0:3"
},
"fifo_mm_s_0": {
"vlnv": "xilinx.com:ip:axi_fifo_mm_s:4.1",
"baseaddr": 24576,
"baseaddr_axi4": 49152,
"port": "switch_0:2",
"ports": {
"master": [ { "num": 0, "other": "switch_0:2" } ],
"slave": [ { "num": 0, "other": "switch_0:2" } ]
},
"irq": "axi_pcie_intc_0:2"
},
"rtds_axis_0": {
"vlnv": "acs.eonerc.rwth-aachen.de:user:rtds_axis:1.0",
"baseaddr": 32768,
"port": "switch_0:0",
"ports": {
"master": [ { "num": 0, "other": "switch_0:0" } ],
"slave": [ { "num": 0, "other": "switch_0:0" } ]
},
"irq": "axi_pcie_intc_0:5"
},
"hls_dft_0": {
"vlnv": "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.0",
"baseaddr": 36864,
"port": "switch_0:5",
"ports": {
"master": [ { "num": 0, "other": "switch_0:5" } ],
"slave": [ { "num": 0, "other": "switch_0:5" } ]
},
"irq": "axi_pcie_intc_0:1",
"period": 400,
"harmonics": [
......@@ -82,23 +92,47 @@
},
"axis_data_fifo_0": {
"vlnv": "xilinx.com:ip:axis_data_fifo:1.1",
"port": "switch_0:3"
"ports": {
"master": [ { "num": 0, "other": "switch_0:3" } ],
"slave": [ { "num": 0, "other": "switch_0:3" } ]
}
},
"switch_0": {
"vlnv": "xilinx.com:ip:axis_interconnect:2.1",
"baseaddr": 20480,
"num_ports": 10,
"paths": [
{
"in": "rtds_axis_0",
"out": "dma_1",
"reverse": true
}
]
"ports": {
"master": [
{ "num": 0 },
{ "num": 1 },
{ "num": 2 },
{ "num": 3 },
{ "num": 4 },
{ "num": 5 },
{ "num": 6 },
{ "num": 7 },
{ "num": 8 },
{ "num": 9 }
],
"slave": [
{ "num": 0 },
{ "num": 1 },
{ "num": 2 },
{ "num": 3 },
{ "num": 4 },
{ "num": 5 },
{ "num": 6 },
{ "num": 7 },
{ "num": 8 },
{ "num": 9 }
]
}
},
"axis_data_fifo_1": {
"vlnv": "xilinx.com:ip:axis_data_fifo:1.1",
"port": "switch_0:6"
"ports": {
"master": [ { "num": 0, "other": "switch_0:6" } ],
"slave": [ { "num": 0, "other": "switch_0:6" } ]
}
}
}
}
......
......@@ -122,7 +122,7 @@ using IpCoreList = std::list<std::unique_ptr<IpCore>>;
class IpCoreFactory : public Plugin {
public:
IpCoreFactory(std::string concreteName) :
Plugin(std::string("FPGA IpCore Factory: ") + concreteName)
Plugin(std::string("IpCore - ") + concreteName)
{ pluginType = Plugin::Type::FpgaIp; }
/// Returns a running and checked FPGA IP
......
/** Interlectual Property component.
*
* This class represents a module within the FPGA.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Daniel Krebs <github@daniel-krebs.net>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASfpga
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
/** @addtogroup fpga VILLASfpga
* @{
*/
#ifndef VILLAS_IP_NODE_HPP
#define VILLAS_IP_NODE_HPP
#include <map>
#include <string>
#include <jansson.h>
#include "ip.hpp"
#include "log.hpp"
namespace villas {
namespace fpga {
namespace ip {
// TODO: reflect on interface that an IpNode exposes and how to design it to
// blend in with VILLASnode software nodes
class IpNode : public IpCore {
public:
friend class IpNodeFactory;
struct OtherIpNode {
int otherPortNum;
std::string otherName;
};
bool connectTo(int port, const OtherIpNode& other);
bool disconnect(int port);
protected:
std::map<int, OtherIpNode> portsMaster;
std::map<int, OtherIpNode> portsSlave;
};
class IpNodeFactory : public IpCoreFactory {
public:
IpNodeFactory(std::string name) : IpCoreFactory("Ip Node - " + name) {}
virtual bool configureJson(IpCore& ip, json_t *json_ip);
private:
bool populatePorts(std::map<int, IpNode::OtherIpNode>& portMap, json_t* json);
};
/** @} */
} // namespace ip
} // namespace fpga
} // namespace villas
#endif // VILLAS_IP_NODE_HPP
......@@ -31,6 +31,8 @@
#include "fpga/ip.hpp"
#include <xilinx/xintc.h>
#include "fpga/ip_node.hpp"
namespace villas {
namespace fpga {
namespace ip {
......
set(SOURCES
ip.cpp
ip.c
ip_node.cpp
vlnv.cpp
vlnv.c
card.c
......
#include <map>
#include <stdexcept>
#include <jansson.h>
#include "utils.hpp"
#include "fpga/ip_node.hpp"
namespace villas {
namespace fpga {
namespace ip {
bool
IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
{
auto ipNode = reinterpret_cast<IpNode&>(ip);
json_t* json_ports = json_object_get(json_ip, "ports");
if(json_ports == nullptr) {
cpp_error << "IpNode " << ip << " has no ports property";
return false;
}
json_t* json_master = json_object_get(json_ports, "master");
json_t* json_slave = json_object_get(json_ports, "slave");
const bool hasMasterPorts = json_is_array(json_master);
const bool hasSlavePorts = json_is_array(json_slave);
if( (not hasMasterPorts) and (not hasSlavePorts)) {
cpp_error << "IpNode " << ip << " has not ports";
return false;
}
// intentionally use short-circuit evaluation to only call populatePorts
// if the property exists
bool masterPortsSuccess =
(hasMasterPorts and populatePorts(ipNode.portsMaster, json_master))
or (not hasMasterPorts);
bool slavePortsSuccess =
(hasSlavePorts and populatePorts(ipNode.portsSlave, json_slave))
or (not hasSlavePorts);
return (masterPortsSuccess and slavePortsSuccess);
}
bool
IpNodeFactory::populatePorts(std::map<int, IpNode::OtherIpNode>& portMap, json_t* json)
{
size_t index;
json_t* json_port;
json_array_foreach(json, index, json_port) {
int myPortNum;
const char* other = nullptr;
int ret = json_unpack(json_port, "{ s : i, s? : s}",
"num", &myPortNum,
"other", &other);
if(ret != 0) {
cpp_error << "Port definition required field 'num'";
return false;
}
if(other == nullptr) {
cpp_warn << "Nothing connected to port " << myPortNum;
portMap[myPortNum] = {};
continue;
}
const auto tokens = utils::tokenize(other, ":");
if(tokens.size() != 2) {
cpp_error << "Too many tokens in property 'other'";
return false;
}
int otherPortNum;
try {
otherPortNum = std::stoi(tokens[1]);
} catch(const std::invalid_argument&) {
cpp_error << "Other port number is not an integral number";
return false;
}
cpp_debug << "Adding port mapping: " << myPortNum << ":" << other;
portMap[myPortNum] = { otherPortNum, tokens[0] };
}
return true;
}
} // namespace ip
} // namespace fpga
} // namespace villas
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