diff options
Diffstat (limited to 'host/lib')
| -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 1d102c7f0..b5cf4bddc 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -758,7 +758,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); @@ -790,7 +790,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 f28ae040f..744d5398e 100644 --- a/host/lib/usrp/cores/CMakeLists.txt +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -40,4 +40,5 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_3000.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_3000.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_core_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 6d66e83c0..c17161e41 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -1027,7 +1027,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 1e424414e..a47f4e5a9 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -50,20 +50,34 @@ using namespace uhd::niusrprio;  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)  { @@ -729,6 +743,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); @@ -940,7 +984,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 @@ -1143,7 +1190,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); @@ -1151,7 +1198,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);          } @@ -1314,7 +1361,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 1630047af..683c1cb32 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -41,6 +41,7 @@  #include "radio_ctrl_core_3000.hpp"  #include "rx_frontend_core_200.hpp"  #include "tx_frontend_core_200.hpp" +#include "dma_fifo_core_3000.hpp"  #include "gpio_core_200.hpp"  #include <boost/weak_ptr.hpp>  #include <uhd/usrp/gps_ctrl.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) | 
