From 40d0452b0a260d96dfc1b1c2f4958e88794d8a38 Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Thu, 5 Jan 2023 10:50:27 +0100 Subject: [PATCH] move connectString parsing into separate class Signed-off-by: Niklas Eiling --- fpga/include/villas/fpga/utils.hpp | 56 +++++++++++++--- fpga/lib/utils.cpp | 102 +++++++++++++++++++++-------- fpga/src/villas-fpga-ctrl.cpp | 3 +- 3 files changed, 124 insertions(+), 37 deletions(-) diff --git a/fpga/include/villas/fpga/utils.hpp b/fpga/include/villas/fpga/utils.hpp index d21ef0ebc..fae15afde 100644 --- a/fpga/include/villas/fpga/utils.hpp +++ b/fpga/include/villas/fpga/utils.hpp @@ -1,9 +1,24 @@ /** Helper function for directly using VILLASfpga outside of VILLASnode * - * Author: Niklas Eiling - * SPDX-FileCopyrightText: 2022 Steffen Vogel - * SPDX-FileCopyrightText: 2022 Niklas Eiling - * SPDX-License-Identifier: Apache-2.0 + * @file + * @author Niklas Eiling + * @copyright 2022, Steffen Vogel, Niklas Eiling + * @license GNU General Public License (version 3) + * + * VILLASfpga + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . *********************************************************************************/ #pragma once @@ -17,11 +32,36 @@ namespace fpga { std::shared_ptr setupFpgaCard(const std::string &configFile, const std::string &fpgaName); -void configCrossBarUsingConnectString(std::string connectString, - std::shared_ptr dma, - std::vector>& aurora_channels); - 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>& aurora_channels) 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; }; +protected: + villas::Logger log; + int maxPortNum; + bool bidirectional; + bool invert; + int srcAsInt; + int dstAsInt; + bool srcIsStdin; + bool dstIsStdout; + bool dmaLoopback; +}; + + } /* namespace fpga */ } /* namespace villas */ diff --git a/fpga/lib/utils.cpp b/fpga/lib/utils.cpp index 32107a40a..071336cef 100644 --- a/fpga/lib/utils.cpp +++ b/fpga/lib/utils.cpp @@ -35,46 +35,42 @@ using namespace villas; static std::shared_ptr pciDevices; static auto logger = villas::logging.get("streamer"); -const std::shared_ptr portStringToStreamVertex(std::string &str, - std::shared_ptr dma, - std::vector>& aurora_channels) +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) { - if (str == "stdin" || str == "stdout") { - return dma; - } else { - int port = std::stoi(str); - - if (port > 7 || port < 0) - throw std::runtime_error("Invalid port number"); - - return aurora_channels[port]; - } + parseString(connectString); } -// parses a string lik "1->2" or "1<->stdout" and configures the crossbar -void fpga::configCrossBarUsingConnectString(std::string connectString, - std::shared_ptr dma, - std::vector>& aurora_channels) +void fpga::ConnectString::parseString(std::string& connectString) { - bool bidirectional = false; - bool invert = false; - if (connectString.empty()) return; if (connectString == "loopback") { logger->info("Connecting loopback"); - // is this working? - dma->connectLoopback(); + srcIsStdin = true; + dstIsStdout = true; + bidirectional = true; + dmaLoopback = true; + return; } - static std::regex re("([0-9]+)([<\\->]+)([0-9]+|stdin|stdout)"); + std::regex regex("([0-9]+)([<\\->]+)([0-9]+|stdin|stdout)"); std::smatch match; - if (!std::regex_match(connectString, match, re)) { + 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] == "<-") { @@ -83,11 +79,61 @@ void fpga::configCrossBarUsingConnectString(std::string connectString, std::string srcStr = (invert ? match[3] : match[1]); std::string dstStr = (invert ? match[1] : match[3]); - logger->info("Connect string {}: Connecting {} to {}, {}directional", - connectString, srcStr, dstStr, + + srcAsInt = portStringToInt(srcStr); + dstAsInt = portStringToInt(dstStr); + if (srcAsInt == -1) { + srcIsStdin = true; + } + if (dstAsInt == -1) { + dstIsStdout = true; + } +} + +int fpga::ConnectString::portStringToInt(std::string &str) const +{ + if (str == "stdin" || str == "stdout") { + return -1; + } else { + const int port = std::stoi(str); + + if (port > maxPortNum || port < 0) + throw std::runtime_error("Invalid port number"); + + return port; + } +} + + +// parses a string lik "1->2" or "1<->stdout" and configures the crossbar +void fpga::ConnectString::configCrossBar(std::shared_ptr dma, + std::vector>& aurora_channels) const +{ + if (dmaLoopback) { + log->info("Configuring DMA loopback"); + dma->connectLoopback(); + return; + } + + log->info("Connecting {} to {}, {}directional", + (srcAsInt==-1 ? "stdin" : std::to_string(srcAsInt)), + (dstAsInt==-1 ? "stdout" : std::to_string(dstAsInt)), (bidirectional ? "bi" : "uni")); - auto src = portStringToStreamVertex(srcStr, dma, aurora_channels); - auto dest = portStringToStreamVertex(dstStr, dma, aurora_channels); + + std::shared_ptr src; + std::shared_ptr dest; + if (srcIsStdin) { + src = dma; + } else { + src = aurora_channels[srcAsInt]; + } + + if (dstIsStdout) { + dest = dma; + } else { + dest = aurora_channels[dstAsInt]; + } + src->connect(src->getDefaultMasterPort(), dest->getDefaultSlavePort()); if (bidirectional) { dest->connect(dest->getDefaultMasterPort(), src->getDefaultSlavePort()); diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index 2ad64557e..bb5a93b61 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -99,7 +99,8 @@ int main(int argc, char* argv[]) aurora->dump(); // Configure Crossbar switch - fpga::configCrossBarUsingConnectString(connectStr, dma, aurora_channels); + const fpga::ConnectString parsedConnectString(connectStr); + parsedConnectString.configCrossBar(dma, aurora_channels); if (!noDma) { for (auto b : block) {