diff options
author | Martin Braun <martin.braun@ettus.com> | 2016-11-01 16:45:29 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-03-16 10:48:46 -0700 |
commit | 49520bfecb5e13126224ee915208c2cd936f911c (patch) | |
tree | 8daa638d55ffe5294306a6fe8e2c8b6261d8a375 /host | |
parent | 60a911cd460ca1e29d838ee0039d67bf7c8fe7f3 (diff) | |
download | uhd-49520bfecb5e13126224ee915208c2cd936f911c.tar.gz uhd-49520bfecb5e13126224ee915208c2cd936f911c.tar.bz2 uhd-49520bfecb5e13126224ee915208c2cd936f911c.zip |
rfnoc: ctrl_iface cleanup
- ctrl_iface is now longer a wb_iface. All it can do now is send command
packets, and receive responses to those.
- ctrl_iface does not store command time or tick rate
- wb_iface_adapter is no longer a set of functors, but a wrapper around
ctrl_iface. Command times are stored once, in the block.
- DMA FIFO and radio block controllers have an easier time getting
access to a timed_wb_iface
Diffstat (limited to 'host')
-rw-r--r-- | host/include/uhd/rfnoc/block_ctrl_base.hpp | 17 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/constants.hpp | 2 | ||||
-rw-r--r-- | host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp | 52 | ||||
-rw-r--r-- | host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp | 53 | ||||
-rw-r--r-- | host/lib/rfnoc/block_ctrl_base.cpp | 87 | ||||
-rw-r--r-- | host/lib/rfnoc/ctrl_iface.cpp | 219 | ||||
-rw-r--r-- | host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp | 20 | ||||
-rw-r--r-- | host/lib/rfnoc/radio_ctrl_impl.cpp | 24 | ||||
-rw-r--r-- | host/lib/rfnoc/wb_iface_adapter.cpp | 50 | ||||
-rw-r--r-- | host/lib/usrp/device3/device3_impl.cpp | 12 | ||||
-rw-r--r-- | host/tests/device3_test.cpp | 63 |
11 files changed, 261 insertions, 338 deletions
diff --git a/host/include/uhd/rfnoc/block_ctrl_base.hpp b/host/include/uhd/rfnoc/block_ctrl_base.hpp index 25b1e4a09..70725627a 100644 --- a/host/include/uhd/rfnoc/block_ctrl_base.hpp +++ b/host/include/uhd/rfnoc/block_ctrl_base.hpp @@ -24,8 +24,9 @@ namespace uhd { namespace rfnoc { + // Forward declarations + class ctrl_iface; namespace nocscript { - // Forward declaration class block_iface; } @@ -39,8 +40,8 @@ struct make_args_t block_key(key) {} - //! A valid interface that allows us to do peeks and pokes - std::map<size_t, uhd::wb_iface::sptr> ctrl_ifaces; + //! A valid interface that allows us to read and write registers + std::map<size_t, boost::shared_ptr<ctrl_iface> > ctrl_ifaces; //! This block's base address (address of block port 0) uint32_t base_address; //! The device index (or motherboard index). @@ -359,8 +360,7 @@ protected: }; //! Get a control interface object for block port \p block_port - wb_iface::sptr get_ctrl_iface(const size_t block_port); - + timed_wb_iface::sptr get_ctrl_iface(const size_t block_port); /*********************************************************************** * Hooks & Derivables @@ -397,11 +397,16 @@ private: //! Helper function to initialize the block args (used by ctor only) void _init_block_args(); + //! Helper to create a lambda to read tick rate + double get_command_tick_rate(const size_t port); + /*********************************************************************** * Private members **********************************************************************/ //! Objects to actually send and receive the commands - std::map<size_t, wb_iface::sptr> _ctrl_ifaces; + std::map<size_t, boost::shared_ptr<ctrl_iface> > _ctrl_ifaces; + std::map<size_t, time_spec_t> _cmd_timespecs; + std::map<size_t, double> _cmd_tickrates; //! The base address of this block (the address of block port 0) uint32_t _base_address; diff --git a/host/include/uhd/rfnoc/constants.hpp b/host/include/uhd/rfnoc/constants.hpp index 53514c157..94cca3e7a 100644 --- a/host/include/uhd/rfnoc/constants.hpp +++ b/host/include/uhd/rfnoc/constants.hpp @@ -80,6 +80,8 @@ static const uint32_t AXI_WRAPPER_BASE = 128; static const uint32_t AXIS_CONFIG_BUS = AXI_WRAPPER_BASE+1; // tdata with tvalid asserted static const uint32_t AXIS_CONFIG_BUS_TLAST = AXI_WRAPPER_BASE+2; // tdata with tvalid & tlast asserted +static const size_t CMD_FIFO_SIZE = 128; // Lines == multiples of 8 bytes + // Named settings registers static const uhd::dict<std::string, uint32_t> DEFAULT_NAMED_SR = boost::assign::map_list_of ("AXIS_CONFIG_BUS", AXIS_CONFIG_BUS) diff --git a/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp b/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp index 2ef50a1a1..d89dea534 100644 --- a/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp +++ b/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp @@ -8,37 +8,57 @@ #ifndef INCLUDED_LIBUHD_RFNOC_CTRL_IFACE_HPP #define INCLUDED_LIBUHD_RFNOC_CTRL_IFACE_HPP -#include <uhd/utils/msg_task.hpp> -#include <uhd/types/time_spec.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <uhd/types/wb_iface.hpp> +#include "xports.hpp" #include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> #include <string> namespace uhd { namespace rfnoc { /*! - * Provide access to peek, poke for the radio ctrl module + * Provide read/write access to registers on an RFNoC block via Noc-Shell. */ -class ctrl_iface : public uhd::timed_wb_iface +class ctrl_iface { public: typedef boost::shared_ptr<ctrl_iface> sptr; - virtual ~ctrl_iface(void) = 0; - //! Make a new control object + /*! Make a new control object + * + * \param xports Bidirectional transport object to the RFNoC block port. + * \param name Optional name for better identification in error messages. + */ static sptr make( - const bool big_endian, - uhd::transport::zero_copy_if::sptr ctrl_xport, - uhd::transport::zero_copy_if::sptr resp_xport, - const uint32_t sid, - const std::string &name = "0" + const both_xports_t &xports, + const std::string &name="0" ); - //! Set the tick rate (converting time into ticks) - virtual void set_tick_rate(const double rate) = 0; + /*! Send a command packet. + * + * \param addr Register address. This is the value that gets put into the + * command packet, its interpretation is defined on the FPGA. + * \param data Register value to write. + * \param readback If true, assume the command packet is for a readback, + * and wait for a response packet to return. The return + * value will then be the 64-bit payload of that response + * packet. If false, the return value is the payload of + * any outstanding ACK packet. + * \param timestamp Optional timestamp. The command packet will include this + * timestamp. Depending on the block configuration, this + * can trigger timed commands. + * A value of zero indicates that no timestamp will be + * applied. It is not possible to request anything to + * happen at time zero. + * + * \throws uhd::io_error if the response is malformed; uhd::runtime_error if + * no packet could be sent. + */ + virtual uint64_t send_cmd_pkt( + const size_t addr, + const size_t data, + const bool readback=false, + const uint64_t timestamp=0 + ) = 0; }; }} /* namespace uhd::rfnoc */ diff --git a/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp b/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp index 753fa13af..1ed8cf69b 100644 --- a/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp +++ b/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp @@ -9,50 +9,47 @@ #define INCLUDED_RFNOC_WB_IFACE_ADAPTER_HPP #include <uhd/config.hpp> +#include "ctrl_iface.hpp" #include <uhd/types/wb_iface.hpp> #include <boost/function.hpp> namespace uhd { namespace rfnoc { +/*! wb_iface control into RFNoC block registers. + * + * This is specifically for mimicking a wb_iface that talks to an RFNoC block. + * It assumes an underlying ctrl_iface is talking to an RFNoC block. + */ class UHD_API wb_iface_adapter : public uhd::timed_wb_iface { public: - typedef boost::shared_ptr<wb_iface_adapter> sptr; - typedef boost::function<void(wb_addr_type, uint32_t)> poke32_type; - typedef boost::function<uint32_t(wb_addr_type)> peek32_type; - typedef boost::function<uint64_t(wb_addr_type)> peek64_type; - typedef boost::function<time_spec_t(void)> gettime_type; - typedef boost::function<void(const time_spec_t&)> settime_type; + typedef boost::function<double()> gettickrate_type; + typedef boost::function<uhd::time_spec_t()> gettime_type; + typedef boost::function<void(const uhd::time_spec_t &)> settime_type; wb_iface_adapter( - const poke32_type &, - const peek32_type &, - const peek64_type &, - const gettime_type &, - const settime_type & + ctrl_iface::sptr iface, + const gettickrate_type &, + const settime_type &, + const gettime_type & ); - wb_iface_adapter( - const poke32_type &, - const peek32_type &, - const peek64_type & - ); + virtual ~wb_iface_adapter(void) {} - virtual ~wb_iface_adapter(void) {}; - - virtual void poke32(const wb_addr_type addr, const uint32_t data); - virtual uint32_t peek32(const wb_addr_type addr); - virtual uint64_t peek64(const wb_addr_type addr); - virtual time_spec_t get_time(void); - virtual void set_time(const time_spec_t& t); + void poke32(const wb_addr_type addr, const uint32_t data); + uint32_t peek32(const wb_addr_type addr); + uint64_t peek64(const wb_addr_type addr); + time_spec_t get_time() { return gettime_functor(); } + void set_time(const uhd::time_spec_t& t) { settime_functor(t); } private: - const poke32_type poke32_functor; - const peek32_type peek32_functor; - const peek64_type peek64_functor; - const gettime_type gettime_functor; - const settime_type settime_functor; + ctrl_iface::sptr _iface; + const gettickrate_type gettickrate_functor; + const settime_type settime_functor; + const gettime_type gettime_functor; + + inline uint64_t get_timestamp() { return gettime_functor().to_ticks(gettickrate_functor()); } }; }} // namespace uhd::rfnoc diff --git a/host/lib/rfnoc/block_ctrl_base.cpp b/host/lib/rfnoc/block_ctrl_base.cpp index e842dabff..20d79d262 100644 --- a/host/lib/rfnoc/block_ctrl_base.cpp +++ b/host/lib/rfnoc/block_ctrl_base.cpp @@ -16,6 +16,7 @@ #include <uhd/rfnoc/constants.hpp> #include <uhdlib/utils/compat_check.hpp> #include <uhdlib/rfnoc/ctrl_iface.hpp> +#include <uhdlib/rfnoc/wb_iface_adapter.hpp> #include <boost/format.hpp> #include <boost/bind.hpp> @@ -26,13 +27,6 @@ using namespace uhd::rfnoc; using std::string; /*********************************************************************** - * Helpers - **********************************************************************/ -//! Convert register to a peek/poke compatible address -inline uint32_t _sr_to_addr(const uint32_t reg) { return reg * 4; }; -inline uint32_t _sr_to_addr64(const uint32_t reg) { return reg * 8; }; // for peek64 - -/*********************************************************************** * Structors **********************************************************************/ block_ctrl_base::block_ctrl_base( @@ -82,6 +76,9 @@ block_ctrl_base::block_ctrl_base( /*** Configure ports ****************************************************/ size_t n_valid_input_buffers = 0; for(const size_t ctrl_port: get_ctrl_ports()) { + // Set command times to sensible defaults + set_command_tick_rate(1.0, ctrl_port); + set_command_time(time_spec_t(0.0), ctrl_port); // Set source addresses: sr_write(SR_BLOCK_SID, get_address(ctrl_port), ctrl_port); // Set sink buffer sizes: @@ -208,16 +205,21 @@ void block_ctrl_base::_init_block_args() /*********************************************************************** * FPGA control & communication **********************************************************************/ -wb_iface::sptr block_ctrl_base::get_ctrl_iface(const size_t block_port) +timed_wb_iface::sptr block_ctrl_base::get_ctrl_iface(const size_t block_port) { - return _ctrl_ifaces[block_port]; + return boost::make_shared<wb_iface_adapter>( + _ctrl_ifaces[block_port], + boost::bind(&block_ctrl_base::get_command_tick_rate, this, block_port), + boost::bind(&block_ctrl_base::set_command_time, this, _1, block_port), + boost::bind(&block_ctrl_base::get_command_time, this, block_port) + ); } std::vector<size_t> block_ctrl_base::get_ctrl_ports() const { std::vector<size_t> ctrl_ports; ctrl_ports.reserve(_ctrl_ifaces.size()); - std::pair<size_t, wb_iface::sptr> it; + std::pair<size_t, ctrl_iface::sptr> it; for(auto it: _ctrl_ifaces) { ctrl_ports.push_back(it.first); } @@ -232,7 +234,10 @@ void block_ctrl_base::sr_write(const uint32_t reg, const uint32_t data, const si throw uhd::key_error(str(boost::format("[%s] sr_write(): No such port: %d") % get_block_id().get() % port)); } try { - _ctrl_ifaces[port]->poke32(_sr_to_addr(reg), data); + _ctrl_ifaces[port]->send_cmd_pkt( + reg, data, false, + _cmd_timespecs[port].to_ticks(_cmd_tickrates[port]) + ); } catch(const std::exception &ex) { throw uhd::io_error(str(boost::format("[%s] sr_write() failed: %s") % get_block_id().get() % ex.what())); @@ -263,7 +268,11 @@ uint64_t block_ctrl_base::sr_read64(const settingsbus_reg_t reg, const size_t po throw uhd::key_error(str(boost::format("[%s] sr_read64(): No such port: %d") % get_block_id().get() % port)); } try { - return _ctrl_ifaces[port]->peek64(_sr_to_addr64(reg)); + return _ctrl_ifaces[port]->send_cmd_pkt( + SR_READBACK, reg, + true, + _cmd_timespecs[port].to_ticks(_cmd_tickrates[port]) + ); } catch(const std::exception &ex) { throw uhd::io_error(str(boost::format("[%s] sr_read64() failed: %s") % get_block_id().get() % ex.what())); @@ -276,7 +285,11 @@ uint32_t block_ctrl_base::sr_read32(const settingsbus_reg_t reg, const size_t po throw uhd::key_error(str(boost::format("[%s] sr_read32(): No such port: %d") % get_block_id().get() % port)); } try { - return _ctrl_ifaces[port]->peek32(_sr_to_addr64(reg)); + return uint32_t(_ctrl_ifaces[port]->send_cmd_pkt( + SR_READBACK, reg, + true, + _cmd_timespecs[port].to_ticks(_cmd_tickrates[port]) + )); } catch(const std::exception &ex) { throw uhd::io_error(str(boost::format("[%s] sr_read32() failed: %s") % get_block_id().get() % ex.what())); @@ -286,6 +299,7 @@ uint32_t block_ctrl_base::sr_read32(const settingsbus_reg_t reg, const size_t po uint64_t block_ctrl_base::user_reg_read64(const uint32_t addr, const size_t port) { try { + // TODO: When timed readbacks are used, time the second, but not the first // Set readback register address sr_write(SR_READBACK_ADDR, addr, port); // Read readback register via RFNoC @@ -345,32 +359,15 @@ void block_ctrl_base::set_command_time( } return; } - boost::shared_ptr<ctrl_iface> iface_sptr = - boost::dynamic_pointer_cast<ctrl_iface>(get_ctrl_iface(port)); - if (not iface_sptr) { - throw uhd::assertion_error(str( - boost::format("[%s] Cannot set command time on port '%d'") - % unique_id() % port - )); - } - iface_sptr->set_time(time_spec); + _cmd_timespecs[port] = time_spec; _set_command_time(time_spec, port); } time_spec_t block_ctrl_base::get_command_time( const size_t port ) { - boost::shared_ptr<ctrl_iface> iface_sptr = - boost::dynamic_pointer_cast<ctrl_iface>(get_ctrl_iface(port)); - if (not iface_sptr) { - throw uhd::assertion_error(str( - boost::format("[%s] Cannot get command time on port '%d'") - % unique_id() % port - )); - } - - return iface_sptr->get_time(); + return _cmd_timespecs[port]; } void block_ctrl_base::set_command_tick_rate( @@ -383,30 +380,18 @@ void block_ctrl_base::set_command_tick_rate( } return; } - boost::shared_ptr<ctrl_iface> iface_sptr = - boost::dynamic_pointer_cast<ctrl_iface>(get_ctrl_iface(port)); - if (not iface_sptr) { - throw uhd::assertion_error(str( - boost::format("[%s] Cannot set command time on port '%d'") - % unique_id() % port - )); - } - iface_sptr->set_tick_rate(tick_rate); + _cmd_tickrates[port] = tick_rate; } -void block_ctrl_base::clear_command_time(const size_t port) +double block_ctrl_base::get_command_tick_rate(const size_t port) { - boost::shared_ptr<ctrl_iface> iface_sptr = - boost::dynamic_pointer_cast<ctrl_iface>(get_ctrl_iface(port)); - if (not iface_sptr) { - throw uhd::assertion_error(str( - boost::format("[%s] Cannot set command time on port '%d'") - % unique_id() % port - )); - } + return _cmd_tickrates[port]; +} - iface_sptr->set_time(time_spec_t(0.0)); +void block_ctrl_base::clear_command_time(const size_t port) +{ + _cmd_timespecs[port] = time_spec_t(0.0); } void block_ctrl_base::clear() diff --git a/host/lib/rfnoc/ctrl_iface.cpp b/host/lib/rfnoc/ctrl_iface.cpp index 147f81e0c..9515cda0d 100644 --- a/host/lib/rfnoc/ctrl_iface.cpp +++ b/host/lib/rfnoc/ctrl_iface.cpp @@ -10,6 +10,7 @@ #include <uhd/utils/safe_call.hpp> #include <uhd/transport/bounded_buffer.hpp> #include <uhd/types/sid.hpp> +#include <uhd/types/endianness.hpp> #include <uhd/transport/chdr.hpp> #include <uhd/rfnoc/constants.hpp> #include <uhdlib/rfnoc/ctrl_iface.hpp> @@ -17,6 +18,7 @@ #include <boost/thread/thread.hpp> #include <boost/format.hpp> #include <boost/bind.hpp> +#include <boost/make_shared.hpp> #include <queue> using namespace uhd; @@ -30,89 +32,53 @@ ctrl_iface::~ctrl_iface(void){ /* NOP */ } +template <uhd::endianness_t _endianness> class ctrl_iface_impl: public ctrl_iface { public: - ctrl_iface_impl(const bool big_endian, - uhd::transport::zero_copy_if::sptr ctrl_xport, - uhd::transport::zero_copy_if::sptr resp_xport, - const uint32_t sid, const std::string &name - ) : - _link_type(vrt::if_packet_info_t::LINK_TYPE_CHDR), - _packet_type(vrt::if_packet_info_t::PACKET_TYPE_CONTEXT), - _bige(big_endian), - _ctrl_xport(ctrl_xport), _resp_xport(resp_xport), - _sid(sid), + ctrl_iface_impl( + const both_xports_t &xports, + const std::string &name + ) : _xports(xports), _name(name), _seq_out(0), - _timeout(ACK_TIMEOUT), - _resp_queue_size(_resp_xport->get_num_recv_frames()), - _rb_address(uhd::rfnoc::SR_READBACK) + _max_outstanding_acks( + std::min( + uhd::rfnoc::CMD_FIFO_SIZE / 3, // Max command packet size is 3 lines + _xports.recv->get_num_recv_frames() + ) + ) { - UHD_ASSERT_THROW(_ctrl_xport); - UHD_ASSERT_THROW(_resp_xport); - while (resp_xport->get_recv_buff(0.0)) {} //flush - this->set_time(uhd::time_spec_t(0.0)); - this->set_tick_rate(1.0); //something possible but bogus + UHD_ASSERT_THROW(bool(_xports.send)); + UHD_ASSERT_THROW(bool(_xports.recv)); + // Flush the response transport in case we have something over: + while (_xports.recv->get_recv_buff(0.0)) {} } ~ctrl_iface_impl(void) { - _timeout = ACK_TIMEOUT; //reset timeout to something small UHD_SAFE_CALL( - this->peek32(0);//dummy peek with the purpose of ack'ing all packets + // dummy peek with the purpose of ack'ing all packets + this->send_cmd_pkt(0, 0, true); ) } /******************************************************************* - * Peek and poke 32 bit implementation - ******************************************************************/ - void poke32(const wb_addr_type addr, const uint32_t data) - { - boost::mutex::scoped_lock lock(_mutex); - this->send_pkt(addr/4, data); - this->wait_for_ack(false); - } - - uint32_t peek32(const wb_addr_type addr) - { - boost::mutex::scoped_lock lock(_mutex); - this->send_pkt(_rb_address, addr/8); - const uint64_t res = this->wait_for_ack(true); - const uint32_t lo = uint32_t(res & 0xffffffff); - const uint32_t hi = uint32_t(res >> 32); - return ((addr/4) & 0x1)? hi : lo; - } - - uint64_t peek64(const wb_addr_type addr) - { - boost::mutex::scoped_lock lock(_mutex); - this->send_pkt(_rb_address, addr/8); - return this->wait_for_ack(true); - } - - /******************************************************************* - * Update methods for time + * Get and set register implementation ******************************************************************/ - void set_time(const uhd::time_spec_t &time) - { - boost::mutex::scoped_lock lock(_mutex); - _time = time; - _use_time = _time != uhd::time_spec_t(0.0); - if (_use_time) _timeout = MASSIVE_TIMEOUT; //permanently sets larger timeout - } - - uhd::time_spec_t get_time(void) - { + uint64_t send_cmd_pkt( + const size_t addr, + const size_t data, + const bool readback, + const uint64_t timestamp=0 + ) { boost::mutex::scoped_lock lock(_mutex); - return _time; - } - - void set_tick_rate(const double rate) - { - boost::mutex::scoped_lock lock(_mutex); - _tick_rate = rate; + this->send_pkt(addr, data, timestamp); + return this->wait_for_ack( + readback, + bool(timestamp) ? MASSIVE_TIMEOUT : ACK_TIMEOUT + ); } private: @@ -125,9 +91,12 @@ private: /******************************************************************* * Primary control and interaction private methods ******************************************************************/ - inline void send_pkt(const uint32_t addr, const uint32_t data = 0) - { - managed_send_buffer::sptr buff = _ctrl_xport->get_send_buff(0.0); + inline void send_pkt( + const uint32_t addr, + const uint32_t data, + const uint64_t timestamp + ) { + managed_send_buffer::sptr buff = _xports.send->get_send_buff(0.0); if (not buff) { throw uhd::runtime_error("fifo ctrl timed out getting a send buffer"); } @@ -135,29 +104,33 @@ private: //load packet info vrt::if_packet_info_t packet_info; - packet_info.link_type = _link_type; - packet_info.packet_type = _packet_type; + packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; + packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_CMD; packet_info.num_payload_words32 = 2; packet_info.num_payload_bytes = packet_info.num_payload_words32*sizeof(uint32_t); packet_info.packet_count = _seq_out; - packet_info.tsf = _time.to_ticks(_tick_rate); + packet_info.tsf = timestamp; packet_info.sob = false; packet_info.eob = false; - packet_info.sid = _sid; + packet_info.sid = _xports.send_sid; packet_info.has_sid = true; packet_info.has_cid = false; packet_info.has_tsi = false; - packet_info.has_tsf = _use_time; + packet_info.has_tsf = bool(timestamp); packet_info.has_tlr = false; - //load header - if (_bige) vrt::if_hdr_pack_be(pkt, packet_info); - else vrt::if_hdr_pack_le(pkt, packet_info); + // Unpack header and load payload + if (_endianness == uhd::ENDIANNESS_BIG) { // This if statement gets compiled out + vrt::if_hdr_pack_be(pkt, packet_info); + pkt[packet_info.num_header_words32+0] = uhd::htonx(addr); + pkt[packet_info.num_header_words32+1] = uhd::htonx(data); + } else { + vrt::if_hdr_pack_le(pkt, packet_info); + pkt[packet_info.num_header_words32+0] = uhd::htowx(addr); + pkt[packet_info.num_header_words32+1] = uhd::htowx(data); + } - //load payload - pkt[packet_info.num_header_words32+0] = (_bige)? uhd::htonx(addr) : uhd::htowx(addr); - pkt[packet_info.num_header_words32+1] = (_bige)? uhd::htonx(data) : uhd::htowx(data); - //UHD_LOGGER_INFO("RFNOC") << boost::format("0x%08x, 0x%08x\n") % addr % data; + //UHD_LOGGER_TRACE("RFNOC") << boost::format("0x%08x, 0x%08x\n") % addr % data; //send the buffer over the interface _outstanding_seqs.push(_seq_out); buff->commit(sizeof(uint32_t)*(packet_info.num_packet_words32)); @@ -165,9 +138,9 @@ private: _seq_out++;//inc seq for next call } - UHD_INLINE uint64_t wait_for_ack(const bool readback) + inline uint64_t wait_for_ack(const bool readback, const double timeout) { - while (readback or (_outstanding_seqs.size() >= _resp_queue_size)) + while (readback or (_outstanding_seqs.size() >= _max_outstanding_acks)) { //get seq to ack from outstanding packets list UHD_ASSERT_THROW(not _outstanding_seqs.empty()); @@ -180,24 +153,29 @@ private: uint32_t const *pkt = NULL; managed_recv_buffer::sptr buff; - buff = _resp_xport->get_recv_buff(_timeout); + buff = _xports.recv->get_recv_buff(timeout); try { UHD_ASSERT_THROW(bool(buff)); UHD_ASSERT_THROW(buff->size() > 0); _outstanding_seqs.pop(); } catch(const std::exception &ex) { - throw uhd::io_error(str(boost::format("Block ctrl (%s) no response packet - %s") % _name % ex.what())); + throw uhd::io_error(str( + boost::format("Block ctrl (%s) no response packet - %s") + % _name + % ex.what() + )); } pkt = buff->cast<const uint32_t *>(); packet_info.num_packet_words32 = buff->size()/sizeof(uint32_t); //parse the buffer - try - { - packet_info.link_type = _link_type; - if (_bige) vrt::chdr::if_hdr_unpack_be(pkt, packet_info); - else vrt::chdr::if_hdr_unpack_le(pkt, packet_info); + try { + if (_endianness == uhd::ENDIANNESS_BIG) { + vrt::chdr::if_hdr_unpack_be(pkt, packet_info); + } else { + vrt::chdr::if_hdr_unpack_le(pkt, packet_info); + } } catch(const std::exception &ex) { @@ -214,14 +192,13 @@ private: } //check the buffer - try - { + try { UHD_ASSERT_THROW(packet_info.has_sid); - if (packet_info.sid != uint32_t((_sid >> 16) | (_sid << 16))) { + if (packet_info.sid != _xports.recv_sid.get()) { throw uhd::io_error( str( boost::format("Expected SID: %s Received SID: %s") - % uhd::sid_t(_sid).reversed().to_pp_string_hex() + % _xports.recv_sid.to_pp_string_hex() % uhd::sid_t(packet_info.sid).to_pp_string_hex() ) ); @@ -239,18 +216,23 @@ private: } UHD_ASSERT_THROW(packet_info.num_payload_words32 == 2); - //UHD_ASSERT_THROW(packet_info.packet_type == _packet_type); } - catch(const std::exception &ex) - { - throw uhd::io_error(str(boost::format("Block ctrl (%s) packet parse error - %s") % _name % ex.what())); + catch (const std::exception &ex) { + throw uhd::io_error(str( + boost::format("Block ctrl (%s) packet parse error - %s") + % _name + % ex.what() + )); } //return the readback value - if (readback and _outstanding_seqs.empty()) - { - const uint64_t hi = (_bige)? uhd::ntohx(pkt[packet_info.num_header_words32+0]) : uhd::wtohx(pkt[packet_info.num_header_words32+0]); - const uint64_t lo = (_bige)? uhd::ntohx(pkt[packet_info.num_header_words32+1]) : uhd::wtohx(pkt[packet_info.num_header_words32+1]); + if (readback and _outstanding_seqs.empty()) { + const uint64_t hi = (_endianness == uhd::ENDIANNESS_BIG) ? + uhd::ntohx(pkt[packet_info.num_header_words32+0]) + : uhd::wtohx(pkt[packet_info.num_header_words32+0]); + const uint64_t lo = (_endianness == uhd::ENDIANNESS_BIG) ? + uhd::ntohx(pkt[packet_info.num_header_words32+1]) + : uhd::wtohx(pkt[packet_info.num_header_words32+1]); return ((hi << 32) | lo); } } @@ -258,33 +240,28 @@ private: return 0; } - const vrt::if_packet_info_t::link_type_t _link_type; - const vrt::if_packet_info_t::packet_type_t _packet_type; - const bool _bige; - const uhd::transport::zero_copy_if::sptr _ctrl_xport; - const uhd::transport::zero_copy_if::sptr _resp_xport; - const uint32_t _sid; + + const uhd::both_xports_t _xports; const std::string _name; - boost::mutex _mutex; size_t _seq_out; - uhd::time_spec_t _time; - bool _use_time; - double _tick_rate; - double _timeout; std::queue<size_t> _outstanding_seqs; - const size_t _resp_queue_size; + const size_t _max_outstanding_acks; - const size_t _rb_address; + boost::mutex _mutex; }; ctrl_iface::sptr ctrl_iface::make( - const bool big_endian, - zero_copy_if::sptr ctrl_xport, - zero_copy_if::sptr resp_xport, - const uint32_t sid, + const both_xports_t &xports, const std::string &name ) { - return sptr(new ctrl_iface_impl( - big_endian, ctrl_xport, resp_xport, sid, name - )); + if (xports.endianness == uhd::ENDIANNESS_BIG) { + return boost::make_shared<ctrl_iface_impl<uhd::ENDIANNESS_BIG>>( + xports, name + ); + } else { + return boost::make_shared<ctrl_iface_impl<uhd::ENDIANNESS_LITTLE>>( + xports, name + ); + } } + diff --git a/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp b/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp index cbbd59323..e27c20809 100644 --- a/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp +++ b/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp @@ -27,25 +27,7 @@ public: { _perifs.resize(get_input_ports().size()); for(size_t i = 0; i < _perifs.size(); i++) { - _perifs[i].ctrl = boost::make_shared<wb_iface_adapter>( - // poke32 functor - boost::bind( - static_cast< void (block_ctrl_base::*)(const uint32_t, const uint32_t, const size_t) >(&block_ctrl_base::sr_write), - this, _1, _2, i - ), - // peek32 functor - boost::bind( - static_cast< uint32_t (block_ctrl_base::*)(const uint32_t, const size_t) >(&block_ctrl_base::user_reg_read32), - this, - _1, i - ), - // peek64 functor - boost::bind( - static_cast< uint64_t (block_ctrl_base::*)(const uint32_t, const size_t) >(&block_ctrl_base::user_reg_read64), - this, - _1, i - ) - ); + _perifs[i].ctrl = this->get_ctrl_iface(i); static const uint32_t USER_SR_BASE = 128*4; static const uint32_t USER_RB_BASE = 0; //Don't care _perifs[i].base_addr = DEFAULT_SIZE*i; diff --git a/host/lib/rfnoc/radio_ctrl_impl.cpp b/host/lib/rfnoc/radio_ctrl_impl.cpp index fe8d51468..a151b2690 100644 --- a/host/lib/rfnoc/radio_ctrl_impl.cpp +++ b/host/lib/rfnoc/radio_ctrl_impl.cpp @@ -45,29 +45,7 @@ radio_ctrl_impl::radio_ctrl_impl() : ///////////////////////////////////////////////////////////////////////// for (size_t i = 0; i < _get_num_radios(); i++) { _register_loopback_self_test(i); - _perifs[i].ctrl = boost::make_shared<wb_iface_adapter>( - // poke32 functor - [this, i](const uint32_t addr, const uint32_t data){ - this->sr_write(addr, data, i); - }, - // peek32 functor - [this, i](const uint32_t addr){ - return this->user_reg_read32(addr, i); - }, - // peek64 functor - [this, i](const uint32_t addr){ - return this->user_reg_read64(addr, i); - }, - // get_time functor - [this, i](){ - return this->get_command_time(i); - }, - // set_time functor - [this, i](const time_spec_t& time_spec){ - this->set_command_time(time_spec, i); - } - ); - + _perifs[i].ctrl = this->get_ctrl_iface(i); // FIXME there's currently no way to set the underflow policy if (i == 0) { diff --git a/host/lib/rfnoc/wb_iface_adapter.cpp b/host/lib/rfnoc/wb_iface_adapter.cpp index 3b9202661..64b41d6d2 100644 --- a/host/lib/rfnoc/wb_iface_adapter.cpp +++ b/host/lib/rfnoc/wb_iface_adapter.cpp @@ -6,56 +6,42 @@ // #include <uhdlib/rfnoc/wb_iface_adapter.hpp> +#include <uhd/rfnoc/constants.hpp> using namespace uhd::rfnoc; wb_iface_adapter::wb_iface_adapter( - const poke32_type &poke32_functor_, - const peek32_type &peek32_functor_, - const peek64_type &peek64_functor_, - const gettime_type &gettime_functor_, - const settime_type &settime_functor_ -) : poke32_functor(poke32_functor_) - , peek32_functor(peek32_functor_) - , peek64_functor(peek64_functor_) - , gettime_functor(gettime_functor_) + ctrl_iface::sptr iface, + const gettickrate_type & gettickrate_functor_, + const settime_type & settime_functor_, + const gettime_type & gettime_functor_ +) : _iface(iface) + , gettickrate_functor(gettickrate_functor_) , settime_functor(settime_functor_) -{ - // nop -} - -wb_iface_adapter::wb_iface_adapter( - const poke32_type &poke32_functor_, - const peek32_type &peek32_functor_, - const peek64_type &peek64_functor_ -) : poke32_functor(poke32_functor_) - , peek32_functor(peek32_functor_) - , peek64_functor(peek64_functor_) + , gettime_functor(gettime_functor_) { // nop } void wb_iface_adapter::poke32(const wb_addr_type addr, const uint32_t data) { - poke32_functor(addr / 4, data); // FIXME remove the requirement for /4 + const uint64_t timestamp = gettime_functor().to_ticks(gettickrate_functor()); + _iface->send_cmd_pkt(addr / 4, data, false, timestamp); } uint32_t wb_iface_adapter::peek32(const wb_addr_type addr) { - return peek32_functor(addr / 8); + const uint64_t reg_value = peek64(addr); + return ((addr/4) & 0x1) ? + uint32_t(reg_value >> 32) : + uint32_t(reg_value & 0xffffffff); } uint64_t wb_iface_adapter::peek64(const wb_addr_type addr) { - return peek64_functor(addr / 8); -} - -uhd::time_spec_t wb_iface_adapter::get_time(void) -{ - return gettime_functor(); + const uint64_t timestamp = gettime_functor().to_ticks(gettickrate_functor()); + // TODO: Figure out if we should have a timestamp here + _iface->send_cmd_pkt(SR_READBACK_ADDR, addr / 8, false, timestamp); + return _iface->send_cmd_pkt(SR_READBACK, SR_READBACK_REG_USER, true, timestamp); } -void wb_iface_adapter::set_time(const uhd::time_spec_t& t) -{ - settime_functor(t); -} diff --git a/host/lib/usrp/device3/device3_impl.cpp b/host/lib/usrp/device3/device3_impl.cpp index d4ea8a19f..6f1719500 100644 --- a/host/lib/usrp/device3/device3_impl.cpp +++ b/host/lib/usrp/device3/device3_impl.cpp @@ -119,13 +119,10 @@ void device3_impl::enumerate_rfnoc_blocks( ); UHD_DEVICE3_LOG() << str(boost::format("Setting up NoC-Shell Control for port #0 (SID: %s)...") % xport.send_sid.to_pp_string_hex()); uhd::rfnoc::ctrl_iface::sptr ctrl = uhd::rfnoc::ctrl_iface::make( - xport.endianness == uhd::ENDIANNESS_BIG, - xport.send, - xport.recv, - xport.send_sid, + xport, str(boost::format("CE_%02d_Port_%02X") % i % ctrl_sid.get_dst_endpoint()) ); - uint64_t noc_id = ctrl->peek64(uhd::rfnoc::SR_READBACK_REG_ID); + uint64_t noc_id = ctrl->send_cmd_pkt(uhd::rfnoc::SR_READBACK, uhd::rfnoc::SR_READBACK_REG_ID, true); UHD_DEVICE3_LOG() << str(boost::format("Port %d: Found NoC-Block with ID %016X.") % int(ctrl_sid.get_dst_endpoint()) % noc_id) ; uhd::rfnoc::make_args_t make_args; uhd::rfnoc::blockdef::sptr block_def = uhd::rfnoc::blockdef::make_from_noc_id(noc_id); @@ -147,10 +144,7 @@ void device3_impl::enumerate_rfnoc_blocks( ); UHD_DEVICE3_LOG() << str(boost::format("Setting up NoC-Shell Control for port #%d (SID: %s)...") % port_number % xport1.send_sid.to_pp_string_hex()); uhd::rfnoc::ctrl_iface::sptr ctrl1 = uhd::rfnoc::ctrl_iface::make( - xport1.endianness == uhd::ENDIANNESS_BIG, - xport1.send, - xport1.recv, - xport1.send_sid, + xport1, str(boost::format("CE_%02d_Port_%02d") % i % ctrl_sid.get_dst_endpoint()) ); UHD_DEVICE3_LOG() << "OK" ; diff --git a/host/tests/device3_test.cpp b/host/tests/device3_test.cpp index a5639a346..62b90920e 100644 --- a/host/tests/device3_test.cpp +++ b/host/tests/device3_test.cpp @@ -5,14 +5,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <exception> -#include <iostream> -#include <boost/test/unit_test.hpp> +#include "../lib/rfnoc/ctrl_iface.hpp" #include <uhd/property_tree.hpp> #include <uhd/types/wb_iface.hpp> #include <uhd/device3.hpp> #include <uhd/rfnoc/block_ctrl.hpp> #include <uhd/rfnoc/graph.hpp> +#include <boost/test/unit_test.hpp> +#include <exception> +#include <iostream> using namespace uhd; using namespace uhd::rfnoc; @@ -22,39 +23,35 @@ static const sid_t TEST_SID0 = 0x00000200; // 0.0.2.0 static const sid_t TEST_SID1 = 0x00000210; // 0.0.2.F // Pseudo-wb-iface -class pseudo_wb_iface_impl : public uhd::wb_iface +class pseudo_ctrl_iface_impl : public ctrl_iface { public: - pseudo_wb_iface_impl() {}; - ~pseudo_wb_iface_impl() {}; - - void poke64(const wb_addr_type addr, const uint64_t data) { - std::cout << str(boost::format("[PSEUDO] poke64 to addr: %016X, data == %016X") % addr % data) << std::endl; - }; - - uint64_t peek64(const wb_addr_type addr) { - std::cout << str(boost::format("[PSEUDO] peek64 to addr: %016X") % addr) << std::endl; - switch (addr) { - case SR_READBACK_REG_ID: - return TEST_NOC_ID; - case SR_READBACK_REG_FIFOSIZE: - return 0x000000000000000B; - case SR_READBACK_REG_USER: - return 0x0123456789ABCDEF; - default: - return 0; + pseudo_ctrl_iface_impl() {}; + ~pseudo_ctrl_iface_impl() {}; + + uint64_t send_cmd_pkt( + const size_t addr, + const size_t data, + const bool readback=false, + const uint64_t timestamp=0 + ) { + if (not readback) { + std::cout << str(boost::format("[PSEUDO] poke to addr: %016X, data == %016X") % addr % data) << std::endl; + } else { + std::cout << str(boost::format("[PSEUDO] peek64 to addr: %016X") % data) << std::endl; + switch (data) { + case SR_READBACK_REG_ID: + return TEST_NOC_ID; + case SR_READBACK_REG_FIFOSIZE: + return 0x000000000000000B; + case SR_READBACK_REG_USER: + return 0x0123456789ABCDEF; + default: + return 0; + } } return 0; } - - void poke32(const wb_addr_type addr, const uint32_t data) { - std::cout << str(boost::format("poke32 to addr: %08X, data == %08X") % addr % data) << std::endl; - } - - uint32_t peek32(const wb_addr_type addr) { - std::cout << str(boost::format("peek32 to addr: %08X") % addr) << std::endl; - return 0; - } }; // Pseudo-device @@ -67,8 +64,8 @@ class pseudo_device3_impl : public uhd::device3 _tree->create<std::string>("/name").set("Test Pseudo-Device3"); // We can re-use this: - std::map<size_t, wb_iface::sptr> ctrl_ifaces = boost::assign::map_list_of - (0, wb_iface::sptr(new pseudo_wb_iface_impl())) + std::map<size_t, ctrl_iface::sptr> ctrl_ifaces = boost::assign::map_list_of + (0, ctrl_iface::sptr(new pseudo_ctrl_iface_impl())) ; // Add two block controls: |