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