From b05910f24ea4f84ab03db6a78bffb39266d4ea04 Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Mon, 20 Mar 2023 17:12:47 +0100 Subject: [PATCH] add C bindings for external use of VILLASfpga Signed-off-by: Niklas Eiling --- fpga/include/villas/fpga/utils.hpp | 16 +- fpga/include/villas/fpga/villasfpga_dma.h | 31 ++++ fpga/lib/CMakeLists.txt | 1 + fpga/lib/utils.cpp | 12 ++ fpga/lib/villasfpga_dma.cpp | 195 ++++++++++++++++++++++ fpga/src/villas-fpga-ctrl.cpp | 1 - 6 files changed, 242 insertions(+), 14 deletions(-) create mode 100644 fpga/include/villas/fpga/villasfpga_dma.h create mode 100644 fpga/lib/villasfpga_dma.cpp diff --git a/fpga/include/villas/fpga/utils.hpp b/fpga/include/villas/fpga/utils.hpp index 5e93465cf..fd9e7fbcd 100644 --- a/fpga/include/villas/fpga/utils.hpp +++ b/fpga/include/villas/fpga/utils.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace villas { namespace fpga { @@ -25,7 +26,7 @@ public: int portStringToInt(std::string &str) const; void configCrossBar(std::shared_ptr dma, - std::vector>& aurora_channels) const; + std::vector>& aurora_channels) const; bool isBidirectional() const { return bidirectional; }; bool isDmaLoopback() const { return dmaLoopback; }; @@ -119,18 +120,7 @@ protected: }; -std::unique_ptr getBufferedSampleFormatter( - const std::string &format, - size_t bufSizeInSamples) -{ - if (format == "long") { - return std::make_unique(bufSizeInSamples); - } else if (format == "short") { - return std::make_unique(bufSizeInSamples); - } else { - throw RuntimeError("Unknown output format '{}'", format); - } -} +std::unique_ptr getBufferedSampleFormatter(const std::string &format, size_t bufSizeInSamples); } /* namespace fpga */ } /* namespace villas */ diff --git a/fpga/include/villas/fpga/villasfpga_dma.h b/fpga/include/villas/fpga/villasfpga_dma.h new file mode 100644 index 000000000..353a7eb75 --- /dev/null +++ b/fpga/include/villas/fpga/villasfpga_dma.h @@ -0,0 +1,31 @@ +/** C bindings for VILLASfpga + * + * Author: Niklas Eiling + * SPDX-FileCopyrightText: 2023 Niklas Eiling + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +#pragma once + +extern "C" { + +#include + +typedef struct villasfpga_handle_t *villasfpga_handle; +typedef struct villasfpga_memory_t *villasfpga_memory; + +villasfpga_handle villasfpga_init(const char *configFile); + +void villasfpga_destroy(villasfpga_handle handle); + +int villasfpga_alloc(villasfpga_handle handle, villasfpga_memory *mem, size_t size); +int villasfpga_register(villasfpga_handle handle, villasfpga_memory *mem); +int villasfpga_free(villasfpga_memory mem); + +int villasfpga_read(villasfpga_handle handle, villasfpga_memory mem, size_t size); +int vilalsfpga_read_complete(villasfpga_handle handle, size_t *size); + +int villasfpga_write(villasfpga_handle handle, villasfpga_memory mem, size_t size); +int vilalsfpga_write_complete(villasfpga_handle handle, size_t *size); + +} // extern "C" diff --git a/fpga/lib/CMakeLists.txt b/fpga/lib/CMakeLists.txt index a89150c07..148d77867 100644 --- a/fpga/lib/CMakeLists.txt +++ b/fpga/lib/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES core.cpp node.cpp utils.cpp + villasfpga_dma.cpp ips/aurora_xilinx.cpp ips/aurora.cpp diff --git a/fpga/lib/utils.cpp b/fpga/lib/utils.cpp index b8979afe8..763a68739 100644 --- a/fpga/lib/utils.cpp +++ b/fpga/lib/utils.cpp @@ -215,3 +215,15 @@ fpga::setupFpgaCard(const std::string &configFile, const std::string &fpgaName) return card; } +std::unique_ptr fpga::getBufferedSampleFormatter( + const std::string &format, + size_t bufSizeInSamples) +{ + if (format == "long") { + return std::make_unique(bufSizeInSamples); + } else if (format == "short") { + return std::make_unique(bufSizeInSamples); + } else { + throw RuntimeError("Unknown output format '{}'", format); + } +} diff --git a/fpga/lib/villasfpga_dma.cpp b/fpga/lib/villasfpga_dma.cpp new file mode 100644 index 000000000..31699cf55 --- /dev/null +++ b/fpga/lib/villasfpga_dma.cpp @@ -0,0 +1,195 @@ +/** API for interacting with the FPGA DMA Controller. + * + * Author: Niklas Eiling + * SPDX-FileCopyrightText: 2023 Niklas Eiling + * SPDX-License-Identifier: Apache-2.0 + *********************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace villas; + +static std::shared_ptr pciDevices; +static auto logger = villas::logging.get("villasfpga_dma"); + +struct villasfpga_handle_t { + std::shared_ptr card; + std::shared_ptr dma; +}; +struct villasfpga_memory_t { + std::shared_ptr block; +}; + +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(); + + 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); + + std::vector> aurora_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; + } + + aurora_channels.push_back(aurora); + } + + 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; + } + + if (dumpGraph) { + auto &mm = MemoryManager::get(); + mm.getGraph().dump("graph.dot"); + } + + if (dumpAuroraChannels) { + for (auto aurora : aurora_channels) + aurora->dump(); + } + + // Configure Crossbar switch + const fpga::ConnectString parsedConnectString(connectStr); + parsedConnectString.configCrossBar(handle->dma, aurora_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; + } +} + +void villasfpga_destroy(villasfpga_handle handle) +{ + delete handle; +} + +int villasfpga_alloc(villasfpga_handle handle, villasfpga_memory *mem, size_t size) +{ + try { + auto &alloc = villas::HostRam::getAllocator(); + *mem = new villasfpga_memory_t; + (*mem)->block = alloc.allocateBlock(size); + return villasfpga_register(handle, mem); + } catch (const RuntimeError &e) { + logger->error("Failed to allocate memory: {}", e.what()); + return -1; + } +} +int villasfpga_register(villasfpga_handle handle, villasfpga_memory *mem) +{ + try { + handle->dma->makeAccesibleFromVA((*mem)->block); + return 0; + } catch (const RuntimeError &e) { + logger->error("Failed to register memory: {}", e.what()); + return -1; + } +} +int villasfpga_free(villasfpga_memory mem) +{ + try { + delete mem; + return 0; + } catch (const RuntimeError &e) { + logger->error("Failed to free memory: {}", e.what()); + return -1; + } +} + +int villasfpga_read(villasfpga_handle handle, villasfpga_memory mem, size_t size) +{ + try { + if (!handle->dma->read(*mem->block, size)) { + logger->error("Failed to read from device"); + return -1; + } + return 0; + } catch (const RuntimeError &e) { + logger->error("Failed to read memory: {}", e.what()); + return -1; + } +} + +int vilalsfpga_read_complete(villasfpga_handle handle, size_t *size) +{ + try { + auto readComp = handle->dma->readComplete(); + logger->debug("Wrote {} bytes", readComp.bytes); + *size = readComp.bytes; + return 0; + } catch (const RuntimeError &e) { + logger->error("Failed to read memory: {}", e.what()); + return -1; + } +} + +int villasfpga_write(villasfpga_handle handle, villasfpga_memory mem, size_t size) +{ + try { + if (!handle->dma->write(*mem->block, size)) { + logger->error("Failed to write to device"); + return -1; + } + return 0; + } catch (const RuntimeError &e) { + logger->error("Failed to write memory: {}", e.what()); + return -1; + } +} + +int vilalsfpga_write_complete(villasfpga_handle handle, size_t *size) +{ + try { + auto writeComp = handle->dma->writeComplete(); + logger->debug("Wrote {} bytes", writeComp.bytes); + *size = writeComp.bytes; + return 0; + } catch (const RuntimeError &e) { + logger->error("Failed to write memory: {}", e.what()); + return -1; + } +} diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index c88a7c32d..e1a6ac066 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include