Skip to content
This repository was archived by the owner on Feb 29, 2024. It is now read-only.

Commit 29f8101

Browse files
authored
Merge pull request #81 from VILLASframework/dma-ingress
adds C bindings and other smaller changes
2 parents 4419d5d + 589b2bf commit 29f8101

File tree

15 files changed

+504
-83
lines changed

15 files changed

+504
-83
lines changed

etc/fpgas.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"id": "10ee:7021",
55
"slot": "0000:88:00.0",
66
"do_reset": true,
7-
"ips": "etc/vc707-xbar-pcie/vc707-xbar-pcie.json",
7+
"ips": "vc707-xbar-pcie/vc707-xbar-pcie.json",
88
"polling": false
99
}
1010
}

include/villas/fpga/dma.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/** C bindings for VILLASfpga
2+
*
3+
* Author: Niklas Eiling <[email protected]>
4+
* SPDX-FileCopyrightText: 2023 Niklas Eiling <[email protected]>
5+
* SPDX-License-Identifier: Apache-2.0
6+
******************************************************************************/
7+
8+
#ifndef _VILLASFPGA_DMA_H
9+
#define _VILLASFPGA_DMA_H
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
15+
#include <stddef.h>
16+
17+
typedef struct villasfpga_handle_t *villasfpga_handle;
18+
typedef struct villasfpga_memory_t *villasfpga_memory;
19+
20+
villasfpga_handle villasfpga_init(const char *configFile);
21+
22+
void villasfpga_destroy(villasfpga_handle handle);
23+
24+
int villasfpga_alloc(villasfpga_handle handle, villasfpga_memory *mem, size_t size);
25+
int villasfpga_register(villasfpga_handle handle, villasfpga_memory *mem);
26+
int villasfpga_free(villasfpga_memory mem);
27+
void* villasfpga_get_ptr(villasfpga_memory mem);
28+
29+
int villasfpga_read(villasfpga_handle handle, villasfpga_memory mem, size_t size);
30+
int villasfpga_read_complete(villasfpga_handle handle, size_t *size);
31+
32+
int villasfpga_write(villasfpga_handle handle, villasfpga_memory mem, size_t size);
33+
int villasfpga_write_complete(villasfpga_handle handle, size_t *size);
34+
35+
#ifdef __cplusplus
36+
} // extern "C"
37+
#endif
38+
39+
#endif /* _VILLASFPGA_DMA_H */

include/villas/fpga/ips/dma.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class Dma : public Node
129129
int delay = 0;
130130
// Coalesce is the number of messages/BDs to wait for before issuing an interrupt
131131
uint32_t writeCoalesce = 1;
132-
uint32_t readCoalesce = 16;
132+
uint32_t readCoalesce = 1;
133133

134134
// (maximum) size of a single message on the read channel in bytes.
135135
// The message buffer/BD should have enough room for this many bytes.

include/villas/fpga/pcie_card.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <set>
1515
#include <string>
1616
#include <jansson.h>
17+
#include <filesystem>
1718

1819
#include <villas/plugin.hpp>
1920
#include <villas/memory.hpp>
@@ -78,8 +79,10 @@ class PCIeCard : public Card {
7879
class PCIeCardFactory : public plugin::Plugin {
7980
public:
8081

81-
static
82-
std::list<std::shared_ptr<PCIeCard>> make(json_t *json, std::shared_ptr<kernel::pci::DeviceList> pci, std::shared_ptr<kernel::vfio::Container> vc);
82+
static std::list<std::shared_ptr<PCIeCard>> make(json_t *json,
83+
std::shared_ptr<kernel::pci::DeviceList> pci,
84+
std::shared_ptr<kernel::vfio::Container> vc,
85+
const std::filesystem::path& searchPath = std::filesystem::path());
8386

8487
static
8588
PCIeCard* make()

include/villas/fpga/utils.hpp

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <string>
1010
#include <villas/fpga/pcie_card.hpp>
11+
#include <villas/fpga/ips/aurora_xilinx.hpp>
1112

1213
namespace villas {
1314
namespace fpga {
@@ -25,7 +26,7 @@ class ConnectString {
2526
int portStringToInt(std::string &str) const;
2627

2728
void configCrossBar(std::shared_ptr<villas::fpga::ip::Dma> dma,
28-
std::vector<std::shared_ptr<fpga::ip::AuroraXilinx>>& aurora_channels) const;
29+
std::vector<std::shared_ptr<villas::fpga::ip::AuroraXilinx>>& aurora_channels) const;
2930

3031
bool isBidirectional() const { return bidirectional; };
3132
bool isDmaLoopback() const { return dmaLoopback; };
@@ -86,14 +87,16 @@ class BufferedSampleFormatterShort : public BufferedSampleFormatter {
8687

8788
virtual void format(float value) override
8889
{
89-
if (std::snprintf(nextBufPos(), formatStringSize+1, formatString, value) > (int)formatStringSize) {
90-
throw RuntimeError("Output buffer too small");
90+
size_t chars;
91+
if ((chars = std::snprintf(nextBufPos(), formatStringSize+1, formatString, value)) > (int)formatStringSize) {
92+
throw RuntimeError("Output buffer too small. Expected " + std::to_string(formatStringSize) +
93+
" characters, got " + std::to_string(chars));
9194
}
9295
}
9396

9497
protected:
95-
static constexpr char formatString[] = "%7f\n";
96-
static constexpr size_t formatStringSize = 9;
98+
static constexpr char formatString[] = "%013.6f\n";
99+
static constexpr size_t formatStringSize = 14;
97100
};
98101

99102
class BufferedSampleFormatterLong : public BufferedSampleFormatter {
@@ -111,24 +114,13 @@ class BufferedSampleFormatterLong : public BufferedSampleFormatter {
111114
}
112115

113116
protected:
114-
static constexpr char formatString[] = "%05zd: %7f\n";
115-
static constexpr size_t formatStringSize = 16;
117+
static constexpr char formatString[] = "%05zd: %013.6f\n";
118+
static constexpr size_t formatStringSize = 22;
116119
size_t sampleCnt;
117120
};
118121

119122

120-
std::unique_ptr<BufferedSampleFormatter> getBufferedSampleFormatter(
121-
const std::string &format,
122-
size_t bufSizeInSamples)
123-
{
124-
if (format == "long") {
125-
return std::make_unique<BufferedSampleFormatterLong>(bufSizeInSamples);
126-
} else if (format == "short") {
127-
return std::make_unique<BufferedSampleFormatterShort>(bufSizeInSamples);
128-
} else {
129-
throw RuntimeError("Unknown output format '{}'", format);
130-
}
131-
}
123+
std::unique_ptr<BufferedSampleFormatter> getBufferedSampleFormatter(const std::string &format, size_t bufSizeInSamples);
132124

133125
} /* namespace fpga */
134126
} /* namespace villas */

lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(SOURCES
1212
core.cpp
1313
node.cpp
1414
utils.cpp
15+
dma.cpp
1516

1617
ips/aurora_xilinx.cpp
1718
ips/aurora.cpp

lib/dma.cpp

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/** API for interacting with the FPGA DMA Controller.
2+
*
3+
* Author: Niklas Eiling <[email protected]>
4+
* SPDX-FileCopyrightText: 2023 Niklas Eiling <[email protected]>
5+
* SPDX-License-Identifier: Apache-2.0
6+
*********************************************************************************/
7+
8+
#include <villas/fpga/dma.h>
9+
10+
#include <csignal>
11+
#include <iostream>
12+
#include <string>
13+
#include <stdexcept>
14+
15+
#include <villas/exceptions.hpp>
16+
#include <villas/log.hpp>
17+
#include <villas/utils.hpp>
18+
19+
#include <villas/fpga/core.hpp>
20+
#include <villas/fpga/card.hpp>
21+
#include <villas/fpga/vlnv.hpp>
22+
#include <villas/fpga/ips/dma.hpp>
23+
#include <villas/fpga/utils.hpp>
24+
25+
using namespace villas;
26+
27+
static std::shared_ptr<kernel::pci::DeviceList> pciDevices;
28+
static auto logger = villas::logging.get("villasfpga_dma");
29+
30+
struct villasfpga_handle_t {
31+
std::shared_ptr<villas::fpga::Card> card;
32+
std::shared_ptr<villas::fpga::ip::Dma> dma;
33+
};
34+
struct villasfpga_memory_t {
35+
std::shared_ptr<villas::MemoryBlock> block;
36+
};
37+
38+
villasfpga_handle villasfpga_init(const char *configFile)
39+
{
40+
std::string fpgaName = "vc707";
41+
std::string connectStr = "3<->pipe";
42+
std::string outputFormat = "short";
43+
bool dumpGraph = false;
44+
bool dumpAuroraChannels = true;
45+
try {
46+
// Logging setup
47+
logging.setLevel(spdlog::level::debug);
48+
fpga::setupColorHandling();
49+
50+
if (configFile == nullptr || configFile[0] == '\0') {
51+
logger->error("No configuration file provided/ Please use -c/--config argument");
52+
return nullptr;
53+
}
54+
55+
auto handle = new villasfpga_handle_t;
56+
handle->card = fpga::setupFpgaCard(configFile, fpgaName);
57+
58+
std::vector<std::shared_ptr<fpga::ip::AuroraXilinx>> aurora_channels;
59+
for (int i = 0; i < 4; i++) {
60+
auto name = fmt::format("aurora_8b10b_ch{}", i);
61+
auto id = fpga::ip::IpIdentifier("xilinx.com:ip:aurora_8b10b:", name);
62+
auto aurora = std::dynamic_pointer_cast<fpga::ip::AuroraXilinx>(handle->card->lookupIp(id));
63+
if (aurora == nullptr) {
64+
logger->error("No Aurora interface found on FPGA");
65+
return nullptr;
66+
}
67+
68+
aurora_channels.push_back(aurora);
69+
}
70+
71+
handle->dma = std::dynamic_pointer_cast<fpga::ip::Dma>
72+
(handle->card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:")));
73+
if (handle->dma == nullptr) {
74+
logger->error("No DMA found on FPGA ");
75+
return nullptr;
76+
}
77+
78+
if (dumpGraph) {
79+
auto &mm = MemoryManager::get();
80+
mm.getGraph().dump("graph.dot");
81+
}
82+
83+
if (dumpAuroraChannels) {
84+
for (auto aurora : aurora_channels)
85+
aurora->dump();
86+
}
87+
88+
// Configure Crossbar switch
89+
const fpga::ConnectString parsedConnectString(connectStr);
90+
parsedConnectString.configCrossBar(handle->dma, aurora_channels);
91+
92+
return handle;
93+
} catch (const RuntimeError &e) {
94+
logger->error("Error: {}", e.what());
95+
return nullptr;
96+
} catch (const std::exception &e) {
97+
logger->error("Error: {}", e.what());
98+
return nullptr;
99+
} catch (...) {
100+
logger->error("Unknown error");
101+
return nullptr;
102+
}
103+
}
104+
105+
void villasfpga_destroy(villasfpga_handle handle)
106+
{
107+
delete handle;
108+
}
109+
110+
int villasfpga_alloc(villasfpga_handle handle, villasfpga_memory *mem, size_t size)
111+
{
112+
try {
113+
auto &alloc = villas::HostRam::getAllocator();
114+
*mem = new villasfpga_memory_t;
115+
(*mem)->block = alloc.allocateBlock(size);
116+
return villasfpga_register(handle, mem);
117+
} catch (const RuntimeError &e) {
118+
logger->error("Failed to allocate memory: {}", e.what());
119+
return -1;
120+
}
121+
}
122+
int villasfpga_register(villasfpga_handle handle, villasfpga_memory *mem)
123+
{
124+
try {
125+
handle->dma->makeAccesibleFromVA((*mem)->block);
126+
return 0;
127+
} catch (const RuntimeError &e) {
128+
logger->error("Failed to register memory: {}", e.what());
129+
return -1;
130+
}
131+
}
132+
int villasfpga_free(villasfpga_memory mem)
133+
{
134+
try {
135+
delete mem;
136+
return 0;
137+
} catch (const RuntimeError &e) {
138+
logger->error("Failed to free memory: {}", e.what());
139+
return -1;
140+
}
141+
}
142+
143+
int villasfpga_read(villasfpga_handle handle, villasfpga_memory mem, size_t size)
144+
{
145+
try {
146+
if (!handle->dma->read(*mem->block, size)) {
147+
logger->error("Failed to read from device");
148+
return -1;
149+
}
150+
return 0;
151+
} catch (const RuntimeError &e) {
152+
logger->error("Failed to read memory: {}", e.what());
153+
return -1;
154+
}
155+
}
156+
157+
int villasfpga_read_complete(villasfpga_handle handle, size_t *size)
158+
{
159+
try {
160+
auto readComp = handle->dma->readComplete();
161+
logger->debug("Read {} bytes", readComp.bytes);
162+
*size = readComp.bytes;
163+
return 0;
164+
} catch (const RuntimeError &e) {
165+
logger->error("Failed to read memory: {}", e.what());
166+
return -1;
167+
}
168+
}
169+
170+
int villasfpga_write(villasfpga_handle handle, villasfpga_memory mem, size_t size)
171+
{
172+
try {
173+
if (!handle->dma->write(*mem->block, size)) {
174+
logger->error("Failed to write to device");
175+
return -1;
176+
}
177+
return 0;
178+
} catch (const RuntimeError &e) {
179+
logger->error("Failed to write memory: {}", e.what());
180+
return -1;
181+
}
182+
}
183+
184+
int villasfpga_write_complete(villasfpga_handle handle, size_t *size)
185+
{
186+
try {
187+
auto writeComp = handle->dma->writeComplete();
188+
logger->debug("Wrote {} bytes", writeComp.bytes);
189+
*size = writeComp.bytes;
190+
return 0;
191+
} catch (const RuntimeError &e) {
192+
logger->error("Failed to write memory: {}", e.what());
193+
return -1;
194+
}
195+
}
196+
197+
void* villasfpga_get_ptr(villasfpga_memory mem)
198+
{
199+
return (void*)MemoryManager::get().getTranslationFromProcess(mem->block->getAddrSpaceId()).getLocalAddr(0);
200+
}
201+

lib/ips/dma.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ bool Dma::write(const MemoryBlock &mem, size_t len)
243243
if (buf == nullptr)
244244
throw RuntimeError("Buffer was null");
245245

246-
logger->debug("Write to stream from address {:p}", buf);
246+
logger->trace("Write to stream from address {:p}", buf);
247247

248248
return hasScatterGather() ? writeScatterGather(buf, len) : writeSimple(buf, len);
249249
}

0 commit comments

Comments
 (0)