mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
lib/ip-node: add IpNode class, IpCore which has streaming ports
This commit is contained in:
parent
f3f0f4d630
commit
12024d53e5
6 changed files with 229 additions and 17 deletions
|
@ -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
|
||||
|
|
81
fpga/include/villas/fpga/ip_node.hpp
Normal file
81
fpga/include/villas/fpga/ip_node.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
/** 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 {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
set(SOURCES
|
||||
ip.cpp
|
||||
ip.c
|
||||
ip_node.cpp
|
||||
vlnv.cpp
|
||||
vlnv.c
|
||||
card.c
|
||||
|
|
94
fpga/lib/ip_node.cpp
Normal file
94
fpga/lib/ip_node.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
#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
|
Loading…
Add table
Reference in a new issue