diff options
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_io_impl.cpp | 1 | ||||
-rw-r--r-- | host/lib/usrp/cores/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/usrp/cores/dma_fifo_core_3000.cpp | 397 | ||||
-rw-r--r-- | host/lib/usrp/cores/dma_fifo_core_3000.hpp | 86 | ||||
-rw-r--r-- | host/lib/usrp/cores/tx_vita_core_3000.cpp | 59 | ||||
-rw-r--r-- | host/lib/usrp/cores/tx_vita_core_3000.hpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_impl.cpp | 1 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_io_impl.cpp | 1 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_fw_common.h | 2 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 70 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 12 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_io_impl.cpp | 10 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 4 |
14 files changed, 615 insertions, 46 deletions
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 360dc39b9..3aaf28ab3 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -760,7 +760,7 @@ void b200_impl::setup_radio(const size_t dspno) perif.ddc->set_link_rate(10e9/8); //whatever perif.ddc->set_mux("IQ", false, dspno == 1 ? true : false, dspno == 1 ? true : false); perif.ddc->set_freq(rx_dsp_core_3000::DEFAULT_CORDIC_FREQ); - perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); + perif.deframer = tx_vita_core_3000::make_no_radio_buff(perif.ctrl, TOREG(SR_TX_CTRL)); perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever perif.duc->set_freq(tx_dsp_core_3000::DEFAULT_CORDIC_FREQ); @@ -792,7 +792,6 @@ void b200_impl::setup_radio(const size_t dspno) // create tx dsp control objects //////////////////////////////////////////////////////////////////// _tree->access<double>(mb_path / "tick_rate") - .subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1)) .subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1)); const fs_path tx_dsp_path = mb_path / "tx_dsps" / dspno; perif.duc->populate_subtree(_tree->subtree(tx_dsp_path)); diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 7fcd04823..41b4b8a74 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -159,7 +159,6 @@ void b200_impl::update_tick_rate(const double new_tick_rate) boost::shared_ptr<sph::send_packet_streamer> my_streamer = boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock()); if (my_streamer) my_streamer->set_tick_rate(new_tick_rate); - perif.deframer->set_tick_rate(new_tick_rate); } } diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt index 909c02941..7a0f6cc93 100644 --- a/host/lib/usrp/cores/CMakeLists.txt +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -41,4 +41,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_3000.cpp ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_core_3000.cpp ${CMAKE_CURRENT_SOURCE_DIR}/gpio_atr_3000.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dma_fifo_core_3000.cpp ) diff --git a/host/lib/usrp/cores/dma_fifo_core_3000.cpp b/host/lib/usrp/cores/dma_fifo_core_3000.cpp new file mode 100644 index 000000000..1a9d5dd5c --- /dev/null +++ b/host/lib/usrp/cores/dma_fifo_core_3000.cpp @@ -0,0 +1,397 @@ +// +// Copyright 2015 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "dma_fifo_core_3000.hpp" +#include <uhd/exception.hpp> +#include <boost/thread/thread.hpp> //sleep +#include <uhd/utils/soft_register.hpp> +#include <uhd/utils/msg.hpp> + +using namespace uhd; + +#define SR_DRAM_BIST_BASE 16 + +dma_fifo_core_3000::~dma_fifo_core_3000(void) { + /* NOP */ +} + +class dma_fifo_core_3000_impl : public dma_fifo_core_3000 +{ +protected: + class rb_addr_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(ADDR, /*width*/ 3, /*shift*/ 0); //[2:0] + + static const boost::uint32_t RB_FIFO_STATUS = 0; + static const boost::uint32_t RB_BIST_STATUS = 1; + static const boost::uint32_t RB_BIST_XFER_CNT = 2; + static const boost::uint32_t RB_BIST_CYC_CNT = 3; + + rb_addr_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 0) + { + //Initial values + set(ADDR, RB_FIFO_STATUS); + } + }; + + class fifo_ctrl_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(CLEAR_FIFO, /*width*/ 1, /*shift*/ 0); //[0] + UHD_DEFINE_SOFT_REG_FIELD(RD_SUPPRESS_EN, /*width*/ 1, /*shift*/ 1); //[1] + UHD_DEFINE_SOFT_REG_FIELD(BURST_TIMEOUT, /*width*/ 12, /*shift*/ 4); //[15:4] + UHD_DEFINE_SOFT_REG_FIELD(RD_SUPPRESS_THRESH, /*width*/ 16, /*shift*/ 16); //[31:16] + + fifo_ctrl_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 4) + { + //Initial values + set(CLEAR_FIFO, 1); + set(RD_SUPPRESS_EN, 0); + set(BURST_TIMEOUT, 256); + set(RD_SUPPRESS_THRESH, 0); + } + }; + + class base_addr_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(BASE_ADDR, /*width*/ 30, /*shift*/ 0); //[29:0] + + base_addr_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 8) + { + //Initial values + set(BASE_ADDR, 0x00000000); + } + }; + + class addr_mask_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(ADDR_MASK, /*width*/ 30, /*shift*/ 0); //[29:0] + + addr_mask_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 12) + { + //Initial values + set(ADDR_MASK, 0xFF000000); + } + }; + + class bist_ctrl_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(GO, /*width*/ 1, /*shift*/ 0); //[0] + UHD_DEFINE_SOFT_REG_FIELD(CONTINUOUS_MODE, /*width*/ 1, /*shift*/ 1); //[1] + UHD_DEFINE_SOFT_REG_FIELD(TEST_PATT, /*width*/ 2, /*shift*/ 4); //[5:4] + + static const boost::uint32_t TEST_PATT_ZERO_ONE = 0; + static const boost::uint32_t TEST_PATT_CHECKERBOARD = 1; + static const boost::uint32_t TEST_PATT_COUNT = 2; + static const boost::uint32_t TEST_PATT_COUNT_INV = 3; + + bist_ctrl_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 16) + { + //Initial values + set(GO, 0); + set(CONTINUOUS_MODE, 0); + set(TEST_PATT, TEST_PATT_ZERO_ONE); + } + }; + + class bist_cfg_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(MAX_PKTS, /*width*/ 18, /*shift*/ 0); //[17:0] + UHD_DEFINE_SOFT_REG_FIELD(MAX_PKT_SIZE, /*width*/ 13, /*shift*/ 18); //[30:18] + UHD_DEFINE_SOFT_REG_FIELD(PKT_SIZE_RAMP, /*width*/ 1, /*shift*/ 31); //[31] + + bist_cfg_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 20) + { + //Initial values + set(MAX_PKTS, 0); + set(MAX_PKT_SIZE, 0); + set(PKT_SIZE_RAMP, 0); + } + }; + + class bist_delay_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(TX_PKT_DELAY, /*width*/ 16, /*shift*/ 0); //[15:0] + UHD_DEFINE_SOFT_REG_FIELD(RX_SAMP_DELAY, /*width*/ 8, /*shift*/ 16); //[23:16] + + bist_delay_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 24) + { + //Initial values + set(TX_PKT_DELAY, 0); + set(RX_SAMP_DELAY, 0); + } + }; + + class bist_sid_reg_t : public soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(SID, /*width*/ 32, /*shift*/ 0); //[31:0] + + bist_sid_reg_t(boost::uint32_t base): + soft_reg32_wo_t(base + 28) + { + //Initial values + set(SID, 0); + } + }; + +public: + class fifo_readback { + public: + fifo_readback(wb_iface::sptr iface, const size_t base, const size_t rb_addr) : + _iface(iface), _addr_reg(base), _rb_addr(rb_addr) + { + _addr_reg.initialize(*iface, true); + } + + bool is_fifo_instantiated() { + boost::lock_guard<boost::mutex> lock(_mutex); + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_FIFO_STATUS); + return _iface->peek32(_rb_addr) & 0x80000000; + } + + boost::uint32_t get_occupied_cnt() { + boost::lock_guard<boost::mutex> lock(_mutex); + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_FIFO_STATUS); + return _iface->peek32(_rb_addr) & 0x7FFFFFF; + } + + boost::uint32_t is_fifo_busy() { + boost::lock_guard<boost::mutex> lock(_mutex); + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_FIFO_STATUS); + return _iface->peek32(_rb_addr) & 0x40000000; + } + + struct bist_status_t { + bool running; + bool finished; + boost::uint8_t error; + }; + + bist_status_t get_bist_status() { + boost::lock_guard<boost::mutex> lock(_mutex); + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_STATUS); + boost::uint32_t st32 = _iface->peek32(_rb_addr) & 0xF; + bist_status_t status; + status.running = st32 & 0x1; + status.finished = st32 & 0x2; + status.error = static_cast<boost::uint8_t>((st32>>2) & 0x3); + return status; + } + + bool is_ext_bist_supported() { + boost::lock_guard<boost::mutex> lock(_mutex); + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_STATUS); + return _iface->peek32(_rb_addr) & 0x80000000; + } + + double get_xfer_ratio() { + boost::lock_guard<boost::mutex> lock(_mutex); + boost::uint32_t xfer_cnt = 0, cyc_cnt = 0; + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_XFER_CNT); + xfer_cnt = _iface->peek32(_rb_addr); + _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_CYC_CNT); + cyc_cnt = _iface->peek32(_rb_addr); + return (static_cast<double>(xfer_cnt)/cyc_cnt); + } + + private: + wb_iface::sptr _iface; + rb_addr_reg_t _addr_reg; + const size_t _rb_addr; + boost::mutex _mutex; + }; + +public: + dma_fifo_core_3000_impl(wb_iface::sptr iface, const size_t base, const size_t readback): + _iface(iface), _base(base), _fifo_readback(iface, base, readback), + _fifo_ctrl_reg(base), _base_addr_reg(base), _addr_mask_reg(base), + _bist_ctrl_reg(base), _bist_cfg_reg(base), _bist_delay_reg(base), _bist_sid_reg(base) + { + _fifo_ctrl_reg.initialize(*iface, true); + _base_addr_reg.initialize(*iface, true); + _addr_mask_reg.initialize(*iface, true); + _bist_ctrl_reg.initialize(*iface, true); + _bist_cfg_reg.initialize(*iface, true); + _has_ext_bist = _fifo_readback.is_ext_bist_supported(); + if (_has_ext_bist) { + _bist_delay_reg.initialize(*iface, true); + _bist_sid_reg.initialize(*iface, true); + } + flush(); + } + + virtual void flush() { + //Clear the FIFO and hold it in that state + _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 1); + //Re-arm the FIFO + _wait_for_fifo_empty(); + _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 0); + } + + virtual void resize(const boost::uint32_t base_addr, const boost::uint32_t size) { + //Validate parameters + if (size < 8192) throw uhd::runtime_error("DMA FIFO must be larger than 8KiB"); + boost::uint32_t size_mask = size - 1; + if (size & size_mask) throw uhd::runtime_error("DMA FIFO size must be a power of 2"); + + //Clear the FIFO and hold it in that state + _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 1); + //Write base address and mask + _base_addr_reg.write(base_addr_reg_t::BASE_ADDR, base_addr); + _addr_mask_reg.write(addr_mask_reg_t::ADDR_MASK, ~size_mask); + + //Re-arm the FIFO + flush(); + } + + virtual boost::uint32_t get_bytes_occupied() { + return _fifo_readback.get_occupied_cnt() * 8; + } + + virtual bool ext_bist_supported() { + return _fifo_readback.is_ext_bist_supported(); + } + + virtual boost::uint8_t run_bist(bool finite = true, boost::uint32_t timeout_ms = 500) { + return run_ext_bist(finite, 0, 0, 0, timeout_ms); + } + + virtual boost::uint8_t run_ext_bist( + bool finite, + boost::uint32_t rx_samp_delay, + boost::uint32_t tx_pkt_delay, + boost::uint32_t sid, + boost::uint32_t timeout_ms = 500 + ) { + boost::lock_guard<boost::mutex> lock(_mutex); + + _wait_for_bist_done(timeout_ms, true); //Stop previous BIST and wait (if running) + _bist_ctrl_reg.write(bist_ctrl_reg_t::GO, 0); //Reset + + _bist_cfg_reg.set(bist_cfg_reg_t::MAX_PKTS, (2^18)-1); + _bist_cfg_reg.set(bist_cfg_reg_t::MAX_PKT_SIZE, 8000); + _bist_cfg_reg.set(bist_cfg_reg_t::PKT_SIZE_RAMP, 0); + _bist_cfg_reg.flush(); + + if (_has_ext_bist) { + _bist_delay_reg.set(bist_delay_reg_t::RX_SAMP_DELAY, rx_samp_delay); + _bist_delay_reg.set(bist_delay_reg_t::TX_PKT_DELAY, tx_pkt_delay); + _bist_delay_reg.flush(); + + _bist_sid_reg.write(bist_sid_reg_t::SID, sid); + } else { + if (rx_samp_delay != 0 || tx_pkt_delay != 0 || sid != 0) { + throw uhd::not_implemented_error( + "dma_fifo_core_3000: Runtime delay and SID support only available on FPGA images with extended BIST enabled"); + } + } + + _bist_ctrl_reg.set(bist_ctrl_reg_t::TEST_PATT, bist_ctrl_reg_t::TEST_PATT_COUNT); + _bist_ctrl_reg.set(bist_ctrl_reg_t::CONTINUOUS_MODE, finite ? 0 : 1); + _bist_ctrl_reg.write(bist_ctrl_reg_t::GO, 1); + + if (!finite) { + boost::this_thread::sleep(boost::posix_time::milliseconds(timeout_ms)); + } + + _wait_for_bist_done(timeout_ms, !finite); + if (!_fifo_readback.get_bist_status().finished) { + throw uhd::runtime_error("dma_fifo_core_3000: DRAM BIST state machine is in a bad state."); + } + + return _fifo_readback.get_bist_status().error; + } + + virtual double get_bist_throughput(double fifo_clock_rate) { + if (_has_ext_bist) { + _wait_for_bist_done(1000); + static const double BYTES_PER_CYC = 8; + return _fifo_readback.get_xfer_ratio() * fifo_clock_rate * BYTES_PER_CYC; + } else { + throw uhd::not_implemented_error( + "dma_fifo_core_3000: Throughput counter only available on FPGA images with extended BIST enabled"); + } + } + +private: + void _wait_for_fifo_empty() + { + boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time(); + boost::posix_time::time_duration elapsed; + + while (_fifo_readback.is_fifo_busy()) { + boost::this_thread::sleep(boost::posix_time::microsec(1000)); + elapsed = boost::posix_time::microsec_clock::local_time() - start_time; + if (elapsed.total_milliseconds() > 100) break; + } + } + + void _wait_for_bist_done(boost::uint32_t timeout_ms, bool force_stop = false) + { + boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time(); + boost::posix_time::time_duration elapsed; + + while (_fifo_readback.get_bist_status().running) { + if (force_stop) { + _bist_ctrl_reg.write(bist_ctrl_reg_t::GO, 0); + force_stop = false; + } + boost::this_thread::sleep(boost::posix_time::microsec(1000)); + elapsed = boost::posix_time::microsec_clock::local_time() - start_time; + if (elapsed.total_milliseconds() > timeout_ms) break; + } + } + +private: + wb_iface::sptr _iface; + const size_t _base; + boost::mutex _mutex; + bool _has_ext_bist; + + fifo_readback _fifo_readback; + fifo_ctrl_reg_t _fifo_ctrl_reg; + base_addr_reg_t _base_addr_reg; + addr_mask_reg_t _addr_mask_reg; + bist_ctrl_reg_t _bist_ctrl_reg; + bist_cfg_reg_t _bist_cfg_reg; + bist_delay_reg_t _bist_delay_reg; + bist_sid_reg_t _bist_sid_reg; +}; + +// +// Static make function +// +dma_fifo_core_3000::sptr dma_fifo_core_3000::make(wb_iface::sptr iface, const size_t set_base, const size_t rb_addr) +{ + if (check(iface, set_base, rb_addr)) { + return sptr(new dma_fifo_core_3000_impl(iface, set_base, rb_addr)); + } else { + throw uhd::runtime_error(""); + } +} + +bool dma_fifo_core_3000::check(wb_iface::sptr iface, const size_t set_base, const size_t rb_addr) +{ + dma_fifo_core_3000_impl::fifo_readback fifo_rb(iface, set_base, rb_addr); + return fifo_rb.is_fifo_instantiated(); +} diff --git a/host/lib/usrp/cores/dma_fifo_core_3000.hpp b/host/lib/usrp/cores/dma_fifo_core_3000.hpp new file mode 100644 index 000000000..41430e5c3 --- /dev/null +++ b/host/lib/usrp/cores/dma_fifo_core_3000.hpp @@ -0,0 +1,86 @@ +// +// Copyright 2015 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_DMA_FIFO_CORE_3000_HPP +#define INCLUDED_LIBUHD_USRP_DMA_FIFO_CORE_3000_HPP + +#include <uhd/config.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> +#include <uhd/types/wb_iface.hpp> + + +class dma_fifo_core_3000 : boost::noncopyable +{ +public: + typedef boost::shared_ptr<dma_fifo_core_3000> sptr; + virtual ~dma_fifo_core_3000(void) = 0; + + /*! + * Create a DMA FIFO controller using the given bus, settings and readback base + * Throws uhd::runtime_error if a DMA FIFO is not instantiated in the FPGA + */ + static sptr make(uhd::wb_iface::sptr iface, const size_t set_base, const size_t rb_addr); + + /*! + * Check if a DMA FIFO is instantiated in the FPGA + */ + static bool check(uhd::wb_iface::sptr iface, const size_t set_base, const size_t rb_addr); + + /*! + * Flush the DMA FIFO. Will clear all contents. + */ + virtual void flush() = 0; + + /*! + * Resize and rebase the DMA FIFO. Will clear all contents. + */ + virtual void resize(const boost::uint32_t base_addr, const boost::uint32_t size) = 0; + + /*! + * Get the (approx) number of bytes currently in the DMA FIFO + */ + virtual boost::uint32_t get_bytes_occupied() = 0; + + /*! + * Run the built-in-self-test routine for the DMA FIFO + */ + virtual boost::uint8_t run_bist(bool finite = true, boost::uint32_t timeout_ms = 500) = 0; + + /*! + * Is extended BIST supported + */ + virtual bool ext_bist_supported() = 0; + + /*! + * Run the built-in-self-test routine for the DMA FIFO (extended BIST only) + */ + virtual boost::uint8_t run_ext_bist( + bool finite, + boost::uint32_t rx_samp_delay, + boost::uint32_t tx_pkt_delay, + boost::uint32_t sid, + boost::uint32_t timeout_ms = 500) = 0; + + /*! + * Get the throughput measured from the last invocation of the BIST (extended BIST only) + */ + virtual double get_bist_throughput(double fifo_clock_rate) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_DMA_FIFO_CORE_3000_HPP */ diff --git a/host/lib/usrp/cores/tx_vita_core_3000.cpp b/host/lib/usrp/cores/tx_vita_core_3000.cpp index 71a2b7e21..c76b384d9 100644 --- a/host/lib/usrp/cores/tx_vita_core_3000.cpp +++ b/host/lib/usrp/cores/tx_vita_core_3000.cpp @@ -18,9 +18,11 @@ #include "tx_vita_core_3000.hpp" #include <uhd/utils/safe_call.hpp> -#define REG_CTRL_ERROR_POLICY _base + 0 -#define REG_DEFRAMER_CYCLE_FC_UPS _base + 2*4 + 0 -#define REG_DEFRAMER_PACKET_FC_UPS _base + 2*4 + 4 +#define REG_CTRL_ERROR_POLICY (_base + 0) +#define REG_FC_PRE_RADIO_RESP_BASE (_base + 2*4) +#define REG_FC_PRE_FIFO_RESP_BASE (_base + 4*4) +#define REG_CTRL_FC_CYCLE_OFFSET (0*4) +#define REG_CTRL_FC_PACKET_OFFSET (1*4) using namespace uhd; @@ -32,12 +34,22 @@ struct tx_vita_core_3000_impl : tx_vita_core_3000 { tx_vita_core_3000_impl( wb_iface::sptr iface, - const size_t base + const size_t base, + fc_monitor_loc fc_location ): _iface(iface), - _base(base) + _base(base), + _fc_base((fc_location==FC_PRE_RADIO or fc_location==FC_DEFAULT) ? + REG_FC_PRE_RADIO_RESP_BASE : REG_FC_PRE_FIFO_RESP_BASE), + _fc_location(fc_location) { - this->set_tick_rate(1); //init to non zero + if (fc_location != FC_DEFAULT) { + //Turn off the other FC monitoring module + const size_t other_fc_base = (fc_location==FC_PRE_RADIO) ? + REG_FC_PRE_FIFO_RESP_BASE : REG_FC_PRE_RADIO_RESP_BASE; + _iface->poke32(other_fc_base + REG_CTRL_FC_CYCLE_OFFSET, 0); + _iface->poke32(other_fc_base + REG_CTRL_FC_PACKET_OFFSET, 0); + } this->set_underflow_policy("next_packet"); this->clear(); } @@ -56,11 +68,6 @@ struct tx_vita_core_3000_impl : tx_vita_core_3000 this->set_underflow_policy(_policy); //clears the seq } - void set_tick_rate(const double rate) - { - _tick_rate = rate; - } - void set_underflow_policy(const std::string &policy) { if (policy == "next_packet") @@ -89,23 +96,35 @@ struct tx_vita_core_3000_impl : tx_vita_core_3000 void configure_flow_control(const size_t cycs_per_up, const size_t pkts_per_up) { - if (cycs_per_up == 0) _iface->poke32(REG_DEFRAMER_CYCLE_FC_UPS, 0); - else _iface->poke32(REG_DEFRAMER_CYCLE_FC_UPS, (1 << 31) | ((cycs_per_up) & 0xffffff)); + if (cycs_per_up == 0) _iface->poke32(_fc_base + REG_CTRL_FC_CYCLE_OFFSET, 0); + else _iface->poke32(_fc_base + REG_CTRL_FC_CYCLE_OFFSET, (1 << 31) | ((cycs_per_up) & 0xffffff)); - if (pkts_per_up == 0) _iface->poke32(REG_DEFRAMER_PACKET_FC_UPS, 0); - else _iface->poke32(REG_DEFRAMER_PACKET_FC_UPS, (1 << 31) | ((pkts_per_up) & 0xffff)); + if (pkts_per_up == 0) _iface->poke32(_fc_base + REG_CTRL_FC_PACKET_OFFSET, 0); + else _iface->poke32(_fc_base + REG_CTRL_FC_PACKET_OFFSET, (1 << 31) | ((pkts_per_up) & 0xffff)); } - wb_iface::sptr _iface; - const size_t _base; - double _tick_rate; - std::string _policy; + wb_iface::sptr _iface; + const size_t _base; + const size_t _fc_base; + std::string _policy; + fc_monitor_loc _fc_location; + }; tx_vita_core_3000::sptr tx_vita_core_3000::make( wb_iface::sptr iface, + const size_t base, + fc_monitor_loc fc_location +) +{ + return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base, fc_location)); +} + +tx_vita_core_3000::sptr tx_vita_core_3000::make_no_radio_buff( + wb_iface::sptr iface, const size_t base ) { - return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base)); + //No internal radio buffer so only pre-radio monitoring is supported. + return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base, FC_DEFAULT)); } diff --git a/host/lib/usrp/cores/tx_vita_core_3000.hpp b/host/lib/usrp/cores/tx_vita_core_3000.hpp index 4c0052d4f..bd0f20ba4 100644 --- a/host/lib/usrp/cores/tx_vita_core_3000.hpp +++ b/host/lib/usrp/cores/tx_vita_core_3000.hpp @@ -32,17 +32,27 @@ class tx_vita_core_3000 : boost::noncopyable public: typedef boost::shared_ptr<tx_vita_core_3000> sptr; + enum fc_monitor_loc { + FC_DEFAULT, + FC_PRE_RADIO, + FC_PRE_FIFO + }; + virtual ~tx_vita_core_3000(void) = 0; static sptr make( uhd::wb_iface::sptr iface, + const size_t base, + fc_monitor_loc fc_location = FC_PRE_RADIO + ); + + static sptr make_no_radio_buff( + uhd::wb_iface::sptr iface, const size_t base ); virtual void clear(void) = 0; - virtual void set_tick_rate(const double rate) = 0; - virtual void setup(const uhd::stream_args_t &stream_args) = 0; virtual void configure_flow_control(const size_t cycs_per_up, const size_t pkts_per_up) = 0; diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index cfa85a46a..c82ab3d0e 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -998,7 +998,6 @@ void e300_impl::_setup_radio(const size_t dspno) // create tx dsp control objects //////////////////////////////////////////////////////////////////// _tree->access<double>(mb_path / "tick_rate") - .subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1)) .subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1)); const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % dspno); perif.duc->populate_subtree(_tree->subtree(tx_dsp_path)); diff --git a/host/lib/usrp/e300/e300_io_impl.cpp b/host/lib/usrp/e300/e300_io_impl.cpp index 29d250c8f..209a73077 100644 --- a/host/lib/usrp/e300/e300_io_impl.cpp +++ b/host/lib/usrp/e300/e300_io_impl.cpp @@ -87,7 +87,6 @@ void e300_impl::_update_tick_rate(const double rate) boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock()); if (my_streamer) my_streamer->set_tick_rate(rate); - perif.deframer->set_tick_rate(_tick_rate); } } diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index 1b88db69a..dc9e6eba1 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -33,7 +33,7 @@ extern "C" { #define X300_REVISION_MIN 2 #define X300_FW_COMPAT_MAJOR 4 #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 15 +#define X300_FPGA_COMPAT_MAJOR 16 //shared memory sections - in between the stack and the program space #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 98806fe07..0483ecf11 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -51,20 +51,34 @@ using namespace uhd::usrp::gpio_atr; using namespace uhd::usrp::x300; namespace asio = boost::asio; -/*********************************************************************** - * Discovery over the udp and pcie transport - **********************************************************************/ +static bool has_dram_buff(wb_iface::sptr zpu_ctrl) { + bool dramR0 = dma_fifo_core_3000::check( + zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO0), SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO0)); + bool dramR1 = dma_fifo_core_3000::check( + zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO1), SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO1)); + return (dramR0 and dramR1); +} + static std::string get_fpga_option(wb_iface::sptr zpu_ctrl) { - //1G = {0:1G, 1:1G} w/ DRAM, HG = {0:1G, 1:10G} w/ DRAM, XG = {0:10G, 1:10G} w/ DRAM - //HGS = {0:1G, 1:10G} w/ SRAM, XGS = {0:10G, 1:10G} w/ SRAM + //Possible options: + //1G = {0:1G, 1:1G} w/ DRAM, HG = {0:1G, 1:10G} w/ DRAM, XG = {0:10G, 1:10G} w/ DRAM + //1GS = {0:1G, 1:1G} w/ SRAM, HGS = {0:1G, 1:10G} w/ SRAM, XGS = {0:10G, 1:10G} w/ SRAM - //In the default configuration, UHD does not support the HG and XG images so - //they are never autodetected. + std::string option; bool eth0XG = (zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_ETH_TYPE0)) == 0x1); bool eth1XG = (zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_ETH_TYPE1)) == 0x1); - return (eth0XG && eth1XG) ? "XGS" : (eth1XG ? "HGS" : "1G"); + option = (eth0XG && eth1XG) ? "XG" : (eth1XG ? "HG" : "1G"); + + if (not has_dram_buff(zpu_ctrl)) { + option += "S"; + } + return option; } +/*********************************************************************** + * Discovery over the udp and pcie transport + **********************************************************************/ + //@TODO: Refactor the find functions to collapse common code for ethernet and PCIe static device_addrs_t x300_find_with_addr(const device_addr_t &hint) { @@ -730,6 +744,36 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) } //////////////////////////////////////////////////////////////////// + // DRAM FIFO initialization + //////////////////////////////////////////////////////////////////// + mb.has_dram_buff = has_dram_buff(mb.zpu_ctrl); + if (mb.has_dram_buff) { + for (size_t i = 0; i < mboard_members_t::NUM_RADIOS; i++) { + static const size_t NUM_REGS = 8; + mb.dram_buff_ctrl[i] = dma_fifo_core_3000::make( + mb.zpu_ctrl, + SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO0+(i*NUM_REGS)), + SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO0+i)); + mb.dram_buff_ctrl[i]->resize(X300_DRAM_FIFO_SIZE * i, X300_DRAM_FIFO_SIZE); + + if (mb.dram_buff_ctrl[i]->ext_bist_supported()) { + UHD_MSG(status) << boost::format("Running BIST for DRAM FIFO %d... ") % i; + boost::uint32_t bisterr = mb.dram_buff_ctrl[i]->run_bist(); + if (bisterr != 0) { + throw uhd::runtime_error(str(boost::format("DRAM FIFO BIST failed! (code: %d)\n") % bisterr)); + } else { + double throughput = mb.dram_buff_ctrl[i]->get_bist_throughput(X300_BUS_CLOCK_RATE); + UHD_MSG(status) << (boost::format("pass (Throughput: %.1fMB/s)") % (throughput/1e6)) << std::endl; + } + } else { + if (mb.dram_buff_ctrl[i]->run_bist() != 0) { + throw uhd::runtime_error(str(boost::format("DRAM FIFO %d BIST failed!\n") % i)); + } + } + } + } + + //////////////////////////////////////////////////////////////////// // setup radios //////////////////////////////////////////////////////////////////// this->setup_radio(mb_i, "A", dev_addr); @@ -942,7 +986,10 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); perif.ddc->set_link_rate(10e9/8); //whatever - perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + //The DRAM FIFO is treated as in internal radio FIFO for flow control purposes + tx_vita_core_3000::fc_monitor_loc fc_loc = + mb.has_dram_buff ? tx_vita_core_3000::FC_PRE_FIFO : tx_vita_core_3000::FC_PRE_RADIO; + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL), fc_loc); perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); perif.duc->set_link_rate(10e9/8); //whatever @@ -1145,7 +1192,7 @@ x300_impl::both_xports_t x300_impl::make_transport( * connection type.*/ size_t eth_data_rec_frame_size = 0; - if (mb.loaded_fpga_image == "HGS") { + if (mb.loaded_fpga_image.substr(0,2) == "HG") { if (mb.router_dst_here == X300_XB_DST_E0) { eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE; _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_1GIGE); @@ -1153,7 +1200,7 @@ x300_impl::both_xports_t x300_impl::make_transport( eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE); } - } else if (mb.loaded_fpga_image == "XGS") { + } else if (mb.loaded_fpga_image.substr(0,2) == "XG") { eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE; _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE); } @@ -1316,7 +1363,6 @@ void x300_impl::set_tick_rate(mboard_members_t &mb, const double rate) perif.time64->set_tick_rate(rate); perif.framer->set_tick_rate(rate); perif.ddc->set_tick_rate(rate); - perif.deframer->set_tick_rate(rate); perif.duc->set_tick_rate(rate); } } diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index c351e7f00..521ce8a0e 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -42,6 +42,7 @@ #include "rx_frontend_core_200.hpp" #include "tx_frontend_core_200.hpp" #include "gpio_atr_3000.hpp" +#include "dma_fifo_core_3000.hpp" #include <boost/weak_ptr.hpp> #include <uhd/usrp/gps_ctrl.hpp> #include <uhd/usrp/mboard_eeprom.hpp> @@ -56,8 +57,11 @@ static const std::string X300_FW_FILE_NAME = "usrp_x300_fw.bin"; static const double X300_DEFAULT_TICK_RATE = 200e6; //Hz static const double X300_BUS_CLOCK_RATE = 166.666667e6; //Hz -static const size_t X300_TX_HW_BUFF_SIZE = 520*1024; //512K SRAM buffer + 8K 2Clk FIFO -static const size_t X300_TX_FC_RESPONSE_FREQ = 8; //per flow-control window +static const size_t X300_TX_HW_BUFF_SIZE_SRAM = 520*1024; //512K SRAM buffer + 8K 2Clk FIFO +static const size_t X300_TX_FC_RESPONSE_FREQ_SRAM = 8; //per flow-control window +static const size_t X300_TX_HW_BUFF_SIZE_DRAM = 128*1024; +static const size_t X300_TX_FC_RESPONSE_FREQ_DRAM = 32; +static const boost::uint32_t X300_DRAM_FIFO_SIZE = 32*1024*1024; static const size_t X300_RX_SW_BUFF_SIZE_ETH = 0x2000000;//32MiB For an ~8k frame size any size >32MiB is just wasted buffer space static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib @@ -226,6 +230,10 @@ private: return slot_name == "A" ? 0 : 1; } + bool has_dram_buff; + dma_fifo_core_3000::sptr dram_buff_ctrl[NUM_RADIOS]; + + //other perifs on mboard x300_clock_ctrl::sptr clock; uhd::gps_ctrl::sptr gps; diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index e3515af0c..1356daec5 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -216,9 +216,10 @@ struct x300_tx_fc_guts_t * FC credit we have is C = F + M - N (i.e. we can send C more packets * before getting another ack). */ -static size_t get_tx_flow_control_window(size_t frame_size, const device_addr_t& tx_args) +static size_t get_tx_flow_control_window(size_t frame_size, const bool dram_buff, const device_addr_t& tx_args) { - double hw_buff_size = tx_args.cast<double>("send_buff_size", X300_TX_HW_BUFF_SIZE); + double default_buff_size = dram_buff ? X300_TX_HW_BUFF_SIZE_DRAM : X300_TX_HW_BUFF_SIZE_SRAM; + double hw_buff_size = tx_args.cast<double>("send_buff_size", default_buff_size); size_t window_in_pkts = (static_cast<size_t>(hw_buff_size) / frame_size); if (window_in_pkts == 0) { throw uhd::value_error("send_buff_size must be larger than the send_frame_size."); @@ -580,8 +581,9 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_) perif.duc->setup(args); //flow control setup - size_t fc_window = get_tx_flow_control_window(xport.send->get_send_frame_size(), device_addr); //In packets - const size_t fc_handle_window = std::max<size_t>(1, fc_window/X300_TX_FC_RESPONSE_FREQ); + size_t fc_window = get_tx_flow_control_window(xport.send->get_send_frame_size(), mb.has_dram_buff, device_addr); //In packets + const size_t fc_handle_window = std::max<size_t>(1, + fc_window/ (mb.has_dram_buff ? X300_TX_FC_RESPONSE_FREQ_DRAM : X300_TX_FC_RESPONSE_FREQ_SRAM)); UHD_LOG << "TX Flow Control Window = " << fc_window << ", TX Flow Control Handler Window = " << fc_handle_window << std::endl; diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index eba30abb5..7173c0660 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -77,6 +77,8 @@ localparam ZPU_SR_XB_LOCAL = 03; localparam ZPU_SR_SPI = 32; localparam ZPU_SR_ETHINT0 = 40; localparam ZPU_SR_ETHINT1 = 56; +localparam ZPU_SR_DRAM_FIFO0 = 72; +localparam ZPU_SR_DRAM_FIFO1 = 80; //reset bits #define ZPU_SR_SW_RST_ETH_PHY (1<<0) @@ -89,6 +91,8 @@ localparam ZPU_RB_CLK_STATUS = 3; localparam ZPU_RB_COMPAT_NUM = 6; localparam ZPU_RB_ETH_TYPE0 = 4; localparam ZPU_RB_ETH_TYPE1 = 5; +localparam ZPU_RB_DRAM_FIFO0 = 10; +localparam ZPU_RB_DRAM_FIFO1 = 11; //spi slaves on radio #define DB_DAC_SEN (1 << 7) |