diff --git a/fpga/include/villas/fpga/node.hpp b/fpga/include/villas/fpga/node.hpp index bd4632882..0a75c22ac 100644 --- a/fpga/include/villas/fpga/node.hpp +++ b/fpga/include/villas/fpga/node.hpp @@ -84,11 +84,21 @@ public: return *portsMaster.at(name); } + const std::map> &getMasterPorts() const + { + return portsMaster; + } + const StreamVertex& getSlavePort(const std::string &name) const { return *portsSlave.at(name); } + const std::map> &getSlavePorts() const + { + return portsSlave; + } + bool connect(const StreamVertex &from, const StreamVertex &to); bool connect(const StreamVertex &from, const StreamVertex &to, bool reverse) { diff --git a/fpga/include/villas/fpga/utils.hpp b/fpga/include/villas/fpga/utils.hpp index 4adeed10e..2af117954 100644 --- a/fpga/include/villas/fpga/utils.hpp +++ b/fpga/include/villas/fpga/utils.hpp @@ -20,34 +20,39 @@ setupFpgaCard(const std::string &configFile, const std::string &fpgaName); int createCards(json_t *config, std::list> &cards, std::filesystem::path &searchPath); +std::shared_ptr>> +getAuroraChannels(std::shared_ptr card); + void setupColorHandling(); class ConnectString { public: - ConnectString(std::string& connectString, int maxPortNum = 7); - - void parseString(std::string& connectString); - int portStringToInt(std::string &str) const; - void configCrossBar(std::shared_ptr dma, - std::vector> - &switch_channels) const; - + enum class ConnectType { AURORA, DMA, DINO, LOOPBACK }; + ConnectString(std::string &connectString, int maxPortNum = 7); + void parseString(std::string &connectString); + int portStringToInt(std::string &str) const; + void configCrossBar(std::shared_ptr card) const; bool isBidirectional() const { return bidirectional; }; - bool isDmaLoopback() const { return dmaLoopback; }; - bool isSrcStdin() const { return srcIsStdin; }; - bool isDstStdout() const { return dstIsStdout; }; - int getSrcAsInt() const { return srcAsInt; }; - int getDstAsInt() const { return dstAsInt; }; + bool isDmaLoopback() const { return srcType == ConnectType::LOOPBACK; }; + bool isSrcStdin() const { return srcType == ConnectType::DMA; }; + bool isDstStdout() const { return dstType == ConnectType::DMA; }; + int getSrcAsInt() const { return srcAsInt; }; + int getDstAsInt() const { return dstAsInt; }; + static std::string connectTypeToString(ConnectType type) { + static const std::string connectTypeStrings[] = {"aurora", "dma", "dino", + "loopback"}; + return connectTypeStrings[(int)type]; + } + protected: - villas::Logger log; - int maxPortNum; - bool bidirectional; - bool invert; - int srcAsInt; - int dstAsInt; - bool srcIsStdin; - bool dstIsStdout; - bool dmaLoopback; + villas::Logger log; + int maxPortNum; + bool bidirectional; + bool invert; + ConnectType srcType; + ConnectType dstType; + int srcAsInt; + int dstAsInt; }; class BufferedSampleFormatter { diff --git a/fpga/lib/dma.cpp b/fpga/lib/dma.cpp index e6ef22b23..cf50712da 100644 --- a/fpga/lib/dma.cpp +++ b/fpga/lib/dma.cpp @@ -37,71 +37,51 @@ struct villasfpga_memory_t { villasfpga_handle villasfpga_init(const char *configFile) { - std::string fpgaName = "vc707"; - std::string connectStr = "3<->pipe"; - std::string outputFormat = "short"; - bool dumpGraph = false; - bool dumpAuroraChannels = true; - try { - // Logging setup - logging.setLevel(spdlog::level::debug); - fpga::setupColorHandling(); + std::string fpgaName = "vc707"; + std::string connectStr = "3<->pipe"; + std::string outputFormat = "short"; + bool dumpGraph = false; + bool dumpAuroraChannels = true; + try { + // Logging setup + logging.setLevel(spdlog::level::debug); + fpga::setupColorHandling(); - if (configFile == nullptr || configFile[0] == '\0') { - logger->error("No configuration file provided/ Please use -c/--config argument"); - return nullptr; - } + if (configFile == nullptr || configFile[0] == '\0') { + logger->error( + "No configuration file provided/ Please use -c/--config argument"); + return nullptr; + } - auto handle = new villasfpga_handle_t; - handle->card = fpga::setupFpgaCard(configFile, fpgaName); + auto handle = new villasfpga_handle_t; + handle->card = fpga::setupFpgaCard(configFile, fpgaName); - std::vector> switch_channels; - for (int i = 0; i < 4; i++) { - auto name = fmt::format("aurora_8b10b_ch{}", i); - auto id = fpga::ip::IpIdentifier("xilinx.com:ip:aurora_8b10b:", name); - auto aurora = std::dynamic_pointer_cast( - handle->card->lookupIp(id)); - if (aurora == nullptr) { - logger->error("No Aurora interface found on FPGA"); - return nullptr; - } + if (dumpGraph) { + auto &mm = MemoryManager::get(); + mm.getGraph().dump("graph.dot"); + } - switch_channels.push_back(aurora); - } + if (dumpAuroraChannels) { + auto aurora_channels = getAuroraChannels(handle->card); + for (auto aurora : *aurora_channels) + aurora->dump(); + } - handle->dma = std::dynamic_pointer_cast - (handle->card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); - if (handle->dma == nullptr) { - logger->error("No DMA found on FPGA "); - return nullptr; - } + // Configure Crossbar switch + const fpga::ConnectString parsedConnectString(connectStr); + parsedConnectString.configCrossBar(handle->card); - if (dumpGraph) { - auto &mm = MemoryManager::get(); - mm.getGraph().dump("graph.dot"); - } - - if (dumpAuroraChannels) { - for (auto aurora : switch_channels) - aurora->dump(); - } - - // Configure Crossbar switch - const fpga::ConnectString parsedConnectString(connectStr); - parsedConnectString.configCrossBar(handle->dma, - switch_channels); - - return handle; - } catch (const RuntimeError &e) { - logger->error("Error: {}", e.what()); - return nullptr; - } catch (const std::exception &e) { - logger->error("Error: {}", e.what()); - return nullptr; - } catch (...) { - logger->error("Unknown error"); - return nullptr; - } + return handle; + } catch (const RuntimeError &e) { + logger->error("Error: {}", e.what()); + return nullptr; + } catch (const std::exception &e) { + logger->error("Error: {}", e.what()); + return nullptr; + } catch (...) { + logger->error("Unknown error"); + return nullptr; + } } void villasfpga_destroy(villasfpga_handle handle) diff --git a/fpga/lib/utils.cpp b/fpga/lib/utils.cpp index 28af178e3..42f1918c5 100644 --- a/fpga/lib/utils.cpp +++ b/fpga/lib/utils.cpp @@ -23,80 +23,106 @@ #include #include -#include #include -#include +#include +#include +#include #include #include -#include #include +#include using namespace villas; static auto logger = villas::logging.get("streamer"); -fpga::ConnectString::ConnectString(std::string& connectString, int maxPortNum) : - log(villas::logging.get("ConnectString")), - maxPortNum(maxPortNum), - bidirectional(false), - invert(false), - srcAsInt(-1), - dstAsInt(-1), - srcIsStdin(false), - dstIsStdout(false), - dmaLoopback(false) -{ - parseString(connectString); +std::shared_ptr>> +fpga::getAuroraChannels(std::shared_ptr card) { + auto aurora_channels = + std::make_shared>>(); + for (int i = 0; i < 4; i++) { + auto name = fmt::format("aurora_aurora_8b10b_ch{}", i); + auto id = fpga::ip::IpIdentifier("xilinx.com:ip:aurora_8b10b:", name); + auto aurora = std::dynamic_pointer_cast(card->lookupIp(id)); + if (aurora == nullptr) { + logger->error("No Aurora interface found on FPGA"); + throw std::runtime_error("No Aurora interface found on FPGA"); + } + + aurora_channels->push_back(aurora); + } + return aurora_channels; +} + +fpga::ConnectString::ConnectString(std::string &connectString, int maxPortNum) + : log(villas::logging.get("ConnectString")), maxPortNum(maxPortNum), + bidirectional(false), invert(false), srcType(ConnectType::LOOPBACK), + dstType(ConnectType::LOOPBACK), srcAsInt(-1), dstAsInt(-1) { + parseString(connectString); } void fpga::ConnectString::parseString(std::string& connectString) { - if (connectString.empty()) - return; + if (connectString.empty()) + return; - if (connectString == "loopback") { - logger->info("Connecting loopback"); - srcIsStdin = true; - dstIsStdout = true; - bidirectional = true; - dmaLoopback = true; - return; - } + if (connectString == "loopback") { + logger->info("Connecting loopback"); + srcType = ConnectType::LOOPBACK; + dstType = ConnectType::LOOPBACK; + bidirectional = true; + return; + } + static const std::regex regex("([0-9]+|stdin|stdout|pipe|dma|dino)([<\\->]+)(" + "[0-9]+|stdin|stdout|pipe|dma|dino)"); + std::smatch match; - static const std::regex regex( - "([0-9]+)([<\\->]+)([0-9]+|stdin|stdout|pipe|dma)"); - std::smatch match; + if (!std::regex_match(connectString, match, regex) || match.size() != 4) { + logger->error("Invalid connect string: {}", connectString); + throw std::runtime_error("Invalid connect string"); + } - if (!std::regex_match(connectString, match, regex) || - match.size() != 4) { - logger->error("Invalid connect string: {}", connectString); - throw std::runtime_error("Invalid connect string"); - } + if (match[2] == "<->") { + bidirectional = true; + } else if (match[2] == "<-") { + invert = true; + } - if (match[2] == "<->") { - bidirectional = true; - } else if (match[2] == "<-") { - invert = true; - } + std::string srcStr = (invert ? match[3] : match[1]); + std::string dstStr = (invert ? match[1] : match[3]); - std::string srcStr = (invert ? match[3] : match[1]); - std::string dstStr = (invert ? match[1] : match[3]); - - srcAsInt = portStringToInt(srcStr); - dstAsInt = portStringToInt(dstStr); - if (srcAsInt == -1) { - srcIsStdin = true; - dstIsStdout = bidirectional; - } - if (dstAsInt == -1) { - dstIsStdout = true; - srcIsStdin = bidirectional; - } + srcAsInt = portStringToInt(srcStr); + dstAsInt = portStringToInt(dstStr); + if (srcAsInt == -1) { + if (srcStr == "dino") { + srcType = ConnectType::DINO; + } else if (srcStr == "dma" || srcStr == "pipe" || srcStr == "stdin" || + srcStr == "stdout") { + srcType = ConnectType::DMA; + } else { + throw std::runtime_error("Invalid source type"); + } + } else { + srcType = ConnectType::AURORA; + } + if (dstAsInt == -1) { + if (dstStr == "dino") { + dstType = ConnectType::DINO; + } else if (dstStr == "dma" || dstStr == "pipe" || dstStr == "stdin" || + dstStr == "stdout") { + dstType = ConnectType::DMA; + } else { + throw std::runtime_error("Invalid destination type"); + } + } else { + dstType = ConnectType::AURORA; + } } int fpga::ConnectString::portStringToInt(std::string &str) const { - if (str == "stdin" || str == "stdout" || str == "pipe" || str == "dma") { + if (str == "stdin" || str == "stdout" || str == "pipe" || str == "dma" || + str == "dino") { return -1; } else { const int port = std::stoi(str); @@ -111,35 +137,70 @@ int fpga::ConnectString::portStringToInt(std::string &str) const // parses a string like "1->2" or "1<->stdout" and configures the crossbar accordingly void fpga::ConnectString::configCrossBar( - std::shared_ptr dma, - std::vector> &switch_channels) const { - if (dmaLoopback) { + std::shared_ptr card) const { + + auto dma = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); + if (dma == nullptr) { + logger->error("No DMA found on FPGA "); + throw std::runtime_error("No DMA found on FPGA"); + } + + if (isDmaLoopback()) { log->info("Configuring DMA loopback"); dma->connectLoopback(); return; } + auto aurora_channels = getAuroraChannels(card); + + auto dinoDac = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:module_ref:dinoif_dac:"))); + if (dinoDac == nullptr) { + logger->error("No Dino DAC found on FPGA "); + throw std::runtime_error("No Dino DAC found on FPGA"); + } + + auto dinoAdc = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:module_ref:dinoif_fast:"))); + if (dinoAdc == nullptr) { + logger->error("No Dino ADC found on FPGA "); + throw std::runtime_error("No Dino ADC found on FPGA"); + } + log->info("Connecting {} to {}, {}directional", - (srcAsInt == -1 ? "stdin" : std::to_string(srcAsInt)), - (dstAsInt == -1 ? "stdout" : std::to_string(dstAsInt)), + (srcAsInt == -1 ? connectTypeToString(srcType) + : std::to_string(srcAsInt)), + (dstAsInt == -1 ? connectTypeToString(dstType) + : std::to_string(dstAsInt)), (bidirectional ? "bi" : "uni")); std::shared_ptr src; std::shared_ptr dest; - if (srcIsStdin) { + if (srcType == ConnectType::DINO) { + src = dinoAdc; + } else if (srcType == ConnectType::DMA) { src = dma; } else { - src = switch_channels[srcAsInt]; + src = (*aurora_channels)[srcAsInt]; } - if (dstIsStdout) { + if (dstType == ConnectType::DINO) { + dest = dinoDac; + } else if (dstType == ConnectType::DMA) { dest = dma; } else { - dest = switch_channels[dstAsInt]; + dest = (*aurora_channels)[dstAsInt]; } src->connect(src->getDefaultMasterPort(), dest->getDefaultSlavePort()); if (bidirectional) { + if (srcType == ConnectType::DINO) { + src = dinoDac; + } + if (dstType == ConnectType::DINO) { + dest = dinoAdc; + } dest->connect(dest->getDefaultMasterPort(), src->getDefaultSlavePort()); } } diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index 4dd9d815a..ba332ce4e 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -212,60 +213,57 @@ int main(int argc, char *argv[]) { auto card = fpga::setupFpgaCard(configFile, fpgaName); - std::vector> switch_channels; - for (int i = 0; i < 4; i++) { - auto name = fmt::format("aurora_aurora_8b10b_ch{}", i); - auto id = fpga::ip::IpIdentifier("xilinx.com:ip:aurora_8b10b:", name); - auto aurora = - std::dynamic_pointer_cast(card->lookupIp(id)); - if (aurora == nullptr) { - logger->error("No Aurora interface found on FPGA"); - return 1; - } - - switch_channels.push_back(aurora); - } - - auto dma = std::dynamic_pointer_cast( - card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); - if (dma == nullptr) { - logger->error("No DMA found on FPGA "); - return 1; - } - if (dumpGraph) { auto &mm = MemoryManager::get(); mm.getGraph().dump("graph.dot"); } if (dumpAuroraChannels) { - for (auto aurora : switch_channels) + auto aurora_channels = getAuroraChannels(card); + for (auto aurora : *aurora_channels) aurora->dump(); } - bool dstIsStdout = false; - bool srcIsStdin = false; + bool writeToStdout = false; + bool readFromStdin = false; // Configure Crossbar switch for (std::string str : connectStr) { const fpga::ConnectString parsedConnectString(str); - parsedConnectString.configCrossBar(dma, switch_channels); - dstIsStdout = dstIsStdout || parsedConnectString.isDstStdout(); - srcIsStdin = srcIsStdin || parsedConnectString.isSrcStdin(); + parsedConnectString.configCrossBar(card); + if (parsedConnectString.isSrcStdin()) { + readFromStdin = true; + if (parsedConnectString.isBidirectional()) { + writeToStdout = true; + } + } + if (parsedConnectString.isDstStdout()) { + writeToStdout = true; + if (parsedConnectString.isBidirectional()) { + readFromStdin = true; + } + } } + if (writeToStdout || readFromStdin) { + auto dma = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); + if (dma == nullptr) { + logger->error("No DMA found on FPGA "); + throw std::runtime_error("No DMA found on FPGA"); + } + std::unique_ptr stdInThread = nullptr; + if (!noDma && writeToStdout) { + auto formatter = fpga::getBufferedSampleFormatter(outputFormat, 16); + // We copy the dma shared ptr but move the fomatter unqiue ptr as we don't need it + // in this thread anymore + stdInThread = std::make_unique(readFromDmaToStdOut, dma, + std::move(formatter)); + } + if (!noDma && readFromStdin) { + writeToDmaFromStdIn(dma); + } - std::unique_ptr stdInThread = nullptr; - if (!noDma && dstIsStdout) { - auto formatter = fpga::getBufferedSampleFormatter(outputFormat, 16); - // We copy the dma shared ptr but move the fomatter unqiue ptr as we don't need it - // in this thread anymore - stdInThread = std::make_unique(readFromDmaToStdOut, dma, - std::move(formatter)); - } - if (!noDma && srcIsStdin) { - writeToDmaFromStdIn(dma); - } - - if (stdInThread) { - stdInThread->join(); + if (stdInThread) { + stdInThread->join(); + } } } catch (const RuntimeError &e) { logger->error("Error: {}", e.what());