aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2018-07-16 07:39:30 -0500
committerBrent Stapleton <brent.stapleton@ettus.com>2018-08-29 15:45:55 -0700
commitbed75f0ccbb6da139283a07c1442293bef95f26a (patch)
tree54cda1bbb73bd291d264bf995d0b0bdf8de737d7 /host/lib
parent639797e5924b42764711b69b09e48ee07ed3d683 (diff)
downloaduhd-bed75f0ccbb6da139283a07c1442293bef95f26a.tar.gz
uhd-bed75f0ccbb6da139283a07c1442293bef95f26a.tar.bz2
uhd-bed75f0ccbb6da139283a07c1442293bef95f26a.zip
RFNoC: Add Replay API and example
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/rfnoc/CMakeLists.txt1
-rw-r--r--host/lib/rfnoc/replay_block_ctrl_impl.cpp183
2 files changed, 184 insertions, 0 deletions
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index 527c99e14..f98518272 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -40,6 +40,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/siggen_block_ctrl_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dma_fifo_block_ctrl_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/replay_block_ctrl_impl.cpp
)
INCLUDE_SUBDIRECTORY(nocscript)
diff --git a/host/lib/rfnoc/replay_block_ctrl_impl.cpp b/host/lib/rfnoc/replay_block_ctrl_impl.cpp
new file mode 100644
index 000000000..a78632bf9
--- /dev/null
+++ b/host/lib/rfnoc/replay_block_ctrl_impl.cpp
@@ -0,0 +1,183 @@
+//
+// Copyright 2016 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/rfnoc/replay_block_ctrl.hpp>
+#include <mutex>
+
+using namespace uhd;
+using namespace uhd::rfnoc;
+
+class replay_block_ctrl_impl : public replay_block_ctrl
+{
+public:
+ static const uint32_t REPLAY_WORD_SIZE = 8; // In bytes
+ static const uint32_t SAMPLES_PER_WORD = 2;
+ static const uint32_t BYTES_PER_SAMPLE = 4;
+ static const uint32_t WORDS_PER_PACKET = 128;
+ static const uint32_t DEFAULT_BUFFER_SIZE = 32*1024*1024;
+ static const uint32_t DEFAULT_WPP = 182;
+ static const uint32_t DEFAULT_SPP = DEFAULT_WPP * SAMPLES_PER_WORD;
+
+
+ UHD_RFNOC_BLOCK_CONSTRUCTOR(replay_block_ctrl)
+ {
+ _num_channels = get_input_ports().size();
+ _params.resize(_num_channels);
+ for(size_t chan = 0; chan < _params.size(); chan++) {
+ _params[chan].words_per_packet = DEFAULT_WPP;
+ sr_write("RX_CTRL_MAXLEN", WORDS_PER_PACKET, chan);
+
+ // Configure replay channels to be adjacent DEFAULT_BUFFER_SIZE'd blocks
+ _params[chan].rec_base_addr = chan*DEFAULT_BUFFER_SIZE;
+ _params[chan].play_base_addr = chan*DEFAULT_BUFFER_SIZE;
+ _params[chan].rec_buffer_size = DEFAULT_BUFFER_SIZE;
+ _params[chan].play_buffer_size = DEFAULT_BUFFER_SIZE;
+ sr_write("REC_BASE_ADDR", _params[chan].rec_base_addr, chan);
+ sr_write("REC_BUFFER_SIZE", _params[chan].rec_buffer_size, chan);
+ sr_write("PLAY_BASE_ADDR", _params[chan].play_base_addr, chan);
+ sr_write("PLAY_BUFFER_SIZE", _params[chan].play_buffer_size, chan);
+ }
+ }
+
+
+ /**************************************************************************
+ * API Calls
+ **************************************************************************/
+
+ void config_record(const uint32_t base_addr, const uint32_t size, const size_t chan) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _params[chan].rec_base_addr = base_addr;
+ _params[chan].rec_buffer_size = size;
+ sr_write("REC_BASE_ADDR", base_addr, chan);
+ sr_write("REC_BUFFER_SIZE", size, chan);
+ sr_write("REC_RESTART", 0, chan);
+ }
+
+ void config_play(const uint32_t base_addr, const uint32_t size, const size_t chan) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _params[chan].play_base_addr = base_addr;
+ _params[chan].play_buffer_size = size;
+ sr_write("PLAY_BASE_ADDR", base_addr, chan);
+ sr_write("PLAY_BUFFER_SIZE", size, chan);
+ }
+
+ void record_restart(const size_t chan) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ sr_write("REC_RESTART", 0, chan);
+ }
+
+ uint32_t get_record_addr(const size_t chan) {
+ return _params[chan].rec_base_addr;
+ }
+
+ uint32_t get_record_size(const size_t chan) {
+ return _params[chan].rec_buffer_size;
+ }
+
+ uint32_t get_record_fullness(const size_t chan) {
+ return user_reg_read32("REC_FULLNESS", chan);
+ }
+
+ uint32_t get_play_addr(const size_t chan) {
+ return _params[chan].play_base_addr;
+ }
+
+ uint32_t get_play_size(const size_t chan) {
+ return _params[chan].play_buffer_size;
+ }
+
+ void set_words_per_packet(const uint32_t num_words, const size_t chan) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _params[chan].words_per_packet = num_words;
+ sr_write("RX_CTRL_MAXLEN", num_words, chan);
+ }
+
+ uint32_t get_words_per_packet(const size_t chan) {
+ return _params[chan].words_per_packet;
+ }
+
+
+ /***************************************************************************
+ * Radio-like Streamer
+ **************************************************************************/
+
+ void issue_stream_cmd(
+ const uhd::stream_cmd_t &stream_cmd,
+ const size_t chan
+ ) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ UHD_RFNOC_BLOCK_TRACE()
+ << "replay_block_ctrl_impl::issue_stream_cmd() " << chan
+ << " " << char(stream_cmd.stream_mode) ;
+
+ if (not (_rx_streamer_active.count(chan) and _rx_streamer_active.at(chan))) {
+ UHD_RFNOC_BLOCK_TRACE()
+ << "replay_block_ctrl_impl::issue_stream_cmd() called on inactive "
+ "channel. Skipping.";
+ return;
+ }
+
+ constexpr size_t max_num_samps = 0x0fffffff;
+ if (stream_cmd.num_samps > max_num_samps) {
+ UHD_LOG_ERROR("REPLAY",
+ "Requesting too many samples in a single burst! "
+ "Requested " + std::to_string(stream_cmd.num_samps) + ", maximum "
+ "is " + std::to_string(max_num_samps) + ".");
+ throw uhd::value_error("Requested too many samples in a single burst.");
+ }
+
+ // Setup the mode to instruction flags
+ typedef std::tuple<bool, bool, bool, bool> inst_t;
+ static const std::map<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst {
+ // reload, chain, samps, stop
+ {stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false)},
+ {stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true)},
+ {stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false)},
+ {stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false)}
+ };
+
+ // Setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps, inst_stop;
+ std::tie(inst_reload, inst_chain, inst_samps, inst_stop) =
+ mode_to_inst.at(stream_cmd.stream_mode);
+
+ // Calculate how many words to transfer at a time in CONTINUOUS mode
+ uint32_t cont_burst_size =
+ (_params[chan].play_buffer_size > WORDS_PER_PACKET) ?
+ WORDS_PER_PACKET : _params[chan].play_buffer_size;
+
+ // Calculate the number of words to transfer in NUM_SAMPS mode
+ uint32_t num_words = stream_cmd.num_samps / SAMPLES_PER_WORD;
+
+ // Calculate the word from flags and length
+ const uint32_t cmd_word = 0
+ | (uint32_t(stream_cmd.stream_now ? 1 : 0) << 31)
+ | (uint32_t(inst_chain ? 1 : 0) << 30)
+ | (uint32_t(inst_reload ? 1 : 0) << 29)
+ | (uint32_t(inst_stop ? 1 : 0) << 28)
+ | (inst_samps ? num_words : (inst_stop ? 0 : cont_burst_size));
+
+ // Issue the stream command
+ sr_write("RX_CTRL_COMMAND", cmd_word, chan);
+ }
+
+private:
+ struct replay_params_t {
+ size_t words_per_packet;
+ uint32_t rec_base_addr;
+ uint32_t rec_buffer_size;
+ uint32_t play_base_addr;
+ uint32_t play_buffer_size;
+ };
+
+ size_t _num_channels;
+ std::vector<replay_params_t> _params;
+
+ std::mutex _mutex;
+};
+
+UHD_RFNOC_BLOCK_REGISTER(replay_block_ctrl, "Replay");