aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authormattprost <matt.prost@ni.com>2020-03-20 10:31:10 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-04-02 12:12:26 -0500
commitc65166562f1278f6633b183b7188789158210544 (patch)
treedd61b3cff3241af2cb5aa8c9a7da1b5727652d55 /host
parent6aed4b5a45cf0057bc175e19a86888259bf17cec (diff)
downloaduhd-c65166562f1278f6633b183b7188789158210544.tar.gz
uhd-c65166562f1278f6633b183b7188789158210544.tar.bz2
uhd-c65166562f1278f6633b183b7188789158210544.zip
rfnoc: Use multichannel register interface for RFNoC blocks
Allows RFNoC blocks to perform register peeks and pokes on blocks with multiple channels without having to worry about handling register address translation every time. Signed-off-by: mattprost <matt.prost@ni.com>
Diffstat (limited to 'host')
-rw-r--r--host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp4
-rw-r--r--host/lib/rfnoc/ddc_block_control.cpp25
-rw-r--r--host/lib/rfnoc/duc_block_control.cpp25
-rw-r--r--host/lib/rfnoc/radio_control_impl.cpp61
4 files changed, 61 insertions, 54 deletions
diff --git a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
index 1a78d7cab..69577b9e4 100644
--- a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
+++ b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
@@ -5,6 +5,7 @@
//
#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
#include <uhd/rfnoc/radio_control.hpp>
#include <unordered_map>
#include <mutex>
@@ -296,6 +297,9 @@ protected:
//! Properties for samp_rate (one per port)
std::vector<property_t<double>> _samp_rate_out;
+ //! Block-specific register interface
+ multichan_register_iface _radio_reg_iface;
+
private:
//! Validator for the async messages
//
diff --git a/host/lib/rfnoc/ddc_block_control.cpp b/host/lib/rfnoc/ddc_block_control.cpp
index 8942d128d..a35d750ff 100644
--- a/host/lib/rfnoc/ddc_block_control.cpp
+++ b/host/lib/rfnoc/ddc_block_control.cpp
@@ -7,6 +7,7 @@
#include <uhd/exception.hpp>
#include <uhd/rfnoc/ddc_block_control.hpp>
#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
#include <uhd/rfnoc/property.hpp>
#include <uhd/rfnoc/registry.hpp>
#include <uhd/types/ranges.hpp>
@@ -56,7 +57,8 @@ public:
, _fpga_compat(regs().peek32(RB_COMPAT_NUM)),
_num_halfbands(regs().peek32(RB_NUM_HB)),
_cic_max_decim(regs().peek32(RB_CIC_MAX_DECIM)),
- _residual_scaling(get_num_input_ports(), DEFAULT_SCALING)
+ _residual_scaling(get_num_input_ports(), DEFAULT_SCALING),
+ _ddc_reg_iface(*this, 0, REG_CHAN_OFFSET)
{
UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports());
UHD_ASSERT_THROW(_cic_max_decim > 0 && _cic_max_decim <= 0xFF);
@@ -186,6 +188,10 @@ public:
issue_stream_cmd_action_handler(dst_edge, new_action);
}
+protected:
+ //! Block-specific register interface
+ multichan_register_iface _ddc_reg_iface;
+
private:
//! Shorthand for num ports, since num input ports always equals num output ports
inline size_t get_num_ports()
@@ -193,11 +199,6 @@ private:
return get_num_input_ports();
}
- inline uint32_t get_addr(const uint32_t base_addr, const size_t chan)
- {
- return base_addr + REG_CHAN_OFFSET * chan;
- }
-
/**************************************************************************
* Initialization
*************************************************************************/
@@ -468,14 +469,14 @@ private:
UHD_ASSERT_THROW(hb_enable <= _num_halfbands);
UHD_ASSERT_THROW(cic_decim > 0 and cic_decim <= _cic_max_decim);
const uint32_t decim_word = (hb_enable << 8) | cic_decim;
- regs().poke32(get_addr(SR_DECIM_ADDR, chan), decim_word);
+ _ddc_reg_iface.poke32(SR_DECIM_ADDR, decim_word, chan);
// Rate change = M/N
- regs().poke32(get_addr(SR_N_ADDR, chan), decim);
+ _ddc_reg_iface.poke32(SR_N_ADDR, decim, chan);
// FIXME:
// - eiscat DDC had a real mode, where M needed to be 2
// - TwinRX had some issues with M == 1
- regs().poke32(get_addr(SR_M_ADDR, chan), 1);
+ _ddc_reg_iface.poke32(SR_M_ADDR, 1, chan);
if (cic_decim > 1 and hb_enable == 0) {
RFNOC_LOG_WARNING(
@@ -515,7 +516,7 @@ private:
const int32_t actual_factor = boost::math::iround(target_factor);
// Write DDC with scaling correction for CIC and DDS that maximizes
// dynamic range
- regs().poke32(get_addr(SR_SCALE_IQ_ADDR, chan), actual_factor);
+ _ddc_reg_iface.poke32(SR_SCALE_IQ_ADDR, actual_factor, chan);
// Calculate the error introduced by using fixedpoint representation for
// the scaler, can be corrected in host later.
@@ -538,8 +539,8 @@ private:
int32_t freq_word;
std::tie(actual_freq, freq_word) =
get_freq_and_freq_word(requested_freq, input_rate);
- regs().poke32(
- get_addr(SR_FREQ_ADDR, chan), uint32_t(freq_word), get_command_time(chan));
+ _ddc_reg_iface.poke32(
+ SR_FREQ_ADDR, uint32_t(freq_word), chan, get_command_time(chan));
return actual_freq;
}
diff --git a/host/lib/rfnoc/duc_block_control.cpp b/host/lib/rfnoc/duc_block_control.cpp
index ff1c4e97a..1795a275a 100644
--- a/host/lib/rfnoc/duc_block_control.cpp
+++ b/host/lib/rfnoc/duc_block_control.cpp
@@ -7,6 +7,7 @@
#include <uhd/exception.hpp>
#include <uhd/rfnoc/defaults.hpp>
#include <uhd/rfnoc/duc_block_control.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
#include <uhd/rfnoc/property.hpp>
#include <uhd/rfnoc/registry.hpp>
#include <uhd/types/ranges.hpp>
@@ -54,7 +55,8 @@ public:
, _fpga_compat(regs().peek32(RB_COMPAT_NUM)),
_num_halfbands(regs().peek32(RB_NUM_HB)),
_cic_max_interp(regs().peek32(RB_CIC_MAX_INTERP)),
- _residual_scaling(get_num_input_ports(), DEFAULT_SCALING)
+ _residual_scaling(get_num_input_ports(), DEFAULT_SCALING),
+ _duc_reg_iface(*this, 0, REG_CHAN_OFFSET)
{
UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports());
UHD_ASSERT_THROW(_cic_max_interp > 0 && _cic_max_interp <= 0xFF);
@@ -167,6 +169,10 @@ public:
return _samp_rate_in.at(chan).get();
}
+protected:
+ //! Block-specific register interface
+ multichan_register_iface _duc_reg_iface;
+
private:
//! Shorthand for num ports, since num input ports always equals num output ports
inline size_t get_num_ports()
@@ -174,11 +180,6 @@ private:
return get_num_input_ports();
}
- inline uint32_t get_addr(const uint32_t base_addr, const size_t chan)
- {
- return base_addr + REG_CHAN_OFFSET * chan;
- }
-
/**************************************************************************
* Initialization
*************************************************************************/
@@ -454,13 +455,13 @@ private:
UHD_ASSERT_THROW(hb_enable <= _num_halfbands);
UHD_ASSERT_THROW(cic_interp > 0 and cic_interp <= _cic_max_interp);
const uint32_t interp_word = (hb_enable << 8) | cic_interp;
- regs().poke32(get_addr(SR_INTERP_ADDR, chan), interp_word);
+ _duc_reg_iface.poke32(SR_INTERP_ADDR, interp_word, chan);
// Rate change = M/N, where N = 1
- regs().poke32(get_addr(SR_M_ADDR, chan), interp);
+ _duc_reg_iface.poke32(SR_M_ADDR, interp, chan);
// FIXME:
// - TwinRX had some issues with N == 1
- regs().poke32(get_addr(SR_N_ADDR, chan), 1);
+ _duc_reg_iface.poke32(SR_N_ADDR, 1, chan);
if (cic_interp > 1 and hb_enable == 0) {
RFNOC_LOG_WARNING(
@@ -496,7 +497,7 @@ private:
const int32_t actual_factor = boost::math::iround(target_factor);
// Write DUC with scaling correction for CIC and DDS that maximizes
// dynamic range
- regs().poke32(get_addr(SR_SCALE_IQ_ADDR, chan), actual_factor);
+ _duc_reg_iface.poke32(SR_SCALE_IQ_ADDR, actual_factor, chan);
// Calculate the error introduced by using fixedpoint representation for
// the scaler, can be corrected in host later.
@@ -519,8 +520,8 @@ private:
int32_t freq_word;
std::tie(actual_freq, freq_word) =
get_freq_and_freq_word(requested_freq, input_rate);
- regs().poke32(
- get_addr(SR_FREQ_ADDR, chan), uint32_t(freq_word), get_command_time(chan));
+ _duc_reg_iface.poke32(
+ SR_FREQ_ADDR, uint32_t(freq_word), chan, get_command_time(chan));
return actual_freq;
}
diff --git a/host/lib/rfnoc/radio_control_impl.cpp b/host/lib/rfnoc/radio_control_impl.cpp
index faa6a01a6..b5c3181a5 100644
--- a/host/lib/rfnoc/radio_control_impl.cpp
+++ b/host/lib/rfnoc/radio_control_impl.cpp
@@ -6,6 +6,8 @@
#include <uhd/exception.hpp>
#include <uhd/rfnoc/mb_controller.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
+#include <uhd/rfnoc/register_iface.hpp>
#include <uhd/utils/log.hpp>
#include <uhdlib/rfnoc/radio_control_impl.hpp>
#include <uhdlib/utils/compat_check.hpp>
@@ -16,12 +18,6 @@ using namespace uhd::rfnoc;
namespace {
-inline uint32_t get_addr(const uint32_t base_addr, const size_t chan)
-{
- return radio_control_impl::regmap::RADIO_BASE_ADDR + base_addr
- + radio_control_impl::regmap::REG_CHAN_OFFSET * chan;
-}
-
const std::string DEFAULT_GAIN_PROFILE("default");
} // namespace
@@ -77,6 +73,9 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
, _spc(_radio_width & 0xFFFF)
, _last_stream_cmd(
get_num_output_ports(), uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS)
+ , _radio_reg_iface(*this,
+ radio_control_impl::regmap::RADIO_BASE_ADDR,
+ radio_control_impl::regmap::REG_CHAN_OFFSET)
{
uhd::assert_fpga_compat(MAJOR_COMPAT,
MINOR_COMPAT,
@@ -156,8 +155,8 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
const uint32_t words_per_pkt = spp.get();
RFNOC_LOG_TRACE(
"Setting words_per_pkt to " << words_per_pkt << " on chan " << chan);
- regs().poke32(
- get_addr(regmap::REG_RX_MAX_WORDS_PER_PKT, chan), words_per_pkt);
+ _radio_reg_iface.poke32(
+ regmap::REG_RX_MAX_WORDS_PER_PKT, words_per_pkt, chan);
});
register_property(&_samp_rate_in.back());
register_property(&_samp_rate_out.back());
@@ -220,28 +219,30 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
for (size_t tx_chan = 0; tx_chan < get_num_output_ports(); tx_chan++) {
// Set the EPID and port of our regs() object (all async messages go to
// the same location)
- regs().poke32(
- get_addr(regmap::REG_TX_ERR_REM_EPID, tx_chan), regs().get_src_epid());
- regs().poke32(
- get_addr(regmap::REG_TX_ERR_REM_PORT, tx_chan), regs().get_port_num());
+ _radio_reg_iface.poke32(
+ regmap::REG_TX_ERR_REM_EPID, regs().get_src_epid(), tx_chan);
+ _radio_reg_iface.poke32(
+ regmap::REG_TX_ERR_REM_PORT, regs().get_port_num(), tx_chan);
// Set the crossbar port for the async packet routing
- regs().poke32(get_addr(regmap::REG_TX_ERR_PORT, tx_chan), xbar_port);
+ _radio_reg_iface.poke32(regmap::REG_TX_ERR_PORT, xbar_port, tx_chan);
// Set the async message address
- regs().poke32(get_addr(regmap::REG_TX_ERR_ADDR, tx_chan),
- regmap::SWREG_TX_ERR + regmap::SWREG_CHAN_OFFSET * tx_chan);
+ _radio_reg_iface.poke32(regmap::REG_TX_ERR_ADDR,
+ regmap::SWREG_TX_ERR + regmap::SWREG_CHAN_OFFSET * tx_chan,
+ tx_chan);
}
for (size_t rx_chan = 0; rx_chan < get_num_input_ports(); rx_chan++) {
// Set the EPID and port of our regs() object (all async messages go to
// the same location)
- regs().poke32(
- get_addr(regmap::REG_RX_ERR_REM_EPID, rx_chan), regs().get_src_epid());
- regs().poke32(
- get_addr(regmap::REG_RX_ERR_REM_PORT, rx_chan), regs().get_port_num());
+ _radio_reg_iface.poke32(
+ regmap::REG_RX_ERR_REM_EPID, regs().get_src_epid(), rx_chan);
+ _radio_reg_iface.poke32(
+ regmap::REG_RX_ERR_REM_PORT, regs().get_port_num(), rx_chan);
// Set the crossbar port for the async packet routing
- regs().poke32(get_addr(regmap::REG_RX_ERR_PORT, rx_chan), xbar_port);
+ _radio_reg_iface.poke32(regmap::REG_RX_ERR_PORT, xbar_port, rx_chan);
// Set the async message address
- regs().poke32(get_addr(regmap::REG_RX_ERR_ADDR, rx_chan),
- regmap::SWREG_RX_ERR + regmap::SWREG_CHAN_OFFSET * rx_chan);
+ _radio_reg_iface.poke32(regmap::REG_RX_ERR_ADDR,
+ regmap::SWREG_RX_ERR + regmap::SWREG_CHAN_OFFSET * rx_chan,
+ rx_chan);
}
// Now register a function to receive the async messages
regs().register_async_msg_validator(
@@ -827,22 +828,22 @@ void radio_control_impl::issue_stream_cmd(
"requested fewer samples.");
throw uhd::value_error("Requested too many samples in a single burst.");
}
- regs().poke32(
- get_addr(regmap::REG_RX_CMD_NUM_WORDS_HI, chan), uint32_t(num_words >> 32));
- regs().poke32(get_addr(regmap::REG_RX_CMD_NUM_WORDS_LO, chan),
- uint32_t(num_words & 0xFFFFFFFF));
+ _radio_reg_iface.poke32(
+ regmap::REG_RX_CMD_NUM_WORDS_HI, uint32_t(num_words >> 32), chan);
+ _radio_reg_iface.poke32(
+ regmap::REG_RX_CMD_NUM_WORDS_LO, uint32_t(num_words & 0xFFFFFFFF), chan);
}
if (!stream_cmd.stream_now) {
const uint64_t ticks = stream_cmd.time_spec.to_ticks(get_tick_rate());
- regs().poke32(get_addr(regmap::REG_RX_CMD_TIME_HI, chan), uint32_t(ticks >> 32));
- regs().poke32(get_addr(regmap::REG_RX_CMD_TIME_LO, chan), uint32_t(ticks >> 0));
+ _radio_reg_iface.poke32(regmap::REG_RX_CMD_TIME_HI, uint32_t(ticks >> 32), chan);
+ _radio_reg_iface.poke32(regmap::REG_RX_CMD_TIME_LO, uint32_t(ticks >> 0), chan);
}
- regs().poke32(get_addr(regmap::REG_RX_CMD, chan), cmd_word);
+ _radio_reg_iface.poke32(regmap::REG_RX_CMD, cmd_word, chan);
}
void radio_control_impl::enable_rx_timestamps(const bool enable, const size_t chan)
{
- regs().poke32(get_addr(regmap::REG_RX_HAS_TIME, chan), enable ? 0x1 : 0x0);
+ _radio_reg_iface.poke32(regmap::REG_RX_HAS_TIME, enable ? 0x1 : 0x0, chan);
}
/******************************************************************************