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 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
}; };

View file

@ -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 {

View file

@ -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

View file

@ -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");
} }

View file

@ -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;
} }

View file

@ -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);

View file

@ -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;
} }

View file

@ -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

View file

@ -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);
} }