mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
src: add streamer application for RTDS
This commit is contained in:
parent
7bffe82e0e
commit
31c854f26f
2 changed files with 179 additions and 35 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -15,11 +15,185 @@
|
|||
|
||||
#include <villas/fpga/ip.hpp>
|
||||
#include <villas/fpga/card.hpp>
|
||||
#include <villas/fpga/vlnv.hpp>
|
||||
#include <villas/fpga/ips/dma.hpp>
|
||||
#include <villas/fpga/ips/rtds.hpp>
|
||||
#include <villas/fpga/ips/fifo.hpp>
|
||||
|
||||
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<villas::fpga::PCIeCardFactory*>(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<fpga::ip::Rtds*>
|
||||
(card.lookupIp(fpga::Vlnv("acs.eonerc.rwth-aachen.de:user:rtds_axis:")));
|
||||
|
||||
auto dma = reinterpret_cast<fpga::ip::Dma*>
|
||||
(card.lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:")));
|
||||
|
||||
auto fifo = reinterpret_cast<fpga::ip::Fifo*>
|
||||
(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<int32_t>(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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue