aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/block_ctrl_base.hpp17
-rw-r--r--host/include/uhd/rfnoc/constants.hpp2
-rw-r--r--host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp52
-rw-r--r--host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp53
-rw-r--r--host/lib/rfnoc/block_ctrl_base.cpp87
-rw-r--r--host/lib/rfnoc/ctrl_iface.cpp219
-rw-r--r--host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp20
-rw-r--r--host/lib/rfnoc/radio_ctrl_impl.cpp24
-rw-r--r--host/lib/rfnoc/wb_iface_adapter.cpp50
-rw-r--r--host/lib/usrp/device3/device3_impl.cpp12
-rw-r--r--host/tests/device3_test.cpp63
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: