Skip to content

Commit 618208a

Browse files
committed
feat(sgdma): get_next_packet() API
1 parent ae38935 commit 618208a

File tree

3 files changed

+172
-6
lines changed

3 files changed

+172
-6
lines changed

inc/udmaio/UioMemSgdma.hpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,17 @@ class UioMemSgdma : public UioIf {
103103
/// @return Address of first SGDMA descriptor
104104
uintptr_t get_first_desc_addr() const;
105105

106-
/// @brief Get full SGDMA buffers
107-
/// @return Vector of indices of full buffers
106+
/// @brief Get all full SGDMA buffers
107+
/// @return Vector of buffer indices of full buffers
108108
std::vector<size_t> get_full_buffers();
109109

110+
/// @brief Get SGDMA buffers for next packet
111+
/// @return Vector of buffer indices for next packet
112+
/// Returns only complete packets
113+
std::vector<size_t> get_next_packet();
114+
115+
/// @brief Read data from a set of buffers
116+
/// @param indices Vector of buffer indices to read
110117
std::vector<uint8_t> read_buffers(const std::vector<size_t> indices);
111118
};
112119

src/UioMemSgdma.cpp

+66-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,29 @@
1313

1414
#include <cstddef>
1515
#include <cstdint>
16+
#include <iterator>
1617
#include <memory>
1718
#include <stdexcept>
1819
#include <string>
1920
#include <vector>
2021

2122
#include "udmaio/DmaBufferAbstract.hpp"
23+
#include <boost/log/sources/severity_feature.hpp>
24+
25+
namespace std {
26+
// To dump e.g. buffer indices
27+
// To look a operator up, it has to live in the same namespace as the type it is supposed to stream
28+
// We want to stream std::vector<size_t> so we have to put it into std namespace :-/
29+
ostream& operator<<(ostream& os, const vector<size_t>& vec) {
30+
os << '[';
31+
if (!vec.empty()) {
32+
copy(vec.begin(), vec.end() - 1, ostream_iterator<size_t>(os, ", "));
33+
os << vec.back();
34+
}
35+
os << ']';
36+
return os;
37+
}
38+
}; // namespace std
2239

2340
namespace udmaio {
2441

@@ -117,10 +134,9 @@ std::vector<size_t> UioMemSgdma::get_full_buffers() {
117134
break;
118135
}
119136
120-
if ((!stat.rxeof && (stat.num_stored_bytes != _buf_size)) || stat.num_stored_bytes == 0) {
121-
throw std::runtime_error("Descriptor #" + std::to_string(i) +
122-
" size mismatch (expected " + std::to_string(_buf_size) +
123-
", received " + std::to_string(stat.num_stored_bytes) + ")");
137+
if (stat.num_stored_bytes == 0) {
138+
throw std::runtime_error("Descriptor #" + std::to_string(_next_readable_buf) +
139+
" yields zero buffer length");
124140
}
125141
126142
result.push_back(_next_readable_buf);
@@ -129,9 +145,55 @@ std::vector<size_t> UioMemSgdma::get_full_buffers() {
129145
_next_readable_buf %= _nr_cyc_desc;
130146
}
131147
148+
if (!result.empty()) {
149+
BOOST_LOG_SEV(_lg, bls::trace) << "get_full_buffers() result: " << result;
150+
}
132151
return result;
133152
}
134153
154+
std::vector<size_t> UioMemSgdma::get_next_packet() {
155+
std::vector<size_t> result;
156+
157+
bool has_sof = false;
158+
size_t n = _next_readable_buf;
159+
160+
for (size_t i = 0; i < _nr_cyc_desc; i++) {
161+
auto stat = desc_statuses[n].rd();
162+
if (!stat.cmplt) {
163+
break;
164+
}
165+
166+
if (stat.num_stored_bytes == 0) {
167+
throw std::runtime_error("Descriptor #" + std::to_string(n) +
168+
" yields zero buffer length");
169+
}
170+
if (!has_sof && !stat.rxsof) {
171+
BOOST_LOG_SEV(_lg, bls::warning) << "buffer #" << n << " has no SOF, skipping";
172+
n++;
173+
n %= _nr_cyc_desc;
174+
_next_readable_buf = n;
175+
continue;
176+
}
177+
if (stat.rxsof) {
178+
if (!has_sof) {
179+
has_sof = true;
180+
} else {
181+
BOOST_LOG_SEV(_lg, bls::warning) << "buffer #" << n << ": duplicate SOF";
182+
}
183+
}
184+
result.push_back(n);
185+
n++;
186+
n %= _nr_cyc_desc;
187+
if (stat.rxeof) {
188+
_next_readable_buf = n;
189+
BOOST_LOG_SEV(_lg, bls::trace) << "get_next_packet() result: " << result;
190+
return result;
191+
}
192+
}
193+
194+
return {};
195+
}
196+
135197
std::vector<uint8_t> UioMemSgdma::read_buffers(const std::vector<size_t> indices) {
136198
// Read statuses for all buffers
137199
std::vector<S2mmDescStatus> stats{indices.size()};

tests/test_UioMemSgdma.cpp

+97
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,101 @@ BOOST_FIXTURE_TEST_CASE(buffer_read, UioMemSgdmaTest) {
162162
BOOST_CHECK_MESSAGE(cmplt_reset, "Complete flags are not reset");
163163
}
164164

165+
BOOST_FIXTURE_TEST_CASE(packets_read, UioMemSgdmaTest) {
166+
// Make a packet filling up the first buffer
167+
fill_buffer(hw_fpga_mem, buf_size * 0, 0, buf_size);
168+
169+
auto desc = descriptors[0].rd();
170+
desc.status.cmplt = true;
171+
desc.status.rxsof = true;
172+
desc.status.rxeof = true;
173+
desc.status.num_stored_bytes = buf_size;
174+
descriptors[0].wr(desc);
175+
176+
auto bufs = sgdma.get_next_packet();
177+
BOOST_CHECK_MESSAGE(bufs.size() == 1, "Expected one full buffer, received " << bufs.size());
178+
BOOST_CHECK_MESSAGE(bufs[0] == 0, "Expected first buffer to be full, received " << bufs[0]);
179+
180+
std::vector<uint8_t> data = sgdma.read_buffers(bufs);
181+
BOOST_CHECK_MESSAGE(data.size() == buf_size, "Buffer size mismatch");
182+
check_buffer(data);
183+
184+
bool cmplt_reset = !descriptors[0].rd().status.cmplt;
185+
BOOST_CHECK_MESSAGE(cmplt_reset, "Complete flag is not reset");
186+
187+
// Make a packet spanning 1.5 buffers
188+
fill_buffer(hw_fpga_mem, buf_size * 1, 0, buf_size * 3 / 2);
189+
desc = descriptors[1].rd();
190+
desc.status.cmplt = true;
191+
desc.status.rxsof = true;
192+
desc.status.rxeof = false;
193+
desc.status.num_stored_bytes = buf_size;
194+
descriptors[1].wr(desc);
195+
desc = descriptors[2].rd();
196+
desc.status.cmplt = true;
197+
desc.status.rxsof = false;
198+
desc.status.rxeof = true;
199+
desc.status.num_stored_bytes = buf_size / 2;
200+
descriptors[2].wr(desc);
201+
202+
bufs = sgdma.get_next_packet();
203+
BOOST_CHECK_MESSAGE((bufs == std::vector<size_t>{1, 2}), "Buffer indices mismatch");
204+
205+
data = sgdma.read_buffers(bufs);
206+
BOOST_CHECK_MESSAGE(data.size() == buf_size * 3 / 2, "Data size mismatch");
207+
check_buffer(data);
208+
209+
cmplt_reset = !descriptors[1].rd().status.cmplt && !descriptors[2].rd().status.cmplt;
210+
BOOST_CHECK_MESSAGE(cmplt_reset, "Complete flags are not reset");
211+
212+
// Make two packets spanning 4 buffers
213+
fill_buffer(hw_fpga_mem, buf_size * 3, 1234, buf_size * 3 / 2);
214+
desc = descriptors[3].rd();
215+
desc.status.cmplt = true;
216+
desc.status.rxsof = true;
217+
desc.status.rxeof = false;
218+
desc.status.num_stored_bytes = buf_size;
219+
descriptors[3].wr(desc);
220+
221+
// Try to read a packet; ensure it doesn't return anything yet w/o EOF
222+
bufs = sgdma.get_next_packet();
223+
BOOST_CHECK_MESSAGE(bufs.empty(), "Packet is not full yet");
224+
225+
desc = descriptors[4].rd();
226+
desc.status.cmplt = true;
227+
desc.status.rxsof = false;
228+
desc.status.rxeof = true;
229+
desc.status.num_stored_bytes = buf_size / 2;
230+
descriptors[4].wr(desc);
231+
232+
fill_buffer(hw_fpga_mem, buf_size * 5, 5678, buf_size * 2);
233+
desc = descriptors[5].rd();
234+
desc.status.cmplt = true;
235+
desc.status.rxsof = true;
236+
desc.status.rxeof = false;
237+
desc.status.num_stored_bytes = buf_size;
238+
descriptors[5].wr(desc);
239+
desc = descriptors[6].rd();
240+
desc.status.cmplt = true;
241+
desc.status.rxsof = false;
242+
desc.status.rxeof = true;
243+
desc.status.num_stored_bytes = buf_size;
244+
descriptors[6].wr(desc);
245+
246+
bufs = sgdma.get_next_packet();
247+
BOOST_CHECK_MESSAGE((bufs == std::vector<size_t>{3, 4}), "Buffer indices mismatch");
248+
data = sgdma.read_buffers(bufs);
249+
BOOST_CHECK_MESSAGE(data.size() == buf_size * 3 / 2, "Data size mismatch");
250+
check_buffer(data, 1234);
251+
cmplt_reset = !descriptors[3].rd().status.cmplt && !descriptors[4].rd().status.cmplt;
252+
BOOST_CHECK_MESSAGE(cmplt_reset, "Complete flags are not reset");
253+
254+
bufs = sgdma.get_next_packet();
255+
BOOST_CHECK_MESSAGE((bufs == std::vector<size_t>{5, 6}), "Buffer indices mismatch");
256+
data = sgdma.read_buffers(bufs);
257+
BOOST_CHECK_MESSAGE(data.size() == buf_size * 2, "Data size mismatch");
258+
check_buffer(data, 5678);
259+
cmplt_reset = !descriptors[3].rd().status.cmplt && !descriptors[4].rd().status.cmplt;
260+
BOOST_CHECK_MESSAGE(cmplt_reset, "Complete flags are not reset");
261+
}
165262
} // namespace udmaio

0 commit comments

Comments
 (0)