diff --git a/fpga/src/CMakeLists.txt b/fpga/src/CMakeLists.txt index 0cf2a5ae3..fbca7c72a 100644 --- a/fpga/src/CMakeLists.txt +++ b/fpga/src/CMakeLists.txt @@ -1,36 +1,6 @@ -set(SOURCES - bench-datamovers.c - bench-jitter.c - bench-latency.c - bench-memcpy.c - bench.c - fpga.c -) +add_executable(streamer streamer.cpp) -add_executable(fpga ${SOURCES}) - -target_include_directories(fpga PUBLIC - ../include/villas - ../include -) - -target_link_libraries(fpga PUBLIC +target_link_libraries(streamer PUBLIC villas-fpga ) -find_package(LAPACK) - -if(LAPACK_FOUND) - target_sources(fpga PUBLIC bench-overruns.c) - target_link_libraries(fpga PUBLIC ${LAPACK_LIBRARIES}) - target_include_directories(fpga PUBLIC ${LAPACK_INCLUDE_DIRS}) - target_compile_definitions(fpga PUBLIC WITH_LAPACK) -endif() - -include(GNUInstallDirs) - -install(TARGETS fpga - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/static -) diff --git a/fpga/src/streamer.cpp b/fpga/src/streamer.cpp index b261b79a5..b040fc8ec 100644 --- a/fpga/src/streamer.cpp +++ b/fpga/src/streamer.cpp @@ -15,11 +15,185 @@ #include #include +#include +#include +#include +#include -int main(int argc, const char* argv[]) +using namespace villas; + +static struct pci pci; +static auto logger = loggerGetOrCreate("streamer"); + +void setupColorHandling() { - (void) argc; - cxxopts::Options options(argv[0], " - example command line options"); + // Nice Control-C + struct sigaction sigIntHandler; + sigIntHandler.sa_handler = [](int){ + std::cout << std::endl << rang::style::reset << rang::fgB::red; + std::cout << "Control-C detected, exiting..." << rang::style::reset << std::endl; + std::exit(1); // will call the correct exit func, no unwinding of the stack though + }; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + sigaction(SIGINT, &sigIntHandler, nullptr); + + // reset color if exiting not by signal + std::atexit([](){std::cout << rang::style::reset;}); +} + +fpga::PCIeCard& +setupFpgaCard(const std::string& configFile, const std::string& fpgaName) +{ + if(pci_init(&pci) != 0) { + logger->error("Cannot initialize PCI"); + exit(1); + } + + auto vfioContainer = villas::VfioContainer::create(); + + /* Parse FPGA configuration */ + FILE* f = fopen(configFile.c_str(), "r"); + if(f == nullptr) { + logger->error("Cannot open config file: {}", configFile); + } + + json_t* json = json_loadf(f, 0, nullptr); + if(json == nullptr) { + logger->error("Cannot parse JSON config"); + fclose(f); + exit(1); + } + + fclose(f); + + json_t* fpgas = json_object_get(json, "fpgas"); + if(fpgas == nullptr) { + logger->error("No section 'fpgas' found in config"); + exit(1); + } + + // get the FPGA card plugin + villas::Plugin* plugin = villas::Plugin::lookup(villas::Plugin::Type::FpgaCard, ""); + if(plugin == nullptr) { + logger->error("No FPGA plugin found"); + exit(1); + } + + + villas::fpga::PCIeCardFactory* fpgaCardPlugin = + dynamic_cast(plugin); + + // create all FPGA card instances using the corresponding plugin + auto cards = fpgaCardPlugin->make(fpgas, &pci, vfioContainer); + villas::fpga::PCIeCard* card = nullptr; + + for(auto& fpgaCard : cards) { + if(fpgaCard->name == fpgaName) { + card = fpgaCard.get(); + break; + } + } + + if(card == nullptr) { + logger->error("FPGA card {} not found in config or not working", fpgaName); + exit(1); + } + + // deallocate JSON config +// json_decref(json); + + return *card; +} + +int main(int argc, char* argv[]) +{ + /* Command Line Parser */ + + CLI::App app{"VILLASfpga data streamer"}; + + std::string configFile = "../etc/fpga.json"; + app.add_option("-c,--config", configFile, "Configuration file") + ->check(CLI::ExistingFile); + + std::string fpgaName = "vc707"; + app.add_option("--fpga", fpgaName, "Which FPGA to use"); + + try { + app.parse(argc, argv); + } catch (const CLI::ParseError &e) { + return app.exit(e); + } + + /* Logging setup */ + + spdlog::set_level(spdlog::level::debug); + setupColorHandling(); + + + fpga::PCIeCard& card = setupFpgaCard(configFile, fpgaName); + + auto rtds = reinterpret_cast + (card.lookupIp(fpga::Vlnv("acs.eonerc.rwth-aachen.de:user:rtds_axis:"))); + + auto dma = reinterpret_cast + (card.lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); + + auto fifo = reinterpret_cast + (card.lookupIp(fpga::Vlnv("xilinx.com:ip:axi_fifo_mm_s:"))); + + + if(rtds == nullptr) { + logger->error("No RTDS interface found on FPGA"); + return 1; + } + + if(dma == nullptr) { + logger->error("No DMA found on FPGA "); + return 1; + } + + if(fifo == nullptr) { + logger->error("No Fifo found on FPGA "); + return 1; + } + + + rtds->dump(); + + rtds->connect(rtds->getMasterPort(rtds->masterPort), + dma->getSlavePort(dma->s2mmPort)); + + dma->connect(dma->getMasterPort(dma->mm2sPort), + rtds->getSlavePort(rtds->slavePort)); + + auto mem = villas::HostRam::allocate(0x100 / sizeof(int32_t)); + + while(true) { + dma->read(mem, mem.getSize()); + const size_t bytesRead = dma->readComplete(); + const size_t valuesRead = bytesRead / sizeof(int32_t); + + for(size_t i = 0; i < valuesRead; i++) { + std::cerr << mem[i] << ";"; + } + std::cerr << std::endl; + + std::string line; + std::getline(std::cin, line); + auto values = villas::utils::tokenize(line, ";"); + + size_t memIdx = 0; + + for(auto& value: values) { + if(value.empty()) continue; + + const int32_t number = std::stoi(value); + mem[memIdx++] = number; + } + + dma->write(mem, memIdx * sizeof(int32_t)); + } return 0; }