1 //
2 // Copyright 2019 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6
7 #pragma once
8
9 #include <uhd/rfnoc/rfnoc_types.hpp>
10 #include <uhd/types/endianness.hpp>
11 #include <uhd/utils/byteswap.hpp>
12 #include <boost/format.hpp>
13 #include <boost/optional.hpp>
14 #include <deque>
15 #include <list>
16 #include <memory>
17 #include <vector>
18
19 namespace uhd { namespace rfnoc { namespace chdr {
20
21 enum packet_type_t {
22 PKT_TYPE_MGMT = 0x0, //! Management packet
23 PKT_TYPE_STRS = 0x1, //! Stream status
24 PKT_TYPE_STRC = 0x2, //! Stream Command
25 PKT_TYPE_CTRL = 0x4, //! Control Transaction
26 PKT_TYPE_DATA_NO_TS = 0x6, //! Data Packet without TimeStamp
27 PKT_TYPE_DATA_WITH_TS = 0x7, //! Data Packet with TimeStamp
28 };
29
30 //----------------------------------------------------
31 // CHDR Header
32 //----------------------------------------------------
33
34 class chdr_header
35 {
36 public: // Functions
37 chdr_header() = default;
38 chdr_header(const chdr_header& rhs) = default;
39 chdr_header(chdr_header&& rhs) = default;
40
41 //! Unpack the header from a uint64_t
chdr_header(uint64_t flat_hdr)42 chdr_header(uint64_t flat_hdr) : _flat_hdr(flat_hdr) {}
43
44 //! Get the virtual channel field (6 bits)
get_vc() const45 inline uint8_t get_vc() const
46 {
47 return get_field<uint8_t>(_flat_hdr, VC_OFFSET, VC_WIDTH);
48 }
49
50 //! Set the virtual channel field (6 bits)
set_vc(uint8_t vc)51 inline void set_vc(uint8_t vc)
52 {
53 _flat_hdr = set_field(_flat_hdr, vc, VC_OFFSET, VC_WIDTH);
54 }
55
56 //! Get the end-of-burst flag (1 bit)
get_eob() const57 inline bool get_eob() const
58 {
59 return get_field<bool>(_flat_hdr, EOB_OFFSET, EOB_WIDTH);
60 }
61
62 //! Set the end-of-burst flag (1 bit)
set_eob(bool eob)63 inline void set_eob(bool eob)
64 {
65 _flat_hdr = set_field(_flat_hdr, eob, EOB_OFFSET, EOB_WIDTH);
66 }
67
68 //! Get the end-of-vector flag (1 bit)
get_eov() const69 inline bool get_eov() const
70 {
71 return get_field<bool>(_flat_hdr, EOV_OFFSET, EOV_WIDTH);
72 }
73
74 //! Set the end-of-vector flag (1 bit)
set_eov(bool eov)75 inline void set_eov(bool eov)
76 {
77 _flat_hdr = set_field(_flat_hdr, eov, EOV_OFFSET, EOV_WIDTH);
78 }
79
80 //! Get the packet type field (3 bits)
get_pkt_type() const81 inline packet_type_t get_pkt_type() const
82 {
83 return get_field<packet_type_t>(_flat_hdr, PKT_TYPE_OFFSET, PKT_TYPE_WIDTH);
84 }
85
86 //! Set the packet type field (3 bits)
set_pkt_type(packet_type_t pkt_type)87 inline void set_pkt_type(packet_type_t pkt_type)
88 {
89 _flat_hdr = set_field(_flat_hdr, pkt_type, PKT_TYPE_OFFSET, PKT_TYPE_WIDTH);
90 }
91
92 //! Get number of metadata words field (5 bits)
get_num_mdata() const93 inline uint8_t get_num_mdata() const
94 {
95 return get_field<uint8_t>(_flat_hdr, NUM_MDATA_OFFSET, NUM_MDATA_WIDTH);
96 }
97
98 //! Set number of metadata words field (5 bits)
set_num_mdata(uint8_t num_mdata)99 inline void set_num_mdata(uint8_t num_mdata)
100 {
101 _flat_hdr = set_field(_flat_hdr, num_mdata, NUM_MDATA_OFFSET, NUM_MDATA_WIDTH);
102 }
103
104 //! Get the sequence number field (16 bits)
get_seq_num() const105 inline uint16_t get_seq_num() const
106 {
107 return get_field<uint16_t>(_flat_hdr, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH);
108 }
109
110 //! Set the sequence number field (16 bits)
set_seq_num(uint16_t seq_num)111 inline void set_seq_num(uint16_t seq_num)
112 {
113 _flat_hdr = set_field(_flat_hdr, seq_num, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH);
114 }
115
116 //! Get the packet length field (16 bits)
get_length() const117 inline uint16_t get_length() const
118 {
119 return get_field<uint16_t>(_flat_hdr, LENGTH_OFFSET, LENGTH_WIDTH);
120 }
121
122 //! Set the packet length field (16 bits)
set_length(uint16_t length)123 inline void set_length(uint16_t length)
124 {
125 _flat_hdr = set_field(_flat_hdr, length, LENGTH_OFFSET, LENGTH_WIDTH);
126 }
127
128 //! Get the destination EPID field (16 bits)
get_dst_epid() const129 inline uint16_t get_dst_epid() const
130 {
131 return get_field<uint16_t>(_flat_hdr, DST_EPID_OFFSET, DST_EPID_WIDTH);
132 }
133
134 //! Set the destination EPID field (16 bits)
set_dst_epid(uint16_t dst_epid)135 inline void set_dst_epid(uint16_t dst_epid)
136 {
137 _flat_hdr = set_field(_flat_hdr, dst_epid, DST_EPID_OFFSET, DST_EPID_WIDTH);
138 }
139
140 //! Pack the header into a uint64_t
pack() const141 inline uint64_t pack() const
142 {
143 return _flat_hdr;
144 }
145
146 //! Pack the header into a uint64_t as an implicit cast
operator uint64_t() const147 inline operator uint64_t() const
148 {
149 return pack();
150 }
151
152 //! Comparison operator (==)
operator ==(const chdr_header & rhs) const153 inline bool operator==(const chdr_header& rhs) const
154 {
155 return _flat_hdr == rhs._flat_hdr;
156 }
157
158 //! Comparison operator (!=)
operator !=(const chdr_header & rhs) const159 inline bool operator!=(const chdr_header& rhs) const
160 {
161 return _flat_hdr != rhs._flat_hdr;
162 }
163
164 //! Assignment operator (=) from a chdr_header
operator =(const chdr_header & rhs)165 inline const chdr_header& operator=(const chdr_header& rhs)
166 {
167 _flat_hdr = rhs._flat_hdr;
168 return *this;
169 }
170
171 //! Assignment operator (=) from a uint64_t
operator =(const uint64_t & rhs)172 inline const chdr_header& operator=(const uint64_t& rhs)
173 {
174 _flat_hdr = rhs;
175 return *this;
176 }
177
178 //! Return a string representation of this object
to_string() const179 inline const std::string to_string() const
180 {
181 // The static_casts are because vc and num_mdata are uint8_t -> unsigned char
182 // For some reason, despite the %u meaning unsigned int, boost still formats them
183 // as chars
184 return str(boost::format("chdr_header{vc:%u, eob:%b, eov:%b, pkt_type:%u, "
185 "num_mdata:%u, seq_num:%u, length:%u, dst_epid:%u}\n")
186 % static_cast<uint16_t>(get_vc()) % get_eob() % get_eov()
187 % get_pkt_type() % static_cast<uint16_t>(get_num_mdata())
188 % get_seq_num() % get_length() % get_dst_epid());
189 }
190
191 private:
192 // The flattened representation of the header stored in host order
193 uint64_t _flat_hdr = 0;
194
195 static constexpr size_t VC_WIDTH = 6;
196 static constexpr size_t EOB_WIDTH = 1;
197 static constexpr size_t EOV_WIDTH = 1;
198 static constexpr size_t PKT_TYPE_WIDTH = 3;
199 static constexpr size_t NUM_MDATA_WIDTH = 5;
200 static constexpr size_t SEQ_NUM_WIDTH = 16;
201 static constexpr size_t LENGTH_WIDTH = 16;
202 static constexpr size_t DST_EPID_WIDTH = 16;
203
204 static constexpr size_t VC_OFFSET = 58;
205 static constexpr size_t EOB_OFFSET = 57;
206 static constexpr size_t EOV_OFFSET = 56;
207 static constexpr size_t PKT_TYPE_OFFSET = 53;
208 static constexpr size_t NUM_MDATA_OFFSET = 48;
209 static constexpr size_t SEQ_NUM_OFFSET = 32;
210 static constexpr size_t LENGTH_OFFSET = 16;
211 static constexpr size_t DST_EPID_OFFSET = 0;
212
mask(const size_t width)213 static inline uint64_t mask(const size_t width)
214 {
215 return ((uint64_t(1) << width) - 1);
216 }
217
218 template <typename field_t>
get_field(const uint64_t flat_hdr,const size_t offset,const size_t width)219 static inline field_t get_field(
220 const uint64_t flat_hdr, const size_t offset, const size_t width)
221 {
222 return static_cast<field_t>((flat_hdr >> offset) & mask(width));
223 }
224
225 template <typename field_t>
set_field(const uint64_t old_val,const field_t field,const size_t offset,const size_t width)226 static inline uint64_t set_field(const uint64_t old_val,
227 const field_t field,
228 const size_t offset,
229 const size_t width)
230 {
231 return (old_val & ~(mask(width) << offset))
232 | ((static_cast<uint64_t>(field) & mask(width)) << offset);
233 }
234 };
235
236
237 //----------------------------------------------------
238 // CHDR Control Packet Payload
239 //----------------------------------------------------
240
241 enum ctrl_status_t {
242 CMD_OKAY = 0x0, //! Transaction successful
243 CMD_CMDERR = 0x1, //! Slave asserted a command error
244 CMD_TSERR = 0x2, //! Slave asserted a time stamp error
245 CMD_WARNING = 0x3, //! Slave asserted non-critical error
246 };
247
248 enum ctrl_opcode_t {
249 OP_SLEEP = 0x0,
250 OP_WRITE = 0x1,
251 OP_READ = 0x2,
252 OP_READ_WRITE = 0x3,
253 OP_BLOCK_WRITE = 0x4,
254 OP_BLOCK_READ = 0x5,
255 OP_POLL = 0x6,
256 OP_USER1 = 0xA,
257 OP_USER2 = 0xB,
258 OP_USER3 = 0xC,
259 OP_USER4 = 0xD,
260 OP_USER5 = 0xE,
261 OP_USER6 = 0xF,
262 };
263
264 class UHD_API ctrl_payload
265 {
266 public: // Members
267 //! Destination port for transaction (10 bits)
268 uint16_t dst_port = 0;
269 //! Source port for transaction (10 bits)
270 uint16_t src_port = 0;
271 //! Sequence number (6 bits)
272 uint8_t seq_num = 0;
273 //! Has Time Flag (1 bit) and timestamp (64 bits)
274 boost::optional<uint64_t> timestamp = boost::none;
275 //! Is Acknowledgment Flag (1 bit)
276 bool is_ack = false;
277 //! Source endpoint ID of transaction (16 bits)
278 uint16_t src_epid = 0;
279 //! Address for transaction (20 bits)
280 uint32_t address = 0;
281 //! Data for transaction (vector of 32 bits)
282 std::vector<uint32_t> data_vtr = {0};
283 //! Byte-enable mask for transaction (4 bits)
284 uint8_t byte_enable = 0xF;
285 //! Operation code (4 bits)
286 ctrl_opcode_t op_code = OP_SLEEP;
287 //! Transaction status (4 bits)
288 ctrl_status_t status = CMD_OKAY;
289
290 public: // Functions
291 ctrl_payload() = default;
292 ctrl_payload(const ctrl_payload& rhs) = default;
293 ctrl_payload(ctrl_payload&& rhs) = default;
294
295 ctrl_payload& operator=(const ctrl_payload& rhs) = default;
296
297 //! Populate the header for this type of packet
298 void populate_header(chdr_header& header) const;
299
300 //! Serialize the payload to a uint64_t buffer
301 size_t serialize(uint64_t* buff,
302 size_t max_size_bytes,
303 const std::function<uint64_t(uint64_t)>& conv_byte_order) const;
304
305 //! Serialize the payload to a uint64_t buffer (no conversion function)
306 template <endianness_t endianness>
serialize(uint64_t * buff,size_t max_size_bytes) const307 size_t serialize(uint64_t* buff, size_t max_size_bytes) const
308 {
309 auto conv_byte_order = [](uint64_t x) -> uint64_t {
310 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(x)
311 : uhd::htowx<uint64_t>(x);
312 };
313 return serialize(buff, max_size_bytes, conv_byte_order);
314 }
315
316 //! Deserialize the payload from a uint64_t buffer
317 void deserialize(const uint64_t* buff,
318 size_t num_elems,
319 const std::function<uint64_t(uint64_t)>& conv_byte_order);
320
321 //! Deserialize the payload from a uint64_t buffer (no conversion function)
322 template <endianness_t endianness>
deserialize(const uint64_t * buff,size_t num_elems)323 void deserialize(const uint64_t* buff, size_t num_elems)
324 {
325 auto conv_byte_order = [](uint64_t x) -> uint64_t {
326 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx<uint64_t>(x)
327 : uhd::wtohx<uint64_t>(x);
328 };
329 deserialize(buff, num_elems, conv_byte_order);
330 }
331
332 //! Get the serialized size of this payload in 64 bit words
333 size_t get_length() const;
334
335 // Return whether or not we have a valid timestamp
has_timestamp() const336 bool has_timestamp() const
337 {
338 return bool(timestamp);
339 }
340
341 //! Comparison operator (==)
342 bool operator==(const ctrl_payload& rhs) const;
343
344 //! Comparison operator (!=)
operator !=(const ctrl_payload & rhs) const345 inline bool operator!=(const ctrl_payload& rhs) const
346 {
347 return !(*this == rhs);
348 }
349
350 //! Return a string representation of this object
351 const std::string to_string() const;
352
353 private:
354 static constexpr size_t DST_PORT_WIDTH = 10;
355 static constexpr size_t SRC_PORT_WIDTH = 10;
356 static constexpr size_t NUM_DATA_WIDTH = 4;
357 static constexpr size_t SEQ_NUM_WIDTH = 6;
358 static constexpr size_t HAS_TIME_WIDTH = 1;
359 static constexpr size_t IS_ACK_WIDTH = 1;
360 static constexpr size_t SRC_EPID_WIDTH = 16;
361 static constexpr size_t ADDRESS_WIDTH = 20;
362 static constexpr size_t BYTE_ENABLE_WIDTH = 4;
363 static constexpr size_t OPCODE_WIDTH = 4;
364 static constexpr size_t STATUS_WIDTH = 2;
365
366 // Offsets assume 64-bit alignment
367 static constexpr size_t DST_PORT_OFFSET = 0;
368 static constexpr size_t SRC_PORT_OFFSET = 10;
369 static constexpr size_t NUM_DATA_OFFSET = 20;
370 static constexpr size_t SEQ_NUM_OFFSET = 24;
371 static constexpr size_t HAS_TIME_OFFSET = 30;
372 static constexpr size_t IS_ACK_OFFSET = 31;
373 static constexpr size_t SRC_EPID_OFFSET = 32;
374 static constexpr size_t ADDRESS_OFFSET = 0;
375 static constexpr size_t BYTE_ENABLE_OFFSET = 20;
376 static constexpr size_t OPCODE_OFFSET = 24;
377 static constexpr size_t STATUS_OFFSET = 30;
378 static constexpr size_t LO_DATA_OFFSET = 0;
379 static constexpr size_t HI_DATA_OFFSET = 32;
380 };
381
382 //----------------------------------------------------
383 // CHDR Stream Status Packet Payload
384 //----------------------------------------------------
385
386 enum strs_status_t {
387 STRS_OKAY = 0x0, //! No error
388 STRS_CMDERR = 0x1, //! A stream command signalled an error
389 STRS_SEQERR = 0x2, //! Packet out of sequence (sequence error)
390 STRS_DATAERR = 0x3, //! Data integrity check failed
391 STRS_RTERR = 0x4, //! Unexpected destination (routing error)
392 };
393
394 class UHD_API strs_payload
395 {
396 public: // Members
397 //! The source EPID for the stream (16 bits)
398 uint16_t src_epid = 0;
399 //! The status of the stream (4 bits)
400 strs_status_t status = STRS_OKAY;
401 //! Buffer capacity in bytes (40 bits)
402 uint64_t capacity_bytes = 0;
403 //! Buffer capacity in packets (24 bits)
404 uint32_t capacity_pkts = 0;
405 //! Transfer count in bytes (64 bits)
406 uint64_t xfer_count_bytes = 0;
407 //! Transfer count in packets (40 bits)
408 uint64_t xfer_count_pkts = 0;
409 //! Buffer info (16 bits)
410 uint16_t buff_info = 0;
411 //! Extended status info (48 bits)
412 uint64_t status_info = 0;
413
414 public: // Functions
415 strs_payload() = default;
416 strs_payload(const strs_payload& rhs) = default;
417 strs_payload(strs_payload&& rhs) = default;
418
419 strs_payload& operator=(const strs_payload& rhs) = default;
420
421 //! Populate the header for this type of packet
422 void populate_header(chdr_header& header) const;
423
424 //! Serialize the payload to a uint64_t buffer
425 size_t serialize(uint64_t* buff,
426 size_t max_size_bytes,
427 const std::function<uint64_t(uint64_t)>& conv_byte_order) const;
428
429 //! Serialize the payload to a uint64_t buffer (no conversion function)
430 template <endianness_t endianness>
serialize(uint64_t * buff,size_t max_size_bytes) const431 size_t serialize(uint64_t* buff, size_t max_size_bytes) const
432 {
433 auto conv_byte_order = [](uint64_t x) -> uint64_t {
434 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(x)
435 : uhd::htowx<uint64_t>(x);
436 };
437 return serialize(buff, max_size_bytes, conv_byte_order);
438 }
439
440 //! Deserialize the payload from a uint64_t buffer
441 void deserialize(const uint64_t* buff,
442 size_t num_elems,
443 const std::function<uint64_t(uint64_t)>& conv_byte_order);
444
445 //! Deserialize the payload from a uint64_t buffer (no conversion function)
446 template <endianness_t endianness>
deserialize(const uint64_t * buff,size_t num_elems)447 void deserialize(const uint64_t* buff, size_t num_elems)
448 {
449 auto conv_byte_order = [](uint64_t x) -> uint64_t {
450 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx<uint64_t>(x)
451 : uhd::wtohx<uint64_t>(x);
452 };
453 deserialize(buff, num_elems, conv_byte_order);
454 }
455
456 //! Get the serialized size of this payload in 64 bit words
457 size_t get_length() const;
458
459 //! Comparison operator (==)
460 bool operator==(const strs_payload& rhs) const;
461
462 //! Comparison operator (!=)
operator !=(const strs_payload & rhs) const463 inline bool operator!=(const strs_payload& rhs) const
464 {
465 return !(*this == rhs);
466 }
467
468 //! Return a string representation of this object
469 const std::string to_string() const;
470
471 private:
472 static constexpr size_t SRC_EPID_WIDTH = 16;
473 static constexpr size_t STATUS_WIDTH = 4;
474 static constexpr size_t CAPACITY_BYTES_WIDTH = 40;
475 static constexpr size_t CAPACITY_PKTS_WIDTH = 24;
476 static constexpr size_t XFER_COUNT_PKTS_WIDTH = 40;
477 static constexpr size_t BUFF_INFO_WIDTH = 16;
478 static constexpr size_t STATUS_INFO_WIDTH = 48;
479
480 // Offsets assume 64-bit alignment
481 static constexpr size_t SRC_EPID_OFFSET = 0;
482 static constexpr size_t STATUS_OFFSET = 16;
483 static constexpr size_t CAPACITY_BYTES_OFFSET = 24;
484 static constexpr size_t CAPACITY_PKTS_OFFSET = 0;
485 static constexpr size_t XFER_COUNT_PKTS_OFFSET = 24;
486 static constexpr size_t BUFF_INFO_OFFSET = 0;
487 static constexpr size_t STATUS_INFO_OFFSET = 16;
488 };
489
490 //----------------------------------------------------
491 // CHDR Stream Command Packet Payload
492 //----------------------------------------------------
493
494 enum strc_op_code_t {
495 STRC_INIT = 0x0, //! Initialize stream
496 STRC_PING = 0x1, //! Trigger a stream status response
497 STRC_RESYNC = 0x2, //! Re-synchronize flow control
498 };
499
500 class UHD_API strc_payload
501 {
502 public: // Members
503 //! The source EPID for the stream (16 bits)
504 uint16_t src_epid = 0;
505 //! Operation code for the command (4 bits)
506 strc_op_code_t op_code = STRC_INIT;
507 //! Data associated with the operation (4 bits)
508 uint8_t op_data = 0;
509 //! Number of packets to use for operation (40 bits)
510 uint64_t num_pkts = 0;
511 //! Number of bytes to use for operation (64 bits)
512 uint64_t num_bytes = 0;
513 //! Worst-case size of a strc packet (including header)
514 static constexpr size_t MAX_PACKET_SIZE = 128;
515
516 public: // Functions
517 strc_payload() = default;
518 strc_payload(const strc_payload& rhs) = default;
519 strc_payload(strc_payload&& rhs) = default;
520
521 strc_payload& operator=(const strc_payload& rhs) = default;
522
523 //! Populate the header for this type of packet
524 void populate_header(chdr_header& header) const;
525
526 //! Serialize the payload to a uint64_t buffer
527 size_t serialize(uint64_t* buff,
528 size_t max_size_bytes,
529 const std::function<uint64_t(uint64_t)>& conv_byte_order) const;
530
531 //! Serialize the payload to a uint64_t buffer (no conversion function)
532 template <endianness_t endianness>
serialize(uint64_t * buff,size_t max_size_bytes) const533 size_t serialize(uint64_t* buff, size_t max_size_bytes) const
534 {
535 auto conv_byte_order = [](uint64_t x) -> uint64_t {
536 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(x)
537 : uhd::htowx<uint64_t>(x);
538 };
539 return serialize(buff, max_size_bytes, conv_byte_order);
540 }
541
542 //! Deserialize the payload from a uint64_t buffer
543 void deserialize(const uint64_t* buff,
544 size_t num_elems,
545 const std::function<uint64_t(uint64_t)>& conv_byte_order);
546
547 //! Deserialize the payload from a uint64_t buffer (no conversion function)
548 template <endianness_t endianness>
deserialize(const uint64_t * buff,size_t num_elems)549 void deserialize(const uint64_t* buff, size_t num_elems)
550 {
551 auto conv_byte_order = [](uint64_t x) -> uint64_t {
552 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx<uint64_t>(x)
553 : uhd::wtohx<uint64_t>(x);
554 };
555 deserialize(buff, num_elems, conv_byte_order);
556 }
557
558 //! Get the serialized size of this payload in 64 bit words
559 size_t get_length() const;
560
561 //! Comparison operator (==)
562 bool operator==(const strc_payload& rhs) const;
563
564 //! Comparison operator (!=)
operator !=(const strc_payload & rhs) const565 inline bool operator!=(const strc_payload& rhs) const
566 {
567 return !(*this == rhs);
568 }
569
570 //! Return a string representation of this object
571 const std::string to_string() const;
572
573 private:
574 static constexpr size_t SRC_EPID_WIDTH = 16;
575 static constexpr size_t OP_CODE_WIDTH = 4;
576 static constexpr size_t OP_DATA_WIDTH = 4;
577 static constexpr size_t NUM_PKTS_WIDTH = 40;
578
579 // Offsets assume 64-bit alignment
580 static constexpr size_t SRC_EPID_OFFSET = 0;
581 static constexpr size_t OP_CODE_OFFSET = 16;
582 static constexpr size_t OP_DATA_OFFSET = 20;
583 static constexpr size_t NUM_PKTS_OFFSET = 24;
584 };
585
586 //----------------------------------------------------
587 // CHDR Management Packet Payload
588 //----------------------------------------------------
589
590 //! A class that represents a single management operation
591 // An operation consists of an operation code and some
592 // payload associated with that operation.
593 class UHD_API mgmt_op_t
594 {
595 public:
596 // Operation code
597 enum op_code_t {
598 //! Do nothing
599 MGMT_OP_NOP = 0,
600 //! Advertise this operation to the outside logic
601 MGMT_OP_ADVERTISE = 1,
602 //! Select the next destination for routing
603 MGMT_OP_SEL_DEST = 2,
604 //! Return the management packet back to its source
605 MGMT_OP_RETURN = 3,
606 //! Request information about the current node
607 MGMT_OP_INFO_REQ = 4,
608 //! A response to an information request
609 MGMT_OP_INFO_RESP = 5,
610 //! Perform a configuration write on the node
611 MGMT_OP_CFG_WR_REQ = 6,
612 //! Perform a configuration read on the node
613 MGMT_OP_CFG_RD_REQ = 7,
614 //! A response to a configuration read
615 MGMT_OP_CFG_RD_RESP = 8
616 };
617
618 //! The payload for an operation is 48 bits wide.
619 using payload_t = uint64_t;
620
621 //! An interpretation class for the payload for MGMT_OP_SEL_DEST
622 struct sel_dest_payload
623 {
624 const uint16_t dest;
625
sel_dest_payloaduhd::rfnoc::chdr::mgmt_op_t::sel_dest_payload626 sel_dest_payload(uint16_t dest_) : dest(dest_) {}
sel_dest_payloaduhd::rfnoc::chdr::mgmt_op_t::sel_dest_payload627 sel_dest_payload(payload_t payload_) : dest(static_cast<uint16_t>(payload_)) {}
operator payload_tuhd::rfnoc::chdr::mgmt_op_t::sel_dest_payload628 operator payload_t() const
629 {
630 return static_cast<payload_t>(dest);
631 }
632 };
633
634 //! An interpretation class for the payload for MGMT_OP_CFG_WR_REQ,
635 //! MGMT_OP_CFG_RD_REQ and MGMT_OP_CFG_RD_RESP
636 struct cfg_payload
637 {
638 const uint16_t addr;
639 const uint32_t data;
640
cfg_payloaduhd::rfnoc::chdr::mgmt_op_t::cfg_payload641 cfg_payload(uint16_t addr_, uint32_t data_ = 0) : addr(addr_), data(data_) {}
cfg_payloaduhd::rfnoc::chdr::mgmt_op_t::cfg_payload642 cfg_payload(payload_t payload_)
643 : addr(static_cast<uint16_t>(payload_ >> 0))
644 , data(static_cast<uint32_t>(payload_ >> 16))
645 {
646 }
operator payload_tuhd::rfnoc::chdr::mgmt_op_t::cfg_payload647 operator payload_t() const
648 {
649 return ((static_cast<payload_t>(data) << 16) | static_cast<payload_t>(addr));
650 }
651 };
652
653 //! An interpretation class for the payload for MGMT_OP_INFO_RESP
654 struct node_info_payload
655 {
656 const uint16_t device_id;
657 const uint8_t node_type;
658 const uint16_t node_inst;
659 const uint32_t ext_info;
660
node_info_payloaduhd::rfnoc::chdr::mgmt_op_t::node_info_payload661 node_info_payload(uint16_t device_id_,
662 uint8_t node_type_,
663 uint16_t node_inst_,
664 uint32_t ext_info_)
665 : device_id(device_id_)
666 , node_type(node_type_)
667 , node_inst(node_inst_)
668 , ext_info(ext_info_)
669 {
670 }
node_info_payloaduhd::rfnoc::chdr::mgmt_op_t::node_info_payload671 node_info_payload(payload_t payload_)
672 : device_id(static_cast<uint16_t>(payload_ >> 0))
673 , node_type(static_cast<uint8_t>((payload_ >> 16) & 0xF))
674 , node_inst(static_cast<uint16_t>((payload_ >> 20) & 0x3FF))
675 , ext_info(static_cast<uint32_t>((payload_ >> 30) & 0x3FFFF))
676 {
677 }
operator payload_tuhd::rfnoc::chdr::mgmt_op_t::node_info_payload678 operator payload_t() const
679 {
680 return ((static_cast<payload_t>(device_id) << 0)
681 | (static_cast<payload_t>(node_type & 0xF) << 16)
682 | (static_cast<payload_t>(node_inst & 0x3FF) << 20)
683 | (static_cast<payload_t>(ext_info & 0x3FFFF) << 30));
684 }
685 };
686
mgmt_op_t(const op_code_t op_code,const payload_t op_payload=0)687 mgmt_op_t(const op_code_t op_code, const payload_t op_payload = 0)
688 : _op_code(op_code), _op_payload(op_payload)
689 {
690 }
691 mgmt_op_t(const mgmt_op_t& rhs) = default;
692
693 //! Get the op-code for this transaction
get_op_code() const694 inline op_code_t get_op_code() const
695 {
696 return _op_code;
697 }
698
699 //! Get the payload for this transaction
get_op_payload() const700 inline uint64_t get_op_payload() const
701 {
702 return _op_payload;
703 }
704
705 //! Comparison operator (==)
operator ==(const mgmt_op_t & rhs) const706 inline bool operator==(const mgmt_op_t& rhs) const
707 {
708 return (_op_code == rhs._op_code) && (_op_payload == rhs._op_payload);
709 }
710
711 //! Return a string representation of this object
712 const std::string to_string() const;
713
714 private:
715 op_code_t _op_code;
716 payload_t _op_payload;
717 };
718
719 //! A class that represents a single management hop
720 // A hop is a collection for management transactions for
721 // a single node.
722 class UHD_API mgmt_hop_t
723 {
724 public:
725 mgmt_hop_t() = default;
726 mgmt_hop_t(const mgmt_hop_t& rhs) = default;
727
728 //! Add a management operation to this hop.
729 // Operations are added to the hop in FIFO order and executed in FIFO order.
add_op(const mgmt_op_t & op)730 inline void add_op(const mgmt_op_t& op)
731 {
732 _ops.push_back(op);
733 }
734
735 //! Get the number of management operations in this hop
get_num_ops() const736 inline size_t get_num_ops() const
737 {
738 return _ops.size();
739 }
740
741 //! Get the n'th operation in the hop
get_op(size_t i) const742 inline const mgmt_op_t& get_op(size_t i) const
743 {
744 return _ops.at(i);
745 }
746
747 //! Serialize the payload to a uint64_t buffer
748 // The RFNoC Specification section 2.2.6 specifies that for chdr widths
749 // greater than 64, all MSBs are 0, so we pad out the hop based on the width
750 size_t serialize(std::vector<uint64_t>& target,
751 const std::function<uint64_t(uint64_t)>& conv_byte_order,
752 const size_t padding_size) const;
753
754 //! Deserialize the payload from a uint64_t buffer
755 // The RFNoC Specification section 2.2.6 specifies that for chdr widths
756 // greater than 64, all MSBs are 0, so we remove padding based on the width
757 void deserialize(std::list<uint64_t>& src,
758 const std::function<uint64_t(uint64_t)>& conv_byte_order,
759 const size_t padding_size);
760
761 //! Comparison operator (==)
operator ==(const mgmt_hop_t & rhs) const762 inline bool operator==(const mgmt_hop_t& rhs) const
763 {
764 return _ops == rhs._ops;
765 }
766
767 //! Return a string representation of this object
768 const std::string to_string() const;
769
770 private:
771 std::vector<mgmt_op_t> _ops;
772 };
773
774 //! A class that represents a complete multi-hop management transaction
775 // A transaction is a collection of hops, where each hop is a collection
776 // of management transactions.
777 class UHD_API mgmt_payload
778 {
779 public:
780 mgmt_payload() = default;
781 mgmt_payload(const mgmt_payload& rhs) = default;
782 mgmt_payload(mgmt_payload&& rhs) = default;
783
784 mgmt_payload& operator=(const mgmt_payload& rhs) = default;
785
set_header(sep_id_t src_epid,uint16_t protover,chdr_w_t chdr_w)786 inline void set_header(sep_id_t src_epid, uint16_t protover, chdr_w_t chdr_w)
787 {
788 set_src_epid(src_epid);
789 set_chdr_w(chdr_w);
790 set_proto_ver(protover);
791 }
792
793 //! Add a management hop to this transaction
794 // Hops are added to the hop in FIFO order and executed in FIFO order.
add_hop(const mgmt_hop_t & hop)795 inline void add_hop(const mgmt_hop_t& hop)
796 {
797 _hops.push_back(hop);
798 }
799
800 //! Get the number of management hops in this hop
get_num_hops() const801 inline size_t get_num_hops() const
802 {
803 return _hops.size();
804 }
805
806 //! Get the n'th hop in the transaction
get_hop(size_t i) const807 inline const mgmt_hop_t& get_hop(size_t i) const
808 {
809 return _hops.at(i);
810 }
811
812 //! Pop the first hop of the transaction and return it
pop_hop()813 inline mgmt_hop_t pop_hop()
814 {
815 auto hop = _hops.front();
816 _hops.pop_front();
817 return hop;
818 }
819
get_size_bytes() const820 inline size_t get_size_bytes() const
821 {
822 size_t num_lines = 1; /* header */
823 for (const auto& hop : _hops) {
824 num_lines += hop.get_num_ops();
825 }
826 return num_lines * (chdr_w_to_bits(_chdr_w) / 8);
827 }
828
829 //! Populate the header for this type of packet
830 void populate_header(chdr_header& header) const;
831
832 //! Serialize the payload to a uint64_t buffer
833 size_t serialize(uint64_t* buff,
834 size_t max_size_bytes,
835 const std::function<uint64_t(uint64_t)>& conv_byte_order) const;
836
837 //! Serialize the payload to a uint64_t buffer (no conversion function)
838 template <endianness_t endianness>
serialize(uint64_t * buff,size_t max_size_bytes) const839 size_t serialize(uint64_t* buff, size_t max_size_bytes) const
840 {
841 auto conv_byte_order = [](uint64_t x) -> uint64_t {
842 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(x)
843 : uhd::htowx<uint64_t>(x);
844 };
845 return serialize(buff, max_size_bytes, conv_byte_order);
846 }
847
848 //! Deserialize the payload from a uint64_t buffer
849 void deserialize(const uint64_t* buff,
850 size_t num_elems,
851 const std::function<uint64_t(uint64_t)>& conv_byte_order);
852
853 //! Deserialize the payload from a uint64_t buffer (no conversion function)
854 template <endianness_t endianness>
deserialize(const uint64_t * buff,size_t num_elems)855 void deserialize(const uint64_t* buff, size_t num_elems)
856 {
857 auto conv_byte_order = [](uint64_t x) -> uint64_t {
858 return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx<uint64_t>(x)
859 : uhd::wtohx<uint64_t>(x);
860 };
861 deserialize(buff, num_elems, conv_byte_order);
862 }
863
864 //! Get the serialized size of this payload in 64 bit words
865 size_t get_length() const;
866
867 //! Return a string representation of this object
868 const std::string to_string() const;
869
870 //! Return a string representaiton of the hops contained by this object
871 const std::string hops_to_string() const;
872
873 //! Return the source EPID for this transaction
get_src_epid() const874 inline sep_id_t get_src_epid() const
875 {
876 return _src_epid;
877 }
878
879 //! Set the source EPID for this transaction
set_src_epid(sep_id_t src_epid)880 inline void set_src_epid(sep_id_t src_epid)
881 {
882 _src_epid = src_epid;
883 }
884
885 //! Comparison operator (==)
886 bool operator==(const mgmt_payload& rhs) const;
887
888 //! Return the CHDR_W for this transaction
get_chdr_w() const889 inline chdr_w_t get_chdr_w() const
890 {
891 return _chdr_w;
892 }
893
894 //! Set the CHDR_W for this transaction
set_chdr_w(chdr_w_t chdr_w)895 inline void set_chdr_w(chdr_w_t chdr_w)
896 {
897 _chdr_w = chdr_w;
898 _padding_size = (chdr_w_to_bits(_chdr_w) / 64) - 1;
899 }
900
901 //! Return the protocol version for this transaction
get_proto_ver() const902 inline uint16_t get_proto_ver() const
903 {
904 return _protover;
905 }
906
907 //! Set the protocol version for this transaction
set_proto_ver(uint16_t proto_ver)908 inline void set_proto_ver(uint16_t proto_ver)
909 {
910 _protover = proto_ver;
911 }
912
913 private:
914 sep_id_t _src_epid = 0;
915 uint16_t _protover = 0;
916 chdr_w_t _chdr_w = CHDR_W_64;
917 size_t _padding_size = 0;
918 std::deque<mgmt_hop_t> _hops;
919 };
920
921 //! Conversion from payload_t to pkt_type
922 template <typename payload_t>
923 constexpr packet_type_t payload_to_packet_type();
924
925 template <>
payload_to_packet_type()926 constexpr packet_type_t payload_to_packet_type<ctrl_payload>()
927 {
928 return PKT_TYPE_CTRL;
929 }
930
931 template <>
payload_to_packet_type()932 constexpr packet_type_t payload_to_packet_type<mgmt_payload>()
933 {
934 return PKT_TYPE_MGMT;
935 }
936
937 template <>
payload_to_packet_type()938 constexpr packet_type_t payload_to_packet_type<strc_payload>()
939 {
940 return PKT_TYPE_STRC;
941 }
942
943 template <>
payload_to_packet_type()944 constexpr packet_type_t payload_to_packet_type<strs_payload>()
945 {
946 return PKT_TYPE_STRS;
947 }
948
949 }}} // namespace uhd::rfnoc::chdr
950