mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-30 00:00:11 +01:00
lib/ip: adapt to fit new config layout provided by hwdef-parse
This commit is contained in:
parent
92aea92f19
commit
f14df8aa32
9 changed files with 136 additions and 109 deletions
|
@ -134,7 +134,7 @@ protected:
|
||||||
PCIeCard* card; ///< FPGA card this IP is instantiated on
|
PCIeCard* card; ///< FPGA card this IP is instantiated on
|
||||||
IpIdentifier id; ///< VLNV and name defined in JSON config
|
IpIdentifier id; ///< VLNV and name defined in JSON config
|
||||||
uintptr_t baseaddr; ///< The baseadress of this IP component
|
uintptr_t baseaddr; ///< The baseadress of this IP component
|
||||||
std::map<int, IrqPort> irqs; ///< Interrupts of this IP component
|
std::map<std::string, IrqPort> irqs; ///< Interrupts of this IP component
|
||||||
std::map<std::string, IpCore*> dependencies; ///< dependencies on other IPs
|
std::map<std::string, IpCore*> dependencies; ///< dependencies on other IPs
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -54,18 +54,18 @@ public:
|
||||||
std::string nodeName;
|
std::string nodeName;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool connect(int port, const StreamPort& to);
|
bool connect(std::string portName, const StreamPort& to);
|
||||||
bool disconnect(int port);
|
bool disconnect(std::string portName);
|
||||||
|
|
||||||
bool loopbackPossible() const;
|
bool loopbackPossible() const;
|
||||||
bool connectLoopback();
|
bool connectLoopback();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::pair<int, int> getLoopbackPorts() const;
|
std::pair<std::string, std::string> getLoopbackPorts() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::map<int, StreamPort> portsMaster;
|
std::map<std::string, StreamPort> portsMaster;
|
||||||
std::map<int, StreamPort> portsSlave;
|
std::map<std::string, StreamPort> portsSlave;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IpNodeFactory : public IpCoreFactory {
|
class IpNodeFactory : public IpCoreFactory {
|
||||||
|
|
|
@ -61,6 +61,7 @@ private:
|
||||||
IpCore* slaveIn;
|
IpCore* slaveIn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int num_ports;
|
||||||
XAxis_Switch xSwitch;
|
XAxis_Switch xSwitch;
|
||||||
std::map<int, int> portMapping;
|
std::map<int, int> portMapping;
|
||||||
};
|
};
|
||||||
|
@ -71,6 +72,8 @@ public:
|
||||||
AxiStreamSwitchFactory() :
|
AxiStreamSwitchFactory() :
|
||||||
IpNodeFactory(getName()) {}
|
IpNodeFactory(getName()) {}
|
||||||
|
|
||||||
|
bool configureJson(IpCore& ip, json_t *json_ip);
|
||||||
|
|
||||||
IpCore* create()
|
IpCore* create()
|
||||||
{ return new AxiStreamSwitch; }
|
{ return new AxiStreamSwitch; }
|
||||||
|
|
||||||
|
@ -81,7 +84,7 @@ public:
|
||||||
{ return "Xilinx's AXI4-Stream switch"; }
|
{ return "Xilinx's AXI4-Stream switch"; }
|
||||||
|
|
||||||
Vlnv getCompatibleVlnv() const
|
Vlnv getCompatibleVlnv() const
|
||||||
{ return Vlnv("xilinx.com:ip:axis_interconnect:"); }
|
{ return Vlnv("xilinx.com:ip:axis_switch:"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ip
|
} // namespace ip
|
||||||
|
|
|
@ -42,7 +42,7 @@ using DependencyGraph = villas::utils::DependencyGraph<std::string>;
|
||||||
|
|
||||||
static
|
static
|
||||||
std::list<std::string>
|
std::list<std::string>
|
||||||
dependencyTokens = {"irq", "port", "memory"};
|
dependencyTokens = {"irqs"};
|
||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
|
@ -73,7 +73,10 @@ buildDependencyGraph(DependencyGraph& dependencyGraph, json_t* json_ips, std::st
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* value = json_string_value(json_dependency);
|
const char* irq_name;
|
||||||
|
json_t* json_irq;
|
||||||
|
json_object_foreach(json_dependency, irq_name, json_irq) {
|
||||||
|
const char* value = json_string_value(json_irq);
|
||||||
if(value == nullptr) {
|
if(value == nullptr) {
|
||||||
logger->warn("Property {} of {} is invalid",
|
logger->warn("Property {} of {} is invalid",
|
||||||
dependencyToken, TXT_BOLD(name));
|
dependencyToken, TXT_BOLD(name));
|
||||||
|
@ -110,6 +113,7 @@ buildDependencyGraph(DependencyGraph& dependencyGraph, json_t* json_ips, std::st
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -228,11 +232,13 @@ IpCoreFactory::make(PCIeCard* card, json_t *json_ips)
|
||||||
}
|
}
|
||||||
|
|
||||||
json_t* json_irqs = json_object_get(json_ip, "irqs");
|
json_t* json_irqs = json_object_get(json_ip, "irqs");
|
||||||
if(json_is_array(json_irqs)) {
|
if(json_is_object(json_irqs)) {
|
||||||
size_t index;
|
const char* irq_name;
|
||||||
json_t* json_irq;
|
json_t* json_irq;
|
||||||
json_array_foreach(json_irqs, index, json_irq) {
|
json_object_foreach(json_irqs, irq_name, json_irq) {
|
||||||
const char* irq = json_string_value(json_irq);
|
const char* irq = json_string_value(json_irq);
|
||||||
|
|
||||||
|
|
||||||
auto tokens = utils::tokenize(irq, ":");
|
auto tokens = utils::tokenize(irq, ":");
|
||||||
if(tokens.size() != 2) {
|
if(tokens.size() != 2) {
|
||||||
logger->warn("Cannot parse IRQ '{}' of {}",
|
logger->warn("Cannot parse IRQ '{}' of {}",
|
||||||
|
@ -247,9 +253,11 @@ IpCoreFactory::make(PCIeCard* card, json_t *json_ips)
|
||||||
logger->warn("IRQ number is not an integer: '{}'", irq);
|
logger->warn("IRQ number is not an integer: '{}'", irq);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
logger->debug("IRQ: {} -> {}:{}", irq_name, tokens[0], num);
|
||||||
ip->irqs[index] = {num, tokens[0], ""};
|
ip->irqs[irq_name] = {num, tokens[0], ""};
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger->debug("IP has no interrupts");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,101 +19,79 @@ IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
|
||||||
auto logger = getLogger();
|
auto logger = getLogger();
|
||||||
|
|
||||||
json_t* json_ports = json_object_get(json_ip, "ports");
|
json_t* json_ports = json_object_get(json_ip, "ports");
|
||||||
if(json_ports == nullptr) {
|
if(not json_is_array(json_ports)) {
|
||||||
logger->error("IpNode {} has no ports property", ip);
|
logger->debug("IP has no ports");
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
|
||||||
logger->error("IpNode {} has no ports", ip);
|
|
||||||
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::StreamPort>& portMap, json_t* json)
|
|
||||||
{
|
|
||||||
auto logger = getLogger();
|
|
||||||
|
|
||||||
size_t index;
|
size_t index;
|
||||||
json_t* json_port;
|
json_t* json_port;
|
||||||
json_array_foreach(json, index, json_port) {
|
json_array_foreach(json_ports, index, json_port) {
|
||||||
int myPortNum;
|
if(not json_is_object(json_port)) {
|
||||||
const char* to = nullptr;
|
logger->error("Port {} is not an object", index);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = json_unpack(json_port, "{ s : i, s? : s}",
|
const char *role_raw, *target_raw, *name_raw;
|
||||||
"num", &myPortNum,
|
int ret = json_unpack(json_port, "{ s: s, s: s, s: s }",
|
||||||
"to", &to);
|
"role", &role_raw,
|
||||||
|
"target", &target_raw,
|
||||||
|
"name", &name_raw);
|
||||||
if(ret != 0) {
|
if(ret != 0) {
|
||||||
logger->error("Port definition required field 'num'");
|
logger->error("Cannot parse port {}", index);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(to == nullptr) {
|
const auto tokens = utils::tokenize(target_raw, ":");
|
||||||
logger->debug("Nothing connected to port {}", myPortNum);
|
|
||||||
portMap[myPortNum] = {};
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto tokens = utils::tokenize(to, ":");
|
|
||||||
if(tokens.size() != 2) {
|
if(tokens.size() != 2) {
|
||||||
logger->error("Too many tokens in property 'other'");
|
logger->error("Cannot parse 'target' of port {}", index);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int otherPortNum;
|
int port_num;
|
||||||
try {
|
try {
|
||||||
otherPortNum = std::stoi(tokens[1]);
|
port_num = std::stoi(tokens[1]);
|
||||||
} catch(const std::invalid_argument&) {
|
} catch(const std::invalid_argument&) {
|
||||||
logger->error("Other port number is not an integral number");
|
logger->error("Target port number is not an integer: '{}'", target_raw);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger->debug("Adding port mapping: {}:{}", myPortNum, to);
|
IpNode::StreamPort port;
|
||||||
portMap[myPortNum] = { otherPortNum, tokens[0] };
|
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;
|
||||||
|
} else /* slave */ {
|
||||||
|
ipNode.portsSlave[name_raw] = port;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int>
|
std::pair<std::string, std::string>
|
||||||
IpNode::getLoopbackPorts() const
|
IpNode::getLoopbackPorts() const
|
||||||
{
|
{
|
||||||
for(auto& [masterNum, masterTo] : portsMaster) {
|
for(auto& [masterName, masterTo] : portsMaster) {
|
||||||
for(auto& [slaveNum, slaveTo] : portsSlave) {
|
for(auto& [slaveName, slaveTo] : portsSlave) {
|
||||||
// TODO: should we also check which IP both ports are connected to?
|
// TODO: should we also check which IP both ports are connected to?
|
||||||
if(masterTo.nodeName == slaveTo.nodeName) {
|
if(masterTo.nodeName == slaveTo.nodeName) {
|
||||||
return { masterNum, slaveNum };
|
return { masterName, slaveName };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { -1, -1 };
|
return { "", "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IpNode::loopbackPossible() const
|
IpNode::loopbackPossible() const
|
||||||
{
|
{
|
||||||
auto ports = getLoopbackPorts();
|
auto ports = getLoopbackPorts();
|
||||||
return (ports.first != -1) and (ports.second != -1);
|
return (not ports.first.empty()) and (not ports.second.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -125,12 +103,17 @@ IpNode::connectLoopback()
|
||||||
const auto& portMaster = portsMaster[ports.first];
|
const auto& portMaster = portsMaster[ports.first];
|
||||||
const auto& portSlave = portsSlave[ports.second];
|
const auto& portSlave = portsSlave[ports.second];
|
||||||
|
|
||||||
|
logger->debug("master port: {}", ports.first);
|
||||||
|
logger->debug("slave port: {}", ports.second);
|
||||||
|
|
||||||
|
logger->debug("switch at: {}", portMaster.nodeName);
|
||||||
|
|
||||||
// TODO: verify this is really a switch!
|
// TODO: verify this is really a switch!
|
||||||
auto axiStreamSwitch = reinterpret_cast<ip::AxiStreamSwitch*>(
|
auto axiStreamSwitch = reinterpret_cast<ip::AxiStreamSwitch*>(
|
||||||
card->lookupIp(portMaster.nodeName));
|
card->lookupIp(portMaster.nodeName));
|
||||||
|
|
||||||
if(axiStreamSwitch == nullptr) {
|
if(axiStreamSwitch == nullptr) {
|
||||||
logger->error("Cannot find IP {}", *axiStreamSwitch);
|
logger->error("Cannot find switch");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,8 @@ FifoFactory::configureJson(IpCore &ip, json_t *json_ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& fifo = reinterpret_cast<Fifo&>(ip);
|
auto& fifo = reinterpret_cast<Fifo&>(ip);
|
||||||
if(json_unpack(json_ip, "{ s: i }", "baseaddr_axi4", &fifo.baseaddr_axi4) != 0) {
|
if(json_unpack(json_ip, "{ s: i }", "axi4_baseaddr", &fifo.baseaddr_axi4) != 0) {
|
||||||
logger->warn("Cannot parse property 'baseaddr_axi4'");
|
logger->warn("Cannot parse property 'axi4_baseaddr'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ bool Fifo::init()
|
||||||
XLlFifo_IntEnable(&xFifo, XLLF_INT_RC_MASK);
|
XLlFifo_IntEnable(&xFifo, XLLF_INT_RC_MASK);
|
||||||
|
|
||||||
auto intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
|
auto intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
|
||||||
intc->enableInterrupt(irqs[0], false);
|
intc->enableInterrupt(irqs["interrupt"], false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ size_t Fifo::read(void *buf, size_t len)
|
||||||
auto intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
|
auto intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
|
||||||
|
|
||||||
while (!XLlFifo_IsRxDone(&xFifo))
|
while (!XLlFifo_IsRxDone(&xFifo))
|
||||||
intc->waitForInterrupt(irqs[0].num);
|
intc->waitForInterrupt(irqs["interrupt"].num);
|
||||||
|
|
||||||
XLlFifo_IntClear(&xFifo, XLLF_INT_RC_MASK);
|
XLlFifo_IntClear(&xFifo, XLLF_INT_RC_MASK);
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,8 @@ InterruptController::init()
|
||||||
XIntc_Out32(base + XIN_IER_OFFSET, 0x00000000); /* Disable all IRQs by default */
|
XIntc_Out32(base + XIN_IER_OFFSET, 0x00000000); /* Disable all IRQs by default */
|
||||||
XIntc_Out32(base + XIN_MER_OFFSET, XIN_INT_HARDWARE_ENABLE_MASK | XIN_INT_MASTER_ENABLE_MASK);
|
XIntc_Out32(base + XIN_MER_OFFSET, XIN_INT_HARDWARE_ENABLE_MASK | XIN_INT_MASTER_ENABLE_MASK);
|
||||||
|
|
||||||
logger->debug("enabled interrupts");;
|
logger->debug("enabled interrupts");
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*********************************************************************************/
|
*********************************************************************************/
|
||||||
|
|
||||||
|
#include <jansson.h>
|
||||||
#include <xilinx/xaxis_switch.h>
|
#include <xilinx/xaxis_switch.h>
|
||||||
|
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
@ -39,8 +40,8 @@ AxiStreamSwitch::init()
|
||||||
{
|
{
|
||||||
/* Setup AXI-stream switch */
|
/* Setup AXI-stream switch */
|
||||||
XAxis_Switch_Config sw_cfg;
|
XAxis_Switch_Config sw_cfg;
|
||||||
sw_cfg.MaxNumMI = portsMaster.size();
|
sw_cfg.MaxNumMI = num_ports;
|
||||||
sw_cfg.MaxNumSI = portsSlave.size();
|
sw_cfg.MaxNumSI = num_ports;
|
||||||
|
|
||||||
if(XAxisScr_CfgInitialize(&xSwitch, &sw_cfg, getBaseaddr()) != XST_SUCCESS) {
|
if(XAxisScr_CfgInitialize(&xSwitch, &sw_cfg, getBaseaddr()) != XST_SUCCESS) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -122,6 +123,25 @@ AxiStreamSwitch::disconnectSlave(int port)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AxiStreamSwitchFactory::configureJson(IpCore& ip, json_t* json_ip)
|
||||||
|
{
|
||||||
|
if(not IpNodeFactory::configureJson(ip, json_ip))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto logger = getLogger();
|
||||||
|
|
||||||
|
auto& axiSwitch = reinterpret_cast<AxiStreamSwitch&>(ip);
|
||||||
|
|
||||||
|
if(json_unpack(json_ip, "{ s: i }", "num_ports", &axiSwitch.num_ports) != 0) {
|
||||||
|
logger->error("Cannot parse 'num_ports'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace ip
|
} // namespace ip
|
||||||
} // namespace fpga
|
} // namespace fpga
|
||||||
} // namespace villas
|
} // namespace villas
|
||||||
|
|
|
@ -39,21 +39,33 @@ static TimerFactory factory;
|
||||||
|
|
||||||
bool Timer::init()
|
bool Timer::init()
|
||||||
{
|
{
|
||||||
|
auto logger = getLogger();
|
||||||
|
|
||||||
XTmrCtr_Config xtmr_cfg;
|
XTmrCtr_Config xtmr_cfg;
|
||||||
xtmr_cfg.SysClockFreqHz = getFrequency();
|
xtmr_cfg.SysClockFreqHz = getFrequency();
|
||||||
|
|
||||||
XTmrCtr_CfgInitialize(&xTmr, &xtmr_cfg, getBaseaddr());
|
XTmrCtr_CfgInitialize(&xTmr, &xtmr_cfg, getBaseaddr());
|
||||||
XTmrCtr_InitHw(&xTmr);
|
XTmrCtr_InitHw(&xTmr);
|
||||||
|
|
||||||
|
if(dependencies.find("intc") == dependencies.end()) {
|
||||||
|
logger->error("No intc");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(irqs.find("generateout0") == irqs.end()) {
|
||||||
|
logger->error("no irq");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
|
intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
|
||||||
intc->disableInterrupt(irqs[0]);
|
intc->disableInterrupt(irqs["generateout0"]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timer::start(uint32_t ticks)
|
bool Timer::start(uint32_t ticks)
|
||||||
{
|
{
|
||||||
intc->enableInterrupt(irqs[0], false);
|
intc->enableInterrupt(irqs["generateout0"], false);
|
||||||
|
|
||||||
XTmrCtr_SetOptions(&xTmr, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
|
XTmrCtr_SetOptions(&xTmr, 0, XTC_EXT_COMPARE_OPTION | XTC_DOWN_COUNT_OPTION);
|
||||||
XTmrCtr_SetResetValue(&xTmr, 0, ticks);
|
XTmrCtr_SetResetValue(&xTmr, 0, ticks);
|
||||||
|
@ -64,8 +76,8 @@ bool Timer::start(uint32_t ticks)
|
||||||
|
|
||||||
bool Timer::wait()
|
bool Timer::wait()
|
||||||
{
|
{
|
||||||
int count = intc->waitForInterrupt(irqs[0]);
|
int count = intc->waitForInterrupt(irqs["generateout0"]);
|
||||||
intc->disableInterrupt(irqs[0]);
|
intc->disableInterrupt(irqs["generateout0"]);
|
||||||
|
|
||||||
return (count == 1);
|
return (count == 1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue