1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

move more of the switch configuration boilerplate into ConnectString

Signed-off-by: Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
This commit is contained in:
Niklas Eiling 2024-01-12 11:43:03 +01:00 committed by Niklas Eiling
parent 147725daef
commit b2fcfeaa67
5 changed files with 237 additions and 183 deletions

View file

@ -84,11 +84,21 @@ public:
return *portsMaster.at(name);
}
const std::map<std::string, std::shared_ptr<StreamVertex>> &getMasterPorts() const
{
return portsMaster;
}
const StreamVertex& getSlavePort(const std::string &name) const
{
return *portsSlave.at(name);
}
const std::map<std::string, std::shared_ptr<StreamVertex>> &getSlavePorts() const
{
return portsSlave;
}
bool connect(const StreamVertex &from, const StreamVertex &to);
bool connect(const StreamVertex &from, const StreamVertex &to, bool reverse)
{

View file

@ -20,34 +20,39 @@ setupFpgaCard(const std::string &configFile, const std::string &fpgaName);
int createCards(json_t *config, std::list<std::shared_ptr<fpga::Card>> &cards,
std::filesystem::path &searchPath);
std::shared_ptr<std::vector<std::shared_ptr<fpga::ip::Node>>>
getAuroraChannels(std::shared_ptr<fpga::Card> 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<villas::fpga::ip::Dma> dma,
std::vector<std::shared_ptr<villas::fpga::ip::Node>>
&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<villas::fpga::Card> 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 {

View file

@ -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<std::shared_ptr<fpga::ip::Node>> 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<fpga::ip::Node>(
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<fpga::ip::Dma>
(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)

View file

@ -23,80 +23,106 @@
#include <villas/utils.hpp>
#include <villas/utils.hpp>
#include <villas/fpga/core.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/vlnv.hpp>
#include <villas/fpga/core.hpp>
#include <villas/fpga/ips/aurora_xilinx.hpp>
#include <villas/fpga/ips/dino.hpp>
#include <villas/fpga/ips/dma.hpp>
#include <villas/fpga/ips/rtds.hpp>
#include <villas/fpga/ips/aurora_xilinx.hpp>
#include <villas/fpga/utils.hpp>
#include <villas/fpga/vlnv.hpp>
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<std::vector<std::shared_ptr<fpga::ip::Node>>>
fpga::getAuroraChannels(std::shared_ptr<fpga::Card> card) {
auto aurora_channels =
std::make_shared<std::vector<std::shared_ptr<fpga::ip::Node>>>();
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<fpga::ip::Node>(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<villas::fpga::ip::Dma> dma,
std::vector<std::shared_ptr<fpga::ip::Node>> &switch_channels) const {
if (dmaLoopback) {
std::shared_ptr<villas::fpga::Card> card) const {
auto dma = std::dynamic_pointer_cast<fpga::ip::Dma>(
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<fpga::ip::DinoDac>(
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<fpga::ip::DinoAdc>(
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<fpga::ip::Node> src;
std::shared_ptr<fpga::ip::Node> 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());
}
}

View file

@ -29,6 +29,7 @@
#include <villas/fpga/ips/dma.hpp>
#include <villas/fpga/ips/i2c.hpp>
#include <villas/fpga/ips/rtds.hpp>
#include <villas/fpga/ips/switch.hpp>
#include <villas/fpga/utils.hpp>
#include <villas/fpga/vlnv.hpp>
@ -212,60 +213,57 @@ int main(int argc, char *argv[]) {
auto card = fpga::setupFpgaCard(configFile, fpgaName);
std::vector<std::shared_ptr<fpga::ip::Node>> 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<fpga::ip::Node>(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<fpga::ip::Dma>(
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<fpga::ip::Dma>(
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<std::thread> 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<std::thread>(readFromDmaToStdOut, dma,
std::move(formatter));
}
if (!noDma && readFromStdin) {
writeToDmaFromStdIn(dma);
}
std::unique_ptr<std::thread> 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<std::thread>(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());