1
0
Fork 0
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:
daniel-k 2018-01-23 14:47:44 +01:00
parent 92aea92f19
commit f14df8aa32
9 changed files with 136 additions and 109 deletions

View file

@ -134,7 +134,7 @@ protected:
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 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
};

View file

@ -54,18 +54,18 @@ public:
std::string nodeName;
};
bool connect(int port, const StreamPort& to);
bool disconnect(int port);
bool connect(std::string portName, const StreamPort& to);
bool disconnect(std::string portName);
bool loopbackPossible() const;
bool connectLoopback();
private:
std::pair<int, int> getLoopbackPorts() const;
std::pair<std::string, std::string> getLoopbackPorts() const;
protected:
std::map<int, StreamPort> portsMaster;
std::map<int, StreamPort> portsSlave;
std::map<std::string, StreamPort> portsMaster;
std::map<std::string, StreamPort> portsSlave;
};
class IpNodeFactory : public IpCoreFactory {

View file

@ -61,6 +61,7 @@ private:
IpCore* slaveIn;
};
int num_ports;
XAxis_Switch xSwitch;
std::map<int, int> portMapping;
};
@ -71,6 +72,8 @@ public:
AxiStreamSwitchFactory() :
IpNodeFactory(getName()) {}
bool configureJson(IpCore& ip, json_t *json_ip);
IpCore* create()
{ return new AxiStreamSwitch; }
@ -81,7 +84,7 @@ public:
{ return "Xilinx's AXI4-Stream switch"; }
Vlnv getCompatibleVlnv() const
{ return Vlnv("xilinx.com:ip:axis_interconnect:"); }
{ return Vlnv("xilinx.com:ip:axis_switch:"); }
};
} // namespace ip

View file

@ -42,7 +42,7 @@ using DependencyGraph = villas::utils::DependencyGraph<std::string>;
static
std::list<std::string>
dependencyTokens = {"irq", "port", "memory"};
dependencyTokens = {"irqs"};
static
bool
@ -73,41 +73,45 @@ buildDependencyGraph(DependencyGraph& dependencyGraph, json_t* json_ips, std::st
continue;
}
const char* value = json_string_value(json_dependency);
if(value == nullptr) {
logger->warn("Property {} of {} is invalid",
dependencyToken, TXT_BOLD(name));
continue;
}
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) {
logger->warn("Property {} of {} is invalid",
dependencyToken, TXT_BOLD(name));
continue;
}
auto mapping = villas::utils::tokenize(value, ":");
auto mapping = villas::utils::tokenize(value, ":");
if(mapping.size() != 2) {
logger->error("Invalid {} mapping of {}",
dependencyToken, TXT_BOLD(name));
if(mapping.size() != 2) {
logger->error("Invalid {} mapping of {}",
dependencyToken, TXT_BOLD(name));
dependencyGraph.removeNode(name);
return false;
}
dependencyGraph.removeNode(name);
return false;
}
if(name == mapping[0]) {
logger->error("IP {} cannot depend on itself", TXT_BOLD(name));
if(name == mapping[0]) {
logger->error("IP {} cannot depend on itself", TXT_BOLD(name));
dependencyGraph.removeNode(name);
return false;
}
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]);
// 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])) {
logger->error("Dependency {} of {} not satisfied",
mapping[0], TXT_BOLD(name));
if(not buildDependencyGraph(dependencyGraph, json_ips, mapping[0])) {
logger->error("Dependency {} of {} not satisfied",
mapping[0], TXT_BOLD(name));
dependencyGraph.removeNode(mapping[0]);
return false;
dependencyGraph.removeNode(mapping[0]);
return false;
}
}
}
@ -228,11 +232,13 @@ IpCoreFactory::make(PCIeCard* card, json_t *json_ips)
}
json_t* json_irqs = json_object_get(json_ip, "irqs");
if(json_is_array(json_irqs)) {
size_t index;
if(json_is_object(json_irqs)) {
const char* irq_name;
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);
auto tokens = utils::tokenize(irq, ":");
if(tokens.size() != 2) {
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);
continue;
}
ip->irqs[index] = {num, tokens[0], ""};
logger->debug("IRQ: {} -> {}:{}", irq_name, tokens[0], num);
ip->irqs[irq_name] = {num, tokens[0], ""};
}
} else {
logger->debug("IP has no interrupts");
}

View file

@ -19,101 +19,79 @@ IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
auto logger = getLogger();
json_t* json_ports = json_object_get(json_ip, "ports");
if(json_ports == nullptr) {
logger->error("IpNode {} has no ports property", ip);
return false;
if(not json_is_array(json_ports)) {
logger->debug("IP has no ports");
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;
json_t* json_port;
json_array_foreach(json, index, json_port) {
int myPortNum;
const char* to = nullptr;
json_array_foreach(json_ports, index, json_port) {
if(not json_is_object(json_port)) {
logger->error("Port {} is not an object", index);
return false;
}
int ret = json_unpack(json_port, "{ s : i, s? : s}",
"num", &myPortNum,
"to", &to);
const char *role_raw, *target_raw, *name_raw;
int ret = json_unpack(json_port, "{ s: s, s: s, s: s }",
"role", &role_raw,
"target", &target_raw,
"name", &name_raw);
if(ret != 0) {
logger->error("Port definition required field 'num'");
logger->error("Cannot parse port {}", index);
return false;
}
if(to == nullptr) {
logger->debug("Nothing connected to port {}", myPortNum);
portMap[myPortNum] = {};
continue;
}
const auto tokens = utils::tokenize(to, ":");
const auto tokens = utils::tokenize(target_raw, ":");
if(tokens.size() != 2) {
logger->error("Too many tokens in property 'other'");
logger->error("Cannot parse 'target' of port {}", index);
return false;
}
int otherPortNum;
int port_num;
try {
otherPortNum = std::stoi(tokens[1]);
port_num = std::stoi(tokens[1]);
} 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;
}
logger->debug("Adding port mapping: {}:{}", myPortNum, to);
portMap[myPortNum] = { otherPortNum, tokens[0] };
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;
} else /* slave */ {
ipNode.portsSlave[name_raw] = port;
}
}
return true;
}
std::pair<int, int>
std::pair<std::string, std::string>
IpNode::getLoopbackPorts() const
{
for(auto& [masterNum, masterTo] : portsMaster) {
for(auto& [slaveNum, slaveTo] : portsSlave) {
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) {
return { masterNum, slaveNum };
return { masterName, slaveName };
}
}
}
return { -1, -1 };
return { "", "" };
}
bool
IpNode::loopbackPossible() const
{
auto ports = getLoopbackPorts();
return (ports.first != -1) and (ports.second != -1);
return (not ports.first.empty()) and (not ports.second.empty());
}
bool
@ -125,12 +103,17 @@ IpNode::connectLoopback()
const auto& portMaster = portsMaster[ports.first];
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!
auto axiStreamSwitch = reinterpret_cast<ip::AxiStreamSwitch*>(
card->lookupIp(portMaster.nodeName));
if(axiStreamSwitch == nullptr) {
logger->error("Cannot find IP {}", *axiStreamSwitch);
logger->error("Cannot find switch");
return false;
}

View file

@ -51,8 +51,8 @@ FifoFactory::configureJson(IpCore &ip, json_t *json_ip)
}
auto& fifo = reinterpret_cast<Fifo&>(ip);
if(json_unpack(json_ip, "{ s: i }", "baseaddr_axi4", &fifo.baseaddr_axi4) != 0) {
logger->warn("Cannot parse property 'baseaddr_axi4'");
if(json_unpack(json_ip, "{ s: i }", "axi4_baseaddr", &fifo.baseaddr_axi4) != 0) {
logger->warn("Cannot parse property 'axi4_baseaddr'");
return false;
}
@ -76,7 +76,7 @@ bool Fifo::init()
XLlFifo_IntEnable(&xFifo, XLLF_INT_RC_MASK);
auto intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
intc->enableInterrupt(irqs[0], false);
intc->enableInterrupt(irqs["interrupt"], false);
return true;
}
@ -113,7 +113,7 @@ size_t Fifo::read(void *buf, size_t len)
auto intc = reinterpret_cast<InterruptController*>(dependencies["intc"]);
while (!XLlFifo_IsRxDone(&xFifo))
intc->waitForInterrupt(irqs[0].num);
intc->waitForInterrupt(irqs["interrupt"].num);
XLlFifo_IntClear(&xFifo, XLLF_INT_RC_MASK);

View file

@ -76,7 +76,8 @@ InterruptController::init()
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);
logger->debug("enabled interrupts");;
logger->debug("enabled interrupts");
return true;
}

View file

@ -23,6 +23,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <jansson.h>
#include <xilinx/xaxis_switch.h>
#include "log.hpp"
@ -39,8 +40,8 @@ AxiStreamSwitch::init()
{
/* Setup AXI-stream switch */
XAxis_Switch_Config sw_cfg;
sw_cfg.MaxNumMI = portsMaster.size();
sw_cfg.MaxNumSI = portsSlave.size();
sw_cfg.MaxNumMI = num_ports;
sw_cfg.MaxNumSI = num_ports;
if(XAxisScr_CfgInitialize(&xSwitch, &sw_cfg, getBaseaddr()) != XST_SUCCESS) {
return false;
@ -122,6 +123,25 @@ AxiStreamSwitch::disconnectSlave(int port)
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 fpga
} // namespace villas

View file

@ -39,21 +39,33 @@ static TimerFactory factory;
bool Timer::init()
{
auto logger = getLogger();
XTmrCtr_Config xtmr_cfg;
xtmr_cfg.SysClockFreqHz = getFrequency();
XTmrCtr_CfgInitialize(&xTmr, &xtmr_cfg, getBaseaddr());
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->disableInterrupt(irqs[0]);
intc->disableInterrupt(irqs["generateout0"]);
return true;
}
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_SetResetValue(&xTmr, 0, ticks);
@ -64,8 +76,8 @@ bool Timer::start(uint32_t ticks)
bool Timer::wait()
{
int count = intc->waitForInterrupt(irqs[0]);
intc->disableInterrupt(irqs[0]);
int count = intc->waitForInterrupt(irqs["generateout0"]);
intc->disableInterrupt(irqs["generateout0"]);
return (count == 1);
}