mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
wip implementing dependency parsing and proper memeory handling
works and compiles so for. next is to implement different IP interfaces (Model, Interface, DataMover, Infrastructure, ...)
This commit is contained in:
parent
6a721847e4
commit
a5b5e317d4
11 changed files with 387 additions and 175 deletions
|
@ -26,10 +26,64 @@
|
|||
"slot": "03:00.0",
|
||||
"do_reset": true,
|
||||
"ips": {
|
||||
|
||||
"axi_reset_0": {
|
||||
"vlnv": "xilinx.com:ip:axi_gpio:2.0",
|
||||
"baseaddr": 28672
|
||||
},
|
||||
"timer_0": {
|
||||
"vlnv": "xilinx.com:ip:axi_timer:2.0",
|
||||
"baseaddr": 16384,
|
||||
"irq": "axi_pcie_intc_0:0"
|
||||
},
|
||||
"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": {
|
||||
"vlnv": "acs.eonerc.rwth-aachen.de:user:axi_pcie_intc:1.0",
|
||||
"baseaddr": 45056
|
||||
},
|
||||
"dma_1": {
|
||||
"vlnv": "xilinx.com:ip:axi_dma:7.1",
|
||||
"baseaddr": 8192,
|
||||
"port": "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",
|
||||
"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",
|
||||
"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",
|
||||
"irq": "axi_pcie_intc_0:1",
|
||||
"period": 400,
|
||||
"harmonics": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
7
|
||||
],
|
||||
"decimation": 0
|
||||
},
|
||||
"axis_data_fifo_0": {
|
||||
"vlnv": "xilinx.com:ip:axis_data_fifo:1.1",
|
||||
"port": "switch_0:3"
|
||||
},
|
||||
"switch_0": {
|
||||
"vlnv": "xilinx.com:ip:axis_interconnect:2.1",
|
||||
"baseaddr": 20480,
|
||||
|
@ -42,62 +96,9 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"axi_reset_0": {
|
||||
"vlnv": "xilinx.com:ip:axi_gpio:2.0",
|
||||
"baseaddr": 28672
|
||||
},
|
||||
"timer_0": {
|
||||
"vlnv": "xilinx.com:ip:axi_timer:2.0",
|
||||
"baseaddr": 16384,
|
||||
"irq": 0
|
||||
},
|
||||
"dma_0": {
|
||||
"vlnv": "xilinx.com:ip:axi_dma:7.1",
|
||||
"baseaddr": 12288,
|
||||
"port": 1,
|
||||
"irq": 3
|
||||
},
|
||||
"dma_1": {
|
||||
"vlnv": "xilinx.com:ip:axi_dma:7.1",
|
||||
"baseaddr": 8192,
|
||||
"port": 6,
|
||||
"irq": 3
|
||||
},
|
||||
"fifo_mm_s_0": {
|
||||
"vlnv": "xilinx.com:ip:axi_fifo_mm_s:4.1",
|
||||
"baseaddr": 24576,
|
||||
"baseaddr_axi4": 49152,
|
||||
"port": 2,
|
||||
"irq": 2
|
||||
},
|
||||
"rtds_axis_0": {
|
||||
"vlnv": "acs.eonerc.rwth-aachen.de:user:rtds_axis:1.0",
|
||||
"baseaddr": 32768,
|
||||
"port": 0,
|
||||
"irq": 5
|
||||
},
|
||||
"hls_dft_0": {
|
||||
"vlnv": "acs.eonerc.rwth-aachen.de:hls:hls_dft:1.0",
|
||||
"baseaddr": 36864,
|
||||
"port": 5,
|
||||
"irq": 1,
|
||||
"period": 400,
|
||||
"harmonics": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
7
|
||||
],
|
||||
"decimation": 0
|
||||
},
|
||||
"axis_data_fifo_0": {
|
||||
"vlnv": "xilinx.com:ip:axis_data_fifo:1.1",
|
||||
"port": 3
|
||||
},
|
||||
"axis_data_fifo_1": {
|
||||
"vlnv": "xilinx.com:ip:axis_data_fifo:1.1",
|
||||
"port": 6
|
||||
"port": "switch_0:6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "plugin.hpp"
|
||||
#include "fpga/ip.hpp"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@ -59,11 +60,6 @@ namespace fpga {
|
|||
struct vfio_container;
|
||||
class PCIeCardFactory;
|
||||
|
||||
namespace ip {
|
||||
class IpCore;
|
||||
}
|
||||
|
||||
|
||||
class PCIeCard {
|
||||
public:
|
||||
|
||||
|
@ -78,8 +74,7 @@ public:
|
|||
void dump() { }
|
||||
|
||||
|
||||
using IpList = std::list<ip::IpCore*>;
|
||||
IpList ips; ///< IPs located on this FPGA card
|
||||
ip::IpCoreList ips; ///< IPs located on this FPGA card
|
||||
|
||||
bool do_reset; /**< Reset VILLASfpga during startup? */
|
||||
int affinity; /**< Affinity for MSI interrupts */
|
||||
|
@ -99,7 +94,7 @@ public:
|
|||
size_t dmalen;
|
||||
};
|
||||
|
||||
|
||||
using CardList = std::list<std::unique_ptr<PCIeCard>>;
|
||||
|
||||
class PCIeCardFactory : public Plugin {
|
||||
public:
|
||||
|
@ -108,7 +103,7 @@ public:
|
|||
Plugin("FPGA Card plugin")
|
||||
{ pluginType = Plugin::Type::FpgaCard; }
|
||||
|
||||
static std::list<PCIeCard*>
|
||||
static CardList
|
||||
make(json_t *json, struct pci* pci, ::vfio_container* vc);
|
||||
|
||||
static PCIeCard*
|
||||
|
|
|
@ -41,16 +41,41 @@
|
|||
#include "fpga/vlnv.hpp"
|
||||
|
||||
#include "plugin.hpp"
|
||||
#include "card.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
namespace villas {
|
||||
namespace fpga {
|
||||
|
||||
class PCIeCard;
|
||||
|
||||
namespace ip {
|
||||
|
||||
|
||||
class IpIdentifier {
|
||||
public:
|
||||
IpIdentifier(Vlnv vlnv = Vlnv::getWildcard(), std::string name = "") :
|
||||
vlnv(vlnv), name(name) {}
|
||||
|
||||
IpIdentifier(std::string vlnvString, std::string name = "") :
|
||||
vlnv(vlnvString), name(name) {}
|
||||
|
||||
friend std::ostream&
|
||||
operator<< (std::ostream& stream, const IpIdentifier& id)
|
||||
{ return stream << "VLNV: " << id.vlnv << " Name: " << id.name; }
|
||||
|
||||
Vlnv vlnv;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
using IpDependency = std::pair<std::string, Vlnv>;
|
||||
|
||||
// forward declarations
|
||||
class IpCoreFactory;
|
||||
|
||||
class IpCore {
|
||||
|
@ -58,7 +83,7 @@ public:
|
|||
|
||||
friend IpCoreFactory;
|
||||
|
||||
IpCore() : card(nullptr), baseaddr(0), irq(-1), port(-1) {}
|
||||
IpCore() : card(nullptr), baseaddr(0) {} //, irq(-1), port(-1) {}
|
||||
virtual ~IpCore() {}
|
||||
|
||||
// IPs can implement this interface
|
||||
|
@ -68,25 +93,41 @@ public:
|
|||
virtual bool reset() { return true; }
|
||||
virtual void dump();
|
||||
|
||||
bool
|
||||
operator== (const IpIdentifier& otherId) {
|
||||
const bool vlnvMatch = id.vlnv == otherId.vlnv;
|
||||
const bool nameWildcard = id.name.empty() or otherId.name.empty();
|
||||
|
||||
return vlnvMatch and (nameWildcard or id.name == otherId.name);
|
||||
}
|
||||
|
||||
bool
|
||||
operator== (const Vlnv& otherVlnv)
|
||||
{ return id.vlnv == otherVlnv; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<< (std::ostream& stream, const IpCore& ip)
|
||||
{ return stream << ip.id; }
|
||||
|
||||
protected:
|
||||
uintptr_t
|
||||
getBaseaddr() const
|
||||
{
|
||||
assert(card != nullptr);
|
||||
return reinterpret_cast<uintptr_t>(card->map) + this->baseaddr;
|
||||
}
|
||||
getBaseaddr() const;
|
||||
|
||||
protected:
|
||||
// populated by FpgaIpFactory
|
||||
PCIeCard* card; /**< FPGA card this IP is instantiated on */
|
||||
std::string name; /**< Name defined in JSON config */
|
||||
Vlnv vlnv; /**< VLNV defined in JSON config */
|
||||
PCIeCard* card; /**< FPGA card this IP is instantiated on */
|
||||
IpIdentifier id; /**< VLNV and name defined in JSON config */
|
||||
uintptr_t baseaddr; /**< The baseadress of this FPGA IP component */
|
||||
int irq; /**< The interrupt number of the FPGA IP component. */
|
||||
int port; /**< The port of the AXI4-Stream switch to which this FPGA IP component is connected. */
|
||||
// int irq; /**< The interrupt number of the FPGA IP component. */
|
||||
// int port; /**< The port of the AXI4-Stream switch to which this FPGA IP component is connected. */
|
||||
|
||||
std::map<std::string, IpCore*> dependencies;
|
||||
};
|
||||
|
||||
|
||||
using IpCoreList = std::list<std::unique_ptr<IpCore>>;
|
||||
|
||||
|
||||
class IpCoreFactory : public Plugin {
|
||||
public:
|
||||
IpCoreFactory(std::string concreteName) :
|
||||
|
@ -94,20 +135,21 @@ public:
|
|||
{ pluginType = Plugin::Type::FpgaIp; }
|
||||
|
||||
/// Returns a running and checked FPGA IP
|
||||
static IpCore*
|
||||
make(PCIeCard* card, json_t *json, std::string name);
|
||||
static IpCoreList
|
||||
make(PCIeCard* card, json_t *json_ips);
|
||||
|
||||
private:
|
||||
/// Create a concrete IP instance
|
||||
virtual IpCore* create() = 0;
|
||||
|
||||
/// Configure IP instance from JSON config
|
||||
virtual bool configureJson(IpCore* ip, json_t *json)
|
||||
virtual bool configureJson(const std::unique_ptr<IpCore>& ip, json_t *json)
|
||||
{ return true; }
|
||||
|
||||
virtual Vlnv getCompatibleVlnv() const = 0;
|
||||
virtual std::string getName() const = 0;
|
||||
virtual std::string getDescription() const = 0;
|
||||
virtual std::list<IpDependency> getDependencies() const = 0;
|
||||
|
||||
private:
|
||||
static IpCoreFactory*
|
||||
|
|
|
@ -85,6 +85,9 @@ public:
|
|||
|
||||
Vlnv getCompatibleVlnv() const
|
||||
{ return Vlnv("acs.eonerc.rwth-aachen.de:user:axi_pcie_intc:"); }
|
||||
|
||||
std::list<IpDependency> getDependencies() const
|
||||
{ return {}; }
|
||||
};
|
||||
|
||||
} // namespace ip
|
||||
|
|
|
@ -47,6 +47,10 @@ public:
|
|||
parseFromString(s);
|
||||
}
|
||||
|
||||
static Vlnv
|
||||
getWildcard()
|
||||
{ return Vlnv(); }
|
||||
|
||||
std::string
|
||||
toString() const
|
||||
{
|
||||
|
|
|
@ -3,12 +3,23 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define _ESCAPE "\x1b"
|
||||
#define TXT_BOLD(s) _ESCAPE "[1m" + std::string(s) + _ESCAPE "[0m"
|
||||
|
||||
class LoggerIndent;
|
||||
|
||||
class Logger {
|
||||
friend LoggerIndent;
|
||||
public:
|
||||
|
||||
enum class LogLevel : int {
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Disabled
|
||||
};
|
||||
|
||||
class LoggerNewline {
|
||||
public:
|
||||
LoggerNewline(bool enabled = true) : enabled(enabled) {}
|
||||
|
@ -36,7 +47,7 @@ public:
|
|||
Logger* logger;
|
||||
};
|
||||
|
||||
Logger(int level, std::string prefix = "") : level(level), prefix(prefix) {}
|
||||
Logger(LogLevel level, std::string prefix = "") : level(level), prefix(prefix) {}
|
||||
|
||||
Indenter indent()
|
||||
{ return Indenter(this); }
|
||||
|
@ -80,11 +91,16 @@ public:
|
|||
depthCurrent = --depth;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
setLogLevel(LogLevel level)
|
||||
{ global_level = level; }
|
||||
|
||||
private:
|
||||
int level;
|
||||
LogLevel level;
|
||||
std::string prefix;
|
||||
static int depth;
|
||||
static int global_level;
|
||||
static LogLevel global_level;
|
||||
static int depthCurrent;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,12 @@
|
|||
#include "kernel/vfio.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "fpga/ip.hpp"
|
||||
#include "fpga/card.hpp"
|
||||
|
@ -45,10 +51,11 @@ namespace fpga {
|
|||
// instantiate factory to register
|
||||
static PCIeCardFactory PCIeCardFactory;
|
||||
|
||||
std::list<fpga::PCIeCard*>
|
||||
|
||||
CardList
|
||||
fpga::PCIeCardFactory::make(json_t *json, struct pci* pci, ::vfio_container* vc)
|
||||
{
|
||||
std::list<fpga::PCIeCard*> cards;
|
||||
CardList cards;
|
||||
|
||||
const char *card_name;
|
||||
json_t *json_card;
|
||||
|
@ -74,7 +81,7 @@ fpga::PCIeCardFactory::make(json_t *json, struct pci* pci, ::vfio_container* vc)
|
|||
continue;
|
||||
}
|
||||
|
||||
fpga::PCIeCard* card = create();
|
||||
auto card = std::unique_ptr<PCIeCard>(create());
|
||||
|
||||
// populate generic properties
|
||||
card->name = std::string(card_name);
|
||||
|
@ -87,44 +94,32 @@ fpga::PCIeCardFactory::make(json_t *json, struct pci* pci, ::vfio_container* vc)
|
|||
|
||||
if (pci_slot != nullptr and pci_device_parse_slot(&card->filter, pci_slot, &error) != 0) {
|
||||
cpp_warn << "Failed to parse PCI slot: " << error;
|
||||
// cpp_info << "... ignoring";
|
||||
}
|
||||
|
||||
if (pci_id != nullptr and pci_device_parse_id(&card->filter, pci_id, &error) != 0) {
|
||||
cpp_warn << "Failed to parse PCI ID: " << error;
|
||||
// cpp_info << "ignoring ...";
|
||||
}
|
||||
|
||||
|
||||
// TODO: currently fails, fix and remove comment
|
||||
// if(not card->start()) {
|
||||
// cpp_warn << " cannot start, destroying ...";
|
||||
// cpp_warn << "Cannot start FPGA card " << card_name;
|
||||
// delete card;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
const char *ip_name;
|
||||
json_t *json_ip;
|
||||
json_object_foreach(json_ips, ip_name, json_ip) {
|
||||
cpp_info << "Found IP: " << ip_name;
|
||||
Logger::Indenter indent = cpp_debug.indent();
|
||||
|
||||
ip::IpCore* ip = ip::IpCoreFactory::make(card, json_ip, ip_name);
|
||||
if(ip == nullptr) {
|
||||
cpp_warn << "Cannot initialize, ignoring ...";
|
||||
continue;
|
||||
}
|
||||
|
||||
card->ips.push_back(ip);
|
||||
card->ips = ip::IpCoreFactory::make(card.get(), json_ips);
|
||||
if(card->ips.empty()) {
|
||||
cpp_error << "Cannot initialize IPs";
|
||||
continue;
|
||||
}
|
||||
|
||||
if(not card->check()) {
|
||||
cpp_warn << "Checking failed, destroying ...";
|
||||
delete card;
|
||||
continue;
|
||||
}
|
||||
|
||||
cards.push_back(card);
|
||||
cards.push_back(std::move(card));
|
||||
}
|
||||
|
||||
return cards;
|
||||
|
|
283
fpga/lib/ip.cpp
283
fpga/lib/ip.cpp
|
@ -21,24 +21,112 @@
|
|||
*********************************************************************************/
|
||||
|
||||
#include "log_config.h"
|
||||
#include "log.h"
|
||||
#include "log.hpp"
|
||||
#include "plugin.h"
|
||||
#include "dependency_graph.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include "fpga/ip.hpp"
|
||||
#include "fpga/card.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "log.hpp"
|
||||
|
||||
using DependencyGraph = villas::utils::DependencyGraph<std::string>;
|
||||
|
||||
static
|
||||
std::list<std::string>
|
||||
dependencyTokens = {"irq", "port", "memory"};
|
||||
|
||||
static
|
||||
bool
|
||||
buildDependencyGraph(DependencyGraph& dependencyGraph, json_t* json_ips, std::string name)
|
||||
{
|
||||
// cpp_debug << "preparse " << name;
|
||||
|
||||
const bool nodeExists = dependencyGraph.addNode(name);
|
||||
|
||||
// do not add IP multiple times
|
||||
// this happens if more than 1 IP depends on a certain other IP
|
||||
if(nodeExists) {
|
||||
return true;
|
||||
}
|
||||
|
||||
json_t* json_ip = json_object_get(json_ips, name.c_str());
|
||||
if(json_ip == nullptr) {
|
||||
cpp_error << "IP " << name << " not found in config";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(auto& dependencyToken : dependencyTokens) {
|
||||
json_t* json_dependency = json_object_get(json_ip, dependencyToken.c_str());
|
||||
if(json_dependency == nullptr) {
|
||||
cpp_debug << "Property " << dependencyToken << " of " << TXT_BOLD(name)
|
||||
<< " not present";
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* value = json_string_value(json_dependency);
|
||||
if(value == nullptr) {
|
||||
cpp_warn << "Property " << dependencyToken << " of " << TXT_BOLD(name)
|
||||
<< " is invalid";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto mapping = villas::utils::tokenize(value, ":");
|
||||
|
||||
|
||||
if(mapping.size() != 2) {
|
||||
cpp_error << "Invalid " << dependencyToken << " mapping"
|
||||
<< " of " << TXT_BOLD(name);
|
||||
|
||||
dependencyGraph.removeNode(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(name == mapping[0]) {
|
||||
cpp_error << "IP " << TXT_BOLD(name)<< " cannot depend on itself";
|
||||
|
||||
dependencyGraph.removeNode(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// already add dependency, if adding it fails, removing the dependency
|
||||
// will also remove the current one
|
||||
dependencyGraph.addDependency(name, mapping[0]);
|
||||
|
||||
if(not buildDependencyGraph(dependencyGraph, json_ips, mapping[0])) {
|
||||
cpp_error << "Dependency " << mapping[0] << " of " << TXT_BOLD(name)
|
||||
<< " not satified";
|
||||
|
||||
dependencyGraph.removeNode(mapping[0]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
namespace villas {
|
||||
namespace fpga {
|
||||
namespace ip {
|
||||
|
||||
|
||||
void IpCore::dump() {
|
||||
info("IP %s: vlnv=%s baseaddr=%#jx, irq=%d, port=%d",
|
||||
name.c_str(), vlnv.toString().c_str(), baseaddr, irq, port);
|
||||
cpp_info << id;
|
||||
{
|
||||
Logger::Indenter indent = cpp_info.indent();
|
||||
cpp_info << " Baseaddr: 0x" << std::hex << baseaddr << std::dec;
|
||||
// cpp_info << " IRQ: " << irq;
|
||||
// cpp_info << " Port: " << port;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,80 +142,145 @@ IpCoreFactory* IpCoreFactory::lookup(const Vlnv &vlnv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
IpCore *IpCoreFactory::make(fpga::PCIeCard* card, json_t *json, std::string name)
|
||||
uintptr_t
|
||||
IpCore::getBaseaddr() const {
|
||||
assert(card != nullptr);
|
||||
return reinterpret_cast<uintptr_t>(card->map) + this->baseaddr;
|
||||
}
|
||||
|
||||
|
||||
IpCoreList
|
||||
IpCoreFactory::make(PCIeCard* card, json_t *json_ips)
|
||||
{
|
||||
int ret;
|
||||
const char* vlnv_raw;
|
||||
DependencyGraph dependencyGraph;
|
||||
IpCoreList initializedIps;
|
||||
|
||||
// extract VLNV from JSON
|
||||
ret = json_unpack(json, "{ s: s }",
|
||||
"vlnv", &vlnv_raw);
|
||||
if(ret != 0) {
|
||||
cpp_warn << "IP " << name << " has no entry 'vlnv'";
|
||||
return nullptr;
|
||||
{
|
||||
Logger::Indenter indent = cpp_debug.indent();
|
||||
cpp_debug << "Parsing IP dependency graph:";
|
||||
|
||||
void* iter = json_object_iter(json_ips);
|
||||
while(iter != nullptr) {
|
||||
buildDependencyGraph(dependencyGraph, json_ips, json_object_iter_key(iter));
|
||||
iter = json_object_iter_next(json_ips, iter);
|
||||
}
|
||||
}
|
||||
|
||||
// parse VLNV
|
||||
Vlnv vlnv(vlnv_raw);
|
||||
{
|
||||
Logger::Indenter indent = cpp_debug.indent();
|
||||
cpp_debug << "IP initialization order:";
|
||||
|
||||
// find the appropriate factory that can create the specified VLNV
|
||||
// Note:
|
||||
// This is the magic part! Factories automatically register as a plugin
|
||||
// as soon as they are instantiated. If there are multiple candidates,
|
||||
// the first suitable factory will be used.
|
||||
IpCoreFactory* ipCoreFactory = lookup(vlnv);
|
||||
|
||||
if(ipCoreFactory == nullptr) {
|
||||
cpp_warn << "No plugin found to handle " << vlnv;
|
||||
return nullptr;
|
||||
for(auto& ipName : dependencyGraph.getEvaluationOrder()) {
|
||||
cpp_debug << TXT_BOLD(ipName);
|
||||
}
|
||||
}
|
||||
|
||||
cpp_debug << "Using " << ipCoreFactory->getName() << " for IP " << vlnv;
|
||||
|
||||
|
||||
// Create new IP instance. Since this function is virtual, it will construct
|
||||
// the right, specialized type without knowing it here because we have
|
||||
// already picked the right factory.
|
||||
IpCore* ip = ipCoreFactory->create();
|
||||
if(ip == nullptr) {
|
||||
cpp_warn << "Cannot create an instance of " << ipCoreFactory->getName();
|
||||
goto fail;
|
||||
cpp_info << "Initializing IP cores";
|
||||
|
||||
Logger::Indenter indent = cpp_info.indent();
|
||||
for(auto& ipName : dependencyGraph.getEvaluationOrder()) {
|
||||
cpp_debug << TXT_BOLD(ipName);
|
||||
json_t* json_ip = json_object_get(json_ips, ipName.c_str());
|
||||
|
||||
// extract VLNV from JSON
|
||||
const char* vlnv;
|
||||
if(json_unpack(json_ip, "{ s: s }", "vlnv", &vlnv) != 0) {
|
||||
cpp_warn << "IP " << ipName << " has no entry 'vlnv'";
|
||||
continue;
|
||||
}
|
||||
|
||||
IpIdentifier id(Vlnv(vlnv), ipName);
|
||||
|
||||
// find the appropriate factory that can create the specified VLNV
|
||||
// Note:
|
||||
// This is the magic part! Factories automatically register as a
|
||||
// plugin as soon as they are instantiated. If there are multiple
|
||||
// candidates, the first suitable factory will be used.
|
||||
IpCoreFactory* ipCoreFactory = lookup(id.vlnv);
|
||||
|
||||
if(ipCoreFactory == nullptr) {
|
||||
cpp_warn << "No plugin found to handle " << vlnv;
|
||||
continue;
|
||||
} else {
|
||||
cpp_debug << "Using " << ipCoreFactory->getName()
|
||||
<< " for IP " << vlnv;
|
||||
}
|
||||
|
||||
// Create new IP instance. Since this function is virtual, it will
|
||||
// construct the right, specialized type without knowing it here
|
||||
// because we have already picked the right factory.
|
||||
// If something goes wrong with initialization, the shared_ptr will
|
||||
// take care to desctruct the IpCore again as it is not pushed to
|
||||
// the list and will run out of scope.
|
||||
auto ip = std::unique_ptr<IpCore>(ipCoreFactory->create());
|
||||
|
||||
if(ip == nullptr) {
|
||||
cpp_warn << "Cannot create an instance of "
|
||||
<< ipCoreFactory->getName();
|
||||
continue;
|
||||
}
|
||||
|
||||
// setup generic IP type properties
|
||||
ip->card = card;
|
||||
ip->id = id;
|
||||
|
||||
// extract some optional properties
|
||||
int ret = json_unpack(json_ip, "{ s?: i}", //, s?: i, s?: i }",
|
||||
"baseaddr", &ip->baseaddr);
|
||||
// "irq", &ip->irq,
|
||||
// "port", &ip->port);
|
||||
if(ret != 0) {
|
||||
cpp_warn << "Problem while parsing JSON for IP "
|
||||
<< TXT_BOLD(ipName);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool dependenciesOk = true;
|
||||
for(auto& [depName, depVlnv] : ipCoreFactory->getDependencies()) {
|
||||
// lookup dependency IP core in list of already initialized IPs
|
||||
auto iter = std::find_if(initializedIps.begin(),
|
||||
initializedIps.end(),
|
||||
[&](const std::unique_ptr<IpCore>& ip) {
|
||||
return *ip == depVlnv;
|
||||
});
|
||||
|
||||
if(iter == initializedIps.end()) {
|
||||
cpp_error << "Cannot find '" << depName << "' dependency "
|
||||
<< depVlnv.toString()
|
||||
<< "of " << TXT_BOLD(ipName);
|
||||
dependenciesOk = false;
|
||||
break;
|
||||
}
|
||||
|
||||
cpp_debug << "Found dependency IP " << (*iter)->id;
|
||||
ip->dependencies[depName] = (*iter).get();
|
||||
}
|
||||
|
||||
if(not dependenciesOk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// IP-specific setup via JSON config
|
||||
ipCoreFactory->configureJson(ip, json_ip);
|
||||
|
||||
// TODO: currently fails, fix and remove comment
|
||||
// if(not ip->start()) {
|
||||
// cpp_error << "Cannot start IP" << ip->id.name;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if(not ip->check()) {
|
||||
cpp_error << "Checking IP " << ip->id.name << " failed";
|
||||
continue;
|
||||
}
|
||||
|
||||
initializedIps.push_back(std::move(ip));
|
||||
}
|
||||
|
||||
// setup generic IP type properties
|
||||
ip->card = card;
|
||||
ip->name = name;
|
||||
ip->vlnv = vlnv;
|
||||
|
||||
// extract some optional properties
|
||||
ret = json_unpack(json, "{ s?: i, s?: i, s?: i }",
|
||||
"baseaddr", &ip->baseaddr,
|
||||
"irq", &ip->irq,
|
||||
"port", &ip->port);
|
||||
if(ret != 0) {
|
||||
cpp_warn << "Problem while parsing JSON";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// IP-specific setup via JSON config
|
||||
ipCoreFactory->configureJson(ip, json);
|
||||
|
||||
// TODO: currently fails, fix and remove comment
|
||||
// if(not ip->start()) {
|
||||
// cpp_error << "Cannot start IP" << ip->name;
|
||||
// goto fail;
|
||||
// }
|
||||
|
||||
if(not ip->check()) {
|
||||
cpp_error << "Checking IP " << ip->name << " failed";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return ip;
|
||||
|
||||
fail:
|
||||
delete ip;
|
||||
return nullptr;
|
||||
return initializedIps;
|
||||
}
|
||||
|
||||
} // namespace ip
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
#include "kernel/vfio.h"
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#include "fpga/ip.h"
|
||||
#include "fpga/card.h"
|
||||
#include "fpga/card.hpp"
|
||||
#include "fpga/ips/intc.hpp"
|
||||
|
||||
namespace villas {
|
||||
|
@ -48,6 +47,7 @@ InterruptController::~InterruptController()
|
|||
|
||||
bool InterruptController::start()
|
||||
{
|
||||
return true;
|
||||
const uintptr_t base = getBaseaddr();
|
||||
|
||||
num_irqs = vfio_pci_msi_init(&card->vfio_device, efds);
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
int Logger::depth;
|
||||
int Logger::depthCurrent;
|
||||
int Logger::global_level = 0;
|
||||
Logger::LogLevel Logger::global_level = Logger::LogLevel::Info;
|
||||
|
||||
Logger cpp_debug(0, CLR_BLU("Debug: "));
|
||||
Logger cpp_info(20);
|
||||
Logger cpp_warn(80, CLR_YEL("Warning: "));
|
||||
Logger cpp_error(100, CLR_RED("Error: "));
|
||||
Logger cpp_debug(Logger::LogLevel::Debug, "" CLR_BLU(" Debug ") "| ");
|
||||
Logger cpp_info(Logger::LogLevel::Info);
|
||||
Logger cpp_warn(Logger::LogLevel::Warning, "" CLR_YEL("Warning") "| ");
|
||||
Logger cpp_error(Logger::LogLevel::Error, "" CLR_RED(" Error ") "| ");
|
||||
|
||||
void test()
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <villas/fpga/card.h>
|
||||
#include <villas/fpga/vlnv.h>
|
||||
|
||||
#include <villas/log.hpp>
|
||||
#include <villas/plugin.hpp>
|
||||
#include <villas/fpga/card.hpp>
|
||||
|
||||
|
@ -53,6 +54,8 @@ static void init()
|
|||
|
||||
villas::Plugin::dumpList();
|
||||
|
||||
Logger::setLogLevel(Logger::LogLevel::Debug);
|
||||
|
||||
ret = pci_init(&pci);
|
||||
cr_assert_eq(ret, 0, "Failed to initialize PCI sub-system");
|
||||
|
||||
|
@ -80,7 +83,7 @@ static void init()
|
|||
// create an FPGA card instance using the corresponding plugin
|
||||
// villas::FpgaCard* fpgaCard = fpgaCardPlugin->make(json_);
|
||||
|
||||
std::list<villas::fpga::PCIeCard*> fpgaCards = fpgaCardPlugin->make(fpgas, &pci, &vc);
|
||||
auto fpgaCards = fpgaCardPlugin->make(fpgas, &pci, &vc);
|
||||
|
||||
json_t *json_card = json_object_get(fpgas, FPGA_CARD);
|
||||
cr_assert_not_null(json_card, "FPGA card " FPGA_CARD " not found");
|
||||
|
|
Loading…
Add table
Reference in a new issue