From b4bc85ac972b2e4f3e8e0b092947267f9f8aeee4 Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Sat, 25 May 2019 00:14:36 -0700 Subject: rfnoc: Moved chdr types/packet class out of chdr dir - Moved chdr_packet and chdr_types from rfnoc/chdr to rfnoc and updated all references - Moved non-CHDR definitions to rfnoc_common.hpp --- host/lib/include/uhdlib/rfnoc/chdr/chdr_packet.hpp | 290 ------- host/lib/include/uhdlib/rfnoc/chdr/chdr_types.hpp | 845 --------------------- .../include/uhdlib/rfnoc/chdr_ctrl_endpoint.hpp | 2 +- host/lib/include/uhdlib/rfnoc/chdr_packet.hpp | 296 ++++++++ host/lib/include/uhdlib/rfnoc/chdr_types.hpp | 817 ++++++++++++++++++++ .../lib/include/uhdlib/rfnoc/ctrlport_endpoint.hpp | 2 +- host/lib/include/uhdlib/rfnoc/mb_iface.hpp | 2 +- host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp | 2 +- host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp | 59 ++ host/lib/rfnoc/CMakeLists.txt | 3 +- host/lib/rfnoc/chdr/CMakeLists.txt | 15 - host/lib/rfnoc/chdr/chdr_packet.cpp | 213 ------ host/lib/rfnoc/chdr/chdr_types.cpp | 427 ----------- host/lib/rfnoc/chdr_ctrl_endpoint.cpp | 6 +- host/lib/rfnoc/chdr_packet.cpp | 214 ++++++ host/lib/rfnoc/chdr_types.cpp | 427 +++++++++++ host/lib/rfnoc/ctrlport_endpoint.cpp | 4 +- host/lib/rfnoc/mgmt_portal.cpp | 2 +- host/tests/CMakeLists.txt | 8 +- host/tests/rfnoc_chdr_test.cpp | 4 +- 20 files changed, 1831 insertions(+), 1807 deletions(-) delete mode 100644 host/lib/include/uhdlib/rfnoc/chdr/chdr_packet.hpp delete mode 100644 host/lib/include/uhdlib/rfnoc/chdr/chdr_types.hpp create mode 100644 host/lib/include/uhdlib/rfnoc/chdr_packet.hpp create mode 100644 host/lib/include/uhdlib/rfnoc/chdr_types.hpp create mode 100644 host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp delete mode 100644 host/lib/rfnoc/chdr/CMakeLists.txt delete mode 100644 host/lib/rfnoc/chdr/chdr_packet.cpp delete mode 100644 host/lib/rfnoc/chdr/chdr_types.cpp create mode 100644 host/lib/rfnoc/chdr_packet.cpp create mode 100644 host/lib/rfnoc/chdr_types.cpp (limited to 'host') diff --git a/host/lib/include/uhdlib/rfnoc/chdr/chdr_packet.hpp b/host/lib/include/uhdlib/rfnoc/chdr/chdr_packet.hpp deleted file mode 100644 index 102a6e104..000000000 --- a/host/lib/include/uhdlib/rfnoc/chdr/chdr_packet.hpp +++ /dev/null @@ -1,290 +0,0 @@ -// -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_RFNOC_CHDR_PACKET_HPP -#define INCLUDED_RFNOC_CHDR_PACKET_HPP - -#include -#include -#include -#include - -namespace uhd { namespace rfnoc { namespace chdr { - -//---------------------------------------------------- -// Generic CHDR Packet Container -//---------------------------------------------------- - -//! A container class that wraps a generic buffer that contains a CHDR packet. The -// container provides a high level API to read and write the header, metadata and payload -// of the packet. The payload can be accessed as a generic buffer using this interface. -// -class chdr_packet -{ -public: - //! A unique pointer to a const chdr_packet. Useful as a read-only interface. - typedef std::unique_ptr cuptr; - //! A unique pointer to a non-const chdr_packet. Useful as a read-write interface. - typedef std::unique_ptr uptr; - - virtual ~chdr_packet() = 0; - - /*! Updates the underlying storage of this packet. This is a const method and is - * only useful for read-only (RX) access. - * - * \param pkt_buff Pointer to a buffer that contains the RX packet - */ - virtual void refresh(const void* pkt_buff) const = 0; - - /*! Updates the underlying storage of this packet, and populates it with the specified - * arguments. This is a non-const method and is useful for read-write (TX) access. - * - * \param pkt_buff Pointer to a buffer that should be populated with the TX packet - * \param header The CHDR header to fill into the TX packet - * \param timestamp The timestamp to fill into the TX packet (if requested) - */ - virtual void refresh(void* pkt_buff, chdr_header& header, uint64_t timestamp = 0) = 0; - - /*! Updates the CHDR header with the written payload size - * - * \param payload_size_bytes The payload size in bytes - */ - virtual void update_payload_size(size_t payload_size_bytes) = 0; - - /*! Returns a class that represents the contents of the CHDR header - * - * \return The CHDR header - */ - virtual chdr_header get_chdr_header() const = 0; - - /*! Returns the timestamp in the packet as an optional value - * - * \return A boost::optional which if initialized has the timestamp - */ - virtual boost::optional get_timestamp() const = 0; - - /*! Returns the endianness of the metadata and payload buffers - * - * \return The byte order as a uhd::endianness_t - */ - virtual endianness_t get_byte_order() const = 0; - - /*! Returns the maximum transfer unit in bytes - * - * \return The maximum transfer unit in bytes - */ - virtual size_t get_mtu_bytes() const = 0; - - /*! Returns the metadata size in bytes - * - * \return The size in bytes - */ - virtual size_t get_mdata_size() const = 0; - - /*! Returns a const void pointer to the metadata section in the packet - * - * \return A pointer to the metadata - */ - virtual const void* get_mdata_const_ptr() const = 0; - - /*! Returns a non-const void pointer to the metadata section in the packet - * - * \return A pointer to the metadata - */ - virtual void* get_mdata_ptr() = 0; - - /*! Returns the payload size in bytes - * - * \return The size in bytes - */ - virtual size_t get_payload_size() const = 0; - - /*! Returns a const void pointer to the payload section in the packet - * - * \return A pointer to the payload - */ - virtual const void* get_payload_const_ptr() const = 0; - - /*! Returns a non-const void pointer to the payload section in the packet - * - * \return A pointer to the payload - */ - virtual void* get_payload_ptr() = 0; - - //! Shortcut to return the const metadata pointer cast as a specific type - template - inline const data_t* get_mdata_const_ptr_as() const - { - return reinterpret_cast(get_mdata_const_ptr()); - } - - //! Shortcut to return the non-const metadata pointer cast as a specific type - template - inline data_t* get_mdata_ptr_as() - { - return reinterpret_cast(get_mdata_ptr()); - } - - //! Shortcut to return the const payload pointer cast as a specific type - template - inline const data_t* get_payload_const_ptr_as() const - { - return reinterpret_cast(get_payload_const_ptr()); - } - - //! Shortcut to return the non-const payload pointer cast as a specific type - template - inline data_t* get_payload_ptr_as() - { - return reinterpret_cast(get_payload_ptr()); - } - - //! Return a function to convert a word of type data_t to host order - template - const std::function conv_to_host() const - { - return (get_byte_order() == uhd::ENDIANNESS_BIG) ? uhd::ntohx - : uhd::wtohx; - } - - //! Return a function to convert a word of type data_t from host order - template - const std::function conv_from_host() const - { - return (get_byte_order() == uhd::ENDIANNESS_BIG) ? uhd::htonx - : uhd::htowx; - } -}; - -//---------------------------------------------------- -// Container for specific CHDR Packets -//---------------------------------------------------- - -//! A container class that wraps a generic buffer that contains a CHDR packet. The -// container provides a high level API to read and write the header, metadata and payload -// of the packet. The payload can be accessed as a specific type that will be serialized -// and deserialized appropriately. -// -template -class chdr_packet_specific -{ -public: - //! A unique pointer to a const chdr_packet. Useful as a read-only interface. - typedef std::unique_ptr> cuptr; - //! A unique pointer to a non-const chdr_packet. Useful as a read-write interface. - typedef std::unique_ptr> uptr; - - chdr_packet_specific(chdr_packet::uptr chdr_pkt) : _chdr_pkt(std::move(chdr_pkt)) {} - ~chdr_packet_specific() = default; - - //! Updates the underlying storage of this packet. This is a const method and is - // only useful for read-only access. - inline void refresh(const void* pkt_buff) const - { - _chdr_pkt->refresh(pkt_buff); - } - - //! Updates the underlying storage of this packet, and populates it with the specified - // arguments. This is a non-const method and is useful for read-write access. - inline void refresh(void* pkt_buff, chdr_header& header, const payload_t& payload) - { - payload.populate_header(header); - _chdr_pkt->refresh(pkt_buff, header); - size_t bytes_copied = payload.serialize(_chdr_pkt->get_payload_ptr_as(), - _chdr_pkt->get_mtu_bytes(), - _chdr_pkt->conv_from_host()); - _chdr_pkt->update_payload_size(bytes_copied); - header = _chdr_pkt->get_chdr_header(); - } - - //! Returns a class that represents the contents of the CHDR header - inline chdr_header get_chdr_header() const - { - return std::move(_chdr_pkt->get_chdr_header()); - } - - //! Returns a class that represents the contents of the CHDR payload - inline payload_t get_payload() const - { - payload_t payload; - payload.deserialize(_chdr_pkt->get_payload_const_ptr_as(), - _chdr_pkt->get_payload_size() / sizeof(uint64_t), - _chdr_pkt->conv_to_host()); - return std::move(payload); - } - - //! Fills the CHDR payload into the specified parameter - inline void fill_payload(payload_t& payload) const - { - payload.deserialize(_chdr_pkt->get_payload_const_ptr_as(), - _chdr_pkt->get_payload_size() / sizeof(uint64_t), - _chdr_pkt->conv_to_host()); - } - -private: - chdr_packet::uptr _chdr_pkt; -}; - -//---------------------------------------------------- -// Specific CHDR packet types -//---------------------------------------------------- - -//! CHDR control packet -typedef chdr_packet_specific chdr_ctrl_packet; - -//! CHDR stream status packet -typedef chdr_packet_specific chdr_strs_packet; - -//! CHDR stream command packet -typedef chdr_packet_specific chdr_strc_packet; - -//! CHDR management packet -typedef chdr_packet_specific chdr_mgmt_packet; - -//---------------------------------------------------- -// CHDR packet factory -//---------------------------------------------------- - -//! A copyable and movable factory class that is capable of generating generic and -//! specific CHDR packet containers. -// -class chdr_packet_factory -{ -public: - //! A parametrized ctor that takes in all the info required to generate a CHDR packet - chdr_packet_factory(chdr_w_t chdr_w, endianness_t endianness); - chdr_packet_factory() = delete; - chdr_packet_factory(const chdr_packet_factory& rhs) = default; - chdr_packet_factory(chdr_packet_factory&& rhs) = default; - - //! Makes a generic CHDR packet and transfers ownership to the client - chdr_packet::uptr make_generic( - size_t mtu_bytes = std::numeric_limits::max()) const; - - //! Makes a CHDR control packet and transfers ownership to the client - chdr_ctrl_packet::uptr make_ctrl( - size_t mtu_bytes = std::numeric_limits::max()) const; - - //! Makes a CHDR stream status packet and transfers ownership to the client - chdr_strs_packet::uptr make_strs( - size_t mtu_bytes = std::numeric_limits::max()) const; - - //! Makes a CHDR stream cmd packet and transfers ownership to the client - chdr_strc_packet::uptr make_strc( - size_t mtu_bytes = std::numeric_limits::max()) const; - - //! Makes a CHDR management packet and transfers ownership to the client - chdr_mgmt_packet::uptr make_mgmt( - size_t mtu_bytes = std::numeric_limits::max()) const; - -private: - const chdr_w_t _chdr_w; - const endianness_t _endianness; -}; - -}}} // namespace uhd::rfnoc::chdr - -#endif /* INCLUDED_RFNOC_CHDR_PACKET_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/chdr/chdr_types.hpp b/host/lib/include/uhdlib/rfnoc/chdr/chdr_types.hpp deleted file mode 100644 index 447e7db91..000000000 --- a/host/lib/include/uhdlib/rfnoc/chdr/chdr_types.hpp +++ /dev/null @@ -1,845 +0,0 @@ -// -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_RFNOC_CHDR_TYPES_HPP -#define INCLUDED_RFNOC_CHDR_TYPES_HPP - -#include -#include -#include -#include -#include -#include - -namespace uhd { namespace rfnoc { - -enum chdr_w_t { - //! CHDR_W = 64 bits - CHDR_W_64 = 0, - //! CHDR_W = 128 bits - CHDR_W_128 = 1, - //! CHDR_W = 256 bits - CHDR_W_256 = 2, - //! CHDR_W = 512 bits - CHDR_W_512 = 3 -}; - -using device_id_t = uint16_t; -using sep_inst_t = uint16_t; -using sep_addr_t = std::pair; -using sep_id_t = uint16_t; - -constexpr size_t chdr_w_to_bits(chdr_w_t chdr_w) -{ - switch (chdr_w) { - case CHDR_W_64: - return 64; - case CHDR_W_128: - return 128; - case CHDR_W_256: - return 256; - case CHDR_W_512: - return 512; - default: - return 0; - } -} - -namespace chdr { - -enum packet_type_t { - PKT_TYPE_MGMT = 0x0, //! Management packet - PKT_TYPE_STRS = 0x1, //! Stream status - PKT_TYPE_STRC = 0x2, //! Stream Command - PKT_TYPE_CTRL = 0x4, //! Control Transaction - PKT_TYPE_DATA_NO_TS = 0x6, //! Data Packet without TimeStamp - PKT_TYPE_DATA_WITH_TS = 0x7, //! Data Packet with TimeStamp -}; - -//---------------------------------------------------- -// CHDR Header -//---------------------------------------------------- - -class chdr_header -{ -public: // Functions - chdr_header() = default; - chdr_header(const chdr_header& rhs) = default; - chdr_header(chdr_header&& rhs) = default; - - //! Unpack the header from a uint64_t - chdr_header(uint64_t flat_hdr) : _flat_hdr(flat_hdr) {} - - //! Get the virtual channel field (6 bits) - inline uint8_t get_vc() const - { - return get_field(_flat_hdr, VC_OFFSET, VC_WIDTH); - } - - //! Set the virtual channel field (6 bits) - inline void set_vc(uint8_t vc) - { - _flat_hdr = set_field(_flat_hdr, vc, VC_OFFSET, VC_WIDTH); - } - - //! Get the end-of-burst flag (1 bit) - inline bool get_eob() const - { - return get_field(_flat_hdr, EOB_OFFSET, EOB_WIDTH); - } - - //! Set the end-of-burst flag (1 bit) - inline void set_eob(bool eob) - { - _flat_hdr = set_field(_flat_hdr, eob, EOB_OFFSET, EOB_WIDTH); - } - - //! Get the end-of-vector flag (1 bit) - inline bool get_eov() const - { - return get_field(_flat_hdr, EOV_OFFSET, EOV_WIDTH); - } - - //! Set the end-of-vector flag (1 bit) - inline void set_eov(bool eov) - { - _flat_hdr = set_field(_flat_hdr, eov, EOV_OFFSET, EOV_WIDTH); - } - - //! Get the packet type field (3 bits) - inline packet_type_t get_pkt_type() const - { - return get_field(_flat_hdr, PKT_TYPE_OFFSET, PKT_TYPE_WIDTH); - } - - //! Set the packet type field (3 bits) - inline void set_pkt_type(packet_type_t pkt_type) - { - _flat_hdr = set_field(_flat_hdr, pkt_type, PKT_TYPE_OFFSET, PKT_TYPE_WIDTH); - } - - //! Get number of metadata words field (5 bits) - inline uint8_t get_num_mdata() const - { - return get_field(_flat_hdr, NUM_MDATA_OFFSET, NUM_MDATA_WIDTH); - } - - //! Set number of metadata words field (5 bits) - inline void set_num_mdata(uint8_t num_mdata) - { - _flat_hdr = set_field(_flat_hdr, num_mdata, NUM_MDATA_OFFSET, NUM_MDATA_WIDTH); - } - - //! Get the sequence number field (16 bits) - inline uint16_t get_seq_num() const - { - return get_field(_flat_hdr, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH); - } - - //! Set the sequence number field (16 bits) - inline void set_seq_num(uint16_t seq_num) - { - _flat_hdr = set_field(_flat_hdr, seq_num, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH); - } - - //! Get the packet length field (16 bits) - inline uint16_t get_length() const - { - return get_field(_flat_hdr, LENGTH_OFFSET, LENGTH_WIDTH); - } - - //! Set the packet length field (16 bits) - inline void set_length(uint16_t length) - { - _flat_hdr = set_field(_flat_hdr, length, LENGTH_OFFSET, LENGTH_WIDTH); - } - - //! Get the destination EPID field (16 bits) - inline uint16_t get_dst_epid() const - { - return get_field(_flat_hdr, DST_EPID_OFFSET, DST_EPID_WIDTH); - } - - //! Set the destination EPID field (16 bits) - inline void set_dst_epid(uint16_t dst_epid) - { - _flat_hdr = set_field(_flat_hdr, dst_epid, DST_EPID_OFFSET, DST_EPID_WIDTH); - } - - //! Pack the header into a uint64_t - inline uint64_t pack() const - { - return _flat_hdr; - } - - //! Pack the header into a uint64_t as an implicit cast - inline operator uint64_t() const - { - return pack(); - } - - //! Comparison operator (==) - inline bool operator==(const chdr_header& rhs) const - { - return _flat_hdr == rhs._flat_hdr; - } - - //! Comparison operator (!=) - inline bool operator!=(const chdr_header& rhs) const - { - return _flat_hdr != rhs._flat_hdr; - } - - //! Assignment operator (=) from a chdr_header - inline const chdr_header& operator=(const chdr_header& rhs) - { - _flat_hdr = rhs._flat_hdr; - return *this; - } - - //! Assignment operator (=) from a uint64_t - inline const chdr_header& operator=(const uint64_t& rhs) - { - _flat_hdr = rhs; - return *this; - } - -private: - // The flattened representation of the header stored in host order - uint64_t _flat_hdr = 0; - - static constexpr size_t VC_WIDTH = 6; - static constexpr size_t EOB_WIDTH = 1; - static constexpr size_t EOV_WIDTH = 1; - static constexpr size_t PKT_TYPE_WIDTH = 3; - static constexpr size_t NUM_MDATA_WIDTH = 5; - static constexpr size_t SEQ_NUM_WIDTH = 16; - static constexpr size_t LENGTH_WIDTH = 16; - static constexpr size_t DST_EPID_WIDTH = 16; - - static constexpr size_t VC_OFFSET = 58; - static constexpr size_t EOB_OFFSET = 57; - static constexpr size_t EOV_OFFSET = 56; - static constexpr size_t PKT_TYPE_OFFSET = 53; - static constexpr size_t NUM_MDATA_OFFSET = 48; - static constexpr size_t SEQ_NUM_OFFSET = 32; - static constexpr size_t LENGTH_OFFSET = 16; - static constexpr size_t DST_EPID_OFFSET = 0; - - static inline constexpr uint64_t mask(size_t width) - { - return ((uint64_t(1) << width) - 1); - } - - template - static inline constexpr field_t get_field( - uint64_t flat_hdr, size_t offset, size_t width) - { - return static_cast((flat_hdr >> offset) & mask(width)); - } - - template - static inline constexpr uint64_t set_field( - const uint64_t old_val, field_t field, size_t offset, size_t width) - { - return (old_val & ~(mask(width) << offset)) - | ((static_cast(field) & mask(width)) << offset); - } -}; - - -//---------------------------------------------------- -// CHDR Control Packet Payload -//---------------------------------------------------- - -enum ctrl_status_t { - CMD_OKAY = 0x0, //! Transaction successful - CMD_CMDERR = 0x1, //! Slave asserted a command error - CMD_TSERR = 0x2, //! Slave asserted a time stamp error - CMD_WARNING = 0x3, //! Slave asserted non-critical error -}; - -enum ctrl_opcode_t { - OP_SLEEP = 0x0, - OP_WRITE = 0x1, - OP_READ = 0x2, - OP_READ_WRITE = 0x3, - OP_BLOCK_WRITE = 0x4, - OP_BLOCK_READ = 0x5, - OP_POLL = 0x6, - OP_USER1 = 0xA, - OP_USER2 = 0xB, - OP_USER3 = 0xC, - OP_USER4 = 0xD, - OP_USER5 = 0xE, - OP_USER6 = 0xF, -}; - -class ctrl_payload -{ -public: // Members - //! Destination port for transaction (10 bits) - uint16_t dst_port = 0; - //! Source port for transaction (10 bits) - uint16_t src_port = 0; - //! Sequence number (6 bits) - uint8_t seq_num = 0; - //! Has Time Flag (1 bit) and timestamp (64 bits) - boost::optional timestamp = boost::none; - //! Is Acknowledgment Flag (1 bit) - bool is_ack = false; - //! Source endpoint ID of transaction (16 bits) - uint16_t src_epid = 0; - //! Address for transaction (20 bits) - uint32_t address = 0; - //! Data for transaction (vector of 32 bits) - std::vector data_vtr = {0}; - //! Byte-enable mask for transaction (4 bits) - uint8_t byte_enable = 0xF; - //! Operation code (4 bits) - ctrl_opcode_t op_code = OP_SLEEP; - //! Transaction status (4 bits) - ctrl_status_t status = CMD_OKAY; - -public: // Functions - ctrl_payload() = default; - ctrl_payload(const ctrl_payload& rhs) = default; - ctrl_payload(ctrl_payload&& rhs) = default; - - ctrl_payload& operator=(const ctrl_payload& rhs) = default; - - //! Populate the header for this type of packet - void populate_header(chdr_header& header) const; - - //! Serialize the payload to a uint64_t buffer - size_t serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const; - - //! Serialize the payload to a uint64_t buffer (no conversion function) - template - size_t serialize(uint64_t* buff, size_t max_size_bytes) const - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) - : uhd::htowx(x); - }; - return serialize(buff, max_size_bytes, conv_byte_order); - } - - //! Deserialize the payload from a uint64_t buffer - void deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order); - - //! Deserialize the payload from a uint64_t buffer (no conversion function) - template - void deserialize(const uint64_t* buff, size_t num_elems) - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) - : uhd::wtohx(x); - }; - deserialize(buff, num_elems, conv_byte_order); - } - - //! Comparison operator (==) - bool operator==(const ctrl_payload& rhs) const; - - //! Comparison operator (!=) - inline bool operator!=(const ctrl_payload& rhs) const - { - return !(*this == rhs); - } - - //! Return a string representation of this object - const std::string to_string() const; - -private: - static constexpr size_t DST_PORT_WIDTH = 10; - static constexpr size_t SRC_PORT_WIDTH = 10; - static constexpr size_t NUM_DATA_WIDTH = 4; - static constexpr size_t SEQ_NUM_WIDTH = 6; - static constexpr size_t HAS_TIME_WIDTH = 1; - static constexpr size_t IS_ACK_WIDTH = 1; - static constexpr size_t SRC_EPID_WIDTH = 16; - static constexpr size_t ADDRESS_WIDTH = 20; - static constexpr size_t BYTE_ENABLE_WIDTH = 4; - static constexpr size_t OPCODE_WIDTH = 4; - static constexpr size_t STATUS_WIDTH = 2; - - // Offsets assume 64-bit alignment - static constexpr size_t DST_PORT_OFFSET = 0; - static constexpr size_t SRC_PORT_OFFSET = 10; - static constexpr size_t NUM_DATA_OFFSET = 20; - static constexpr size_t SEQ_NUM_OFFSET = 24; - static constexpr size_t HAS_TIME_OFFSET = 30; - static constexpr size_t IS_ACK_OFFSET = 31; - static constexpr size_t SRC_EPID_OFFSET = 32; - static constexpr size_t ADDRESS_OFFSET = 0; - static constexpr size_t BYTE_ENABLE_OFFSET = 20; - static constexpr size_t OPCODE_OFFSET = 24; - static constexpr size_t STATUS_OFFSET = 30; - static constexpr size_t LO_DATA_OFFSET = 0; - static constexpr size_t HI_DATA_OFFSET = 32; -}; - -//---------------------------------------------------- -// CHDR Stream Status Packet Payload -//---------------------------------------------------- - -enum strs_status_t { - STRS_OKAY = 0x0, //! No error - STRS_CMDERR = 0x1, //! A stream command signalled an error - STRS_SEQERR = 0x2, //! Packet out of sequence (sequence error) - STRS_DATAERR = 0x3, //! Data integrity check failed - STRS_RTERR = 0x4, //! Unexpected destination (routing error) -}; - -class strs_payload -{ -public: // Members - //! The source EPID for the stream (16 bits) - uint16_t src_epid = 0; - //! The status of the stream (4 bits) - strs_status_t status = STRS_OKAY; - //! Buffer capacity in bytes (40 bits) - uint64_t capacity_bytes = 0; - //! Buffer capacity in packets (24 bits) - uint32_t capacity_pkts = 0; - //! Transfer count in bytes (64 bits) - uint64_t xfer_count_bytes = 0; - //! Transfer count in packets (40 bits) - uint64_t xfer_count_pkts = 0; - //! Buffer info (16 bits) - uint16_t buff_info = 0; - //! Extended status info (48 bits) - uint64_t status_info = 0; - -public: // Functions - strs_payload() = default; - strs_payload(const strs_payload& rhs) = default; - strs_payload(strs_payload&& rhs) = default; - - strs_payload& operator=(const strs_payload& rhs) = default; - - //! Populate the header for this type of packet - void populate_header(chdr_header& header) const; - - //! Serialize the payload to a uint64_t buffer - size_t serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const; - - //! Serialize the payload to a uint64_t buffer (no conversion function) - template - size_t serialize(uint64_t* buff, size_t max_size_bytes) const - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) - : uhd::htowx(x); - }; - return serialize(buff, max_size_bytes, conv_byte_order); - } - - //! Deserialize the payload from a uint64_t buffer - void deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order); - - //! Deserialize the payload from a uint64_t buffer (no conversion function) - template - void deserialize(const uint64_t* buff, size_t num_elems) - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) - : uhd::wtohx(x); - }; - deserialize(buff, num_elems, conv_byte_order); - } - - //! Comparison operator (==) - bool operator==(const strs_payload& rhs) const; - - //! Comparison operator (!=) - inline bool operator!=(const strs_payload& rhs) const - { - return !(*this == rhs); - } - - //! Return a string representation of this object - const std::string to_string() const; - -private: - static constexpr size_t SRC_EPID_WIDTH = 16; - static constexpr size_t STATUS_WIDTH = 4; - static constexpr size_t CAPACITY_BYTES_WIDTH = 40; - static constexpr size_t CAPACITY_PKTS_WIDTH = 24; - static constexpr size_t XFER_COUNT_PKTS_WIDTH = 40; - static constexpr size_t BUFF_INFO_WIDTH = 16; - static constexpr size_t STATUS_INFO_WIDTH = 48; - - // Offsets assume 64-bit alignment - static constexpr size_t SRC_EPID_OFFSET = 0; - static constexpr size_t STATUS_OFFSET = 16; - static constexpr size_t CAPACITY_BYTES_OFFSET = 24; - static constexpr size_t CAPACITY_PKTS_OFFSET = 0; - static constexpr size_t XFER_COUNT_PKTS_OFFSET = 24; - static constexpr size_t BUFF_INFO_OFFSET = 0; - static constexpr size_t STATUS_INFO_OFFSET = 16; -}; - -//---------------------------------------------------- -// CHDR Stream Command Packet Payload -//---------------------------------------------------- - -enum strc_op_code_t { - STRC_INIT = 0x0, //! Initialize stream - STRC_PING = 0x1, //! Trigger a stream status response - STRC_RESYNC = 0x2, //! Re-synchronize flow control -}; - -class strc_payload -{ -public: // Members - //! The source EPID for the stream (16 bits) - uint16_t src_epid = 0; - //! Operation code for the command (4 bits) - strc_op_code_t op_code = STRC_INIT; - //! Data associated with the operation (4 bits) - uint8_t op_data = 0; - //! Number of packets to use for operation (40 bits) - uint64_t num_pkts = 0; - //! Number of bytes to use for operation (64 bits) - uint64_t num_bytes = 0; - -public: // Functions - strc_payload() = default; - strc_payload(const strc_payload& rhs) = default; - strc_payload(strc_payload&& rhs) = default; - - strc_payload& operator=(const strc_payload& rhs) = default; - - //! Populate the header for this type of packet - void populate_header(chdr_header& header) const; - - //! Serialize the payload to a uint64_t buffer - size_t serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const; - - //! Serialize the payload to a uint64_t buffer (no conversion function) - template - size_t serialize(uint64_t* buff, size_t max_size_bytes) const - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) - : uhd::htowx(x); - }; - return serialize(buff, max_size_bytes, conv_byte_order); - } - - //! Deserialize the payload from a uint64_t buffer - void deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order); - - //! Deserialize the payload from a uint64_t buffer (no conversion function) - template - void deserialize(const uint64_t* buff, size_t num_elems) - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) - : uhd::wtohx(x); - }; - deserialize(buff, num_elems, conv_byte_order); - } - - //! Comparison operator (==) - bool operator==(const strc_payload& rhs) const; - - //! Comparison operator (!=) - inline bool operator!=(const strc_payload& rhs) const - { - return !(*this == rhs); - } - - //! Return a string representation of this object - const std::string to_string() const; - -private: - static constexpr size_t SRC_EPID_WIDTH = 16; - static constexpr size_t OP_CODE_WIDTH = 4; - static constexpr size_t OP_DATA_WIDTH = 4; - static constexpr size_t NUM_PKTS_WIDTH = 40; - - // Offsets assume 64-bit alignment - static constexpr size_t SRC_EPID_OFFSET = 0; - static constexpr size_t OP_CODE_OFFSET = 16; - static constexpr size_t OP_DATA_OFFSET = 20; - static constexpr size_t NUM_PKTS_OFFSET = 24; -}; - -//---------------------------------------------------- -// CHDR Management Packet Payload -//---------------------------------------------------- - -//! A class that represents a single management operation -// An operation consists of an operation code and some -// payload associated with that operation. -class mgmt_op_t -{ -public: - // Operation code - enum op_code_t { - //! Do nothing - MGMT_OP_NOP = 0, - //! Advertise this operation to the outside logic - MGMT_OP_ADVERTISE = 1, - //! Select the next destination for routing - MGMT_OP_SEL_DEST = 2, - //! Return the management packet back to its source - MGMT_OP_RETURN = 3, - //! Request information about the current node - MGMT_OP_INFO_REQ = 4, - //! A response to an information request - MGMT_OP_INFO_RESP = 5, - //! Perform a configuration write on the node - MGMT_OP_CFG_WR_REQ = 6, - //! Perform a configuration read on the node - MGMT_OP_CFG_RD_REQ = 7, - //! A response to a configuration read - MGMT_OP_CFG_RD_RESP = 8 - }; - - //! The payload for an operation is 48 bits wide. - using payload_t = uint64_t; - - //! An interpretation class for the payload for MGMT_OP_SEL_DEST - struct sel_dest_payload - { - const uint16_t dest; - - sel_dest_payload(uint16_t dest_) : dest(dest_) {} - sel_dest_payload(payload_t payload_) : dest(static_cast(payload_)) {} - operator payload_t() const - { - return static_cast(dest); - } - }; - - //! An interpretation class for the payload for MGMT_OP_CFG_WR_REQ, - //! MGMT_OP_CFG_RD_REQ and MGMT_OP_CFG_RD_RESP - struct cfg_payload - { - const uint16_t addr; - const uint32_t data; - - cfg_payload(uint16_t addr_, uint32_t data_ = 0) : addr(addr_), data(data_) {} - cfg_payload(payload_t payload_) - : addr(static_cast(payload_ >> 0)) - , data(static_cast(payload_ >> 16)) - { - } - operator payload_t() const - { - return ((static_cast(data) << 16) | static_cast(addr)); - } - }; - - //! An interpretation class for the payload for MGMT_OP_INFO_RESP - struct node_info_payload - { - const uint16_t device_id; - const uint8_t node_type; - const uint16_t node_inst; - const uint32_t ext_info; - - node_info_payload(uint16_t device_id_, - uint8_t node_type_, - uint16_t node_inst_, - uint32_t ext_info_) - : device_id(device_id_) - , node_type(node_type_) - , node_inst(node_inst_) - , ext_info(ext_info_) - { - } - node_info_payload(payload_t payload_) - : device_id(static_cast(payload_ >> 0)) - , node_type(static_cast((payload_ >> 16) & 0xF)) - , node_inst(static_cast((payload_ >> 20) & 0x3FF)) - , ext_info(static_cast((payload_ >> 30) & 0x3FFFF)) - { - } - operator payload_t() const - { - return ((static_cast(device_id) << 0) - | (static_cast(node_type & 0xF) << 16) - | (static_cast(node_inst & 0x3FF) << 20) - | (static_cast(ext_info & 0x3FFFF) << 30)); - } - }; - - mgmt_op_t(const op_code_t op_code, const payload_t op_payload = 0) - : _op_code(op_code), _op_payload(op_payload) - { - } - mgmt_op_t(const mgmt_op_t& rhs) = default; - - //! Get the op-code for this transaction - inline op_code_t get_op_code() const - { - return _op_code; - } - - //! Get the payload for this transaction - inline uint64_t get_op_payload() const - { - return _op_payload; - } - -private: - const op_code_t _op_code; - const payload_t _op_payload; -}; - -//! A class that represents a single management hop -// A hop is a collection for management transactions for -// a single node. -class mgmt_hop_t -{ -public: - mgmt_hop_t() = default; - mgmt_hop_t(const mgmt_hop_t& rhs) = default; - - //! Add a management operation to this hop. - // Operations are added to the hop in FIFO order and executed in FIFO order. - inline void add_op(const mgmt_op_t& op) - { - _ops.push_back(op); - } - - //! Get the number of management operations in this hop - inline size_t get_num_ops() const - { - return _ops.size(); - } - - //! Get the n'th operation in the hop - inline const mgmt_op_t& get_op(size_t i) const - { - return _ops.at(i); - } - - //! Serialize the payload to a uint64_t buffer - size_t serialize(std::vector& target, - const std::function& conv_byte_order) const; - - //! Deserialize the payload from a uint64_t buffer - void deserialize(std::list& src, - const std::function& conv_byte_order); - -private: - std::vector _ops; -}; - -//! A class that represents a complete multi-hop management transaction -// A transaction is a collection of hops, where each hop is a collection -// of management transactions. -class mgmt_payload -{ -public: - mgmt_payload() = default; - mgmt_payload(const mgmt_payload& rhs) = default; - mgmt_payload(mgmt_payload&& rhs) = default; - - mgmt_payload& operator=(const mgmt_payload& rhs) = default; - - inline void set_header(sep_id_t src_epid, uint16_t protover, chdr_w_t chdr_w) - { - _src_epid = src_epid; - _chdr_w = chdr_w; - _protover = protover; - } - - //! Add a management hop to this transaction - // Hops are added to the hop in FIFO order and executed in FIFO order. - inline void add_hop(const mgmt_hop_t& hop) - { - _hops.push_back(hop); - } - - //! Get the number of management hops in this hop - inline size_t get_num_hops() const - { - return _hops.size(); - } - - //! Get the n'th hop in the transaction - inline const mgmt_hop_t& get_hop(size_t i) const - { - return _hops.at(i); - } - - inline size_t get_size_bytes() const - { - size_t num_lines = 1; /* header */ - for (const auto& hop : _hops) { - num_lines += hop.get_num_ops(); - } - return num_lines * (chdr_w_to_bits(_chdr_w) / 8); - } - - //! Populate the header for this type of packet - void populate_header(chdr_header& header) const; - - //! Serialize the payload to a uint64_t buffer - size_t serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const; - - //! Serialize the payload to a uint64_t buffer (no conversion function) - template - size_t serialize(uint64_t* buff, size_t max_size_bytes) const - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) - : uhd::htowx(x); - }; - return serialize(buff, max_size_bytes, conv_byte_order); - } - - //! Deserialize the payload from a uint64_t buffer - void deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order); - - //! Deserialize the payload from a uint64_t buffer (no conversion function) - template - void deserialize(const uint64_t* buff, size_t num_elems) - { - auto conv_byte_order = [](uint64_t x) -> uint64_t { - return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) - : uhd::wtohx(x); - }; - deserialize(buff, num_elems, conv_byte_order); - } - - //! Return a string representation of this object - const std::string to_string() const; - -private: - sep_id_t _src_epid = 0; - uint16_t _protover = 0; - chdr_w_t _chdr_w = CHDR_W_64; - std::vector _hops; -}; - -} // namespace chdr -}} // namespace uhd::rfnoc - -#endif /* INCLUDED_RFNOC_CHDR_TYPES_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/chdr_ctrl_endpoint.hpp b/host/lib/include/uhdlib/rfnoc/chdr_ctrl_endpoint.hpp index 29f4da7c2..b50e06d3c 100644 --- a/host/lib/include/uhdlib/rfnoc/chdr_ctrl_endpoint.hpp +++ b/host/lib/include/uhdlib/rfnoc/chdr_ctrl_endpoint.hpp @@ -7,7 +7,7 @@ #ifndef INCLUDED_LIBUHD_RFNOC_CHDR_CTRL_ENDPOINT_HPP #define INCLUDED_LIBUHD_RFNOC_CHDR_CTRL_ENDPOINT_HPP -#include +#include #include #include #include diff --git a/host/lib/include/uhdlib/rfnoc/chdr_packet.hpp b/host/lib/include/uhdlib/rfnoc/chdr_packet.hpp new file mode 100644 index 000000000..89b33a66a --- /dev/null +++ b/host/lib/include/uhdlib/rfnoc/chdr_packet.hpp @@ -0,0 +1,296 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_RFNOC_CHDR_PACKET_HPP +#define INCLUDED_RFNOC_CHDR_PACKET_HPP + +#include +#include +#include +#include + +namespace uhd { namespace rfnoc { namespace chdr { + +//---------------------------------------------------- +// Generic CHDR Packet Container +//---------------------------------------------------- + +//! A container class that wraps a generic buffer that contains a CHDR packet. The +// container provides a high level API to read and write the header, metadata and payload +// of the packet. The payload can be accessed as a generic buffer using this interface. +// +class chdr_packet +{ +public: + //! A unique pointer to a const chdr_packet. Useful as a read-only interface. + typedef std::unique_ptr cuptr; + //! A unique pointer to a non-const chdr_packet. Useful as a read-write interface. + typedef std::unique_ptr uptr; + + virtual ~chdr_packet() = 0; + + /*! Updates the underlying storage of this packet. This is a const method and is + * only useful for read-only (RX) access. + * + * \param pkt_buff Pointer to a buffer that contains the RX packet + */ + virtual void refresh(const void* pkt_buff) const = 0; + + /*! Updates the underlying storage of this packet, and populates it with the specified + * arguments. This is a non-const method and is useful for read-write (TX) access. + * + * \param pkt_buff Pointer to a buffer that should be populated with the TX packet + * \param header The CHDR header to fill into the TX packet + * \param timestamp The timestamp to fill into the TX packet (if requested) + */ + virtual void refresh(void* pkt_buff, chdr_header& header, uint64_t timestamp = 0) = 0; + + /*! Updates the CHDR header with the written payload size + * + * \param payload_size_bytes The payload size in bytes + */ + virtual void update_payload_size(size_t payload_size_bytes) = 0; + + /*! Returns a class that represents the contents of the CHDR header + * + * \return The CHDR header + */ + virtual chdr_header get_chdr_header() const = 0; + + /*! Returns the timestamp in the packet as an optional value + * + * \return A boost::optional which if initialized has the timestamp + */ + virtual boost::optional get_timestamp() const = 0; + + /*! Returns the endianness of the metadata and payload buffers + * + * \return The byte order as a uhd::endianness_t + */ + virtual endianness_t get_byte_order() const = 0; + + /*! Returns the maximum transfer unit in bytes + * + * \return The maximum transfer unit in bytes + */ + virtual size_t get_mtu_bytes() const = 0; + + /*! Returns the metadata size in bytes + * + * \return The size in bytes + */ + virtual size_t get_mdata_size() const = 0; + + /*! Returns a const void pointer to the metadata section in the packet + * + * \return A pointer to the metadata + */ + virtual const void* get_mdata_const_ptr() const = 0; + + /*! Returns a non-const void pointer to the metadata section in the packet + * + * \return A pointer to the metadata + */ + virtual void* get_mdata_ptr() = 0; + + /*! Returns the payload size in bytes + * + * \return The size in bytes + */ + virtual size_t get_payload_size() const = 0; + + /*! Returns a const void pointer to the payload section in the packet + * + * \return A pointer to the payload + */ + virtual const void* get_payload_const_ptr() const = 0; + + /*! Returns a non-const void pointer to the payload section in the packet + * + * \return A pointer to the payload + */ + virtual void* get_payload_ptr() = 0; + + //! Shortcut to return the const metadata pointer cast as a specific type + template + inline const data_t* get_mdata_const_ptr_as() const + { + return reinterpret_cast(get_mdata_const_ptr()); + } + + //! Shortcut to return the non-const metadata pointer cast as a specific type + template + inline data_t* get_mdata_ptr_as() + { + return reinterpret_cast(get_mdata_ptr()); + } + + //! Shortcut to return the const payload pointer cast as a specific type + template + inline const data_t* get_payload_const_ptr_as() const + { + return reinterpret_cast(get_payload_const_ptr()); + } + + //! Shortcut to return the non-const payload pointer cast as a specific type + template + inline data_t* get_payload_ptr_as() + { + return reinterpret_cast(get_payload_ptr()); + } + + //! Return a function to convert a word of type data_t to host order + template + const std::function conv_to_host() const + { + return (get_byte_order() == uhd::ENDIANNESS_BIG) ? uhd::ntohx + : uhd::wtohx; + } + + //! Return a function to convert a word of type data_t from host order + template + const std::function conv_from_host() const + { + return (get_byte_order() == uhd::ENDIANNESS_BIG) ? uhd::htonx + : uhd::htowx; + } +}; + +//---------------------------------------------------- +// Container for specific CHDR Packets +//---------------------------------------------------- + +//! A container class that wraps a generic buffer that contains a CHDR packet. The +// container provides a high level API to read and write the header, metadata and payload +// of the packet. The payload can be accessed as a specific type that will be serialized +// and deserialized appropriately. +// +template +class chdr_packet_specific +{ +public: + //! A unique pointer to a const chdr_packet. Useful as a read-only interface. + typedef std::unique_ptr> cuptr; + //! A unique pointer to a non-const chdr_packet. Useful as a read-write interface. + typedef std::unique_ptr> uptr; + + chdr_packet_specific(chdr_packet::uptr chdr_pkt) : _chdr_pkt(std::move(chdr_pkt)) {} + ~chdr_packet_specific() = default; + + //! Updates the underlying storage of this packet. This is a const method and is + // only useful for read-only access. + inline void refresh(const void* pkt_buff) const + { + _chdr_pkt->refresh(pkt_buff); + } + + //! Updates the underlying storage of this packet, and populates it with the specified + // arguments. This is a non-const method and is useful for read-write access. + inline void refresh(void* pkt_buff, chdr_header& header, const payload_t& payload) + { + payload.populate_header(header); + _chdr_pkt->refresh(pkt_buff, header); + size_t bytes_copied = payload.serialize(_chdr_pkt->get_payload_ptr_as(), + _chdr_pkt->get_mtu_bytes(), + _chdr_pkt->conv_from_host()); + _chdr_pkt->update_payload_size(bytes_copied); + header = _chdr_pkt->get_chdr_header(); + } + + //! Returns a class that represents the contents of the CHDR header + inline chdr_header get_chdr_header() const + { + return std::move(_chdr_pkt->get_chdr_header()); + } + + //! Returns a class that represents the contents of the CHDR payload + inline payload_t get_payload() const + { + payload_t payload; + payload.deserialize(_chdr_pkt->get_payload_const_ptr_as(), + _chdr_pkt->get_payload_size() / sizeof(uint64_t), + _chdr_pkt->conv_to_host()); + return payload; + } + + //! Fills the CHDR payload into the specified parameter + inline void fill_payload(payload_t& payload) const + { + payload.deserialize(_chdr_pkt->get_payload_const_ptr_as(), + _chdr_pkt->get_payload_size() / sizeof(uint64_t), + _chdr_pkt->conv_to_host()); + } + +private: + chdr_packet::uptr _chdr_pkt; +}; + +//---------------------------------------------------- +// Specific CHDR packet types +//---------------------------------------------------- + +//! CHDR control packet +typedef chdr_packet_specific chdr_ctrl_packet; + +//! CHDR stream status packet +typedef chdr_packet_specific chdr_strs_packet; + +//! CHDR stream command packet +typedef chdr_packet_specific chdr_strc_packet; + +//! CHDR management packet +typedef chdr_packet_specific chdr_mgmt_packet; + +//---------------------------------------------------- +// CHDR packet factory +//---------------------------------------------------- + +//! A copyable and movable factory class that is capable of generating generic and +//! specific CHDR packet containers. +// +class chdr_packet_factory +{ +public: + //! A parametrized ctor that takes in all the info required to generate a CHDR packet + // + // \param chdr_w The CHDR width of the remote device + // \param endianness The endianness of the link being used (e.g., Ethernet + // typically uses big-endian, PCIe typically uses + // little-endian). Note: The host endianness is + // automatically derived. + chdr_packet_factory(chdr_w_t chdr_w, endianness_t endianness); + chdr_packet_factory() = delete; + chdr_packet_factory(const chdr_packet_factory& rhs) = default; + chdr_packet_factory(chdr_packet_factory&& rhs) = default; + + //! Makes a generic CHDR packet and transfers ownership to the client + chdr_packet::uptr make_generic( + size_t mtu_bytes = std::numeric_limits::max()) const; + + //! Makes a CHDR control packet and transfers ownership to the client + chdr_ctrl_packet::uptr make_ctrl( + size_t mtu_bytes = std::numeric_limits::max()) const; + + //! Makes a CHDR stream status packet and transfers ownership to the client + chdr_strs_packet::uptr make_strs( + size_t mtu_bytes = std::numeric_limits::max()) const; + + //! Makes a CHDR stream cmd packet and transfers ownership to the client + chdr_strc_packet::uptr make_strc( + size_t mtu_bytes = std::numeric_limits::max()) const; + + //! Makes a CHDR management packet and transfers ownership to the client + chdr_mgmt_packet::uptr make_mgmt( + size_t mtu_bytes = std::numeric_limits::max()) const; + +private: + const chdr_w_t _chdr_w; + const endianness_t _endianness; +}; + +}}} // namespace uhd::rfnoc::chdr + +#endif /* INCLUDED_RFNOC_CHDR_PACKET_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/chdr_types.hpp b/host/lib/include/uhdlib/rfnoc/chdr_types.hpp new file mode 100644 index 000000000..62b24ab61 --- /dev/null +++ b/host/lib/include/uhdlib/rfnoc/chdr_types.hpp @@ -0,0 +1,817 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_RFNOC_CHDR_TYPES_HPP +#define INCLUDED_RFNOC_CHDR_TYPES_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace uhd { namespace rfnoc { namespace chdr { + +enum packet_type_t { + PKT_TYPE_MGMT = 0x0, //! Management packet + PKT_TYPE_STRS = 0x1, //! Stream status + PKT_TYPE_STRC = 0x2, //! Stream Command + PKT_TYPE_CTRL = 0x4, //! Control Transaction + PKT_TYPE_DATA_NO_TS = 0x6, //! Data Packet without TimeStamp + PKT_TYPE_DATA_WITH_TS = 0x7, //! Data Packet with TimeStamp +}; + +//---------------------------------------------------- +// CHDR Header +//---------------------------------------------------- + +class chdr_header +{ +public: // Functions + chdr_header() = default; + chdr_header(const chdr_header& rhs) = default; + chdr_header(chdr_header&& rhs) = default; + + //! Unpack the header from a uint64_t + chdr_header(uint64_t flat_hdr) : _flat_hdr(flat_hdr) {} + + //! Get the virtual channel field (6 bits) + inline uint8_t get_vc() const + { + return get_field(_flat_hdr, VC_OFFSET, VC_WIDTH); + } + + //! Set the virtual channel field (6 bits) + inline void set_vc(uint8_t vc) + { + _flat_hdr = set_field(_flat_hdr, vc, VC_OFFSET, VC_WIDTH); + } + + //! Get the end-of-burst flag (1 bit) + inline bool get_eob() const + { + return get_field(_flat_hdr, EOB_OFFSET, EOB_WIDTH); + } + + //! Set the end-of-burst flag (1 bit) + inline void set_eob(bool eob) + { + _flat_hdr = set_field(_flat_hdr, eob, EOB_OFFSET, EOB_WIDTH); + } + + //! Get the end-of-vector flag (1 bit) + inline bool get_eov() const + { + return get_field(_flat_hdr, EOV_OFFSET, EOV_WIDTH); + } + + //! Set the end-of-vector flag (1 bit) + inline void set_eov(bool eov) + { + _flat_hdr = set_field(_flat_hdr, eov, EOV_OFFSET, EOV_WIDTH); + } + + //! Get the packet type field (3 bits) + inline packet_type_t get_pkt_type() const + { + return get_field(_flat_hdr, PKT_TYPE_OFFSET, PKT_TYPE_WIDTH); + } + + //! Set the packet type field (3 bits) + inline void set_pkt_type(packet_type_t pkt_type) + { + _flat_hdr = set_field(_flat_hdr, pkt_type, PKT_TYPE_OFFSET, PKT_TYPE_WIDTH); + } + + //! Get number of metadata words field (5 bits) + inline uint8_t get_num_mdata() const + { + return get_field(_flat_hdr, NUM_MDATA_OFFSET, NUM_MDATA_WIDTH); + } + + //! Set number of metadata words field (5 bits) + inline void set_num_mdata(uint8_t num_mdata) + { + _flat_hdr = set_field(_flat_hdr, num_mdata, NUM_MDATA_OFFSET, NUM_MDATA_WIDTH); + } + + //! Get the sequence number field (16 bits) + inline uint16_t get_seq_num() const + { + return get_field(_flat_hdr, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH); + } + + //! Set the sequence number field (16 bits) + inline void set_seq_num(uint16_t seq_num) + { + _flat_hdr = set_field(_flat_hdr, seq_num, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH); + } + + //! Get the packet length field (16 bits) + inline uint16_t get_length() const + { + return get_field(_flat_hdr, LENGTH_OFFSET, LENGTH_WIDTH); + } + + //! Set the packet length field (16 bits) + inline void set_length(uint16_t length) + { + _flat_hdr = set_field(_flat_hdr, length, LENGTH_OFFSET, LENGTH_WIDTH); + } + + //! Get the destination EPID field (16 bits) + inline uint16_t get_dst_epid() const + { + return get_field(_flat_hdr, DST_EPID_OFFSET, DST_EPID_WIDTH); + } + + //! Set the destination EPID field (16 bits) + inline void set_dst_epid(uint16_t dst_epid) + { + _flat_hdr = set_field(_flat_hdr, dst_epid, DST_EPID_OFFSET, DST_EPID_WIDTH); + } + + //! Pack the header into a uint64_t + inline uint64_t pack() const + { + return _flat_hdr; + } + + //! Pack the header into a uint64_t as an implicit cast + inline operator uint64_t() const + { + return pack(); + } + + //! Comparison operator (==) + inline bool operator==(const chdr_header& rhs) const + { + return _flat_hdr == rhs._flat_hdr; + } + + //! Comparison operator (!=) + inline bool operator!=(const chdr_header& rhs) const + { + return _flat_hdr != rhs._flat_hdr; + } + + //! Assignment operator (=) from a chdr_header + inline const chdr_header& operator=(const chdr_header& rhs) + { + _flat_hdr = rhs._flat_hdr; + return *this; + } + + //! Assignment operator (=) from a uint64_t + inline const chdr_header& operator=(const uint64_t& rhs) + { + _flat_hdr = rhs; + return *this; + } + +private: + // The flattened representation of the header stored in host order + uint64_t _flat_hdr = 0; + + static constexpr size_t VC_WIDTH = 6; + static constexpr size_t EOB_WIDTH = 1; + static constexpr size_t EOV_WIDTH = 1; + static constexpr size_t PKT_TYPE_WIDTH = 3; + static constexpr size_t NUM_MDATA_WIDTH = 5; + static constexpr size_t SEQ_NUM_WIDTH = 16; + static constexpr size_t LENGTH_WIDTH = 16; + static constexpr size_t DST_EPID_WIDTH = 16; + + static constexpr size_t VC_OFFSET = 58; + static constexpr size_t EOB_OFFSET = 57; + static constexpr size_t EOV_OFFSET = 56; + static constexpr size_t PKT_TYPE_OFFSET = 53; + static constexpr size_t NUM_MDATA_OFFSET = 48; + static constexpr size_t SEQ_NUM_OFFSET = 32; + static constexpr size_t LENGTH_OFFSET = 16; + static constexpr size_t DST_EPID_OFFSET = 0; + + static inline constexpr uint64_t mask(size_t width) + { + return ((uint64_t(1) << width) - 1); + } + + template + static inline constexpr field_t get_field( + uint64_t flat_hdr, size_t offset, size_t width) + { + return static_cast((flat_hdr >> offset) & mask(width)); + } + + template + static inline constexpr uint64_t set_field( + const uint64_t old_val, field_t field, size_t offset, size_t width) + { + return (old_val & ~(mask(width) << offset)) + | ((static_cast(field) & mask(width)) << offset); + } +}; + + +//---------------------------------------------------- +// CHDR Control Packet Payload +//---------------------------------------------------- + +enum ctrl_status_t { + CMD_OKAY = 0x0, //! Transaction successful + CMD_CMDERR = 0x1, //! Slave asserted a command error + CMD_TSERR = 0x2, //! Slave asserted a time stamp error + CMD_WARNING = 0x3, //! Slave asserted non-critical error +}; + +enum ctrl_opcode_t { + OP_SLEEP = 0x0, + OP_WRITE = 0x1, + OP_READ = 0x2, + OP_READ_WRITE = 0x3, + OP_BLOCK_WRITE = 0x4, + OP_BLOCK_READ = 0x5, + OP_POLL = 0x6, + OP_USER1 = 0xA, + OP_USER2 = 0xB, + OP_USER3 = 0xC, + OP_USER4 = 0xD, + OP_USER5 = 0xE, + OP_USER6 = 0xF, +}; + +class ctrl_payload +{ +public: // Members + //! Destination port for transaction (10 bits) + uint16_t dst_port = 0; + //! Source port for transaction (10 bits) + uint16_t src_port = 0; + //! Sequence number (6 bits) + uint8_t seq_num = 0; + //! Has Time Flag (1 bit) and timestamp (64 bits) + boost::optional timestamp = boost::none; + //! Is Acknowledgment Flag (1 bit) + bool is_ack = false; + //! Source endpoint ID of transaction (16 bits) + uint16_t src_epid = 0; + //! Address for transaction (20 bits) + uint32_t address = 0; + //! Data for transaction (vector of 32 bits) + std::vector data_vtr = {0}; + //! Byte-enable mask for transaction (4 bits) + uint8_t byte_enable = 0xF; + //! Operation code (4 bits) + ctrl_opcode_t op_code = OP_SLEEP; + //! Transaction status (4 bits) + ctrl_status_t status = CMD_OKAY; + +public: // Functions + ctrl_payload() = default; + ctrl_payload(const ctrl_payload& rhs) = default; + ctrl_payload(ctrl_payload&& rhs) = default; + + ctrl_payload& operator=(const ctrl_payload& rhs) = default; + + //! Populate the header for this type of packet + void populate_header(chdr_header& header) const; + + //! Serialize the payload to a uint64_t buffer + size_t serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const; + + //! Serialize the payload to a uint64_t buffer (no conversion function) + template + size_t serialize(uint64_t* buff, size_t max_size_bytes) const + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) + : uhd::htowx(x); + }; + return serialize(buff, max_size_bytes, conv_byte_order); + } + + //! Deserialize the payload from a uint64_t buffer + void deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order); + + //! Deserialize the payload from a uint64_t buffer (no conversion function) + template + void deserialize(const uint64_t* buff, size_t num_elems) + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) + : uhd::wtohx(x); + }; + deserialize(buff, num_elems, conv_byte_order); + } + + //! Comparison operator (==) + bool operator==(const ctrl_payload& rhs) const; + + //! Comparison operator (!=) + inline bool operator!=(const ctrl_payload& rhs) const + { + return !(*this == rhs); + } + + //! Return a string representation of this object + const std::string to_string() const; + +private: + static constexpr size_t DST_PORT_WIDTH = 10; + static constexpr size_t SRC_PORT_WIDTH = 10; + static constexpr size_t NUM_DATA_WIDTH = 4; + static constexpr size_t SEQ_NUM_WIDTH = 6; + static constexpr size_t HAS_TIME_WIDTH = 1; + static constexpr size_t IS_ACK_WIDTH = 1; + static constexpr size_t SRC_EPID_WIDTH = 16; + static constexpr size_t ADDRESS_WIDTH = 20; + static constexpr size_t BYTE_ENABLE_WIDTH = 4; + static constexpr size_t OPCODE_WIDTH = 4; + static constexpr size_t STATUS_WIDTH = 2; + + // Offsets assume 64-bit alignment + static constexpr size_t DST_PORT_OFFSET = 0; + static constexpr size_t SRC_PORT_OFFSET = 10; + static constexpr size_t NUM_DATA_OFFSET = 20; + static constexpr size_t SEQ_NUM_OFFSET = 24; + static constexpr size_t HAS_TIME_OFFSET = 30; + static constexpr size_t IS_ACK_OFFSET = 31; + static constexpr size_t SRC_EPID_OFFSET = 32; + static constexpr size_t ADDRESS_OFFSET = 0; + static constexpr size_t BYTE_ENABLE_OFFSET = 20; + static constexpr size_t OPCODE_OFFSET = 24; + static constexpr size_t STATUS_OFFSET = 30; + static constexpr size_t LO_DATA_OFFSET = 0; + static constexpr size_t HI_DATA_OFFSET = 32; +}; + +//---------------------------------------------------- +// CHDR Stream Status Packet Payload +//---------------------------------------------------- + +enum strs_status_t { + STRS_OKAY = 0x0, //! No error + STRS_CMDERR = 0x1, //! A stream command signalled an error + STRS_SEQERR = 0x2, //! Packet out of sequence (sequence error) + STRS_DATAERR = 0x3, //! Data integrity check failed + STRS_RTERR = 0x4, //! Unexpected destination (routing error) +}; + +class strs_payload +{ +public: // Members + //! The source EPID for the stream (16 bits) + uint16_t src_epid = 0; + //! The status of the stream (4 bits) + strs_status_t status = STRS_OKAY; + //! Buffer capacity in bytes (40 bits) + uint64_t capacity_bytes = 0; + //! Buffer capacity in packets (24 bits) + uint32_t capacity_pkts = 0; + //! Transfer count in bytes (64 bits) + uint64_t xfer_count_bytes = 0; + //! Transfer count in packets (40 bits) + uint64_t xfer_count_pkts = 0; + //! Buffer info (16 bits) + uint16_t buff_info = 0; + //! Extended status info (48 bits) + uint64_t status_info = 0; + +public: // Functions + strs_payload() = default; + strs_payload(const strs_payload& rhs) = default; + strs_payload(strs_payload&& rhs) = default; + + strs_payload& operator=(const strs_payload& rhs) = default; + + //! Populate the header for this type of packet + void populate_header(chdr_header& header) const; + + //! Serialize the payload to a uint64_t buffer + size_t serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const; + + //! Serialize the payload to a uint64_t buffer (no conversion function) + template + size_t serialize(uint64_t* buff, size_t max_size_bytes) const + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) + : uhd::htowx(x); + }; + return serialize(buff, max_size_bytes, conv_byte_order); + } + + //! Deserialize the payload from a uint64_t buffer + void deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order); + + //! Deserialize the payload from a uint64_t buffer (no conversion function) + template + void deserialize(const uint64_t* buff, size_t num_elems) + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) + : uhd::wtohx(x); + }; + deserialize(buff, num_elems, conv_byte_order); + } + + //! Comparison operator (==) + bool operator==(const strs_payload& rhs) const; + + //! Comparison operator (!=) + inline bool operator!=(const strs_payload& rhs) const + { + return !(*this == rhs); + } + + //! Return a string representation of this object + const std::string to_string() const; + +private: + static constexpr size_t SRC_EPID_WIDTH = 16; + static constexpr size_t STATUS_WIDTH = 4; + static constexpr size_t CAPACITY_BYTES_WIDTH = 40; + static constexpr size_t CAPACITY_PKTS_WIDTH = 24; + static constexpr size_t XFER_COUNT_PKTS_WIDTH = 40; + static constexpr size_t BUFF_INFO_WIDTH = 16; + static constexpr size_t STATUS_INFO_WIDTH = 48; + + // Offsets assume 64-bit alignment + static constexpr size_t SRC_EPID_OFFSET = 0; + static constexpr size_t STATUS_OFFSET = 16; + static constexpr size_t CAPACITY_BYTES_OFFSET = 24; + static constexpr size_t CAPACITY_PKTS_OFFSET = 0; + static constexpr size_t XFER_COUNT_PKTS_OFFSET = 24; + static constexpr size_t BUFF_INFO_OFFSET = 0; + static constexpr size_t STATUS_INFO_OFFSET = 16; +}; + +//---------------------------------------------------- +// CHDR Stream Command Packet Payload +//---------------------------------------------------- + +enum strc_op_code_t { + STRC_INIT = 0x0, //! Initialize stream + STRC_PING = 0x1, //! Trigger a stream status response + STRC_RESYNC = 0x2, //! Re-synchronize flow control +}; + +class strc_payload +{ +public: // Members + //! The source EPID for the stream (16 bits) + uint16_t src_epid = 0; + //! Operation code for the command (4 bits) + strc_op_code_t op_code = STRC_INIT; + //! Data associated with the operation (4 bits) + uint8_t op_data = 0; + //! Number of packets to use for operation (40 bits) + uint64_t num_pkts = 0; + //! Number of bytes to use for operation (64 bits) + uint64_t num_bytes = 0; + +public: // Functions + strc_payload() = default; + strc_payload(const strc_payload& rhs) = default; + strc_payload(strc_payload&& rhs) = default; + + strc_payload& operator=(const strc_payload& rhs) = default; + + //! Populate the header for this type of packet + void populate_header(chdr_header& header) const; + + //! Serialize the payload to a uint64_t buffer + size_t serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const; + + //! Serialize the payload to a uint64_t buffer (no conversion function) + template + size_t serialize(uint64_t* buff, size_t max_size_bytes) const + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) + : uhd::htowx(x); + }; + return serialize(buff, max_size_bytes, conv_byte_order); + } + + //! Deserialize the payload from a uint64_t buffer + void deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order); + + //! Deserialize the payload from a uint64_t buffer (no conversion function) + template + void deserialize(const uint64_t* buff, size_t num_elems) + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) + : uhd::wtohx(x); + }; + deserialize(buff, num_elems, conv_byte_order); + } + + //! Comparison operator (==) + bool operator==(const strc_payload& rhs) const; + + //! Comparison operator (!=) + inline bool operator!=(const strc_payload& rhs) const + { + return !(*this == rhs); + } + + //! Return a string representation of this object + const std::string to_string() const; + +private: + static constexpr size_t SRC_EPID_WIDTH = 16; + static constexpr size_t OP_CODE_WIDTH = 4; + static constexpr size_t OP_DATA_WIDTH = 4; + static constexpr size_t NUM_PKTS_WIDTH = 40; + + // Offsets assume 64-bit alignment + static constexpr size_t SRC_EPID_OFFSET = 0; + static constexpr size_t OP_CODE_OFFSET = 16; + static constexpr size_t OP_DATA_OFFSET = 20; + static constexpr size_t NUM_PKTS_OFFSET = 24; +}; + +//---------------------------------------------------- +// CHDR Management Packet Payload +//---------------------------------------------------- + +//! A class that represents a single management operation +// An operation consists of an operation code and some +// payload associated with that operation. +class mgmt_op_t +{ +public: + // Operation code + enum op_code_t { + //! Do nothing + MGMT_OP_NOP = 0, + //! Advertise this operation to the outside logic + MGMT_OP_ADVERTISE = 1, + //! Select the next destination for routing + MGMT_OP_SEL_DEST = 2, + //! Return the management packet back to its source + MGMT_OP_RETURN = 3, + //! Request information about the current node + MGMT_OP_INFO_REQ = 4, + //! A response to an information request + MGMT_OP_INFO_RESP = 5, + //! Perform a configuration write on the node + MGMT_OP_CFG_WR_REQ = 6, + //! Perform a configuration read on the node + MGMT_OP_CFG_RD_REQ = 7, + //! A response to a configuration read + MGMT_OP_CFG_RD_RESP = 8 + }; + + //! The payload for an operation is 48 bits wide. + using payload_t = uint64_t; + + //! An interpretation class for the payload for MGMT_OP_SEL_DEST + struct sel_dest_payload + { + const uint16_t dest; + + sel_dest_payload(uint16_t dest_) : dest(dest_) {} + sel_dest_payload(payload_t payload_) : dest(static_cast(payload_)) {} + operator payload_t() const + { + return static_cast(dest); + } + }; + + //! An interpretation class for the payload for MGMT_OP_CFG_WR_REQ, + //! MGMT_OP_CFG_RD_REQ and MGMT_OP_CFG_RD_RESP + struct cfg_payload + { + const uint16_t addr; + const uint32_t data; + + cfg_payload(uint16_t addr_, uint32_t data_ = 0) : addr(addr_), data(data_) {} + cfg_payload(payload_t payload_) + : addr(static_cast(payload_ >> 0)) + , data(static_cast(payload_ >> 16)) + { + } + operator payload_t() const + { + return ((static_cast(data) << 16) | static_cast(addr)); + } + }; + + //! An interpretation class for the payload for MGMT_OP_INFO_RESP + struct node_info_payload + { + const uint16_t device_id; + const uint8_t node_type; + const uint16_t node_inst; + const uint32_t ext_info; + + node_info_payload(uint16_t device_id_, + uint8_t node_type_, + uint16_t node_inst_, + uint32_t ext_info_) + : device_id(device_id_) + , node_type(node_type_) + , node_inst(node_inst_) + , ext_info(ext_info_) + { + } + node_info_payload(payload_t payload_) + : device_id(static_cast(payload_ >> 0)) + , node_type(static_cast((payload_ >> 16) & 0xF)) + , node_inst(static_cast((payload_ >> 20) & 0x3FF)) + , ext_info(static_cast((payload_ >> 30) & 0x3FFFF)) + { + } + operator payload_t() const + { + return ((static_cast(device_id) << 0) + | (static_cast(node_type & 0xF) << 16) + | (static_cast(node_inst & 0x3FF) << 20) + | (static_cast(ext_info & 0x3FFFF) << 30)); + } + }; + + mgmt_op_t(const op_code_t op_code, const payload_t op_payload = 0) + : _op_code(op_code), _op_payload(op_payload) + { + } + mgmt_op_t(const mgmt_op_t& rhs) = default; + + //! Get the op-code for this transaction + inline op_code_t get_op_code() const + { + return _op_code; + } + + //! Get the payload for this transaction + inline uint64_t get_op_payload() const + { + return _op_payload; + } + +private: + const op_code_t _op_code; + const payload_t _op_payload; +}; + +//! A class that represents a single management hop +// A hop is a collection for management transactions for +// a single node. +class mgmt_hop_t +{ +public: + mgmt_hop_t() = default; + mgmt_hop_t(const mgmt_hop_t& rhs) = default; + + //! Add a management operation to this hop. + // Operations are added to the hop in FIFO order and executed in FIFO order. + inline void add_op(const mgmt_op_t& op) + { + _ops.push_back(op); + } + + //! Get the number of management operations in this hop + inline size_t get_num_ops() const + { + return _ops.size(); + } + + //! Get the n'th operation in the hop + inline const mgmt_op_t& get_op(size_t i) const + { + return _ops.at(i); + } + + //! Serialize the payload to a uint64_t buffer + size_t serialize(std::vector& target, + const std::function& conv_byte_order) const; + + //! Deserialize the payload from a uint64_t buffer + void deserialize(std::list& src, + const std::function& conv_byte_order); + +private: + std::vector _ops; +}; + +//! A class that represents a complete multi-hop management transaction +// A transaction is a collection of hops, where each hop is a collection +// of management transactions. +class mgmt_payload +{ +public: + mgmt_payload() = default; + mgmt_payload(const mgmt_payload& rhs) = default; + mgmt_payload(mgmt_payload&& rhs) = default; + + mgmt_payload& operator=(const mgmt_payload& rhs) = default; + + inline void set_header(sep_id_t src_epid, uint16_t protover, chdr_w_t chdr_w) + { + _src_epid = src_epid; + _chdr_w = chdr_w; + _protover = protover; + } + + //! Add a management hop to this transaction + // Hops are added to the hop in FIFO order and executed in FIFO order. + inline void add_hop(const mgmt_hop_t& hop) + { + _hops.push_back(hop); + } + + //! Get the number of management hops in this hop + inline size_t get_num_hops() const + { + return _hops.size(); + } + + //! Get the n'th hop in the transaction + inline const mgmt_hop_t& get_hop(size_t i) const + { + return _hops.at(i); + } + + inline size_t get_size_bytes() const + { + size_t num_lines = 1; /* header */ + for (const auto& hop : _hops) { + num_lines += hop.get_num_ops(); + } + return num_lines * (chdr_w_to_bits(_chdr_w) / 8); + } + + //! Populate the header for this type of packet + void populate_header(chdr_header& header) const; + + //! Serialize the payload to a uint64_t buffer + size_t serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const; + + //! Serialize the payload to a uint64_t buffer (no conversion function) + template + size_t serialize(uint64_t* buff, size_t max_size_bytes) const + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx(x) + : uhd::htowx(x); + }; + return serialize(buff, max_size_bytes, conv_byte_order); + } + + //! Deserialize the payload from a uint64_t buffer + void deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order); + + //! Deserialize the payload from a uint64_t buffer (no conversion function) + template + void deserialize(const uint64_t* buff, size_t num_elems) + { + auto conv_byte_order = [](uint64_t x) -> uint64_t { + return (endianness == uhd::ENDIANNESS_BIG) ? uhd::ntohx(x) + : uhd::wtohx(x); + }; + deserialize(buff, num_elems, conv_byte_order); + } + + //! Return a string representation of this object + const std::string to_string() const; + + //! Return the source EPID for this transaction + inline const sep_id_t get_src_epid() const + { + return _src_epid; + } + +private: + sep_id_t _src_epid = 0; + uint16_t _protover = 0; + chdr_w_t _chdr_w = CHDR_W_64; + std::vector _hops; +}; + +}}} // namespace uhd::rfnoc::chdr + +#endif /* INCLUDED_RFNOC_CHDR_TYPES_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/ctrlport_endpoint.hpp b/host/lib/include/uhdlib/rfnoc/ctrlport_endpoint.hpp index 00ebe38b9..8f54932e5 100644 --- a/host/lib/include/uhdlib/rfnoc/ctrlport_endpoint.hpp +++ b/host/lib/include/uhdlib/rfnoc/ctrlport_endpoint.hpp @@ -8,8 +8,8 @@ #define INCLUDED_LIBUHD_RFNOC_CTRLPORT_ENDPOINT_HPP #include -#include #include +#include #include namespace uhd { namespace rfnoc { diff --git a/host/lib/include/uhdlib/rfnoc/mb_iface.hpp b/host/lib/include/uhdlib/rfnoc/mb_iface.hpp index 466ec0cbf..60afa92fa 100644 --- a/host/lib/include/uhdlib/rfnoc/mb_iface.hpp +++ b/host/lib/include/uhdlib/rfnoc/mb_iface.hpp @@ -7,7 +7,7 @@ #ifndef INCLUDED_LIBUHD_MB_IFACE_HPP #define INCLUDED_LIBUHD_MB_IFACE_HPP -#include +#include #include namespace uhd { namespace rfnoc { diff --git a/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp b/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp index 305f8fb85..09a155fa0 100644 --- a/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp +++ b/host/lib/include/uhdlib/rfnoc/mgmt_portal.hpp @@ -7,7 +7,7 @@ #ifndef INCLUDED_LIBUHD_MGMT_PORTAL_HPP #define INCLUDED_LIBUHD_MGMT_PORTAL_HPP -#include +#include #include #include diff --git a/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp b/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp new file mode 100644 index 000000000..1fee0d40e --- /dev/null +++ b/host/lib/include/uhdlib/rfnoc/rfnoc_common.hpp @@ -0,0 +1,59 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_RFNOC_RFNOC_COMMON_HPP +#define INCLUDED_RFNOC_RFNOC_COMMON_HPP + +#include + +namespace uhd { namespace rfnoc { + +//---------------------------------------------- +// Types +//---------------------------------------------- + +//! Type that indicates the CHDR Width in bits +enum chdr_w_t { CHDR_W_64 = 0, CHDR_W_128 = 1, CHDR_W_256 = 2, CHDR_W_512 = 3 }; +//! Conversion from chdr_w_t to a number of bits +constexpr size_t chdr_w_to_bits(chdr_w_t chdr_w) +{ + switch (chdr_w) { + case CHDR_W_64: + return 64; + case CHDR_W_128: + return 128; + case CHDR_W_256: + return 256; + case CHDR_W_512: + return 512; + default: + return 0; + } +} + +//! Device ID Type +using device_id_t = uint16_t; +//! Stream Endpoint Instance Number Type +using sep_inst_t = uint16_t; +//! Stream Endpoint Physical Address Type +using sep_addr_t = std::pair; +//! Stream Endpoint ID Type +using sep_id_t = uint16_t; + +//! Type of data carried by the stream endpoint +enum class sep_type_t { CTRL, DATA }; + + +//---------------------------------------------- +// Constants +//---------------------------------------------- + +constexpr uint16_t RFNOC_PROTO_VER = 0x0100; + + +}} // namespace uhd::rfnoc + +#endif /* INCLUDED_RFNOC_RFNOC_COMMON_HPP */ diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index 4b36a8db4..45904a572 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -20,6 +20,8 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/block_ctrl_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/blockdef_xml_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/block_id.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chdr_types.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chdr_packet.cpp ${CMAKE_CURRENT_SOURCE_DIR}/client_zero.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ctrl_iface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/graph_impl.cpp @@ -58,5 +60,4 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/replay_block_ctrl_impl.cpp ) -INCLUDE_SUBDIRECTORY(chdr) INCLUDE_SUBDIRECTORY(nocscript) diff --git a/host/lib/rfnoc/chdr/CMakeLists.txt b/host/lib/rfnoc/chdr/CMakeLists.txt deleted file mode 100644 index fca46fe4a..000000000 --- a/host/lib/rfnoc/chdr/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright 2014-2015,2017 Ettus Research LLC -# Copyright 2018 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -######################################################################## -# This file included, use CMake directory variables -######################################################################## - -LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/chdr_types.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/chdr_packet.cpp -) diff --git a/host/lib/rfnoc/chdr/chdr_packet.cpp b/host/lib/rfnoc/chdr/chdr_packet.cpp deleted file mode 100644 index b058115ab..000000000 --- a/host/lib/rfnoc/chdr/chdr_packet.cpp +++ /dev/null @@ -1,213 +0,0 @@ -// -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::rfnoc::chdr; - -chdr_packet::~chdr_packet() = default; - -//------------------------------------------------------------ -// chdr_packet -//------------------------------------------------------------ - -template -class chdr_packet_impl : public chdr_packet -{ -public: - chdr_packet_impl() = delete; - chdr_packet_impl(size_t mtu_bytes) : _mtu_bytes(mtu_bytes) {} - ~chdr_packet_impl() = default; - - virtual void refresh(const void* pkt_buff) const - { - assert(pkt_buff); - _pkt_buff = const_cast(reinterpret_cast(pkt_buff)); - _compute_mdata_offset(); - } - - virtual void refresh(void* pkt_buff, chdr_header& header, uint64_t timestamp = 0) - { - assert(pkt_buff); - _pkt_buff = reinterpret_cast(pkt_buff); - _pkt_buff[0] = u64_from_host(header); - if (_has_timestamp(header)) { - _pkt_buff[1] = timestamp; - } - _compute_mdata_offset(); - } - - virtual void update_payload_size(size_t payload_size_bytes) - { - chdr_header header = get_chdr_header(); - header.set_length(((_mdata_offset + header.get_num_mdata()) * chdr_w_bytes) - + payload_size_bytes); - _pkt_buff[0] = u64_from_host(header); - } - - virtual endianness_t get_byte_order() const - { - return endianness; - } - - virtual size_t get_mtu_bytes() const - { - return _mtu_bytes; - } - - virtual chdr_header get_chdr_header() const - { - assert(_pkt_buff); - return std::move(chdr_header(u64_to_host(_pkt_buff[0]))); - } - - virtual boost::optional get_timestamp() const - { - if (_has_timestamp(get_chdr_header())) { - // In a unit64_t buffer, the timestamp is always immediately after the header - // regardless of chdr_w. - return u64_to_host(_pkt_buff[1]); - } else { - return boost::none; - } - } - - virtual size_t get_mdata_size() const - { - return get_chdr_header().get_num_mdata() * chdr_w_bytes; - } - - virtual const void* get_mdata_const_ptr() const - { - return const_cast( - const_cast*>(this)->get_mdata_ptr()); - } - - virtual void* get_mdata_ptr() - { - return reinterpret_cast(_pkt_buff + (chdr_w_stride * _mdata_offset)); - } - - virtual size_t get_payload_size() const - { - return get_chdr_header().get_length() - get_mdata_size() - - (chdr_w_bytes * _mdata_offset); - } - - virtual const void* get_payload_const_ptr() const - { - return const_cast( - const_cast*>(this)->get_payload_ptr()); - } - - virtual void* get_payload_ptr() - { - return reinterpret_cast( - _pkt_buff - + (chdr_w_stride * (_mdata_offset + get_chdr_header().get_num_mdata()))); - } - -private: - inline bool _has_timestamp(const chdr_header& header) const - { - return (header.get_pkt_type() == PKT_TYPE_DATA_WITH_TS); - } - - inline void _compute_mdata_offset() const - { - // The metadata offset depends on the chdr_w and whether we have a timestamp - if (chdr_w == 64) { - _mdata_offset = _has_timestamp(get_chdr_header()) ? 2 : 1; - } else { - _mdata_offset = 1; - } - } - - inline static uint64_t u64_to_host(uint64_t word) - { - return (endianness == ENDIANNESS_BIG) ? uhd::ntohx(word) - : uhd::wtohx(word); - } - - inline static uint64_t u64_from_host(uint64_t word) - { - return (endianness == ENDIANNESS_BIG) ? uhd::htonx(word) - : uhd::htowx(word); - } - - static const size_t chdr_w_bytes = (chdr_w / 8); - static const size_t chdr_w_stride = (chdr_w / 64); - - // Packet state - const size_t _mtu_bytes = 0; - mutable uint64_t* _pkt_buff = nullptr; - mutable size_t _mdata_offset = 0; -}; - -chdr_packet_factory::chdr_packet_factory(chdr_w_t chdr_w, endianness_t endianness) - : _chdr_w(chdr_w), _endianness(endianness) -{ -} - -chdr_packet::uptr chdr_packet_factory::make_generic(size_t mtu_bytes) const -{ - if (_endianness == ENDIANNESS_BIG) { - switch (_chdr_w) { - case CHDR_W_512: - return std::make_unique>(mtu_bytes); - case CHDR_W_256: - return std::make_unique>(mtu_bytes); - case CHDR_W_128: - return std::make_unique>(mtu_bytes); - case CHDR_W_64: - return std::make_unique>(mtu_bytes); - default: - assert(0); - } - } else { - switch (_chdr_w) { - case CHDR_W_512: - return std::make_unique>( - mtu_bytes); - case CHDR_W_256: - return std::make_unique>( - mtu_bytes); - case CHDR_W_128: - return std::make_unique>( - mtu_bytes); - case CHDR_W_64: - return std::make_unique>( - mtu_bytes); - default: - assert(0); - } - } - return chdr_packet::uptr(); -} - -chdr_ctrl_packet::uptr chdr_packet_factory::make_ctrl(size_t mtu_bytes) const -{ - return std::make_unique(make_generic(mtu_bytes)); -} - -chdr_strs_packet::uptr chdr_packet_factory::make_strs(size_t mtu_bytes) const -{ - return std::make_unique(make_generic(mtu_bytes)); -} - -chdr_strc_packet::uptr chdr_packet_factory::make_strc(size_t mtu_bytes) const -{ - return std::make_unique(make_generic(mtu_bytes)); -} - -chdr_mgmt_packet::uptr chdr_packet_factory::make_mgmt(size_t mtu_bytes) const -{ - return std::make_unique(make_generic(mtu_bytes)); -} diff --git a/host/lib/rfnoc/chdr/chdr_types.cpp b/host/lib/rfnoc/chdr/chdr_types.cpp deleted file mode 100644 index 8920e4fe3..000000000 --- a/host/lib/rfnoc/chdr/chdr_types.cpp +++ /dev/null @@ -1,427 +0,0 @@ -// -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::rfnoc::chdr; - -//---------------------------------------------------- -// Utility Functions -//---------------------------------------------------- - -static inline constexpr uint64_t mask_u64(size_t width) -{ - return ((uint64_t(1) << width) - 1); -} - -template -static inline constexpr field_t get_field_u64( - uint64_t flat_hdr, size_t offset, size_t width) -{ - return static_cast((flat_hdr >> offset) & mask_u64(width)); -} - -//---------------------------------------------------- -// CHDR Control Payload -//---------------------------------------------------- - -void ctrl_payload::populate_header(chdr_header& header) const -{ - header.set_pkt_type(PKT_TYPE_CTRL); - header.set_eob(false); - header.set_eov(false); - header.set_num_mdata(0); -} - -size_t ctrl_payload::serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const -{ - UHD_ASSERT_THROW((data_vtr.size() > 0 && data_vtr.size() < 16)); - // We assume that buff has room to hold the entire packet - size_t ptr = 0; - - // Populate control header - buff[ptr++] = conv_byte_order( - ((static_cast(dst_port) & mask_u64(DST_PORT_WIDTH)) << DST_PORT_OFFSET) - | ((static_cast(src_port) & mask_u64(SRC_PORT_WIDTH)) - << SRC_PORT_OFFSET) - | ((static_cast(data_vtr.size()) & mask_u64(NUM_DATA_WIDTH)) - << NUM_DATA_OFFSET) - | ((static_cast(seq_num) & mask_u64(SEQ_NUM_WIDTH)) << SEQ_NUM_OFFSET) - | ((static_cast(timestamp.is_initialized() ? 1 : 0) - & mask_u64(HAS_TIME_WIDTH)) - << HAS_TIME_OFFSET) - | ((static_cast(is_ack) & mask_u64(IS_ACK_WIDTH)) << IS_ACK_OFFSET) - | ((static_cast(src_epid) & mask_u64(SRC_EPID_WIDTH)) - << SRC_EPID_OFFSET)); - - // Populate optional timestamp - if (timestamp.is_initialized()) { - buff[ptr++] = conv_byte_order(timestamp.get()); - } - - // Populate control operation word - buff[ptr++] = conv_byte_order( - ((static_cast(address) & mask_u64(ADDRESS_WIDTH)) << ADDRESS_OFFSET) - | ((static_cast(byte_enable) & mask_u64(BYTE_ENABLE_WIDTH)) - << BYTE_ENABLE_OFFSET) - | ((static_cast(op_code) & mask_u64(OPCODE_WIDTH)) << OPCODE_OFFSET) - | ((static_cast(status) & mask_u64(STATUS_WIDTH)) << STATUS_OFFSET) - | (static_cast(data_vtr[0]) << HI_DATA_OFFSET)); - - // Populate the rest of the data - for (size_t i = 1; i < data_vtr.size(); i += 2) { - const uint32_t hi_data = - (((i + 2) >= data_vtr.size()) && (data_vtr.size() % 2 == 0)) - ? 0 - : data_vtr[i + 1]; - buff[ptr++] = - conv_byte_order(static_cast(hi_data) << HI_DATA_OFFSET - | static_cast(data_vtr[i]) << LO_DATA_OFFSET); - } - - // FIXME: This UHD_ASSERT_THROW is a bit late because memory has already been - // corrupted - UHD_ASSERT_THROW(ptr <= max_size_bytes); - // Return bytes written - return (ptr * sizeof(uint64_t)); -} - -void ctrl_payload::deserialize(const uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) -{ - // We assume that buff has room to hold the entire packet - size_t ptr = 0; - - // Read control header - uint64_t ctrl_header = conv_byte_order(buff[ptr++]); - data_vtr.resize(get_field_u64(ctrl_header, NUM_DATA_OFFSET, NUM_DATA_WIDTH)); - UHD_ASSERT_THROW((data_vtr.size() > 0 && data_vtr.size() < 16)); - dst_port = get_field_u64(ctrl_header, DST_PORT_OFFSET, DST_PORT_WIDTH); - src_port = get_field_u64(ctrl_header, SRC_PORT_OFFSET, SRC_PORT_WIDTH); - seq_num = get_field_u64(ctrl_header, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH); - is_ack = get_field_u64(ctrl_header, IS_ACK_OFFSET, IS_ACK_WIDTH); - src_epid = get_field_u64(ctrl_header, SRC_EPID_OFFSET, SRC_EPID_WIDTH); - - // Read optional timestamp - if (get_field_u64(ctrl_header, HAS_TIME_OFFSET, HAS_TIME_WIDTH)) { - timestamp = conv_byte_order(buff[ptr++]); - } else { - timestamp = boost::none; - } - - // Read control operation word - uint64_t op_word = conv_byte_order(buff[ptr++]); - if (data_vtr.size() > 0) { - data_vtr[0] = get_field_u64(op_word, HI_DATA_OFFSET, 32); - } - address = get_field_u64(op_word, ADDRESS_OFFSET, ADDRESS_WIDTH); - byte_enable = get_field_u64(op_word, BYTE_ENABLE_OFFSET, BYTE_ENABLE_WIDTH); - op_code = get_field_u64(op_word, OPCODE_OFFSET, OPCODE_WIDTH); - status = get_field_u64(op_word, STATUS_OFFSET, STATUS_WIDTH); - - // Read the rest of the data - for (size_t i = 1; i < data_vtr.size(); i += 2) { - uint64_t data_word = conv_byte_order(buff[ptr++]); - if (((i + 2) < data_vtr.size()) || (data_vtr.size() % 2 != 0)) { - data_vtr[i + 1] = get_field_u64(data_word, HI_DATA_OFFSET, 32); - } - data_vtr[i] = get_field_u64(data_word, LO_DATA_OFFSET, 32); - } - UHD_ASSERT_THROW(ptr <= max_size_bytes); -} - -bool ctrl_payload::operator==(const ctrl_payload& rhs) const -{ - return (dst_port == rhs.dst_port) && (src_port == rhs.src_port) - && (seq_num == rhs.seq_num) - && (timestamp.is_initialized() == rhs.timestamp.is_initialized()) - && ((!timestamp.is_initialized()) || (timestamp.get() == rhs.timestamp.get())) - && (is_ack == rhs.is_ack) && (src_epid == rhs.src_epid) - && (address == rhs.address) && (data_vtr == rhs.data_vtr) - && (byte_enable == rhs.byte_enable) && (op_code == rhs.op_code) - && (status == rhs.status); -} - -const std::string ctrl_payload::to_string() const -{ - return str( - boost::format("ctrl_payload{dst_port:%d, dst_port:%d, seq_num:%d, timestamp:%s, " - "is_ack:%s, src_epid:%d, address:0x%05x, byte_enable:0x%x, " - "op_code:%d, status:%d, data[0]:0x%08x}\n") - % dst_port % src_port % int(seq_num) - % (timestamp.is_initialized() ? str(boost::format("0x%016x") % timestamp.get()) - : std::string("")) - % (is_ack ? "true" : "false") % src_epid % address % int(byte_enable) % op_code - % status % data_vtr[0]); -} - -//---------------------------------------------------- -// CHDR Stream Status Payload -//---------------------------------------------------- - -void strs_payload::populate_header(chdr_header& header) const -{ - header.set_pkt_type(PKT_TYPE_STRS); - header.set_eob(false); - header.set_eov(false); - header.set_num_mdata(0); -} - -size_t strs_payload::serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const -{ - UHD_ASSERT_THROW(max_size_bytes >= (4 * sizeof(uint64_t))); - - // Populate first word - buff[0] = conv_byte_order( - ((static_cast(src_epid) & mask_u64(SRC_EPID_WIDTH)) << SRC_EPID_OFFSET) - | ((static_cast(status) & mask_u64(STATUS_WIDTH)) << STATUS_OFFSET) - | ((static_cast(capacity_bytes) & mask_u64(CAPACITY_BYTES_WIDTH)) - << CAPACITY_BYTES_OFFSET)); - - // Populate second word - buff[1] = conv_byte_order( - ((static_cast(capacity_pkts) & mask_u64(CAPACITY_PKTS_WIDTH)) - << CAPACITY_PKTS_OFFSET) - | ((static_cast(xfer_count_pkts) & mask_u64(XFER_COUNT_PKTS_WIDTH)) - << XFER_COUNT_PKTS_OFFSET)); - - // Populate third word - buff[2] = conv_byte_order(xfer_count_bytes); - - // Populate fourth word - buff[3] = conv_byte_order( - ((static_cast(buff_info) & mask_u64(BUFF_INFO_WIDTH)) - << BUFF_INFO_OFFSET) - | ((static_cast(status_info) & mask_u64(STATUS_INFO_WIDTH)) - << STATUS_INFO_OFFSET)); - - // Return bytes written - return (4 * sizeof(uint64_t)); -} - -void strs_payload::deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order) -{ - UHD_ASSERT_THROW(num_elems >= 4); - - // Read first word - uint64_t word0 = conv_byte_order(buff[0]); - src_epid = get_field_u64(word0, SRC_EPID_OFFSET, SRC_EPID_WIDTH); - status = get_field_u64(word0, STATUS_OFFSET, STATUS_WIDTH); - capacity_bytes = - get_field_u64(word0, CAPACITY_BYTES_OFFSET, CAPACITY_BYTES_WIDTH); - - // Read second word - uint64_t word1 = conv_byte_order(buff[1]); - capacity_pkts = - get_field_u64(word1, CAPACITY_PKTS_OFFSET, CAPACITY_PKTS_WIDTH); - xfer_count_pkts = - get_field_u64(word1, XFER_COUNT_PKTS_OFFSET, XFER_COUNT_PKTS_WIDTH); - - // Read third word - xfer_count_bytes = conv_byte_order(buff[2]); - - // Read fourth word - uint64_t word3 = conv_byte_order(buff[3]); - buff_info = get_field_u64(word3, BUFF_INFO_OFFSET, BUFF_INFO_WIDTH); - status_info = get_field_u64(word3, STATUS_INFO_OFFSET, STATUS_INFO_WIDTH); -} - -bool strs_payload::operator==(const strs_payload& rhs) const -{ - return (src_epid == rhs.src_epid) && (status == rhs.status) - && (capacity_bytes == rhs.capacity_bytes) - && (capacity_pkts == rhs.capacity_pkts) - && (xfer_count_pkts == rhs.xfer_count_pkts) - && (xfer_count_bytes == rhs.xfer_count_bytes) && (buff_info == rhs.buff_info) - && (status_info == rhs.status_info); -} - -const std::string strs_payload::to_string() const -{ - return str(boost::format("strs_payload{src_epid:%lu, status:%d, capacity_bytes:%lu, " - "capacity_pkts:%lu, " - "xfer_count_pkts:%lu, xfer_count_bytes:%lu, " - "buff_info:0x%x, status_info:0x%x}\n") - % src_epid % int(status) % capacity_bytes % capacity_pkts % xfer_count_pkts - % xfer_count_bytes % buff_info % status_info); -} - -//---------------------------------------------------- -// CHDR Stream Command Payload -//---------------------------------------------------- - -void strc_payload::populate_header(chdr_header& header) const -{ - header.set_pkt_type(PKT_TYPE_STRC); - header.set_eob(false); - header.set_eov(false); - header.set_num_mdata(0); -} - -size_t strc_payload::serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const -{ - UHD_ASSERT_THROW(max_size_bytes >= (2 * sizeof(uint64_t))); - - // Populate first word - buff[0] = conv_byte_order( - ((static_cast(src_epid) & mask_u64(SRC_EPID_WIDTH)) << SRC_EPID_OFFSET) - | ((static_cast(op_code) & mask_u64(OP_CODE_WIDTH)) << OP_CODE_OFFSET) - | ((static_cast(op_data) & mask_u64(OP_DATA_WIDTH)) << OP_DATA_OFFSET) - | ((static_cast(num_pkts) & mask_u64(NUM_PKTS_WIDTH)) - << NUM_PKTS_OFFSET)); - - // Populate second word - buff[1] = conv_byte_order(num_bytes); - - // Return bytes written - return (2 * sizeof(uint64_t)); -} - -void strc_payload::deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order) -{ - UHD_ASSERT_THROW(num_elems >= 2); - - // Read first word - uint64_t word0 = conv_byte_order(buff[0]); - src_epid = get_field_u64(word0, SRC_EPID_OFFSET, SRC_EPID_WIDTH); - op_code = get_field_u64(word0, OP_CODE_OFFSET, OP_CODE_WIDTH); - op_data = get_field_u64(word0, OP_DATA_OFFSET, OP_DATA_WIDTH); - num_pkts = get_field_u64(word0, NUM_PKTS_OFFSET, NUM_PKTS_WIDTH); - // Read second word - num_bytes = conv_byte_order(buff[1]); -} - -bool strc_payload::operator==(const strc_payload& rhs) const -{ - return (src_epid == rhs.src_epid) && (op_code == rhs.op_code) - && (op_data == rhs.op_data) && (num_pkts == rhs.num_pkts) - && (num_bytes == rhs.num_bytes); -} - -const std::string strc_payload::to_string() const -{ - return str(boost::format("strc_payload{src_epid:%lu, op_code:%d, op_data:0x%x, " - "num_pkts:%lu, num_bytes:%lu}\n") - % src_epid % int(op_code) % int(op_data) % num_pkts % num_bytes); -} - -//---------------------------------------------------- -// CHDR Management Payload -//---------------------------------------------------- - -//! Serialize this hop into a list of 64-bit words -size_t mgmt_hop_t::serialize(std::vector& target, - const std::function& conv_byte_order) const -{ - for (size_t i = 0; i < get_num_ops(); i++) { - target.push_back( - conv_byte_order((static_cast(_ops.at(i).get_op_payload()) << 16) - | (static_cast(_ops.at(i).get_op_code()) << 8) - | (static_cast(get_num_ops() - i - 1) << 0))); - } - return get_num_ops(); -} - -//! Deserialize this hop into from list of 64-bit words -void mgmt_hop_t::deserialize( - std::list& src, const std::function& conv_byte_order) -{ - _ops.clear(); - size_t ops_remaining = 0; - do { - // TODO: Change this to a legit exception - UHD_ASSERT_THROW(!src.empty()); - - uint64_t op_word = conv_byte_order(src.front()); - ops_remaining = static_cast(op_word & 0xFF); - mgmt_op_t op(static_cast((op_word >> 8) & 0xFF), - static_cast((op_word >> 16))); - _ops.push_back(op); - src.pop_front(); - } while (ops_remaining > 0); -} - -void mgmt_payload::populate_header(chdr_header& header) const -{ - header.set_pkt_type(PKT_TYPE_MGMT); - header.set_eob(false); - header.set_eov(false); - header.set_num_mdata(0); - header.set_vc(0); - header.set_dst_epid(0); -} - -size_t mgmt_payload::serialize(uint64_t* buff, - size_t max_size_bytes, - const std::function& conv_byte_order) const -{ - std::vector target; - // Insert header - target.push_back(conv_byte_order( - (static_cast(_protover) << 48) - | (static_cast(static_cast(_chdr_w) & 0x7) << 45) - | (static_cast(get_num_hops() & 0x3FF) << 16) - | (static_cast(_src_epid) << 0))); - // Insert data from each hop - for (const auto& hop : _hops) { - hop.serialize(target, conv_byte_order); - } - UHD_ASSERT_THROW(target.size() <= max_size_bytes); - - // We use a vector and copy just for ease of implementation - // These transactions are not performance critical - std::copy(target.begin(), target.end(), buff); - return (target.size() * sizeof(uint64_t)); -} - -void mgmt_payload::deserialize(const uint64_t* buff, - size_t num_elems, - const std::function& conv_byte_order) -{ - UHD_ASSERT_THROW(num_elems > 1); - - // We use a list and copy just for ease of implementation - // These transactions are not performance critical - std::list src_list(buff, buff + num_elems); - - _hops.clear(); - - // Deframe the header - uint64_t hdr = conv_byte_order(src_list.front()); - _hops.resize(static_cast((hdr >> 16) & 0x3FF)); - _src_epid = static_cast(hdr & 0xFFFF); - _chdr_w = static_cast((hdr >> 45) & 0x7); - _protover = static_cast((hdr >> 48) & 0xFFFF); - src_list.pop_front(); - - // Populate all hops - for (size_t i = 0; i < get_num_hops(); i++) { - _hops[i].deserialize(src_list, conv_byte_order); - } -} - -const std::string mgmt_payload::to_string() const -{ - return str(boost::format( - "mgmt_payload{src_epid:%lu, chdr_w:%d, protover:0x%x, num_hops:%lu}\n") - % _src_epid % int(_chdr_w) % _protover % _hops.size()); -} diff --git a/host/lib/rfnoc/chdr_ctrl_endpoint.cpp b/host/lib/rfnoc/chdr_ctrl_endpoint.cpp index 6ded83c0f..fadba566e 100644 --- a/host/lib/rfnoc/chdr_ctrl_endpoint.cpp +++ b/host/lib/rfnoc/chdr_ctrl_endpoint.cpp @@ -8,13 +8,13 @@ #include #include #include -#include -#include #include +#include +#include #include +#include #include #include -#include using namespace uhd; using namespace uhd::rfnoc; diff --git a/host/lib/rfnoc/chdr_packet.cpp b/host/lib/rfnoc/chdr_packet.cpp new file mode 100644 index 000000000..653181c04 --- /dev/null +++ b/host/lib/rfnoc/chdr_packet.cpp @@ -0,0 +1,214 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::rfnoc; +using namespace uhd::rfnoc::chdr; + +chdr_packet::~chdr_packet() = default; + +//------------------------------------------------------------ +// chdr_packet +//------------------------------------------------------------ +// endianness is the link endianness, not the host endianness +template +class chdr_packet_impl : public chdr_packet +{ +public: + chdr_packet_impl() = delete; + chdr_packet_impl(size_t mtu_bytes) : _mtu_bytes(mtu_bytes) {} + ~chdr_packet_impl() = default; + + virtual void refresh(const void* pkt_buff) const + { + assert(pkt_buff); + _pkt_buff = const_cast(reinterpret_cast(pkt_buff)); + _compute_mdata_offset(); + } + + virtual void refresh(void* pkt_buff, chdr_header& header, uint64_t timestamp = 0) + { + assert(pkt_buff); + _pkt_buff = reinterpret_cast(pkt_buff); + _pkt_buff[0] = u64_from_host(header); + if (_has_timestamp(header)) { + _pkt_buff[1] = u64_from_host(timestamp); + } + _compute_mdata_offset(); + } + + virtual void update_payload_size(size_t payload_size_bytes) + { + chdr_header header = get_chdr_header(); + header.set_length(((_mdata_offset + header.get_num_mdata()) * chdr_w_bytes) + + payload_size_bytes); + _pkt_buff[0] = u64_from_host(header); + } + + virtual endianness_t get_byte_order() const + { + return endianness; + } + + virtual size_t get_mtu_bytes() const + { + return _mtu_bytes; + } + + virtual chdr_header get_chdr_header() const + { + assert(_pkt_buff); + return std::move(chdr_header(u64_to_host(_pkt_buff[0]))); + } + + virtual boost::optional get_timestamp() const + { + if (_has_timestamp(get_chdr_header())) { + // In a unit64_t buffer, the timestamp is always immediately after the header + // regardless of chdr_w. + return u64_to_host(_pkt_buff[1]); + } else { + return boost::none; + } + } + + virtual size_t get_mdata_size() const + { + return get_chdr_header().get_num_mdata() * chdr_w_bytes; + } + + virtual const void* get_mdata_const_ptr() const + { + return const_cast( + const_cast*>(this)->get_mdata_ptr()); + } + + virtual void* get_mdata_ptr() + { + return reinterpret_cast(_pkt_buff + (chdr_w_stride * _mdata_offset)); + } + + virtual size_t get_payload_size() const + { + return get_chdr_header().get_length() - get_mdata_size() + - (chdr_w_bytes * _mdata_offset); + } + + virtual const void* get_payload_const_ptr() const + { + return const_cast( + const_cast*>(this)->get_payload_ptr()); + } + + virtual void* get_payload_ptr() + { + return reinterpret_cast( + _pkt_buff + + (chdr_w_stride * (_mdata_offset + get_chdr_header().get_num_mdata()))); + } + +private: + inline bool _has_timestamp(const chdr_header& header) const + { + return (header.get_pkt_type() == PKT_TYPE_DATA_WITH_TS); + } + + inline void _compute_mdata_offset() const + { + // The metadata offset depends on the chdr_w and whether we have a timestamp + if (chdr_w == 64) { + _mdata_offset = _has_timestamp(get_chdr_header()) ? 2 : 1; + } else { + _mdata_offset = 1; + } + } + + inline static uint64_t u64_to_host(uint64_t word) + { + return (endianness == ENDIANNESS_BIG) ? uhd::ntohx(word) + : uhd::wtohx(word); + } + + inline static uint64_t u64_from_host(uint64_t word) + { + return (endianness == ENDIANNESS_BIG) ? uhd::htonx(word) + : uhd::htowx(word); + } + + static const size_t chdr_w_bytes = (chdr_w / 8); + static const size_t chdr_w_stride = (chdr_w / 64); + + // Packet state + const size_t _mtu_bytes = 0; + mutable uint64_t* _pkt_buff = nullptr; + mutable size_t _mdata_offset = 0; +}; + +chdr_packet_factory::chdr_packet_factory(chdr_w_t chdr_w, endianness_t endianness) + : _chdr_w(chdr_w), _endianness(endianness) +{ +} + +chdr_packet::uptr chdr_packet_factory::make_generic(size_t mtu_bytes) const +{ + if (_endianness == ENDIANNESS_BIG) { + switch (_chdr_w) { + case CHDR_W_512: + return std::make_unique>(mtu_bytes); + case CHDR_W_256: + return std::make_unique>(mtu_bytes); + case CHDR_W_128: + return std::make_unique>(mtu_bytes); + case CHDR_W_64: + return std::make_unique>(mtu_bytes); + default: + assert(0); + } + } else { + switch (_chdr_w) { + case CHDR_W_512: + return std::make_unique>( + mtu_bytes); + case CHDR_W_256: + return std::make_unique>( + mtu_bytes); + case CHDR_W_128: + return std::make_unique>( + mtu_bytes); + case CHDR_W_64: + return std::make_unique>( + mtu_bytes); + default: + assert(0); + } + } + return chdr_packet::uptr(); +} + +chdr_ctrl_packet::uptr chdr_packet_factory::make_ctrl(size_t mtu_bytes) const +{ + return std::make_unique(make_generic(mtu_bytes)); +} + +chdr_strs_packet::uptr chdr_packet_factory::make_strs(size_t mtu_bytes) const +{ + return std::make_unique(make_generic(mtu_bytes)); +} + +chdr_strc_packet::uptr chdr_packet_factory::make_strc(size_t mtu_bytes) const +{ + return std::make_unique(make_generic(mtu_bytes)); +} + +chdr_mgmt_packet::uptr chdr_packet_factory::make_mgmt(size_t mtu_bytes) const +{ + return std::make_unique(make_generic(mtu_bytes)); +} diff --git a/host/lib/rfnoc/chdr_types.cpp b/host/lib/rfnoc/chdr_types.cpp new file mode 100644 index 000000000..0e30dca7e --- /dev/null +++ b/host/lib/rfnoc/chdr_types.cpp @@ -0,0 +1,427 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::rfnoc::chdr; + +//---------------------------------------------------- +// Utility Functions +//---------------------------------------------------- + +static inline constexpr uint64_t mask_u64(size_t width) +{ + return ((uint64_t(1) << width) - 1); +} + +template +static inline constexpr field_t get_field_u64( + uint64_t flat_hdr, size_t offset, size_t width) +{ + return static_cast((flat_hdr >> offset) & mask_u64(width)); +} + +//---------------------------------------------------- +// CHDR Control Payload +//---------------------------------------------------- + +void ctrl_payload::populate_header(chdr_header& header) const +{ + header.set_pkt_type(PKT_TYPE_CTRL); + header.set_eob(false); + header.set_eov(false); + header.set_num_mdata(0); +} + +size_t ctrl_payload::serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const +{ + UHD_ASSERT_THROW((data_vtr.size() > 0 && data_vtr.size() < 16)); + // We assume that buff has room to hold the entire packet + size_t ptr = 0; + + // Populate control header + buff[ptr++] = conv_byte_order( + ((static_cast(dst_port) & mask_u64(DST_PORT_WIDTH)) << DST_PORT_OFFSET) + | ((static_cast(src_port) & mask_u64(SRC_PORT_WIDTH)) + << SRC_PORT_OFFSET) + | ((static_cast(data_vtr.size()) & mask_u64(NUM_DATA_WIDTH)) + << NUM_DATA_OFFSET) + | ((static_cast(seq_num) & mask_u64(SEQ_NUM_WIDTH)) << SEQ_NUM_OFFSET) + | ((static_cast(timestamp.is_initialized() ? 1 : 0) + & mask_u64(HAS_TIME_WIDTH)) + << HAS_TIME_OFFSET) + | ((static_cast(is_ack) & mask_u64(IS_ACK_WIDTH)) << IS_ACK_OFFSET) + | ((static_cast(src_epid) & mask_u64(SRC_EPID_WIDTH)) + << SRC_EPID_OFFSET)); + + // Populate optional timestamp + if (timestamp.is_initialized()) { + buff[ptr++] = conv_byte_order(timestamp.get()); + } + + // Populate control operation word + buff[ptr++] = conv_byte_order( + ((static_cast(address) & mask_u64(ADDRESS_WIDTH)) << ADDRESS_OFFSET) + | ((static_cast(byte_enable) & mask_u64(BYTE_ENABLE_WIDTH)) + << BYTE_ENABLE_OFFSET) + | ((static_cast(op_code) & mask_u64(OPCODE_WIDTH)) << OPCODE_OFFSET) + | ((static_cast(status) & mask_u64(STATUS_WIDTH)) << STATUS_OFFSET) + | (static_cast(data_vtr[0]) << HI_DATA_OFFSET)); + + // Populate the rest of the data + for (size_t i = 1; i < data_vtr.size(); i += 2) { + const uint32_t hi_data = + (((i + 2) >= data_vtr.size()) && (data_vtr.size() % 2 == 0)) + ? 0 + : data_vtr[i + 1]; + buff[ptr++] = + conv_byte_order(static_cast(hi_data) << HI_DATA_OFFSET + | static_cast(data_vtr[i]) << LO_DATA_OFFSET); + } + + // FIXME: This UHD_ASSERT_THROW is a bit late because memory has already been + // corrupted + UHD_ASSERT_THROW(ptr <= max_size_bytes); + // Return bytes written + return (ptr * sizeof(uint64_t)); +} + +void ctrl_payload::deserialize(const uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) +{ + // We assume that buff has room to hold the entire packet + size_t ptr = 0; + + // Read control header + uint64_t ctrl_header = conv_byte_order(buff[ptr++]); + data_vtr.resize(get_field_u64(ctrl_header, NUM_DATA_OFFSET, NUM_DATA_WIDTH)); + UHD_ASSERT_THROW((data_vtr.size() > 0 && data_vtr.size() < 16)); + dst_port = get_field_u64(ctrl_header, DST_PORT_OFFSET, DST_PORT_WIDTH); + src_port = get_field_u64(ctrl_header, SRC_PORT_OFFSET, SRC_PORT_WIDTH); + seq_num = get_field_u64(ctrl_header, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH); + is_ack = get_field_u64(ctrl_header, IS_ACK_OFFSET, IS_ACK_WIDTH); + src_epid = get_field_u64(ctrl_header, SRC_EPID_OFFSET, SRC_EPID_WIDTH); + + // Read optional timestamp + if (get_field_u64(ctrl_header, HAS_TIME_OFFSET, HAS_TIME_WIDTH)) { + timestamp = conv_byte_order(buff[ptr++]); + } else { + timestamp = boost::none; + } + + // Read control operation word + uint64_t op_word = conv_byte_order(buff[ptr++]); + if (data_vtr.size() > 0) { + data_vtr[0] = get_field_u64(op_word, HI_DATA_OFFSET, 32); + } + address = get_field_u64(op_word, ADDRESS_OFFSET, ADDRESS_WIDTH); + byte_enable = get_field_u64(op_word, BYTE_ENABLE_OFFSET, BYTE_ENABLE_WIDTH); + op_code = get_field_u64(op_word, OPCODE_OFFSET, OPCODE_WIDTH); + status = get_field_u64(op_word, STATUS_OFFSET, STATUS_WIDTH); + + // Read the rest of the data + for (size_t i = 1; i < data_vtr.size(); i += 2) { + uint64_t data_word = conv_byte_order(buff[ptr++]); + if (((i + 2) < data_vtr.size()) || (data_vtr.size() % 2 != 0)) { + data_vtr[i + 1] = get_field_u64(data_word, HI_DATA_OFFSET, 32); + } + data_vtr[i] = get_field_u64(data_word, LO_DATA_OFFSET, 32); + } + UHD_ASSERT_THROW(ptr <= max_size_bytes); +} + +bool ctrl_payload::operator==(const ctrl_payload& rhs) const +{ + return (dst_port == rhs.dst_port) && (src_port == rhs.src_port) + && (seq_num == rhs.seq_num) + && (timestamp.is_initialized() == rhs.timestamp.is_initialized()) + && ((!timestamp.is_initialized()) || (timestamp.get() == rhs.timestamp.get())) + && (is_ack == rhs.is_ack) && (src_epid == rhs.src_epid) + && (address == rhs.address) && (data_vtr == rhs.data_vtr) + && (byte_enable == rhs.byte_enable) && (op_code == rhs.op_code) + && (status == rhs.status); +} + +const std::string ctrl_payload::to_string() const +{ + return str( + boost::format("ctrl_payload{dst_port:%d, dst_port:%d, seq_num:%d, timestamp:%s, " + "is_ack:%s, src_epid:%d, address:0x%05x, byte_enable:0x%x, " + "op_code:%d, status:%d, data[0]:0x%08x}\n") + % dst_port % src_port % int(seq_num) + % (timestamp.is_initialized() ? str(boost::format("0x%016x") % timestamp.get()) + : std::string("")) + % (is_ack ? "true" : "false") % src_epid % address % int(byte_enable) % op_code + % status % data_vtr[0]); +} + +//---------------------------------------------------- +// CHDR Stream Status Payload +//---------------------------------------------------- + +void strs_payload::populate_header(chdr_header& header) const +{ + header.set_pkt_type(PKT_TYPE_STRS); + header.set_eob(false); + header.set_eov(false); + header.set_num_mdata(0); +} + +size_t strs_payload::serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const +{ + UHD_ASSERT_THROW(max_size_bytes >= (4 * sizeof(uint64_t))); + + // Populate first word + buff[0] = conv_byte_order( + ((static_cast(src_epid) & mask_u64(SRC_EPID_WIDTH)) << SRC_EPID_OFFSET) + | ((static_cast(status) & mask_u64(STATUS_WIDTH)) << STATUS_OFFSET) + | ((static_cast(capacity_bytes) & mask_u64(CAPACITY_BYTES_WIDTH)) + << CAPACITY_BYTES_OFFSET)); + + // Populate second word + buff[1] = conv_byte_order( + ((static_cast(capacity_pkts) & mask_u64(CAPACITY_PKTS_WIDTH)) + << CAPACITY_PKTS_OFFSET) + | ((static_cast(xfer_count_pkts) & mask_u64(XFER_COUNT_PKTS_WIDTH)) + << XFER_COUNT_PKTS_OFFSET)); + + // Populate third word + buff[2] = conv_byte_order(xfer_count_bytes); + + // Populate fourth word + buff[3] = conv_byte_order( + ((static_cast(buff_info) & mask_u64(BUFF_INFO_WIDTH)) + << BUFF_INFO_OFFSET) + | ((static_cast(status_info) & mask_u64(STATUS_INFO_WIDTH)) + << STATUS_INFO_OFFSET)); + + // Return bytes written + return (4 * sizeof(uint64_t)); +} + +void strs_payload::deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order) +{ + UHD_ASSERT_THROW(num_elems >= 4); + + // Read first word + uint64_t word0 = conv_byte_order(buff[0]); + src_epid = get_field_u64(word0, SRC_EPID_OFFSET, SRC_EPID_WIDTH); + status = get_field_u64(word0, STATUS_OFFSET, STATUS_WIDTH); + capacity_bytes = + get_field_u64(word0, CAPACITY_BYTES_OFFSET, CAPACITY_BYTES_WIDTH); + + // Read second word + uint64_t word1 = conv_byte_order(buff[1]); + capacity_pkts = + get_field_u64(word1, CAPACITY_PKTS_OFFSET, CAPACITY_PKTS_WIDTH); + xfer_count_pkts = + get_field_u64(word1, XFER_COUNT_PKTS_OFFSET, XFER_COUNT_PKTS_WIDTH); + + // Read third word + xfer_count_bytes = conv_byte_order(buff[2]); + + // Read fourth word + uint64_t word3 = conv_byte_order(buff[3]); + buff_info = get_field_u64(word3, BUFF_INFO_OFFSET, BUFF_INFO_WIDTH); + status_info = get_field_u64(word3, STATUS_INFO_OFFSET, STATUS_INFO_WIDTH); +} + +bool strs_payload::operator==(const strs_payload& rhs) const +{ + return (src_epid == rhs.src_epid) && (status == rhs.status) + && (capacity_bytes == rhs.capacity_bytes) + && (capacity_pkts == rhs.capacity_pkts) + && (xfer_count_pkts == rhs.xfer_count_pkts) + && (xfer_count_bytes == rhs.xfer_count_bytes) && (buff_info == rhs.buff_info) + && (status_info == rhs.status_info); +} + +const std::string strs_payload::to_string() const +{ + return str(boost::format("strs_payload{src_epid:%lu, status:%d, capacity_bytes:%lu, " + "capacity_pkts:%lu, " + "xfer_count_pkts:%lu, xfer_count_bytes:%lu, " + "buff_info:0x%x, status_info:0x%x}\n") + % src_epid % int(status) % capacity_bytes % capacity_pkts % xfer_count_pkts + % xfer_count_bytes % buff_info % status_info); +} + +//---------------------------------------------------- +// CHDR Stream Command Payload +//---------------------------------------------------- + +void strc_payload::populate_header(chdr_header& header) const +{ + header.set_pkt_type(PKT_TYPE_STRC); + header.set_eob(false); + header.set_eov(false); + header.set_num_mdata(0); +} + +size_t strc_payload::serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const +{ + UHD_ASSERT_THROW(max_size_bytes >= (2 * sizeof(uint64_t))); + + // Populate first word + buff[0] = conv_byte_order( + ((static_cast(src_epid) & mask_u64(SRC_EPID_WIDTH)) << SRC_EPID_OFFSET) + | ((static_cast(op_code) & mask_u64(OP_CODE_WIDTH)) << OP_CODE_OFFSET) + | ((static_cast(op_data) & mask_u64(OP_DATA_WIDTH)) << OP_DATA_OFFSET) + | ((static_cast(num_pkts) & mask_u64(NUM_PKTS_WIDTH)) + << NUM_PKTS_OFFSET)); + + // Populate second word + buff[1] = conv_byte_order(num_bytes); + + // Return bytes written + return (2 * sizeof(uint64_t)); +} + +void strc_payload::deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order) +{ + UHD_ASSERT_THROW(num_elems >= 2); + + // Read first word + uint64_t word0 = conv_byte_order(buff[0]); + src_epid = get_field_u64(word0, SRC_EPID_OFFSET, SRC_EPID_WIDTH); + op_code = get_field_u64(word0, OP_CODE_OFFSET, OP_CODE_WIDTH); + op_data = get_field_u64(word0, OP_DATA_OFFSET, OP_DATA_WIDTH); + num_pkts = get_field_u64(word0, NUM_PKTS_OFFSET, NUM_PKTS_WIDTH); + // Read second word + num_bytes = conv_byte_order(buff[1]); +} + +bool strc_payload::operator==(const strc_payload& rhs) const +{ + return (src_epid == rhs.src_epid) && (op_code == rhs.op_code) + && (op_data == rhs.op_data) && (num_pkts == rhs.num_pkts) + && (num_bytes == rhs.num_bytes); +} + +const std::string strc_payload::to_string() const +{ + return str(boost::format("strc_payload{src_epid:%lu, op_code:%d, op_data:0x%x, " + "num_pkts:%lu, num_bytes:%lu}\n") + % src_epid % int(op_code) % int(op_data) % num_pkts % num_bytes); +} + +//---------------------------------------------------- +// CHDR Management Payload +//---------------------------------------------------- + +//! Serialize this hop into a list of 64-bit words +size_t mgmt_hop_t::serialize(std::vector& target, + const std::function& conv_byte_order) const +{ + for (size_t i = 0; i < get_num_ops(); i++) { + target.push_back( + conv_byte_order((static_cast(_ops.at(i).get_op_payload()) << 16) + | (static_cast(_ops.at(i).get_op_code()) << 8) + | (static_cast(get_num_ops() - i - 1) << 0))); + } + return get_num_ops(); +} + +//! Deserialize this hop into from list of 64-bit words +void mgmt_hop_t::deserialize( + std::list& src, const std::function& conv_byte_order) +{ + _ops.clear(); + size_t ops_remaining = 0; + do { + // TODO: Change this to a legit exception + UHD_ASSERT_THROW(!src.empty()); + + uint64_t op_word = conv_byte_order(src.front()); + ops_remaining = static_cast(op_word & 0xFF); + mgmt_op_t op(static_cast((op_word >> 8) & 0xFF), + static_cast((op_word >> 16))); + _ops.push_back(op); + src.pop_front(); + } while (ops_remaining > 0); +} + +void mgmt_payload::populate_header(chdr_header& header) const +{ + header.set_pkt_type(PKT_TYPE_MGMT); + header.set_eob(false); + header.set_eov(false); + header.set_num_mdata(0); + header.set_vc(0); + header.set_dst_epid(0); +} + +size_t mgmt_payload::serialize(uint64_t* buff, + size_t max_size_bytes, + const std::function& conv_byte_order) const +{ + std::vector target; + // Insert header + target.push_back(conv_byte_order( + (static_cast(_protover) << 48) + | (static_cast(static_cast(_chdr_w) & 0x7) << 45) + | (static_cast(get_num_hops() & 0x3FF) << 16) + | (static_cast(_src_epid) << 0))); + // Insert data from each hop + for (const auto& hop : _hops) { + hop.serialize(target, conv_byte_order); + } + UHD_ASSERT_THROW(target.size() <= max_size_bytes); + + // We use a vector and copy just for ease of implementation + // These transactions are not performance critical + std::copy(target.begin(), target.end(), buff); + return (target.size() * sizeof(uint64_t)); +} + +void mgmt_payload::deserialize(const uint64_t* buff, + size_t num_elems, + const std::function& conv_byte_order) +{ + UHD_ASSERT_THROW(num_elems > 1); + + // We use a list and copy just for ease of implementation + // These transactions are not performance critical + std::list src_list(buff, buff + num_elems); + + _hops.clear(); + + // Deframe the header + uint64_t hdr = conv_byte_order(src_list.front()); + _hops.resize(static_cast((hdr >> 16) & 0x3FF)); + _src_epid = static_cast(hdr & 0xFFFF); + _chdr_w = static_cast((hdr >> 45) & 0x7); + _protover = static_cast((hdr >> 48) & 0xFFFF); + src_list.pop_front(); + + // Populate all hops + for (size_t i = 0; i < get_num_hops(); i++) { + _hops[i].deserialize(src_list, conv_byte_order); + } +} + +const std::string mgmt_payload::to_string() const +{ + return str(boost::format( + "mgmt_payload{src_epid:%lu, chdr_w:%d, protover:0x%x, num_hops:%lu}\n") + % _src_epid % int(_chdr_w) % _protover % _hops.size()); +} diff --git a/host/lib/rfnoc/ctrlport_endpoint.cpp b/host/lib/rfnoc/ctrlport_endpoint.cpp index d5f4ef98c..93236940f 100644 --- a/host/lib/rfnoc/ctrlport_endpoint.cpp +++ b/host/lib/rfnoc/ctrlport_endpoint.cpp @@ -6,8 +6,8 @@ #include #include -#include -#include +#include +#include #include #include #include diff --git a/host/lib/rfnoc/mgmt_portal.cpp b/host/lib/rfnoc/mgmt_portal.cpp index fcb19997e..76d708a0e 100644 --- a/host/lib/rfnoc/mgmt_portal.cpp +++ b/host/lib/rfnoc/mgmt_portal.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 0c48ae058..bd0964def 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -229,11 +229,11 @@ UHD_ADD_NONAPI_TEST( UHD_ADD_NONAPI_TEST( TARGET rfnoc_chdr_test.cpp EXTRA_SOURCES - ${CMAKE_SOURCE_DIR}/lib/rfnoc/chdr/chdr_types.cpp - ${CMAKE_SOURCE_DIR}/lib/rfnoc/chdr/chdr_packet.cpp + ${CMAKE_SOURCE_DIR}/lib/rfnoc/chdr_types.cpp + ${CMAKE_SOURCE_DIR}/lib/rfnoc/chdr_packet.cpp INCLUDE_DIRS - ${CMAKE_BINARY_DIR}/lib/rfnoc/chdr/ - ${CMAKE_SOURCE_DIR}/lib/rfnoc/chdr/ + ${CMAKE_BINARY_DIR}/lib/rfnoc/ + ${CMAKE_SOURCE_DIR}/lib/rfnoc/ ) UHD_ADD_NONAPI_TEST( diff --git a/host/tests/rfnoc_chdr_test.cpp b/host/tests/rfnoc_chdr_test.cpp index 67993cb02..417ed2f96 100644 --- a/host/tests/rfnoc_chdr_test.cpp +++ b/host/tests/rfnoc_chdr_test.cpp @@ -6,8 +6,8 @@ #include #include -#include -#include +#include +#include #include #include #include -- cgit v1.2.3