aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/rfnoc/block_ctrl_base.cpp
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2019-08-20 10:00:47 -0700
committerMartin Braun <martin.braun@ettus.com>2019-11-26 12:16:25 -0800
commit7d69dcdcc318ccdf87038b732acbf2bf7c087b60 (patch)
tree8179f2f4a14be591d7c856f77f13687b45f9a454 /host/lib/rfnoc/block_ctrl_base.cpp
parent1ac6e6f56100a7e8186481ab0715937759f52737 (diff)
downloaduhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.tar.gz
uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.tar.bz2
uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.zip
Remove proto-RFNoC files
This commit removes all files and parts of files that are used by proto-RFNoC only. uhd: Fix include CMakeLists.txt, add missing files
Diffstat (limited to 'host/lib/rfnoc/block_ctrl_base.cpp')
-rw-r--r--host/lib/rfnoc/block_ctrl_base.cpp678
1 files changed, 0 insertions, 678 deletions
diff --git a/host/lib/rfnoc/block_ctrl_base.cpp b/host/lib/rfnoc/block_ctrl_base.cpp
deleted file mode 100644
index d186910b9..000000000
--- a/host/lib/rfnoc/block_ctrl_base.cpp
+++ /dev/null
@@ -1,678 +0,0 @@
-//
-// Copyright 2014-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-// This file contains the block control functions for block controller classes.
-// See block_ctrl_base_factory.cpp for discovery and factory functions.
-
-#include "nocscript/block_iface.hpp"
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/block_ctrl_base.hpp>
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhdlib/rfnoc/ctrl_iface.hpp>
-#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
-#include <uhdlib/utils/compat_check.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <chrono>
-#include <thread>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-using std::string;
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-block_ctrl_base::block_ctrl_base(const make_args_t& make_args)
- : _tree(make_args.tree)
- , _ctrl_ifaces(make_args.ctrl_ifaces)
- , _base_address(make_args.base_address & 0xFFF0)
- , _noc_id(sr_read64(SR_READBACK_REG_ID))
- , _compat_num(sr_read64(SR_READBACK_COMPAT))
-{
- /*** Identify this block (NoC-ID, block-ID, and block definition) *******/
- // Read NoC-ID (name is passed in through make_args):
- _block_def = blockdef::make_from_noc_id(_noc_id);
- if (not _block_def) {
- UHD_LOG_DEBUG("RFNOC",
- "No block definition found, using default block configuration "
- "for block with NOC ID: "
- + str(boost::format("0x%08X") % _noc_id));
- _block_def = blockdef::make_from_noc_id(DEFAULT_NOC_ID_64);
- }
- UHD_ASSERT_THROW(_block_def);
- // For the block ID, we start with block count 0 and increase until
- // we get a block ID that's not already registered:
- _block_id.set(make_args.device_index, make_args.block_name, 0);
- while (_tree->exists("xbar/" + _block_id.get_local())) {
- _block_id++;
- }
- UHD_LOG_INFO(unique_id(),
- str(boost::format("Initializing block control (NOC ID: 0x%016X)") % _noc_id));
-
- /*** Check compat number ************************************************/
- assert_fpga_compat(NOC_SHELL_COMPAT_MAJOR,
- NOC_SHELL_COMPAT_MINOR,
- _compat_num,
- "noc_shell",
- unique_id(),
- false /* fail_on_minor_behind */
- );
-
- /*** Initialize property tree *******************************************/
- _root_path = "xbar/" + _block_id.get_local();
- _tree->create<uint64_t>(_root_path / "noc_id").set(_noc_id);
-
- /*** Reset block state *******************************************/
- // We don't know the state of the data-path of this block before
- // we initialize. If everything tore down properly, the data-path
- // should be disconnected and thus idle. Reconfiguration of parameters
- // like SIDs is safe to do in that scenario.
- // However, if data is still streaming, block configuration
- // can potentially lock up noc_shell. So we flush the data-path here.
-
- // Flush is a block-level operation that can be triggered
- // from any block port.
- // Do it once before clearing...
- if (get_ctrl_ports().size() > 0) {
- _flush(get_ctrl_ports().front());
- }
- // Clear flow control and misc state
- clear();
-
- /*** 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:
- const uint64_t fifo_size_reg = sr_read64(SR_READBACK_REG_FIFOSIZE, ctrl_port);
- const size_t buf_size_bytes = size_t(fifo_size_reg & 0xFFFFFFFF);
- if (buf_size_bytes > 0) {
- n_valid_input_buffers++;
- }
- _tree->create<size_t>(_root_path / "input_buffer_size" / ctrl_port)
- .set(buf_size_bytes);
- // Set MTU size and convert to bytes:
- settingsbus_reg_t reg_mtu = SR_READBACK_REG_MTU;
- size_t mtu = 8 * (1 << size_t(sr_read64(reg_mtu, ctrl_port)));
- _tree->create<size_t>(_root_path / "mtu" / ctrl_port).set(mtu);
- // Set command FIFO size
- const uint32_t cmd_fifo_size = (fifo_size_reg >> 32) & 0xFFFFFFFF;
- _ctrl_ifaces[ctrl_port]->set_cmd_fifo_size(cmd_fifo_size);
- // Set default destination SIDs
- // Otherwise, the default is someone else's SID, which we don't want
- sr_write(SR_RESP_IN_DST_SID, 0xFFFF, ctrl_port);
- sr_write(SR_RESP_OUT_DST_SID, 0xFFFF, ctrl_port);
- }
-
- /*** Register names *****************************************************/
- blockdef::registers_t sregs = _block_def->get_settings_registers();
- for (const std::string& reg_name : sregs.keys()) {
- if (DEFAULT_NAMED_SR.has_key(reg_name)) {
- throw uhd::runtime_error(
- str(boost::format("Register name %s is already defined!") % reg_name));
- }
- _tree->create<size_t>(_root_path / "registers" / "sr" / reg_name)
- .set(sregs.get(reg_name));
- }
- blockdef::registers_t rbacks = _block_def->get_readback_registers();
- for (const std::string& reg_name : rbacks.keys()) {
- _tree->create<size_t>(_root_path / "registers" / "rb" / reg_name)
- .set(rbacks.get(reg_name));
- }
-
- /*** Init I/O port definitions ******************************************/
- _init_port_defs("in", _block_def->get_input_ports());
- _init_port_defs("out", _block_def->get_output_ports());
- _num_input_ports = _block_def->get_input_ports().size();
- _num_output_ports = _block_def->get_output_ports().size();
- // FIXME this warning always fails until the input buffer code above is fixed
- // if (_tree->list(_root_path / "ports/in").size() != n_valid_input_buffers) {
- // UHD_LOGGER_WARNING(unique_id()) <<
- // boost::format("[%s] defines %d input buffer sizes, but %d input ports")
- // % get_block_id().get()
- // % n_valid_input_buffers
- // % _tree->list(_root_path / "ports/in").size()
- // ;
- //}
-
- /*** Init default block args ********************************************/
- _nocscript_iface = nocscript::block_iface::make(this);
- _init_block_args();
-}
-
-block_ctrl_base::~block_ctrl_base()
-{
- UHD_SAFE_CALL(if (get_ctrl_ports().size() > 0) {
- // Notify the data-path gatekeeper in noc_shell that we are done
- // with this block. This operation disconnects the noc_block
- // data-path from noc_shell which dumps all input and output
- // packets that are in flight, for now and until the setting is
- // disabled. This prevents long-running blocks without a tear-down
- // mechanism to gracefully flush.
- _start_drain(get_ctrl_ports().front());
- } _tree->remove(_root_path);)
-}
-
-void block_ctrl_base::_init_port_defs(
- const std::string& direction, blockdef::ports_t ports, const size_t first_port_index)
-{
- size_t port_index = first_port_index;
- for (const blockdef::port_t& port_def : ports) {
- fs_path port_path = _root_path / "ports" / direction / port_index;
- if (not _tree->exists(port_path)) {
- _tree->create<blockdef::port_t>(port_path);
- }
- UHD_LOGGER_TRACE(unique_id())
- << "Adding port definition at " << port_path
- << boost::format(": type = '%s' pkt_size = '%s' vlen = '%s'")
- % port_def["type"] % port_def["pkt_size"] % port_def["vlen"];
- _tree->access<blockdef::port_t>(port_path).set(port_def);
- port_index++;
- }
-}
-
-void block_ctrl_base::_init_block_args()
-{
- blockdef::args_t args = _block_def->get_args();
- fs_path arg_path = _root_path / "args";
- for (const size_t port : get_ctrl_ports()) {
- _tree->create<std::string>(arg_path / port);
- }
-
- // First, create all nodes.
- for (const auto& arg : args) {
- fs_path arg_type_path = arg_path / arg["port"] / arg["name"] / "type";
- _tree->create<std::string>(arg_type_path).set(arg["type"]);
- fs_path arg_val_path = arg_path / arg["port"] / arg["name"] / "value";
- if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else if (arg["type"] == "int") {
- _tree->create<int>(arg_val_path);
- } else if (arg["type"] == "double") {
- _tree->create<double>(arg_val_path);
- } else if (arg["type"] == "string") {
- _tree->create<string>(arg_val_path);
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- // Next: Create all the subscribers and coercers.
- // TODO: Add coercer
-#define _SUBSCRIBE_CHECK_AND_RUN(type, arg_tag, error_message) \
- _tree->access<type>(arg_val_path) \
- .add_coerced_subscriber(boost::bind((&nocscript::block_iface::run_and_check), \
- _nocscript_iface, \
- arg[#arg_tag], \
- error_message))
- for (const auto& arg : args) {
- fs_path arg_val_path = arg_path / arg["port"] / arg["name"] / "value";
- if (not arg["check"].empty()) {
- if (arg["type"] == "string") {
- _SUBSCRIBE_CHECK_AND_RUN(string, check, arg["check_message"]);
- } else if (arg["type"] == "int") {
- _SUBSCRIBE_CHECK_AND_RUN(int, check, arg["check_message"]);
- } else if (arg["type"] == "double") {
- _SUBSCRIBE_CHECK_AND_RUN(double, check, arg["check_message"]);
- } else if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- if (not arg["action"].empty()) {
- if (arg["type"] == "string") {
- _SUBSCRIBE_CHECK_AND_RUN(string, action, "");
- } else if (arg["type"] == "int") {
- _SUBSCRIBE_CHECK_AND_RUN(int, action, "");
- } else if (arg["type"] == "double") {
- _SUBSCRIBE_CHECK_AND_RUN(double, action, "");
- } else if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- }
-
- // Finally: Set the values. This will call subscribers, if we have any.
- for (const auto& arg : args) {
- fs_path arg_val_path = arg_path / arg["port"] / arg["name"] / "value";
- if (not arg["value"].empty()) {
- if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else if (arg["type"] == "int") {
- _tree->access<int>(arg_val_path).set(std::stoi(arg["value"]));
- } else if (arg["type"] == "double") {
- _tree->access<double>(arg_val_path).set(std::stod(arg["value"]));
- } else if (arg["type"] == "string") {
- _tree->access<string>(arg_val_path).set(arg["value"]);
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- }
-}
-
-/***********************************************************************
- * FPGA control & communication
- **********************************************************************/
-timed_wb_iface::sptr block_ctrl_base::get_ctrl_iface(const size_t 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, ctrl_iface::sptr> it;
- for (auto it : _ctrl_ifaces) {
- ctrl_ports.push_back(it.first);
- }
- return ctrl_ports;
-}
-
-void block_ctrl_base::sr_write(const uint32_t reg, const uint32_t data, const size_t port)
-{
- if (not _ctrl_ifaces.count(port)) {
- throw uhd::key_error(str(boost::format("[%s] sr_write(): No such port: %d")
- % get_block_id().get() % port));
- }
- try {
- _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()));
- }
-}
-
-void block_ctrl_base::sr_write(
- const std::string& reg, const uint32_t data, const size_t port)
-{
- uint32_t reg_addr = 255;
- if (DEFAULT_NAMED_SR.has_key(reg)) {
- reg_addr = DEFAULT_NAMED_SR[reg];
- } else {
- if (not _tree->exists(_root_path / "registers" / "sr" / reg)) {
- throw uhd::key_error(
- str(boost::format("Unknown settings register name: %s") % reg));
- }
- reg_addr =
- uint32_t(_tree->access<size_t>(_root_path / "registers" / "sr" / reg).get());
- }
- return sr_write(reg_addr, data, port);
-}
-
-uint64_t block_ctrl_base::sr_read64(const settingsbus_reg_t reg, const size_t port)
-{
- if (not _ctrl_ifaces.count(port)) {
- throw uhd::key_error(str(boost::format("[%s] sr_read64(): No such port: %d")
- % get_block_id().get() % port));
- }
- try {
- 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()));
- }
-}
-
-uint32_t block_ctrl_base::sr_read32(const settingsbus_reg_t reg, const size_t port)
-{
- if (not _ctrl_ifaces.count(port)) {
- throw uhd::key_error(str(boost::format("[%s] sr_read32(): No such port: %d")
- % get_block_id().get() % port));
- }
- try {
- 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()));
- }
-}
-
-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
- return sr_read64(SR_READBACK_REG_USER, port);
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("%s user_reg_read64() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-uint64_t block_ctrl_base::user_reg_read64(const std::string& reg, const size_t port)
-{
- if (not _tree->exists(_root_path / "registers" / "rb" / reg)) {
- throw uhd::key_error(
- str(boost::format("Invalid readback register name: %s") % reg));
- }
- return user_reg_read64(
- uint32_t(_tree->access<size_t>(_root_path / "registers" / "rb" / reg).get()),
- port);
-}
-
-uint32_t block_ctrl_base::user_reg_read32(const uint32_t addr, const size_t port)
-{
- try {
- // Set readback register address
- sr_write(SR_READBACK_ADDR, addr, port);
- // Read readback register via RFNoC
- return sr_read32(SR_READBACK_REG_USER, port);
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("[%s] user_reg_read32() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-uint32_t block_ctrl_base::user_reg_read32(const std::string& reg, const size_t port)
-{
- if (not _tree->exists(_root_path / "registers" / "rb" / reg)) {
- throw uhd::key_error(
- str(boost::format("Invalid readback register name: %s") % reg));
- }
- return user_reg_read32(
- uint32_t(_tree->access<size_t>(_root_path / "registers" / "rb" / reg).get()),
- port);
-}
-
-void block_ctrl_base::set_command_time(const time_spec_t& time_spec, const size_t port)
-{
- if (port == ANY_PORT) {
- for (const size_t specific_port : get_ctrl_ports()) {
- set_command_time(time_spec, specific_port);
- }
- return;
- }
-
- _cmd_timespecs[port] = time_spec;
- _set_command_time(time_spec, port);
-}
-
-time_spec_t block_ctrl_base::get_command_time(const size_t port)
-{
- return _cmd_timespecs[port];
-}
-
-void block_ctrl_base::set_command_tick_rate(const double tick_rate, const size_t port)
-{
- if (port == ANY_PORT) {
- for (const size_t specific_port : get_ctrl_ports()) {
- set_command_tick_rate(tick_rate, specific_port);
- }
- return;
- }
-
- _cmd_tickrates[port] = tick_rate;
-}
-
-double block_ctrl_base::get_command_tick_rate(const size_t port)
-{
- return _cmd_tickrates[port];
-}
-
-void block_ctrl_base::clear_command_time(const size_t port)
-{
- _cmd_timespecs[port] = time_spec_t(0.0);
-}
-
-void block_ctrl_base::clear()
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::clear()");
- // Call parent...
- node_ctrl_base::clear();
- // ...then child
- for (const size_t port_index : get_ctrl_ports()) {
- _clear(port_index);
- }
-}
-
-uint32_t block_ctrl_base::get_address(size_t block_port)
-{
- UHD_ASSERT_THROW(block_port < 16);
- return (_base_address & 0xFFF0) | (block_port & 0xF);
-}
-
-/***********************************************************************
- * Argument handling
- **********************************************************************/
-void block_ctrl_base::set_args(const uhd::device_addr_t& args, const size_t port)
-{
- for (const std::string& key : args.keys()) {
- if (_tree->exists(get_arg_path(key, port))) {
- set_arg(key, args.get(key), port);
- }
- }
-}
-
-void block_ctrl_base::set_arg(
- const std::string& key, const std::string& val, const size_t port)
-{
- fs_path arg_path = get_arg_path(key, port);
- if (not _tree->exists(arg_path / "value")) {
- throw uhd::runtime_error(str(
- boost::format("Attempting to set uninitialized argument '%s' on block '%s'")
- % key % unique_id()));
- }
-
- std::string type = _tree->access<std::string>(arg_path / "type").get();
- fs_path arg_val_path = arg_path / "value";
- try {
- if (type == "string") {
- _tree->access<std::string>(arg_val_path).set(val);
- } else if (type == "int") {
- _tree->access<int>(arg_val_path).set(std::stoi(val));
- } else if (type == "double") {
- _tree->access<double>(arg_val_path).set(std::stod(val));
- } else if (type == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- }
- } catch (const boost::bad_lexical_cast&) {
- throw uhd::value_error(
- str(boost::format("Error trying to cast value %s == '%s' to type '%s'") % key
- % val % type));
- }
-}
-
-device_addr_t block_ctrl_base::get_args(const size_t port) const
-{
- device_addr_t args;
- for (const std::string& key : _tree->list(_root_path / "args" / port)) {
- args[key] = get_arg(key);
- }
- return args;
-}
-
-std::string block_ctrl_base::get_arg(const std::string& key, const size_t port) const
-{
- fs_path arg_path = get_arg_path(key, port);
- if (not _tree->exists(arg_path / "value")) {
- throw uhd::runtime_error(str(
- boost::format("Attempting to get uninitialized argument '%s' on block '%s'")
- % key % unique_id()));
- }
-
- std::string type = _tree->access<std::string>(arg_path / "type").get();
- fs_path arg_val_path = arg_path / "value";
- if (type == "string") {
- return _tree->access<std::string>(arg_val_path).get();
- } else if (type == "int") {
- return std::to_string(_tree->access<int>(arg_val_path).get());
- } else if (type == "double") {
- return std::to_string(_tree->access<double>(arg_val_path).get());
- } else if (type == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- }
-
- UHD_THROW_INVALID_CODE_PATH();
-}
-
-std::string block_ctrl_base::get_arg_type(const std::string& key, const size_t port) const
-{
- fs_path arg_type_path = _root_path / "args" / port / key / "type";
- return _tree->access<std::string>(arg_type_path).get();
-}
-
-stream_sig_t block_ctrl_base::_resolve_port_def(const blockdef::port_t& port_def) const
-{
- if (not port_def.is_valid()) {
- throw uhd::runtime_error(
- str(boost::format("Invalid port definition: %s") % port_def.to_string()));
- }
-
- // TODO this entire section is pretty dumb at this point. Needs better
- // checks.
- stream_sig_t stream_sig;
- // Item Type
- if (port_def.is_variable("type")) {
- std::string var_name = port_def["type"].substr(1);
- // TODO check this is even a string
- stream_sig.item_type = get_arg(var_name);
- } else if (port_def.is_keyword("type")) {
- throw uhd::runtime_error("keywords resolution for type not yet implemented");
- } else {
- stream_sig.item_type = port_def["type"];
- }
-
- // Vector length
- if (port_def.is_variable("vlen")) {
- std::string var_name = port_def["vlen"].substr(1);
- stream_sig.vlen = boost::lexical_cast<size_t>(get_arg(var_name));
- } else if (port_def.is_keyword("vlen")) {
- throw uhd::runtime_error("keywords resolution for vlen not yet implemented");
- } else {
- stream_sig.vlen = boost::lexical_cast<size_t>(port_def["vlen"]);
- }
-
- // Packet size
- if (port_def.is_variable("pkt_size")) {
- std::string var_name = port_def["pkt_size"].substr(1);
- stream_sig.packet_size = boost::lexical_cast<size_t>(get_arg(var_name));
- } else if (port_def.is_keyword("pkt_size")) {
- if (port_def["pkt_size"] != "%vlen") {
- throw uhd::runtime_error(
- "generic keywords resolution for pkt_size not yet implemented");
- }
- if (stream_sig.vlen == 0) {
- stream_sig.packet_size = 0;
- } else {
- if (stream_sig.item_type.empty()) {
- throw uhd::runtime_error(
- "cannot resolve pkt_size if item type is not given");
- }
- size_t bpi = uhd::convert::get_bytes_per_item(stream_sig.item_type);
- stream_sig.packet_size = stream_sig.vlen * bpi;
- }
- } else {
- stream_sig.packet_size = boost::lexical_cast<size_t>(port_def["pkt_size"]);
- }
-
- return stream_sig;
-}
-
-void block_ctrl_base::_start_drain(const size_t port)
-{
- // Begin flushing data out of the block by writing to the flushing
- // registers, then disabling flow control. We do this because we don't know
- // what state the flow-control module was left in in the previous run
- sr_write(SR_CLEAR_TX_FC, 0x2, port);
- sr_write(SR_CLEAR_RX_FC, 0x2, port);
- sr_write(SR_FLOW_CTRL_EN, 0, port);
-}
-
-bool block_ctrl_base::_flush(const size_t port)
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_flush (port=" << port << ")");
-
- auto is_data_streaming = [this](int time_ms) -> bool {
- // noc_shell has 2 16-bit counters (one for TX and one for RX) in the top
- // 32 bits of the SR_READBACK_REG_GLOBAL_PARAMS. For all the checks below
- // we want to make sure that the counts are not changing i.e. no data is
- // streaming. So we just look at the two counters together as a single
- // 32-bit quantity.
- auto old_cnts =
- static_cast<uint32_t>(this->sr_read64(SR_READBACK_REG_GLOBAL_PARAMS) >> 32);
- std::this_thread::sleep_for(std::chrono::milliseconds(time_ms));
- auto new_cnts =
- static_cast<uint32_t>(this->sr_read64(SR_READBACK_REG_GLOBAL_PARAMS) >> 32);
- return (new_cnts != old_cnts);
- };
-
- // We always want to try flushing out data. This is done by starting to
- // drain the data out of the block, then checking if counts have changed.
- // If a change is detected, this is most likely because the last
- // session terminated abnormally or if logic in a noc_block is
- // misbehaving. This is a situation that we may not be able to
- // recover from because we are in a partially initialized state.
- // We will try to at least not lock up the FPGA.
-
- // Disconnect the RX and TX data paths and let them flush.
- // A timeout of 2s is chosen to be conservative. It needs to account for:
- // - Upstream blocks that weren't terminated to run out of FC credits
- // - This block which might be finishing up with its data output
- constexpr int FLUSH_TIMEOUT_MS = 2000; // This is approximate
- bool success = false;
- _start_drain(port);
- for (int i = 0; i < FLUSH_TIMEOUT_MS / 10; i++) {
- if (not is_data_streaming(10)) {
- success = true;
- break;
- }
- }
- // Stop flushing
- sr_write(SR_CLEAR_TX_FC, 0x0, port); // Enable TX data-path
- sr_write(SR_CLEAR_RX_FC, 0x0, port); // Enable RX data-path
-
- if (not success) {
- // Print a warning only if data was still flushing
- // after the timeout elapsed
- UHD_LOGGER_WARNING(unique_id())
- << "This block seems to be busy most likely due to the abnormal termination "
- "of a previous "
- "session. Attempted recovery but it may not have worked depending on the "
- "behavior of "
- "other blocks in the design. Please restart the application.";
- }
- return success;
-}
-
-
-/***********************************************************************
- * Hooks & Derivables
- **********************************************************************/
-void block_ctrl_base::_clear(const size_t port)
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_clear()");
- sr_write(SR_CLEAR_TX_FC, 0x1, port); // Write 1 to trigger a single cycle clear event
- sr_write(SR_CLEAR_TX_FC, 0x0, port); // Write 0 to reset the clear flag
- sr_write(SR_CLEAR_RX_FC, 0x1, port); // Write 1 to trigger a single cycle clear event
- sr_write(SR_CLEAR_RX_FC, 0x0, port); // Write 0 to reset the clear flag
-}
-
-void block_ctrl_base::_set_command_time(
- const time_spec_t& /*time_spec*/, const size_t /*port*/)
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_set_command_time()");
-}
-// vim: sw=4 et: