diff options
author | Josh Blum <josh@joshknows.com> | 2011-02-24 11:00:49 -0800 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2011-02-24 11:00:49 -0800 |
commit | d588314b6f6205e0ea7051d8fc7836bdf9a6b16b (patch) | |
tree | 93ca181b6fb98cae67a639637b6911b7ebebbd73 | |
parent | 76ebda895cae3bd0014a5e428b07440445f3b631 (diff) | |
parent | 57b779c5103d25a94c90fd6ac465c6f7f8add9b1 (diff) | |
download | uhd-d588314b6f6205e0ea7051d8fc7836bdf9a6b16b.tar.gz uhd-d588314b6f6205e0ea7051d8fc7836bdf9a6b16b.tar.bz2 uhd-d588314b6f6205e0ea7051d8fc7836bdf9a6b16b.zip |
Merge branch 'usrp2_dual_dsp' into next
Conflicts:
host/include/uhd/usrp/mboard_props.hpp
37 files changed, 981 insertions, 1314 deletions
diff --git a/firmware/zpu/apps/txrx_uhd.c b/firmware/zpu/apps/txrx_uhd.c index 4ccb585e2..0c93d2352 100644 --- a/firmware/zpu/apps/txrx_uhd.c +++ b/firmware/zpu/apps/txrx_uhd.c @@ -53,20 +53,34 @@ static void setup_network(void); // the fast-path setup global variables // ---------------------------------------------------------------- static eth_mac_addr_t fp_mac_addr_src, fp_mac_addr_dst; -extern struct socket_address fp_socket_src, fp_socket_dst; +struct socket_address fp_socket_src, fp_socket_dst; +extern uint16_t dsp0_dst_port, err0_dst_port, dsp1_dst_port; static void handle_udp_err0_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len ){ sr_udp_sm->err0_port = (((uint32_t)dst.port) << 16) | src.port; + err0_dst_port = src.port; printf("Storing for async error path:\n"); printf(" source udp port: %d\n", dst.port); printf(" destination udp port: %d\n", src.port); newline(); } -static void handle_udp_data_packet( +static void handle_udp_dsp1_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + sr_udp_sm->dsp1_port = (((uint32_t)dst.port) << 16) | src.port; + dsp1_dst_port = src.port; + printf("Storing for dsp1 path:\n"); + printf(" source udp port: %d\n", dst.port); + printf(" destination udp port: %d\n", src.port); + newline(); +} + +static void handle_udp_dsp0_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len ){ @@ -75,7 +89,8 @@ static void handle_udp_data_packet( fp_socket_src = dst; fp_socket_dst = src; sr_udp_sm->dsp0_port = (((uint32_t)dst.port) << 16) | src.port; - printf("Storing for fast path:\n"); + dsp0_dst_port = src.port; + printf("Storing for dsp0 path:\n"); printf(" source mac addr: "); print_mac_addr(&fp_mac_addr_src); newline(); printf(" source ip addr: "); @@ -341,13 +356,14 @@ main(void) //1) register the addresses into the network stack register_addrs(ethernet_mac_addr(), get_ip_addr()); - pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_DATA_PORT); + pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_DSP0_PORT); //2) register callbacks for udp ports we service init_udp_listeners(); register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); - register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); + register_udp_listener(USRP2_UDP_DSP0_PORT, handle_udp_dsp0_packet); register_udp_listener(USRP2_UDP_ERR0_PORT, handle_udp_err0_packet); + register_udp_listener(USRP2_UDP_DSP1_PORT, handle_udp_dsp1_packet); #ifdef USRP2P register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet); #endif diff --git a/firmware/zpu/lib/clock_bits.h b/firmware/zpu/lib/clock_bits.h deleted file mode 100644 index d2052e941..000000000 --- a/firmware/zpu/lib/clock_bits.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef INCLUDED_USRP2_CLOCK_BITS_H -#define INCLUDED_USRP2_CLOCK_BITS_H - -#define _MC_WE_LOCK 0x0001 -#define _MC_MIMO_CLK_INPUT 0x0002 // else SMA input - -/* - * Derived masks (use these): - * - * We get our input from 1 of three places: - * Our free running oscilator, our SMA connector, or from the MIMO connector - */ -#define MC_WE_DONT_LOCK 0x0000 -#define MC_WE_LOCK_TO_SMA (_MC_WE_LOCK | 0) -#define MC_WE_LOCK_TO_MIMO (_MC_WE_LOCK | _MC_MIMO_CLK_INPUT) - -/* - * Independent of the source of the clock, we may or may not drive our - * clock onto the mimo connector. Note that there are dedicated clock - * signals in each direction, so disaster doesn't occurs if we're - * unnecessarily providing clock. - */ -#define MC_PROVIDE_CLK_TO_MIMO 0x0004 - -#define MC_REF_CLK_MASK 0x0f - -#define MC_PPS_SOURCE_SMA (0x00 << 4) -#define MC_PPS_SOURCE_MIMO (0x01 << 4) - -#define MC_PPS_POLARITY_NEG (0x00 << 5) -#define MC_PPS_POLARITY_POS (0x01 << 5) - -#endif /* INCLUDED_USRP2_CLOCK_BITS_H */ diff --git a/firmware/zpu/lib/clocks.c b/firmware/zpu/lib/clocks.c index 2b352a385..c1e8ce827 100644 --- a/firmware/zpu/lib/clocks.c +++ b/firmware/zpu/lib/clocks.c @@ -1,4 +1,6 @@ -/* -*- c++ -*- */ +// +// Copyright 2010-2011 Ettus Research LLC +// /* * Copyright 2008 Free Software Foundation, Inc. * @@ -16,119 +18,39 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif #include <clocks.h> - +#include <stdbool.h> #include "memory_map.h" #include "ad9510.h" #include "spi.h" -#include "u2_init.h" -//USRP2PLUS clocks: -//Clock 0: testclk -//Clock 1: FPGA clk -//Clock 2: ADC clk -//Clock 3: DAC clk -//Clock 4: SER clk -//Clock 5: TX dboard clk -//Clock 6: EXP clk -//Clock 7: RX dboard clk +/*! + * \brief Lock Detect -- Return True if our PLL is locked + */ +bool clocks_lock_detect(); -//TODO: should have enough brains to init the FPGA clock for USRP2+. all others are suspect. -//note that without EEPROM support u2_hw_rev_major is going to be incorrect. +/*! + * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle. + */ +void clocks_enable_fpga_clk(bool enable, int divisor); void clocks_init(void) { // Set up basic clocking functions in AD9510 - ad9510_write_reg(0x45, 0x01); // CLK2 drives distribution + ad9510_write_reg(0x45, 0x01); //enable the 100MHz clock output to the FPGA for 50MHz CPU clock clocks_enable_fpga_clk(true, 1); spi_wait(); - // Set up PLL for 10 MHz reference - // Reg 4, A counter, Don't Care -// ad9510_write_reg(0x05, 0x00); // Reg 5, B counter MSBs, 0 -// ad9510_write_reg(0x06, 0x05); // Reg 6, B counter LSBs, 5 - // Reg 7, Loss of reference detect, doesn't work yet, 0 -// ad9510_write_reg(0x5A, 0x01); // Update Regs - - // Primary clock configuration -// clocks_mimo_config(MC_WE_DONT_LOCK); - - //wait for the clock to stabilize while(!clocks_lock_detect()); //issue a reset to the DCM so it locks up to the new freq output_regs->clk_ctrl |= CLK_RESET; - - // Set up other clocks - //clocks_enable_test_clk(false, 0); - //clocks_enable_tx_dboard(false, 0); - //clocks_enable_rx_dboard(false, 0); -// clocks_enable_eth_phyclk(false, 0); //PHY clk is separate now (u2r4, u2p) - - // Enable clock to ADCs and DACs - //clocks_enable_dac_clk(true, 1); - //clocks_enable_adc_clk(true, 1); -} - -/* -void -clocks_mimo_config(int flags) -{ - if (flags & _MC_WE_LOCK){ - // Reg 8, Charge pump on, dig lock det, positive PFD, 47 - ad9510_write_reg(0x08, 0x47); - } - else { - // Reg 8, Charge pump off, dig lock det, positive PFD - ad9510_write_reg(0x08, 0x00); - } - - // Reg 9, Charge pump current, 0x40=3mA, 0x00=650uA - ad9510_write_reg(0x09, 0x00); - // Reg A, Prescaler of 2, everything normal 04 - ad9510_write_reg(0x0A, 0x04); - // Reg B, R Div MSBs, 0 - ad9510_write_reg(0x0B, 0x00); - // Reg C, R Div LSBs, 1 - ad9510_write_reg(0x0C, 0x01); - // Reg D, Antibacklash, Digital lock det, 0 - - ad9510_write_reg(0x5A, 0x01); // Update Regs - - spi_wait(); - - // Allow for clock switchover - // The below masks include 0x10, which issues a reset to the DCM. - if (flags & _MC_WE_LOCK){ // WE LOCK - if (flags & _MC_MIMO_CLK_INPUT) { - // Turn on ref output and choose the MIMO connector - output_regs->clk_ctrl = 0x15; - } - else { - // turn on ref output and choose the SMA - output_regs->clk_ctrl = 0x1C; - } - } - else { // WE DONT LOCK - // Disable both ext clk inputs - output_regs->clk_ctrl = 0x10; - } - - // Do we drive a clock onto the MIMO connector? -// if (flags & MC_PROVIDE_CLK_TO_MIMO) -// clocks_enable_clkexp_out(true,10); -// else -// clocks_enable_clkexp_out(false,0); } -*/ bool clocks_lock_detect() @@ -188,79 +110,9 @@ clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mod ad9510_write_reg(0x5A, 0x01); // Update Regs } -// Clock 0 -/*void -clocks_enable_test_clk(bool enable, int divisor) -{ - clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); -}*/ - // Clock 1 void clocks_enable_fpga_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL); } -/* -// Clock 2 on Rev 3, Clock 5 on Rev 4, Clock 6 on USRP2+ -void -clocks_enable_clkexp_out(bool enable, int divisor) -{ - if(u2_hw_rev_major == 3) - clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); - else if(u2_hw_rev_major == 4) { - ad9510_write_reg(0x34,0x00); // Turn on fine delay - ad9510_write_reg(0x35,0x00); // Set Full Scale to nearly 10ns - ad9510_write_reg(0x36,0x1c); // Set fine delay. 0x20 is midscale - clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); - } - else if(u2_hw_rev_major == 10) { - ad9510_write_reg(0x34, 0x00); - ad9510_write_reg(0x35, 0x00); - ad9510_write_reg(0x36, 0x1C); - clocks_enable_XXX_clk(enable, divisor, 0x42, 0x52, CLOCK_MODE_LVDS); - } - else - putstr("ERR (clocks_enable_clkexp_out): Invalid hw rev, don't know what to do!\n"); -} -*/ -/* -// Clock 5 on Rev 3, none (was 2) on Rev 4, none on USRP2+ -void -clocks_enable_eth_phyclk(bool enable, int divisor) -{ - if(u2_hw_rev_major == 3) - clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); - else if(u2_hw_rev_major == 4) - clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); - else - putstr("(clocks_enable_eth_phyclk): no eth PHY clock or invalid hw rev\n"); //not really an error -} -*/ -// Clock 3 -/*void -clocks_enable_dac_clk(bool enable, int divisor) -{ - clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); -}*/ - -// Clock 4 -/*void -clocks_enable_adc_clk(bool enable, int divisor) -{ - clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); -}*/ - -// Clock 6 -/*void -clocks_enable_tx_dboard(bool enable, int divisor) -{ - clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); -}*/ - -// Clock 7 -/*void -clocks_enable_rx_dboard(bool enable, int divisor) -{ - clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); -}*/ diff --git a/firmware/zpu/lib/clocks.h b/firmware/zpu/lib/clocks.h index 28d1d542f..7bc7a3cda 100644 --- a/firmware/zpu/lib/clocks.h +++ b/firmware/zpu/lib/clocks.h @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 Ettus Research LLC // /* * Copyright 2008 Free Software Foundation, Inc. @@ -21,75 +21,10 @@ #ifndef INCLUDED_CLOCKS_H #define INCLUDED_CLOCKS_H -/* - * Routines to configure our multitude of clocks - */ - -#include <stdbool.h> -#include "clock_bits.h" - - /*! - * One time call to initialize all clocks to a reasonable state. We - * come out of here using our free running 100MHz oscilator and not - * providing a clock to the MIMO connector (CMC_WE_DONT_LOCK) + * One time call to initialize the master clock to a reasonable state. + * We come out of here using our free running 100MHz oscillator. */ void clocks_init(void); - -/*! - * \brief MIMO clock configuration. - * - * Configure our master clock source, and whether or not we drive a - * clock onto the mimo connector. See MC_flags in usrp2_mimo_config.h. - */ -//void clocks_mimo_config(int flags); - -/*! - * \brief Lock Detect -- Return True if our PLL is locked - */ -bool clocks_lock_detect(); - -/*! - * \brief Enable or disable test clock (extra clock signal) - */ -//void clocks_enable_test_clk(bool enable, int divisor); - -/*! - * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle. - */ -void clocks_enable_fpga_clk(bool enable, int divisor); - -/*! - * \brief Enable or disable clock output sent to MIMO connector - */ -//void clocks_enable_clkexp_out(bool enable, int divisor); - -/*! - * \brief Enable or disable ethernet phyclk, should always be disabled - */ -//void clocks_enable_eth_phyclk(bool enable, int divisor); - -/*! - * \brief Enable or disable clock to DAC - */ -//void clocks_enable_dac_clk(bool enable, int divisor); - -/*! - * \brief Enable or disable clock to ADC - */ -//void clocks_enable_adc_clk(bool enable, int divisor); - -/*! - * \brief Enable or disable clock to Rx daughterboard - */ -//void clocks_enable_rx_dboard(bool enable, int divisor); - - -/*! - * \brief Enable or disable clock to Tx daughterboard - */ -//void clocks_enable_tx_dboard(bool enable, int divisor); - - #endif /* INCLUDED_CLOCKS_H */ diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c index d1b06976d..6a0fd254b 100644 --- a/firmware/zpu/lib/net_common.c +++ b/firmware/zpu/lib/net_common.c @@ -1,6 +1,5 @@ -/* -*- c -*- */ /* - * Copyright 2009,2010 Ettus Research LLC + * Copyright 2009-2011 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 @@ -42,7 +41,7 @@ static const bool debug = false; static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; //used in the top level application... -struct socket_address fp_socket_src, fp_socket_dst; +uint16_t dsp0_dst_port, err0_dst_port, dsp1_dst_port; // ------------------------------------------------------------------------ @@ -277,15 +276,24 @@ handle_icmp_packet(struct ip_addr src, struct ip_addr dst, //filter out non udp data response struct ip_hdr *ip = (struct ip_hdr *)(((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr)); struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); - if (IPH_PROTO(ip) != IP_PROTO_UDP || udp->dest != fp_socket_dst.port) return; - - //end async update packets per second - sr_tx_ctrl->cyc_per_up = 0; - - //the end continuous streaming command - sr_rx_ctrl->cmd = 1 << 31; //no samples now - sr_rx_ctrl->time_secs = 0; - sr_rx_ctrl->time_ticks = 0; //latch the command + if (IPH_PROTO(ip) != IP_PROTO_UDP) break; + + if (udp->dest == dsp0_dst_port){ + //the end continuous streaming command + sr_rx_ctrl0->cmd = 1 << 31; //no samples now + sr_rx_ctrl0->time_secs = 0; + sr_rx_ctrl0->time_ticks = 0; //latch the command + } + else if (udp->dest == dsp1_dst_port){ + //the end continuous streaming command + sr_rx_ctrl1->cmd = 1 << 31; //no samples now + sr_rx_ctrl1->time_secs = 0; + sr_rx_ctrl1->time_ticks = 0; //latch the command + } + else if (udp->dest == err0_dst_port){ + //end async update packets per second + sr_tx_ctrl->cyc_per_up = 0; + } //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28); //printf("icmp port unr %d\n", udp->dest); diff --git a/firmware/zpu/usrp2/memory_map.h b/firmware/zpu/usrp2/memory_map.h index e728a1ddb..79b11759a 100644 --- a/firmware/zpu/usrp2/memory_map.h +++ b/firmware/zpu/usrp2/memory_map.h @@ -1,4 +1,4 @@ -/* -*- c -*- */ +// Copyright 2010-2011 Ettus Research LLC /* * Copyright 2007,2008,2009 Free Software Foundation, Inc. * @@ -227,8 +227,10 @@ hwconfig_wishbone_divisor(void) #define SR_UDP_SM 96 #define SR_TX_DSP 208 #define SR_TX_CTRL 224 -#define SR_RX_DSP 160 -#define SR_RX_CTRL 176 +#define SR_RX_DSP0 160 +#define SR_RX_DSP1 240 +#define SR_RX_CTRL0 176 +#define SR_RX_CTRL1 32 #define SR_TIME64 192 #define SR_SIMTIMER 198 #define SR_LAST 255 @@ -350,10 +352,7 @@ typedef struct { #define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM)) -// --- dsp tx regs --- - -#define MIN_CIC_INTERP 1 -#define MAX_CIC_INTERP 128 +// --- VITA TX CTRL regs --- typedef struct { volatile uint32_t num_chan; @@ -366,52 +365,6 @@ typedef struct { #define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) -typedef struct { - volatile int32_t freq; - volatile uint32_t scale_iq; // {scale_i,scale_q} - volatile uint32_t interp_rate; - volatile uint32_t _padding0; // padding for the tx_mux - // NOT freq, scale, interp - /*! - * \brief output mux configuration. - * - * <pre> - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------------------------------+-------+-------+-------+-------+ - * | | DAC1 | DAC0 | - * +-------------------------------+-------+-------+-------+-------+ - * - * There are N DUCs (1 now) with complex inputs and outputs. - * There are two DACs. - * - * Each 4-bit DACx field specifies the source for the DAC - * Each subfield is coded like this: - * - * 3 2 1 0 - * +-------+ - * | N | - * +-------+ - * - * N specifies which DUC output is connected to this DAC. - * - * N which interp output - * --- ------------------- - * 0 DUC 0 I - * 1 DUC 0 Q - * 2 DUC 1 I - * 3 DUC 1 Q - * F All Zeros - * - * The default value is 0x10 - * </pre> - */ - volatile uint32_t tx_mux; - -} dsp_tx_regs_t; - -#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP)) - // --- VITA RX CTRL regs --- typedef struct { // The following 3 are logically a single command register. @@ -419,81 +372,10 @@ typedef struct { volatile uint32_t cmd; // {now, chain, num_samples(30) volatile uint32_t time_secs; volatile uint32_t time_ticks; - - volatile uint32_t clear_overrun; // write anything to clear overrun - volatile uint32_t vrt_header; // word 0 of packet. FPGA fills in packet counter - volatile uint32_t vrt_stream_id; // word 1 of packet. - volatile uint32_t vrt_trailer; - volatile uint32_t nsamples_per_pkt; - volatile uint32_t nchannels; // 1 in basic case, up to 4 for vector sources - volatile uint32_t pad[7]; // Make each structure 16 elements long } sr_rx_ctrl_t; -#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) - -// --- dsp rx regs --- -#define MIN_CIC_DECIM 1 -#define MAX_CIC_DECIM 128 - -typedef struct { - volatile int32_t freq; - volatile uint32_t scale_iq; // {scale_i,scale_q} - volatile uint32_t decim_rate; - volatile uint32_t dcoffset_i; // Bit 31 high sets fixed offset mode, using lower 14 bits, - // otherwise it is automatic - volatile uint32_t dcoffset_q; // Bit 31 high sets fixed offset mode, using lower 14 bits - - /*! - * \brief input mux configuration. - * - * This determines which ADC (or constant zero) is connected to - * each DDC input. There are N DDCs (1 now). Each has two inputs. - * - * <pre> - * Mux value: - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | |Q0 |I0 | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) - * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) - * - * The default value is 0x4 - * </pre> - */ - volatile uint32_t rx_mux; // called adc_mux in dsp_core_rx.v - - /*! - * \brief Streaming GPIO configuration - * - * This determines whether the LSBs of I and Q samples come from the DSP - * pipeline or from the io_rx GPIO pins. To stream GPIO, one must first - * set the GPIO data direction register to have io_rx[15] and/or io_rx[14] - * configured as inputs. The GPIO pins will be sampled at the time the - * remainder of the DSP sample is strobed into the RX sample FIFO. There - * will be a decimation-dependent fixed time offset between the GPIO - * sample stream and the associated RF samples. - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | MBZ |Q|I| - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * I 0=LSB comes from DSP pipeline (default) - * 1=LSB comes from io_rx[15] - * - * Q 0=LSB comes from DSP pipeline (default) - * 1=LSB comes from io_rx[14] - */ - volatile uint32_t gpio_stream_enable; - -} dsp_rx_regs_t; - -#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP)) +#define sr_rx_ctrl0 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL0)) +#define sr_rx_ctrl1 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL1)) // ---------------------------------------------------------------- // VITA49 64 bit time (write only) diff --git a/firmware/zpu/usrp2p/memory_map.h b/firmware/zpu/usrp2p/memory_map.h index 36d8ac9f2..2567a4588 100644 --- a/firmware/zpu/usrp2p/memory_map.h +++ b/firmware/zpu/usrp2p/memory_map.h @@ -1,4 +1,4 @@ -/* -*- c -*- */ +// Copyright 2010-2011 Ettus Research LLC /* * Copyright 2007,2008,2009 Free Software Foundation, Inc. * @@ -218,8 +218,10 @@ hwconfig_wishbone_divisor(void) #define SR_UDP_SM 96 #define SR_TX_DSP 208 #define SR_TX_CTRL 224 -#define SR_RX_DSP 160 -#define SR_RX_CTRL 176 +#define SR_RX_DSP0 160 +#define SR_RX_DSP1 240 +#define SR_RX_CTRL0 176 +#define SR_RX_CTRL1 32 #define SR_TIME64 192 #define SR_SIMTIMER 198 #define SR_LAST 255 @@ -343,10 +345,7 @@ typedef struct { #define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM)) -// --- dsp tx regs --- - -#define MIN_CIC_INTERP 1 -#define MAX_CIC_INTERP 128 +// --- VITA TX CTRL regs --- typedef struct { volatile uint32_t num_chan; @@ -359,52 +358,6 @@ typedef struct { #define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) -typedef struct { - volatile int32_t freq; - volatile uint32_t scale_iq; // {scale_i,scale_q} - volatile uint32_t interp_rate; - volatile uint32_t _padding0; // padding for the tx_mux - // NOT freq, scale, interp - /*! - * \brief output mux configuration. - * - * <pre> - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------------------------------+-------+-------+-------+-------+ - * | | DAC1 | DAC0 | - * +-------------------------------+-------+-------+-------+-------+ - * - * There are N DUCs (1 now) with complex inputs and outputs. - * There are two DACs. - * - * Each 4-bit DACx field specifies the source for the DAC - * Each subfield is coded like this: - * - * 3 2 1 0 - * +-------+ - * | N | - * +-------+ - * - * N specifies which DUC output is connected to this DAC. - * - * N which interp output - * --- ------------------- - * 0 DUC 0 I - * 1 DUC 0 Q - * 2 DUC 1 I - * 3 DUC 1 Q - * F All Zeros - * - * The default value is 0x10 - * </pre> - */ - volatile uint32_t tx_mux; - -} dsp_tx_regs_t; - -#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP)) - // --- VITA RX CTRL regs --- typedef struct { // The following 3 are logically a single command register. @@ -412,81 +365,10 @@ typedef struct { volatile uint32_t cmd; // {now, chain, num_samples(30) volatile uint32_t time_secs; volatile uint32_t time_ticks; - - volatile uint32_t clear_overrun; // write anything to clear overrun - volatile uint32_t vrt_header; // word 0 of packet. FPGA fills in packet counter - volatile uint32_t vrt_stream_id; // word 1 of packet. - volatile uint32_t vrt_trailer; - volatile uint32_t nsamples_per_pkt; - volatile uint32_t nchannels; // 1 in basic case, up to 4 for vector sources - volatile uint32_t pad[7]; // Make each structure 16 elements long } sr_rx_ctrl_t; -#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) - -// --- dsp rx regs --- -#define MIN_CIC_DECIM 1 -#define MAX_CIC_DECIM 128 - -typedef struct { - volatile int32_t freq; - volatile uint32_t scale_iq; // {scale_i,scale_q} - volatile uint32_t decim_rate; - volatile uint32_t dcoffset_i; // Bit 31 high sets fixed offset mode, using lower 14 bits, - // otherwise it is automatic - volatile uint32_t dcoffset_q; // Bit 31 high sets fixed offset mode, using lower 14 bits - - /*! - * \brief input mux configuration. - * - * This determines which ADC (or constant zero) is connected to - * each DDC input. There are N DDCs (1 now). Each has two inputs. - * - * <pre> - * Mux value: - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | |Q0 |I0 | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) - * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) - * - * The default value is 0x4 - * </pre> - */ - volatile uint32_t rx_mux; // called adc_mux in dsp_core_rx.v - - /*! - * \brief Streaming GPIO configuration - * - * This determines whether the LSBs of I and Q samples come from the DSP - * pipeline or from the io_rx GPIO pins. To stream GPIO, one must first - * set the GPIO data direction register to have io_rx[15] and/or io_rx[14] - * configured as inputs. The GPIO pins will be sampled at the time the - * remainder of the DSP sample is strobed into the RX sample FIFO. There - * will be a decimation-dependent fixed time offset between the GPIO - * sample stream and the associated RF samples. - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | MBZ |Q|I| - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * I 0=LSB comes from DSP pipeline (default) - * 1=LSB comes from io_rx[15] - * - * Q 0=LSB comes from DSP pipeline (default) - * 1=LSB comes from io_rx[14] - */ - volatile uint32_t gpio_stream_enable; - -} dsp_rx_regs_t; - -#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP)) +#define sr_rx_ctrl0 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL0)) +#define sr_rx_ctrl1 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL1)) // ---------------------------------------------------------------- // VITA49 64 bit time (write only) diff --git a/fpga/usrp2/fifo/dsp_framer36.v b/fpga/usrp2/fifo/dsp_framer36.v index 34a05d91e..f7d7fb68e 100644 --- a/fpga/usrp2/fifo/dsp_framer36.v +++ b/fpga/usrp2/fifo/dsp_framer36.v @@ -2,7 +2,7 @@ // Frame DSP packets with a header line to be handled by the protocol machine module dsp_framer36 - #(parameter BUF_SIZE = 9) + #(parameter BUF_SIZE = 9, parameter PORT_SEL = 0) ( input clk, input rst, input clr, input [35:0] inp_data, input inp_valid, output inp_ready, @@ -29,8 +29,9 @@ module dsp_framer36 //The header is generated here from the count. wire [31:0] dsp_frm_data_bram; wire [15:0] dsp_frm_bytes = {dsp_frm_count, 2'b00}; + wire [1:0] port_sel_bits = PORT_SEL; assign out_data = - (dsp_frm_state == DSP_FRM_STATE_WRITE_HDR)? {4'b0001, 16'b1, dsp_frm_bytes} : ( + (dsp_frm_state == DSP_FRM_STATE_WRITE_HDR)? {4'b0001, 13'b0, port_sel_bits, 1'b1, dsp_frm_bytes} : ( (dsp_frm_addr == dsp_frm_count) ? {4'b0010, dsp_frm_data_bram} : ( {4'b0000, dsp_frm_data_bram})); assign out_valid = ( diff --git a/fpga/usrp2/fifo/packet_router.v b/fpga/usrp2/fifo/packet_router.v index 161b59016..bad8fb7fc 100644 --- a/fpga/usrp2/fifo/packet_router.v +++ b/fpga/usrp2/fifo/packet_router.v @@ -33,7 +33,8 @@ module packet_router // Input Interfaces (in to router) input [35:0] ser_inp_data, input ser_inp_valid, output ser_inp_ready, - input [35:0] dsp_inp_data, input dsp_inp_valid, output dsp_inp_ready, + input [35:0] dsp0_inp_data, input dsp0_inp_valid, output dsp0_inp_ready, + input [35:0] dsp1_inp_data, input dsp1_inp_valid, output dsp1_inp_ready, input [35:0] eth_inp_data, input eth_inp_valid, output eth_inp_ready, input [35:0] err_inp_data, input err_inp_valid, output err_inp_ready, @@ -83,11 +84,11 @@ module packet_router ); //setting register to program the UDP data ports - wire [15:0] dsp0_udp_port, dsp1_udp_port; - setting_reg #(.my_addr(CTRL_BASE+2)) sreg_data_ports( + wire [15:0] dsp_udp_port; + setting_reg #(.my_addr(CTRL_BASE+2), .width(16)) sreg_data_ports( .clk(stream_clk),.rst(stream_rst), .strobe(set_stb),.addr(set_addr),.in(set_data), - .out({dsp1_udp_port, dsp0_udp_port}),.changed() + .out(dsp_udp_port),.changed() ); //assign status output signals @@ -116,6 +117,11 @@ module packet_router wire _eth_inp_valid; wire _eth_inp_ready; + // dummy signals to connect fifo_short + wire [35:0] _com_inp_data; + wire _com_inp_valid; + wire _com_inp_ready; + valve36 eth_inp_valve ( .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), .shutoff(~master_mode_flag), .data_i(eth_inp_data), .src_rdy_i(eth_inp_valid), .dst_rdy_o(eth_inp_ready), @@ -126,10 +132,17 @@ module packet_router .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), .cross(~master_mode_flag), .data0_i(_eth_inp_data), .src0_rdy_i(_eth_inp_valid), .dst0_rdy_o(_eth_inp_ready), .data1_i(ser_inp_data), .src1_rdy_i(ser_inp_valid), .dst1_rdy_o(ser_inp_ready), - .data0_o(com_inp_data), .src0_rdy_o(com_inp_valid), .dst0_rdy_i(com_inp_ready), + .data0_o(_com_inp_data), .src0_rdy_o(_com_inp_valid), .dst0_rdy_i(_com_inp_ready), .data1_o(ext_inp_data), .src1_rdy_o(ext_inp_valid), .dst1_rdy_i(ext_inp_ready) ); + // short fifo in the packet inspection path to help timing + fifo_short #(.WIDTH(36)) com_inp_fifo + (.clk(stream_clk), .reset(stream_rst), .clear(stream_clr), + .datain(_com_inp_data), .src_rdy_i(_com_inp_valid), .dst_rdy_o(_com_inp_ready), + .dataout(com_inp_data), .src_rdy_o(com_inp_valid), .dst_rdy_i(com_inp_ready), + .space(), .occupied() ); + //////////////////////////////////////////////////////////////////// // Communication output sink crossbar // When in master mode: @@ -172,9 +185,9 @@ module packet_router //////////////////////////////////////////////////////////////////// //streaming signals from the dsp framer to the combiner - wire [35:0] dsp_frm_data; - wire dsp_frm_valid; - wire dsp_frm_ready; + wire [35:0] dsp0_frm_data, dsp1_frm_data; + wire dsp0_frm_valid, dsp1_frm_valid; + wire dsp0_frm_ready, dsp1_frm_ready; //dummy signals to join the the muxes below wire [35:0] _combiner0_data, _combiner1_data; @@ -183,14 +196,14 @@ module packet_router fifo36_mux _com_output_combiner0( .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), - .data0_i(dsp_frm_data), .src0_rdy_i(dsp_frm_valid), .dst0_rdy_o(dsp_frm_ready), + .data0_i(dsp0_frm_data), .src0_rdy_i(dsp0_frm_valid), .dst0_rdy_o(dsp0_frm_ready), .data1_i(err_inp_data), .src1_rdy_i(err_inp_valid), .dst1_rdy_o(err_inp_ready), .data_o(_combiner0_data), .src_rdy_o(_combiner0_valid), .dst_rdy_i(_combiner0_ready) ); fifo36_mux _com_output_combiner1( .clk(stream_clk), .reset(stream_rst), .clear(stream_clr), - .data0_i(32'b0), .src0_rdy_i(1'b0), .dst0_rdy_o(), //mux out from dsp1 can go here + .data0_i(dsp1_frm_data), .src0_rdy_i(dsp1_frm_valid), .dst0_rdy_o(dsp1_frm_ready), .data1_i(cpu_inp_data), .src1_rdy_i(cpu_inp_valid), .dst1_rdy_o(cpu_inp_ready), .data_o(_combiner1_data), .src_rdy_o(_combiner1_valid), .dst_rdy_i(_combiner1_ready) ); @@ -364,7 +377,7 @@ module packet_router end //UDP data port and VRT: - else if ((com_insp_dregs_udp_dst_port == dsp0_udp_port) && (com_insp_dregs_vrt_size != 16'h0)) begin + else if ((com_insp_dregs_udp_dst_port == dsp_udp_port) && (com_insp_dregs_vrt_size != 16'h0)) begin com_insp_dest <= COM_INSP_DEST_DSP; com_insp_dreg_count <= COM_INSP_DREGS_DSP_OFFSET; end @@ -448,11 +461,16 @@ module packet_router //////////////////////////////////////////////////////////////////// // DSP input framer //////////////////////////////////////////////////////////////////// + dsp_framer36 #(.BUF_SIZE(BUF_SIZE), .PORT_SEL(0)) dsp0_framer36( + .clk(stream_clk), .rst(stream_rst), .clr(stream_clr), + .inp_data(dsp0_inp_data), .inp_valid(dsp0_inp_valid), .inp_ready(dsp0_inp_ready), + .out_data(dsp0_frm_data), .out_valid(dsp0_frm_valid), .out_ready(dsp0_frm_ready) + ); - dsp_framer36 #(.BUF_SIZE(BUF_SIZE)) dsp0_framer36( + dsp_framer36 #(.BUF_SIZE(BUF_SIZE), .PORT_SEL(2)) dsp1_framer36( .clk(stream_clk), .rst(stream_rst), .clr(stream_clr), - .inp_data(dsp_inp_data), .inp_valid(dsp_inp_valid), .inp_ready(dsp_inp_ready), - .out_data(dsp_frm_data), .out_valid(dsp_frm_valid), .out_ready(dsp_frm_ready) + .inp_data(dsp1_inp_data), .inp_valid(dsp1_inp_valid), .inp_ready(dsp1_inp_ready), + .out_data(dsp1_frm_data), .out_valid(dsp1_frm_valid), .out_ready(dsp1_frm_ready) ); //////////////////////////////////////////////////////////////////// @@ -508,7 +526,7 @@ module packet_router assign debug = { //inputs to the router (8) - dsp_inp_ready, dsp_inp_valid, + dsp0_inp_ready, dsp0_inp_valid, ser_inp_ready, ser_inp_valid, eth_inp_ready, eth_inp_valid, cpu_inp_ready, cpu_inp_valid, diff --git a/fpga/usrp2/top/u2_rev3/u2_core.v b/fpga/usrp2/top/u2_rev3/u2_core.v index ab2ed49f0..10bfd5ffb 100644 --- a/fpga/usrp2/top/u2_rev3/u2_core.v +++ b/fpga/usrp2/top/u2_rev3/u2_core.v @@ -3,7 +3,6 @@ // //////////////////////////////////////////////////////////////////////////////// module u2_core - #(parameter RAM_SIZE=16384, parameter RAM_AW=14) (// Clocks input dsp_clk, input wb_clk, @@ -137,20 +136,24 @@ module u2_core input [3:0] clock_divider ); - localparam SR_BUF_POOL = 64; // Uses 1 reg + localparam SR_MISC = 0; // Uses 9 regs + localparam SR_BUF_POOL = 64; // Uses 4 regs localparam SR_UDP_SM = 96; // 64 regs - localparam SR_RX_DSP = 160; // 16 - localparam SR_RX_CTRL = 176; // 16 + localparam SR_RX_DSP0 = 160; // 16 + localparam SR_RX_CTRL0 = 176; // 16 localparam SR_TIME64 = 192; // 3 localparam SR_SIMTIMER = 198; // 2 localparam SR_TX_DSP = 208; // 16 localparam SR_TX_CTRL = 224; // 16 - + localparam SR_RX_DSP1 = 240; + localparam SR_RX_CTRL1 = 32; + + // FIFO Sizes, 9 = 512 lines, 10 = 1024, 11 = 2048 // all (most?) are 36 bits wide, so 9 is 1 BRAM, 10 is 2, 11 is 4 BRAMs - localparam DSP_TX_FIFOSIZE = 10; - localparam DSP_RX_FIFOSIZE = 10; - localparam ETH_TX_FIFOSIZE = 10; + // localparam DSP_TX_FIFOSIZE = 9; unused -- DSPTX uses extram fifo + localparam DSP_RX_FIFOSIZE = 9; + localparam ETH_TX_FIFOSIZE = 9; localparam ETH_RX_FIFOSIZE = 11; localparam SERDES_TX_FIFOSIZE = 9; localparam SERDES_RX_FIFOSIZE = 9; // RX currently doesn't use a fifo? @@ -159,13 +162,14 @@ module u2_core wire [31:0] set_data, set_data_dsp; wire set_stb, set_stb_dsp; - wire ram_loader_done; - wire ram_loader_rst, wb_rst, dsp_rst; - assign dsp_rst = wb_rst; - + wire ram_loader_done, ram_loader_rst; + wire wb_rst; + wire dsp_rst = wb_rst; + wire [31:0] status; wire bus_error, spi_int, i2c_int, pps_int, onetime_int, periodic_int, buffer_int; - wire proc_int, overrun, underrun, uart_tx_int, uart_rx_int; + wire proc_int, overrun0, overrun1, underrun; + wire uart_tx_int, uart_rx_int; wire [31:0] debug_gpio_0, debug_gpio_1; wire [31:0] atr_lines; @@ -182,10 +186,8 @@ module u2_core wire [31:0] irq; wire [63:0] vita_time, vita_time_pps; - wire run_rx, run_tx; - reg run_rx_d1; - always @(posedge dsp_clk) - run_rx_d1 <= run_rx; + wire run_rx0, run_rx1, run_tx; + reg run_rx0_d1, run_rx1_d1; // /////////////////////////////////////////////////////////////////////////////////////////////// // Wishbone Single Master INTERCON @@ -291,7 +293,7 @@ module u2_core wire [15:0] ram_loader_adr; wire [3:0] ram_loader_sel; wire ram_loader_stb, ram_loader_we; - ram_loader #(.AWIDTH(aw),.RAM_SIZE(RAM_SIZE)) + ram_loader #(.AWIDTH(aw),.RAM_SIZE(16384)) ram_loader (.wb_clk(wb_clk),.dsp_clk(dsp_clk),.ram_loader_rst(ram_loader_rst), .wb_dat(ram_loader_dat),.wb_adr(ram_loader_adr), .wb_stb(ram_loader_stb),.wb_sel(ram_loader_sel), @@ -324,21 +326,21 @@ module u2_core // I-port connects directly to processor and ram loader wire flush_icache; - ram_harvard #(.AWIDTH(RAM_AW),.RAM_SIZE(RAM_SIZE),.ICWIDTH(7),.DCWIDTH(6)) + ram_harvard #(.AWIDTH(14),.RAM_SIZE(16384),.ICWIDTH(7),.DCWIDTH(6)) sys_ram(.wb_clk_i(wb_clk),.wb_rst_i(wb_rst), - .ram_loader_adr_i(ram_loader_adr[RAM_AW-1:0]), .ram_loader_dat_i(ram_loader_dat), + .ram_loader_adr_i(ram_loader_adr[13:0]), .ram_loader_dat_i(ram_loader_dat), .ram_loader_stb_i(ram_loader_stb), .ram_loader_sel_i(ram_loader_sel), .ram_loader_we_i(ram_loader_we), .ram_loader_done_i(ram_loader_done), .if_adr(16'b0), .if_data(), - .dwb_adr_i(s0_adr[RAM_AW-1:0]), .dwb_dat_i(s0_dat_o), .dwb_dat_o(s0_dat_i), + .dwb_adr_i(s0_adr[13:0]), .dwb_dat_i(s0_dat_o), .dwb_dat_o(s0_dat_i), .dwb_we_i(s0_we), .dwb_ack_o(s0_ack), .dwb_stb_i(s0_stb), .dwb_sel_i(s0_sel), .flush_icache(flush_icache)); - setting_reg #(.my_addr(7)) sr_icache (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+7)) sr_icache (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(),.changed(flush_icache)); // ///////////////////////////////////////////////////////////////////////// @@ -347,15 +349,13 @@ module u2_core wire rd1_ready_i, rd1_ready_o; wire rd2_ready_i, rd2_ready_o; wire rd3_ready_i, rd3_ready_o; - wire [3:0] rd0_flags, rd1_flags, rd2_flags, rd3_flags; - wire [31:0] rd0_dat, rd1_dat, rd2_dat, rd3_dat; + wire [35:0] rd0_dat, rd1_dat, rd2_dat, rd3_dat; wire wr0_ready_i, wr0_ready_o; wire wr1_ready_i, wr1_ready_o; wire wr2_ready_i, wr2_ready_o; wire wr3_ready_i, wr3_ready_o; - wire [3:0] wr0_flags, wr1_flags, wr2_flags, wr3_flags; - wire [31:0] wr0_dat, wr1_dat, wr2_dat, wr3_dat; + wire [35:0] wr0_dat, wr1_dat, wr2_dat, wr3_dat; wire [35:0] tx_err_data; wire tx_err_src_rdy, tx_err_dst_rdy; @@ -373,14 +373,15 @@ module u2_core .status(status), .sys_int_o(buffer_int), .debug(router_debug), - .ser_inp_data({wr0_flags, wr0_dat}), .ser_inp_valid(wr0_ready_i), .ser_inp_ready(wr0_ready_o), - .dsp_inp_data({wr1_flags, wr1_dat}), .dsp_inp_valid(wr1_ready_i), .dsp_inp_ready(wr1_ready_o), - .eth_inp_data({wr2_flags, wr2_dat}), .eth_inp_valid(wr2_ready_i), .eth_inp_ready(wr2_ready_o), + .ser_inp_data(wr0_dat), .ser_inp_valid(wr0_ready_i), .ser_inp_ready(wr0_ready_o), + .dsp0_inp_data(wr1_dat), .dsp0_inp_valid(wr1_ready_i), .dsp0_inp_ready(wr1_ready_o), + .dsp1_inp_data(wr3_dat), .dsp1_inp_valid(wr3_ready_i), .dsp1_inp_ready(wr3_ready_o), + .eth_inp_data(wr2_dat), .eth_inp_valid(wr2_ready_i), .eth_inp_ready(wr2_ready_o), .err_inp_data(tx_err_data), .err_inp_ready(tx_err_dst_rdy), .err_inp_valid(tx_err_src_rdy), - .ser_out_data({rd0_flags, rd0_dat}), .ser_out_valid(rd0_ready_o), .ser_out_ready(rd0_ready_i), - .dsp_out_data({rd1_flags, rd1_dat}), .dsp_out_valid(rd1_ready_o), .dsp_out_ready(rd1_ready_i), - .eth_out_data({rd2_flags, rd2_dat}), .eth_out_valid(rd2_ready_o), .eth_out_ready(rd2_ready_i) + .ser_out_data(rd0_dat), .ser_out_valid(rd0_ready_o), .ser_out_ready(rd0_ready_i), + .dsp_out_data(rd1_dat), .dsp_out_valid(rd1_ready_o), .dsp_out_ready(rd1_ready_i), + .eth_out_data(rd2_dat), .eth_out_valid(rd2_ready_o), .eth_out_ready(rd2_ready_i) ); // ///////////////////////////////////////////////////////////////////////// @@ -416,7 +417,7 @@ module u2_core // Buffer Pool Status -- Slave #5 //compatibility number -> increment when the fpga has been sufficiently altered - localparam compat_num = 32'd4; + localparam compat_num = 32'd5; wb_readback_mux buff_pool_status (.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb), @@ -469,12 +470,12 @@ module u2_core fifo_cascade #(.WIDTH(36), .SIZE(ETH_RX_FIFOSIZE)) rx_eth_fifo (.clk(dsp_clk), .reset(dsp_rst), .clear(0), .datain(rx_f36_data), .src_rdy_i(rx_f36_src_rdy), .dst_rdy_o(rx_f36_dst_rdy), - .dataout({wr2_flags,wr2_dat}), .src_rdy_o(wr2_ready_i), .dst_rdy_i(wr2_ready_o)); + .dataout(wr2_dat), .src_rdy_o(wr2_ready_i), .dst_rdy_i(wr2_ready_o)); //eth output to mac tx... fifo_cascade #(.WIDTH(36), .SIZE(ETH_TX_FIFOSIZE)) tx_eth_fifo (.clk(dsp_clk), .reset(dsp_rst), .clear(0), - .datain({rd2_flags,rd2_dat}), .src_rdy_i(rd2_ready_o), .dst_rdy_o(rd2_ready_i), + .datain(rd2_dat), .src_rdy_i(rd2_ready_o), .dst_rdy_o(rd2_ready_i), .dataout(tx_f36_data), .src_rdy_o(tx_f36_src_rdy), .dst_rdy_i(tx_f36_dst_rdy)); fifo36_to_fifo19 eth_out_fifo36_to_fifo19 @@ -504,13 +505,13 @@ module u2_core wire phy_reset; assign PHY_RESETn = ~phy_reset; - setting_reg #(.my_addr(0),.width(8)) sr_clk (.clk(wb_clk),.rst(wb_rst),.strobe(s7_ack),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+0),.width(8)) sr_clk (.clk(wb_clk),.rst(wb_rst),.strobe(s7_ack),.addr(set_addr), .in(set_data),.out(clock_outs),.changed()); - setting_reg #(.my_addr(1),.width(8)) sr_ser (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+1),.width(8)) sr_ser (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(serdes_outs),.changed()); - setting_reg #(.my_addr(2),.width(8)) sr_adc (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+2),.width(8)) sr_adc (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(adc_outs),.changed()); - setting_reg #(.my_addr(4),.width(1)) sr_phy (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+4),.width(1)) sr_phy (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(phy_reset),.changed()); // ///////////////////////////////////////////////////////////////////////// @@ -520,12 +521,12 @@ module u2_core // In Rev3 there are only 6 leds, and the highest one is on the ETH connector wire [7:0] led_src, led_sw; - wire [7:0] led_hw = {run_tx, run_rx, clk_status, serdes_link_up, 1'b0}; + wire [7:0] led_hw = {run_tx, (run_rx0_d1 | run_rx1_d1), clk_status, serdes_link_up, 1'b0}; - setting_reg #(.my_addr(3),.width(8)) sr_led (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+3),.width(8)) sr_led (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(led_sw),.changed()); - setting_reg #(.my_addr(8),.width(8), .at_reset(8'b0001_1110)) + setting_reg #(.my_addr(SR_MISC+8),.width(8), .at_reset(8'b0001_1110)) sr_led_src (.clk(wb_clk),.rst(wb_rst), .strobe(set_stb),.addr(set_addr), .in(set_data),.out(led_src),.changed()); assign leds = (led_src & led_hw) | (~led_src & led_sw); @@ -537,7 +538,7 @@ module u2_core wire underrun_wb, overrun_wb, pps_wb; oneshot_2clk underrun_1s (.clk_in(dsp_clk), .in(underrun), .clk_out(wb_clk), .out(underrun_wb)); - oneshot_2clk overrun_1s (.clk_in(dsp_clk), .in(overrun), .clk_out(wb_clk), .out(overrun_wb)); + oneshot_2clk overrun_1s (.clk_in(dsp_clk), .in(overrun0 | overrun1), .clk_out(wb_clk), .out(overrun_wb)); oneshot_2clk pps_1s (.clk_in(dsp_clk), .in(pps_int), .clk_out(wb_clk), .out(pps_wb)); assign irq= {{8'b0}, @@ -580,7 +581,7 @@ module u2_core (.clk_i(wb_clk),.rst_i(wb_rst), .adr_i(sb_adr[5:0]),.sel_i(sb_sel),.dat_i(sb_dat_o),.dat_o(sb_dat_i), .we_i(sb_we),.stb_i(sb_stb),.cyc_i(sb_cyc),.ack_o(sb_ack), - .run_rx(run_rx_d1),.run_tx(run_tx),.ctrl_lines(atr_lines) ); + .run_rx(run_rx0_d1 | run_rx1_d1),.run_tx(run_tx),.ctrl_lines(atr_lines) ); // ////////////////////////////////////////////////////////////////////////// // Time Sync, Slave #12 @@ -601,50 +602,72 @@ module u2_core assign sd_dat_i[31:8] = 0; // ///////////////////////////////////////////////////////////////////////// - // DSP RX - wire [31:0] sample_rx, sample_tx; - wire strobe_rx, strobe_tx; - wire rx_dst_rdy, rx_src_rdy, rx1_dst_rdy, rx1_src_rdy; - wire [99:0] rx_data; - wire [35:0] rx1_data; + // DSP RX 0 + wire [31:0] sample_rx0; + wire [35:0] rx0_data; + wire clear_rx0, strobe_rx0, rx0_dst_rdy, rx0_src_rdy; + + always @(posedge dsp_clk) + run_rx0_d1 <= run_rx0; - dsp_core_rx #(.BASE(SR_RX_DSP)) dsp_core_rx + dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0 (.clk(dsp_clk),.rst(dsp_rst), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), - .sample(sample_rx), .run(run_rx_d1), .strobe(strobe_rx), - .debug(debug_rx_dsp) ); + .sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0), + .debug() ); - wire [31:0] vrc_debug; - wire clear_rx; - - setting_reg #(.my_addr(SR_RX_CTRL+3)) sr_clear + setting_reg #(.my_addr(SR_RX_CTRL0+3)) sr_clear_rx0 (.clk(dsp_clk),.rst(dsp_rst), .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp), - .out(),.changed(clear_rx)); + .out(),.changed(clear_rx0)); - vita_rx_control #(.BASE(SR_RX_CTRL), .WIDTH(32)) vita_rx_control - (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx), + vita_rx_chain #(.BASE(SR_RX_CTRL0)) vita_rx_chain0 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .vita_time(vita_time), .overrun(overrun), - .sample(sample_rx), .run(run_rx), .strobe(strobe_rx), - .sample_fifo_o(rx_data), .sample_fifo_dst_rdy_i(rx_dst_rdy), .sample_fifo_src_rdy_o(rx_src_rdy), - .debug_rx(vrc_debug)); + .vita_time(vita_time), .overrun(overrun0), + .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), + .rx_data_o(rx0_data), .rx_src_rdy_o(rx0_src_rdy), .rx_dst_rdy_i(rx0_dst_rdy), + .debug() ); + + fifo_cascade #(.WIDTH(36), .SIZE(DSP_RX_FIFOSIZE)) rx_fifo_cascade0 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0), + .datain(rx0_data), .src_rdy_i(rx0_src_rdy), .dst_rdy_o(rx0_dst_rdy), + .dataout(wr1_dat), .src_rdy_o(wr1_ready_i), .dst_rdy_i(wr1_ready_o)); - wire [3:0] vita_state; + // ///////////////////////////////////////////////////////////////////////// + // DSP RX 1 + wire [31:0] sample_rx1; + wire [35:0] rx1_data; + wire clear_rx1, strobe_rx1, rx1_dst_rdy, rx1_src_rdy; + + always @(posedge dsp_clk) + run_rx1_d1 <= run_rx1; - vita_rx_framer #(.BASE(SR_RX_CTRL), .MAXCHAN(1)) vita_rx_framer - (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx), + dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1 + (.clk(dsp_clk),.rst(dsp_rst), + .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), + .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), + .sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1), + .debug() ); + + setting_reg #(.my_addr(SR_RX_CTRL1+3)) sr_clear_rx1 + (.clk(dsp_clk),.rst(dsp_rst), + .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp), + .out(),.changed(clear_rx1)); + + vita_rx_chain #(.BASE(SR_RX_CTRL1)) vita_rx_chain1 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .sample_fifo_i(rx_data), .sample_fifo_dst_rdy_o(rx_dst_rdy), .sample_fifo_src_rdy_i(rx_src_rdy), - .data_o(rx1_data), .dst_rdy_i(rx1_dst_rdy), .src_rdy_o(rx1_src_rdy), - .fifo_occupied(), .fifo_full(), .fifo_empty(), - .debug_rx(vita_state) ); + .vita_time(vita_time), .overrun(overrun1), + .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), + .rx_data_o(rx1_data), .rx_src_rdy_o(rx1_src_rdy), .rx_dst_rdy_i(rx1_dst_rdy), + .debug() ); - fifo_cascade #(.WIDTH(36), .SIZE(DSP_RX_FIFOSIZE)) rx_fifo_cascade - (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx), + fifo_cascade #(.WIDTH(36), .SIZE(DSP_RX_FIFOSIZE)) rx_fifo_cascade1 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1), .datain(rx1_data), .src_rdy_i(rx1_src_rdy), .dst_rdy_o(rx1_dst_rdy), - .dataout({wr1_flags,wr1_dat}), .src_rdy_o(wr1_ready_i), .dst_rdy_i(wr1_ready_o)); + .dataout(wr3_dat), .src_rdy_o(wr3_ready_i), .dst_rdy_i(wr3_ready_o)); // /////////////////////////////////////////////////////////////////////////////////// // DSP TX @@ -672,10 +695,10 @@ module u2_core .RAM_LDn(RAM_LDn), .RAM_OEn(RAM_OEn), .RAM_CE1n(RAM_CE1n), - .datain({rd1_flags[3:2],rd1_dat[31:16],rd1_flags[1:0],rd1_dat[15:0]}), + .datain(rd1_dat), .src_rdy_i(rd1_ready_o), .dst_rdy_o(rd1_ready_i), - .dataout({tx_data[35:34],tx_data[31:16],tx_data[33:32],tx_data[15:0]}), + .dataout(tx_data), .src_rdy_o(tx_src_rdy), .dst_rdy_i(tx_dst_rdy), .debug(debug_extfifo), @@ -701,9 +724,9 @@ module u2_core serdes #(.TXFIFOSIZE(SERDES_TX_FIFOSIZE),.RXFIFOSIZE(SERDES_RX_FIFOSIZE)) serdes (.clk(dsp_clk),.rst(dsp_rst), .ser_tx_clk(ser_tx_clk),.ser_t(ser_t),.ser_tklsb(ser_tklsb),.ser_tkmsb(ser_tkmsb), - .rd_dat_i(rd0_dat),.rd_flags_i(rd0_flags),.rd_ready_o(rd0_ready_i),.rd_ready_i(rd0_ready_o), + .rd_dat_i(rd0_dat[31:0]),.rd_flags_i(rd0_dat[35:32]),.rd_ready_o(rd0_ready_i),.rd_ready_i(rd0_ready_o), .ser_rx_clk(ser_rx_clk),.ser_r(ser_r),.ser_rklsb(ser_rklsb),.ser_rkmsb(ser_rkmsb), - .wr_dat_o(wr0_dat),.wr_flags_o(wr0_flags),.wr_ready_o(wr0_ready_i),.wr_ready_i(wr0_ready_o), + .wr_dat_o(wr0_dat[31:0]),.wr_flags_o(wr0_dat[35:32]),.wr_ready_o(wr0_ready_i),.wr_ready_i(wr0_ready_o), .tx_occupied(ser_tx_occ),.tx_full(ser_tx_full),.tx_empty(ser_tx_empty), .rx_occupied(ser_rx_occ),.rx_full(ser_rx_full),.rx_empty(ser_rx_empty), .serdes_link_up(serdes_link_up),.debug0(debug_serdes0), .debug1(debug_serdes1) ); @@ -725,7 +748,7 @@ module u2_core // Debug Pins assign debug_clk = 2'b00; // {dsp_clk, clk_to_mac}; - assign debug = 32'd0; // debug_extfifo; + assign debug = 32'd0; assign debug_gpio_0 = 32'd0; assign debug_gpio_1 = 32'd0; diff --git a/fpga/usrp2/top/u2_rev3/u2_rev3.v b/fpga/usrp2/top/u2_rev3/u2_rev3.v index 759f7b7b8..bc7ae5f16 100644 --- a/fpga/usrp2/top/u2_rev3/u2_rev3.v +++ b/fpga/usrp2/top/u2_rev3/u2_rev3.v @@ -471,7 +471,7 @@ module u2_rev3 // - u2_core #(.RAM_SIZE(16384), .RAM_AW(14)) + u2_core u2_core(.dsp_clk (dsp_clk), .wb_clk (wb_clk), .clock_ready (clock_ready), diff --git a/fpga/usrp2/top/u2plus/u2plus_core.v b/fpga/usrp2/top/u2plus/u2plus_core.v index 3edb539f7..1d568030e 100644 --- a/fpga/usrp2/top/u2plus/u2plus_core.v +++ b/fpga/usrp2/top/u2plus/u2plus_core.v @@ -131,20 +131,24 @@ module u2plus_core output spiflash_cs, output spiflash_clk, input spiflash_miso, output spiflash_mosi ); - localparam SR_BUF_POOL = 64; // router + localparam SR_MISC = 0; // Uses 9 regs + localparam SR_BUF_POOL = 64; // Uses 4 regs localparam SR_UDP_SM = 96; // 64 regs - localparam SR_RX_DSP = 160; // 16 - localparam SR_RX_CTRL = 176; // 16 + localparam SR_RX_DSP0 = 160; // 16 + localparam SR_RX_CTRL0 = 176; // 16 localparam SR_TIME64 = 192; // 3 localparam SR_SIMTIMER = 198; // 2 localparam SR_TX_DSP = 208; // 16 localparam SR_TX_CTRL = 224; // 16 - + localparam SR_RX_DSP1 = 240; + localparam SR_RX_CTRL1 = 32; + + // FIFO Sizes, 9 = 512 lines, 10 = 1024, 11 = 2048 // all (most?) are 36 bits wide, so 9 is 1 BRAM, 10 is 2, 11 is 4 BRAMs - localparam DSP_TX_FIFOSIZE = 10; - localparam DSP_RX_FIFOSIZE = 10; - localparam ETH_TX_FIFOSIZE = 10; + // localparam DSP_TX_FIFOSIZE = 9; unused -- DSPTX uses extram fifo + localparam DSP_RX_FIFOSIZE = 9; + localparam ETH_TX_FIFOSIZE = 9; localparam ETH_RX_FIFOSIZE = 11; localparam SERDES_TX_FIFOSIZE = 9; localparam SERDES_RX_FIFOSIZE = 9; // RX currently doesn't use a fifo? @@ -153,18 +157,19 @@ module u2plus_core wire [31:0] set_data, set_data_dsp; wire set_stb, set_stb_dsp; - reg wb_rst; wire dsp_rst; - + reg wb_rst; + wire dsp_rst = wb_rst; + wire [31:0] status; wire bus_error, spi_int, i2c_int, pps_int, onetime_int, periodic_int, buffer_int; - wire proc_int, overrun, underrun; + wire proc_int, overrun0, overrun1, underrun; wire [3:0] uart_tx_int, uart_rx_int; wire [31:0] debug_gpio_0, debug_gpio_1; wire [31:0] atr_lines; wire [31:0] debug_rx, debug_mac, debug_mac0, debug_mac1, debug_tx_dsp, debug_txc, - debug_serdes0, debug_serdes1, debug_serdes2, debug_rx_dsp, debug_udp; + debug_serdes0, debug_serdes1, debug_serdes2, debug_rx_dsp, debug_udp, debug_extfifo, debug_extfifo2; wire [15:0] ser_rx_occ, ser_tx_occ, dsp_rx_occ, dsp_tx_occ, eth_rx_occ, eth_tx_occ, eth_rx_occ2; wire ser_rx_full, ser_tx_full, dsp_rx_full, dsp_tx_full, eth_rx_full, eth_tx_full, eth_rx_full2; @@ -174,7 +179,9 @@ module u2plus_core wire epoch; wire [31:0] irq; wire [63:0] vita_time, vita_time_pps; - wire run_rx, run_tx; + + wire run_rx0, run_rx1, run_tx; + reg run_rx0_d1, run_rx1_d1; // /////////////////////////////////////////////////////////////////////////////////////////////// // Wishbone Single Master INTERCON @@ -341,15 +348,13 @@ module u2plus_core wire rd1_ready_i, rd1_ready_o; wire rd2_ready_i, rd2_ready_o; wire rd3_ready_i, rd3_ready_o; - wire [3:0] rd0_flags, rd1_flags, rd2_flags, rd3_flags; - wire [31:0] rd0_dat, rd1_dat, rd2_dat, rd3_dat; + wire [35:0] rd0_dat, rd1_dat, rd2_dat, rd3_dat; wire wr0_ready_i, wr0_ready_o; wire wr1_ready_i, wr1_ready_o; wire wr2_ready_i, wr2_ready_o; wire wr3_ready_i, wr3_ready_o; - wire [3:0] wr0_flags, wr1_flags, wr2_flags, wr3_flags; - wire [31:0] wr0_dat, wr1_dat, wr2_dat, wr3_dat; + wire [35:0] wr0_dat, wr1_dat, wr2_dat, wr3_dat; wire [35:0] tx_err_data; wire tx_err_src_rdy, tx_err_dst_rdy; @@ -367,14 +372,15 @@ module u2plus_core .status(status), .sys_int_o(buffer_int), .debug(router_debug), - .ser_inp_data({wr0_flags, wr0_dat}), .ser_inp_valid(wr0_ready_i), .ser_inp_ready(wr0_ready_o), - .dsp_inp_data({wr1_flags, wr1_dat}), .dsp_inp_valid(wr1_ready_i), .dsp_inp_ready(wr1_ready_o), - .eth_inp_data({wr2_flags, wr2_dat}), .eth_inp_valid(wr2_ready_i), .eth_inp_ready(wr2_ready_o), + .ser_inp_data(wr0_dat), .ser_inp_valid(wr0_ready_i), .ser_inp_ready(wr0_ready_o), + .dsp0_inp_data(wr1_dat), .dsp0_inp_valid(wr1_ready_i), .dsp0_inp_ready(wr1_ready_o), + .dsp1_inp_data(wr3_dat), .dsp1_inp_valid(wr3_ready_i), .dsp1_inp_ready(wr3_ready_o), + .eth_inp_data(wr2_dat), .eth_inp_valid(wr2_ready_i), .eth_inp_ready(wr2_ready_o), .err_inp_data(tx_err_data), .err_inp_ready(tx_err_dst_rdy), .err_inp_valid(tx_err_src_rdy), - .ser_out_data({rd0_flags, rd0_dat}), .ser_out_valid(rd0_ready_o), .ser_out_ready(rd0_ready_i), - .dsp_out_data({rd1_flags, rd1_dat}), .dsp_out_valid(rd1_ready_o), .dsp_out_ready(rd1_ready_i), - .eth_out_data({rd2_flags, rd2_dat}), .eth_out_valid(rd2_ready_o), .eth_out_ready(rd2_ready_i) + .ser_out_data(rd0_dat), .ser_out_valid(rd0_ready_o), .ser_out_ready(rd0_ready_i), + .dsp_out_data(rd1_dat), .dsp_out_valid(rd1_ready_o), .dsp_out_ready(rd1_ready_i), + .eth_out_data(rd2_dat), .eth_out_valid(rd2_ready_o), .eth_out_ready(rd2_ready_i) ); // ///////////////////////////////////////////////////////////////////////// @@ -410,12 +416,12 @@ module u2plus_core // Buffer Pool Status -- Slave #5 //compatibility number -> increment when the fpga has been sufficiently altered - localparam compat_num = 32'd4; + localparam compat_num = 32'd5; wb_readback_mux buff_pool_status (.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb), .wb_adr_i(s5_adr), .wb_dat_o(s5_dat_i), .wb_ack_o(s5_ack), - + .word00(32'b0),.word01(32'b0),.word02(32'b0),.word03(32'b0), .word04(32'b0),.word05(32'b0),.word06(32'b0),.word07(32'b0), .word08(status),.word09({sim_mode,27'b0,clock_divider[3:0]}),.word10(vita_time[63:32]), @@ -463,19 +469,19 @@ module u2plus_core fifo_cascade #(.WIDTH(36), .SIZE(ETH_RX_FIFOSIZE)) rx_eth_fifo (.clk(dsp_clk), .reset(dsp_rst), .clear(0), .datain(rx_f36_data), .src_rdy_i(rx_f36_src_rdy), .dst_rdy_o(rx_f36_dst_rdy), - .dataout({wr2_flags,wr2_dat}), .src_rdy_o(wr2_ready_i), .dst_rdy_i(wr2_ready_o)); + .dataout(wr2_dat), .src_rdy_o(wr2_ready_i), .dst_rdy_i(wr2_ready_o)); //eth output to mac tx... fifo_cascade #(.WIDTH(36), .SIZE(ETH_TX_FIFOSIZE)) tx_eth_fifo (.clk(dsp_clk), .reset(dsp_rst), .clear(0), - .datain({rd2_flags,rd2_dat}), .src_rdy_i(rd2_ready_o), .dst_rdy_o(rd2_ready_i), + .datain(rd2_dat), .src_rdy_i(rd2_ready_o), .dst_rdy_o(rd2_ready_i), .dataout(tx_f36_data), .src_rdy_o(tx_f36_src_rdy), .dst_rdy_i(tx_f36_dst_rdy)); fifo36_to_fifo19 eth_out_fifo36_to_fifo19 (.clk(dsp_clk), .reset(dsp_rst), .clear(0), .f36_datain(tx_f36_data), .f36_src_rdy_i(tx_f36_src_rdy), .f36_dst_rdy_o(tx_f36_dst_rdy), .f19_dataout(tx_f19_data), .f19_src_rdy_o(tx_f19_src_rdy), .f19_dst_rdy_i(tx_f19_dst_rdy) ); - + // ///////////////////////////////////////////////////////////////////////// // Settings Bus -- Slave #7 settings_bus settings_bus @@ -498,15 +504,15 @@ module u2plus_core wire phy_reset; assign PHY_RESETn = ~phy_reset; - setting_reg #(.my_addr(0),.width(8)) sr_clk (.clk(wb_clk),.rst(wb_rst),.strobe(s7_ack),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+0),.width(8)) sr_clk (.clk(wb_clk),.rst(wb_rst),.strobe(s7_ack),.addr(set_addr), .in(set_data),.out(clock_outs),.changed()); - setting_reg #(.my_addr(1),.width(8)) sr_ser (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+1),.width(8)) sr_ser (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(serdes_outs),.changed()); - setting_reg #(.my_addr(2),.width(8)) sr_adc (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+2),.width(8)) sr_adc (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(adc_outs),.changed()); - setting_reg #(.my_addr(4),.width(1)) sr_phy (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+4),.width(1)) sr_phy (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(phy_reset),.changed()); - setting_reg #(.my_addr(5),.width(1)) sr_bldr (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+5),.width(1)) sr_bldr (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(bldr_done),.changed()); // ///////////////////////////////////////////////////////////////////////// @@ -516,12 +522,12 @@ module u2plus_core // In Rev3 there are only 6 leds, and the highest one is on the ETH connector wire [7:0] led_src, led_sw; - wire [7:0] led_hw = {run_tx, run_rx, clk_status, serdes_link_up, 1'b0}; + wire [7:0] led_hw = {run_tx, (run_rx0_d1 | run_rx1_d1), clk_status, serdes_link_up, 1'b0}; - setting_reg #(.my_addr(3),.width(8)) sr_led (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), + setting_reg #(.my_addr(SR_MISC+3),.width(8)) sr_led (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(led_sw),.changed()); - setting_reg #(.my_addr(8),.width(8), .at_reset(8'b0001_1110)) + setting_reg #(.my_addr(SR_MISC+8),.width(8), .at_reset(8'b0001_1110)) sr_led_src (.clk(wb_clk),.rst(wb_rst), .strobe(set_stb),.addr(set_addr), .in(set_data),.out(led_src),.changed()); assign leds = (led_src & led_hw) | (~led_src & led_sw); @@ -533,7 +539,7 @@ module u2plus_core wire underrun_wb, overrun_wb, pps_wb; oneshot_2clk underrun_1s (.clk_in(dsp_clk), .in(underrun), .clk_out(wb_clk), .out(underrun_wb)); - oneshot_2clk overrun_1s (.clk_in(dsp_clk), .in(overrun), .clk_out(wb_clk), .out(overrun_wb)); + oneshot_2clk overrun_1s (.clk_in(dsp_clk), .in(overrun0 | overrun1), .clk_out(wb_clk), .out(overrun_wb)); oneshot_2clk pps_1s (.clk_in(dsp_clk), .in(pps_int), .clk_out(wb_clk), .out(pps_wb)); assign irq= {{8'b0}, @@ -572,15 +578,11 @@ module u2plus_core // ///////////////////////////////////////////////////////////////////////// // ATR Controller, Slave #11 - reg run_rx_d1; - always @(posedge dsp_clk) - run_rx_d1 <= run_rx; - atr_controller atr_controller (.clk_i(wb_clk),.rst_i(wb_rst), .adr_i(sb_adr[5:0]),.sel_i(sb_sel),.dat_i(sb_dat_o),.dat_o(sb_dat_i), .we_i(sb_we),.stb_i(sb_stb),.cyc_i(sb_cyc),.ack_o(sb_ack), - .run_rx(run_rx_d1),.run_tx(run_tx),.ctrl_lines(atr_lines) ); + .run_rx(run_rx0_d1 | run_rx1_d1),.run_tx(run_tx),.ctrl_lines(atr_lines) ); // ////////////////////////////////////////////////////////////////////////// // Time Sync, Slave #12 @@ -605,50 +607,72 @@ module u2plus_core .sclk_pad_o(spiflash_clk),.mosi_pad_o(spiflash_mosi),.miso_pad_i(spiflash_miso) ); // ///////////////////////////////////////////////////////////////////////// - // DSP RX - wire [31:0] sample_rx, sample_tx; - wire strobe_rx, strobe_tx; - wire rx_dst_rdy, rx_src_rdy, rx1_dst_rdy, rx1_src_rdy; - wire [99:0] rx_data; - wire [35:0] rx1_data; + // DSP RX 0 + wire [31:0] sample_rx0; + wire [35:0] rx0_data; + wire clear_rx0, strobe_rx0, rx0_dst_rdy, rx0_src_rdy; + + always @(posedge dsp_clk) + run_rx0_d1 <= run_rx0; - dsp_core_rx #(.BASE(SR_RX_DSP)) dsp_core_rx + dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0 (.clk(dsp_clk),.rst(dsp_rst), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), - .sample(sample_rx), .run(run_rx_d1), .strobe(strobe_rx), - .debug(debug_rx_dsp) ); + .sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0), + .debug() ); - wire [31:0] vrc_debug; - wire clear_rx; - - setting_reg #(.my_addr(SR_RX_CTRL+3)) sr_clear + setting_reg #(.my_addr(SR_RX_CTRL0+3)) sr_clear_rx0 (.clk(dsp_clk),.rst(dsp_rst), .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp), - .out(),.changed(clear_rx)); + .out(),.changed(clear_rx0)); - vita_rx_control #(.BASE(SR_RX_CTRL), .WIDTH(32)) vita_rx_control - (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx), + vita_rx_chain #(.BASE(SR_RX_CTRL0)) vita_rx_chain0 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .vita_time(vita_time), .overrun(overrun), - .sample(sample_rx), .run(run_rx), .strobe(strobe_rx), - .sample_fifo_o(rx_data), .sample_fifo_dst_rdy_i(rx_dst_rdy), .sample_fifo_src_rdy_o(rx_src_rdy), - .debug_rx(vrc_debug)); + .vita_time(vita_time), .overrun(overrun0), + .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), + .rx_data_o(rx0_data), .rx_src_rdy_o(rx0_src_rdy), .rx_dst_rdy_i(rx0_dst_rdy), + .debug() ); + + fifo_cascade #(.WIDTH(36), .SIZE(DSP_RX_FIFOSIZE)) rx_fifo_cascade0 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0), + .datain(rx0_data), .src_rdy_i(rx0_src_rdy), .dst_rdy_o(rx0_dst_rdy), + .dataout(wr1_dat), .src_rdy_o(wr1_ready_i), .dst_rdy_i(wr1_ready_o)); - wire [3:0] vita_state; + // ///////////////////////////////////////////////////////////////////////// + // DSP RX 1 + wire [31:0] sample_rx1; + wire [35:0] rx1_data; + wire clear_rx1, strobe_rx1, rx1_dst_rdy, rx1_src_rdy; + + always @(posedge dsp_clk) + run_rx1_d1 <= run_rx1; - vita_rx_framer #(.BASE(SR_RX_CTRL), .MAXCHAN(1)) vita_rx_framer - (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx), + dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1 + (.clk(dsp_clk),.rst(dsp_rst), + .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), + .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b), + .sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1), + .debug() ); + + setting_reg #(.my_addr(SR_RX_CTRL1+3)) sr_clear_rx1 + (.clk(dsp_clk),.rst(dsp_rst), + .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp), + .out(),.changed(clear_rx1)); + + vita_rx_chain #(.BASE(SR_RX_CTRL1)) vita_rx_chain1 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1), .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), - .sample_fifo_i(rx_data), .sample_fifo_dst_rdy_o(rx_dst_rdy), .sample_fifo_src_rdy_i(rx_src_rdy), - .data_o(rx1_data), .dst_rdy_i(rx1_dst_rdy), .src_rdy_o(rx1_src_rdy), - .fifo_occupied(), .fifo_full(), .fifo_empty(), - .debug_rx(vita_state) ); + .vita_time(vita_time), .overrun(overrun1), + .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), + .rx_data_o(rx1_data), .rx_src_rdy_o(rx1_src_rdy), .rx_dst_rdy_i(rx1_dst_rdy), + .debug() ); - fifo_cascade #(.WIDTH(36), .SIZE(DSP_RX_FIFOSIZE)) rx_fifo_cascade - (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx), + fifo_cascade #(.WIDTH(36), .SIZE(DSP_RX_FIFOSIZE)) rx_fifo_cascade1 + (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1), .datain(rx1_data), .src_rdy_i(rx1_src_rdy), .dst_rdy_o(rx1_dst_rdy), - .dataout({wr1_flags,wr1_dat}), .src_rdy_o(wr1_ready_i), .dst_rdy_i(wr1_ready_o)); + .dataout(wr3_dat), .src_rdy_o(wr3_ready_i), .dst_rdy_i(wr3_ready_o)); // /////////////////////////////////////////////////////////////////////////////////// // DSP TX @@ -678,10 +702,10 @@ module u2plus_core .RAM_LDn(RAM_LDn), .RAM_OEn(RAM_OEn), .RAM_CE1n(RAM_CE1n), - .datain({rd1_flags[3:2],rd1_dat[31:16],rd1_flags[1:0],rd1_dat[15:0]}), + .datain(rd1_dat), .src_rdy_i(rd1_ready_o), .dst_rdy_o(rd1_ready_i), - .dataout({tx_data[35:34],tx_data[31:16],tx_data[33:32],tx_data[15:0]}), + .dataout(tx_data), .src_rdy_o(tx_src_rdy), .dst_rdy_i(tx_dst_rdy), .debug(debug_extfifo), @@ -701,17 +725,15 @@ module u2plus_core .underrun(underrun), .run(run_tx), .debug(debug_vt)); - assign dsp_rst = wb_rst; - // /////////////////////////////////////////////////////////////////////////////////// // SERDES serdes #(.TXFIFOSIZE(SERDES_TX_FIFOSIZE),.RXFIFOSIZE(SERDES_RX_FIFOSIZE)) serdes (.clk(dsp_clk),.rst(dsp_rst), .ser_tx_clk(ser_tx_clk),.ser_t(ser_t),.ser_tklsb(ser_tklsb),.ser_tkmsb(ser_tkmsb), - .rd_dat_i(rd0_dat),.rd_flags_i(rd0_flags),.rd_ready_o(rd0_ready_i),.rd_ready_i(rd0_ready_o), + .rd_dat_i(rd0_dat[31:0]),.rd_flags_i(rd0_dat[35:32]),.rd_ready_o(rd0_ready_i),.rd_ready_i(rd0_ready_o), .ser_rx_clk(ser_rx_clk),.ser_r(ser_r),.ser_rklsb(ser_rklsb),.ser_rkmsb(ser_rkmsb), - .wr_dat_o(wr0_dat),.wr_flags_o(wr0_flags),.wr_ready_o(wr0_ready_i),.wr_ready_i(wr0_ready_o), + .wr_dat_o(wr0_dat[31:0]),.wr_flags_o(wr0_dat[35:32]),.wr_ready_o(wr0_ready_i),.wr_ready_i(wr0_ready_o), .tx_occupied(ser_tx_occ),.tx_full(ser_tx_full),.tx_empty(ser_tx_empty), .rx_occupied(ser_rx_occ),.rx_full(ser_rx_full),.rx_empty(ser_rx_empty), .serdes_link_up(serdes_link_up),.debug0(debug_serdes0), .debug1(debug_serdes1) ); @@ -720,18 +742,18 @@ module u2plus_core // VITA Timing wire [31:0] debug_sync; - + time_64bit #(.TICKS_PER_SEC(32'd100000000),.BASE(SR_TIME64)) time_64bit (.clk(dsp_clk), .rst(dsp_rst), .set_stb(set_stb_dsp), .set_addr(set_addr_dsp), .set_data(set_data_dsp), .pps(pps_in), .vita_time(vita_time), .vita_time_pps(vita_time_pps), .pps_int(pps_int), .exp_time_in(exp_time_in), .exp_time_out(exp_time_out), .debug(debug_sync)); - + // ///////////////////////////////////////////////////////////////////////////////////////// // Debug Pins assign debug_clk = 2'b00; // {dsp_clk, clk_to_mac}; - assign debug = 32'd0; // debug_extfifo; + assign debug = 32'd0; assign debug_gpio_0 = 32'd0; assign debug_gpio_1 = 32'd0; diff --git a/fpga/usrp2/vrt/Makefile.srcs b/fpga/usrp2/vrt/Makefile.srcs index aa1356d82..4851bc924 100644 --- a/fpga/usrp2/vrt/Makefile.srcs +++ b/fpga/usrp2/vrt/Makefile.srcs @@ -8,6 +8,7 @@ VRT_SRCS = $(abspath $(addprefix $(BASE_DIR)/../vrt/, \ vita_rx_control.v \ vita_rx_framer.v \ +vita_rx_chain.v \ vita_tx_control.v \ vita_tx_deframer.v \ vita_tx_chain.v \ diff --git a/fpga/usrp2/vrt/vita_rx_chain.v b/fpga/usrp2/vrt/vita_rx_chain.v new file mode 100644 index 000000000..f5578eb15 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_chain.v @@ -0,0 +1,33 @@ + +module vita_rx_chain + #(parameter BASE=0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [63:0] vita_time, output overrun, + input [31:0] sample, output run, input strobe, + output [35:0] rx_data_o, output rx_src_rdy_o, input rx_dst_rdy_i, + output [31:0] debug ); + + wire [100:0] sample_data; + wire sample_dst_rdy, sample_src_rdy; + wire [31:0] vrc_debug, vrf_debug; + + vita_rx_control #(.BASE(BASE), .WIDTH(32)) vita_rx_control + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .vita_time(vita_time), .overrun(overrun), + .sample(sample), .run(run), .strobe(strobe), + .sample_fifo_o(sample_data), .sample_fifo_dst_rdy_i(sample_dst_rdy), .sample_fifo_src_rdy_o(sample_src_rdy), + .debug_rx(vrc_debug)); + + vita_rx_framer #(.BASE(BASE), .MAXCHAN(1)) vita_rx_framer + (.clk(clk), .reset(reset), .clear(clear), + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .sample_fifo_i(sample_data), .sample_fifo_dst_rdy_o(sample_dst_rdy), .sample_fifo_src_rdy_i(sample_src_rdy), + .data_o(rx_data_o), .src_rdy_o(rx_src_rdy_o), .dst_rdy_i(rx_dst_rdy_i), + .fifo_occupied(), .fifo_full(), .fifo_empty(), + .debug_rx(vrf_debug) ); + + assign debug = vrc_debug; // | vrf_debug; + +endmodule // vita_rx_chain diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp index eb3394230..2c0841146 100644 --- a/host/include/uhd/types/device_addr.hpp +++ b/host/include/uhd/types/device_addr.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -84,9 +84,15 @@ namespace uhd{ } }; - //handy typedef for a vector of device addresses + //! A typedef for a vector of device addresses typedef std::vector<device_addr_t> device_addrs_t; + //! Separate an indexed device address into a vector of device addresses + UHD_API device_addrs_t separate_device_addr(const device_addr_t &dev_addr); + + //! Combine a vector of device addresses into an indexed device address + UHD_API device_addr_t combine_device_addrs(const device_addrs_t &dev_addrs); + } //namespace uhd #endif /* INCLUDED_UHD_TYPES_DEVICE_ADDR_HPP */ diff --git a/host/include/uhd/usrp/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp index 3e1690317..e68e11deb 100644 --- a/host/include/uhd/usrp/dsp_props.hpp +++ b/host/include/uhd/usrp/dsp_props.hpp @@ -39,8 +39,8 @@ namespace uhd{ namespace usrp{ enum dsp_prop_t{ DSP_PROP_NAME, //ro, std::string DSP_PROP_OTHERS, //ro, prop_names_t + DSP_PROP_STREAM_CMD, //wo, stream_cmd_t DSP_PROP_FREQ_SHIFT, //rw, double Hz - DSP_PROP_FREQ_SHIFT_NAMES, //ro, prop_names_t DSP_PROP_CODEC_RATE, //ro, double Sps DSP_PROP_HOST_RATE //rw, double Sps }; diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp index 8855e2b75..180c4eeb3 100644 --- a/host/include/uhd/usrp/mboard_props.hpp +++ b/host/include/uhd/usrp/mboard_props.hpp @@ -47,7 +47,6 @@ namespace uhd{ namespace usrp{ MBOARD_PROP_CLOCK_CONFIG, //rw, clock_config_t MBOARD_PROP_TIME_NOW, //rw, time_spec_t MBOARD_PROP_TIME_PPS, //wo, time_spec_t - MBOARD_PROP_STREAM_CMD, //wo, stream_cmd_t MBOARD_PROP_EEPROM_MAP //wr, mboard_eeprom_t }; diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp index 3c8dd5fac..b06975b6c 100644 --- a/host/include/uhd/usrp/multi_usrp.hpp +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -87,6 +87,9 @@ public: //! A wildcard motherboard index static const size_t ALL_MBOARDS = size_t(~0); + //! A wildcard channel index + static const size_t ALL_CHANS = size_t(~0); + //! A wildcard gain element name static const std::string ALL_GAINS; @@ -215,8 +218,9 @@ public: * to ensure that the packets can be aligned by their time specs. * * \param stream_cmd the stream command to issue + * \param chan the channel index 0 to N-1 */ - virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan = ALL_CHANS) = 0; /*! * Set the clock configuration for the usrp device. @@ -282,16 +286,18 @@ public: virtual std::string get_rx_subdev_name(size_t chan = 0) = 0; /*! - * Set the RX sample rate across all channels. + * Set the RX sample rate. * \param rate the rate in Sps + * \param chan the channel index 0 to N-1 */ - virtual void set_rx_rate(double rate) = 0; + virtual void set_rx_rate(double rate, size_t chan = ALL_CHANS) = 0; /*! - * Gets the RX sample rate for all channels. + * Gets the RX sample rate. + * \param chan the channel index 0 to N-1 * \return the rate in Sps */ - virtual double get_rx_rate(void) = 0; + virtual double get_rx_rate(size_t chan = 0) = 0; /*! * Set the RX center frequency. @@ -480,16 +486,18 @@ public: virtual std::string get_tx_subdev_name(size_t chan = 0) = 0; /*! - * Set the TX sample rate across all channels. + * Set the TX sample rate. * \param rate the rate in Sps + * \param chan the channel index 0 to N-1 */ - virtual void set_tx_rate(double rate) = 0; + virtual void set_tx_rate(double rate, size_t chan = ALL_CHANS) = 0; /*! - * Gets the TX sample rate for all channels. + * Gets the TX sample rate. + * \param chan the channel index 0 to N-1 * \return the rate in Sps */ - virtual double get_tx_rate(void) = 0; + virtual double get_tx_rate(size_t chan = 0) = 0; /*! * Set the TX center frequency. diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp index db12241c1..e97ab0298 100644 --- a/host/include/uhd/usrp/tune_helper.hpp +++ b/host/include/uhd/usrp/tune_helper.hpp @@ -32,24 +32,21 @@ namespace uhd{ namespace usrp{ * The ddc cordic is setup to bring the IF down to baseband. * \param subdev the dboard subdevice object with properties * \param ddc the mboard dsp object with properties - * \param chan the channel of the dsp to tune * \param tune_request tune request instructions * \return a tune result struct */ UHD_API tune_result_t tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, size_t chan, - const tune_request_t &tune_request + wax::obj subdev, wax::obj ddc, const tune_request_t &tune_request ); /*! * Calculate the overall frequency from the combination of dboard IF and DDC shift. * \param subdev the dboard subdevice object with properties * \param ddc the mboard dsp object with properties - * \param chan the channel of the dsp to tune * \return the overall tune frequency of the system in Hz */ UHD_API double derive_freq_from_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, size_t chan + wax::obj subdev, wax::obj ddc ); /*! @@ -59,24 +56,21 @@ namespace uhd{ namespace usrp{ * The duc cordic is setup to bring the baseband up to IF. * \param subdev the dboard subdevice object with properties * \param duc the mboard dsp object with properties - * \param chan the channel of the dsp to tune * \param tune_request tune request instructions * \return a tune result struct */ UHD_API tune_result_t tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, size_t chan, - const tune_request_t &tune_request + wax::obj subdev, wax::obj duc, const tune_request_t &tune_request ); /*! * Calculate the overall frequency from the combination of dboard IF and DUC shift. * \param subdev the dboard subdevice object with properties * \param duc the mboard dsp object with properties - * \param chan the channel of the dsp to tune * \return the overall tune frequency of the system in Hz */ UHD_API double derive_freq_from_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, size_t chan + wax::obj subdev, wax::obj duc ); }} diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 6f3ac0421..4f8ce7e52 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -300,18 +300,18 @@ template <typename T> UHD_INLINE T get_context_code( typedef boost::function<bool(managed_send_buffs_t &)> get_send_buffs_t; typedef boost::function<void(boost::uint32_t *, uhd::transport::vrt::if_packet_info_t &)> vrt_packer_t; + static const boost::uint64_t zeros = 0; + struct send_state{ //init the expected seq number size_t next_packet_seq; managed_send_buffs_t managed_buffs; - const boost::uint64_t zeros; std::vector<const void *> zero_buffs; std::vector<const void *> io_buffs; send_state(size_t width = 1): next_packet_seq(0), managed_buffs(width), - zeros(0), zero_buffs(width, &zeros), io_buffs(0) //resized later { diff --git a/host/lib/types/device_addr.cpp b/host/lib/types/device_addr.cpp index 14afaa24b..7f2031272 100644 --- a/host/lib/types/device_addr.cpp +++ b/host/lib/types/device_addr.cpp @@ -16,10 +16,11 @@ // #include <uhd/types/device_addr.hpp> -#include <boost/algorithm/string.hpp> //for trim +#include <boost/algorithm/string.hpp> #include <boost/tokenizer.hpp> #include <boost/foreach.hpp> #include <boost/format.hpp> +#include <boost/regex.hpp> #include <stdexcept> #include <sstream> @@ -71,3 +72,51 @@ std::string device_addr_t::to_string(void) const{ } return args_str; } + +#include <uhd/utils/warning.hpp> + +device_addrs_t uhd::separate_device_addr(const device_addr_t &dev_addr){ + //------------ support old deprecated way and print warning -------- + if (dev_addr.has_key("addr") and not dev_addr["addr"].empty()){ + std::vector<std::string> addrs; boost::split(addrs, dev_addr["addr"], boost::is_any_of(" ")); + if (addrs.size() > 1){ + device_addr_t fixed_dev_addr = dev_addr; + fixed_dev_addr.pop("addr"); + for (size_t i = 0; i < addrs.size(); i++){ + fixed_dev_addr[str(boost::format("addr%d") % i)] = addrs[i]; + } + uhd::warning::post( + "addr = <space separated list of ip addresses> is deprecated.\n" + "To address a multi-device, use multiple <key><index> = <val>.\n" + "See the USRP-NXXX application notes. Two device example:\n" + " addr0 = 192.168.10.2\n" + " addr1 = 192.168.10.3\n" + ); + return separate_device_addr(fixed_dev_addr); + } + } + //------------------------------------------------------------------ + device_addrs_t dev_addrs; + BOOST_FOREACH(const std::string &key, dev_addr.keys()){ + boost::cmatch matches; + if (not boost::regex_match(key.c_str(), matches, boost::regex("^(\\D+)(\\d*)$"))){ + throw std::runtime_error("unknown key format: " + key); + } + std::string key_part(matches[1].first, matches[1].second); + std::string num_part(matches[2].first, matches[2].second); + size_t num = (num_part.empty())? 0 : boost::lexical_cast<size_t>(num_part); + dev_addrs.resize(std::max(num+1, dev_addrs.size())); + dev_addrs[num][key_part] = dev_addr[key]; + } + return dev_addrs; +} + +device_addr_t uhd::combine_device_addrs(const device_addrs_t &dev_addrs){ + device_addr_t dev_addr; + for (size_t i = 0; i < dev_addrs.size(); i++){ + BOOST_FOREACH(const std::string &key, dev_addrs[i].keys()){ + dev_addr[str(boost::format("%s%d") % key % i)] = dev_addrs[i][key]; + } + } + return dev_addr; +} diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 73bac029d..23049d569 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -85,17 +85,14 @@ public: //----------- rx side of life ---------------------------------- for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){ - buff += str(boost::format( - " RX DSP %d: %s\n" - ) % m - % _rx_dsp(m)[DSP_PROP_NAME].as<std::string>() - ); for (; chan < (m + 1)*get_rx_subdev_spec(m).size(); chan++){ buff += str(boost::format( " RX Channel: %u\n" + " RX DSP: %s\n" " RX Dboard: %s\n" " RX Subdev: %s\n" ) % chan + % _rx_dsp(chan)[DSP_PROP_NAME].as<std::string>() % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() ); @@ -104,17 +101,14 @@ public: //----------- tx side of life ---------------------------------- for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){ - buff += str(boost::format( - " TX DSP %d: %s\n" - ) % m - % _tx_dsp(m)[DSP_PROP_NAME].as<std::string>() - ); for (; chan < (m + 1)*get_tx_subdev_spec(m).size(); chan++){ buff += str(boost::format( " TX Channel: %u\n" + " TX DSP: %s\n" " TX Dboard: %s\n" " TX Subdev: %s\n" ) % chan + % _tx_dsp(chan)[DSP_PROP_NAME].as<std::string>() % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() ); @@ -194,9 +188,13 @@ public: return true; } - void issue_stream_cmd(const stream_cmd_t &stream_cmd){ - for (size_t m = 0; m < get_num_mboards(); m++){ - _mboard(m)[MBOARD_PROP_STREAM_CMD] = stream_cmd; + void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){ + if (chan != ALL_CHANS){ + _rx_dsp(chan)[DSP_PROP_STREAM_CMD] = stream_cmd; + return; + } + for (size_t c = 0; c < get_rx_num_channels(); c++){ + issue_stream_cmd(stream_cmd, c); } } @@ -240,36 +238,44 @@ public: } size_t get_rx_num_channels(void){ - return rx_cpm()*get_num_mboards(); //total num channels + size_t sum = 0; + for (size_t m = 0; m < get_num_mboards(); m++){ + sum += get_rx_subdev_spec(m).size(); + } + return sum; } std::string get_rx_subdev_name(size_t chan){ return _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>(); } - void set_rx_rate(double rate){ - for (size_t m = 0; m < get_num_mboards(); m++){ - _rx_dsp(m)[DSP_PROP_HOST_RATE] = rate; + void set_rx_rate(double rate, size_t chan){ + if (chan != ALL_CHANS){ + _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + do_samp_rate_warning_message(rate, get_rx_rate(chan), "RX"); + return; + } + for (size_t c = 0; c < get_rx_num_channels(); c++){ + set_rx_rate(rate, c); } - do_samp_rate_warning_message(rate, get_rx_rate(), "RX"); } - double get_rx_rate(void){ - return _rx_dsp(0)[DSP_PROP_HOST_RATE].as<double>(); + double get_rx_rate(size_t chan){ + return _rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>(); } tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){ - tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), tune_request); + tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), tune_request); do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX"); return r; } double get_rx_freq(size_t chan){ - return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm()); + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan)); } freq_range_t get_rx_freq_range(size_t chan){ - return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan/rx_cpm())); + return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan)); } void set_rx_gain(double gain, const std::string &name, size_t chan){ @@ -342,32 +348,40 @@ public: } size_t get_tx_num_channels(void){ - return tx_cpm()*get_num_mboards(); //total num channels + size_t sum = 0; + for (size_t m = 0; m < get_num_mboards(); m++){ + sum += get_tx_subdev_spec(m).size(); + } + return sum; } - void set_tx_rate(double rate){ - for (size_t m = 0; m < get_num_mboards(); m++){ - _tx_dsp(m)[DSP_PROP_HOST_RATE] = rate; + void set_tx_rate(double rate, size_t chan){ + if (chan != ALL_CHANS){ + _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + do_samp_rate_warning_message(rate, get_tx_rate(chan), "TX"); + return; + } + for (size_t c = 0; c < get_tx_num_channels(); c++){ + set_tx_rate(rate, c); } - do_samp_rate_warning_message(rate, get_tx_rate(), "TX"); } - double get_tx_rate(void){ - return _tx_dsp(0)[DSP_PROP_HOST_RATE].as<double>(); + double get_tx_rate(size_t chan){ + return _tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>(); } tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){ - tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), tune_request); + tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), tune_request); do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX"); return r; } double get_tx_freq(size_t chan){ - return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm()); + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan)); } freq_range_t get_tx_freq_range(size_t chan){ - return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan/tx_cpm())); + return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan)); } void set_tx_gain(double gain, const std::string &name, size_t chan){ @@ -421,58 +435,75 @@ public: private: device::sptr _dev; - size_t rx_cpm(void){ //channels per mboard - size_t nchan = get_rx_subdev_spec(0).size(); - for (size_t m = 1; m < get_num_mboards(); m++){ - if (nchan != get_rx_subdev_spec(m).size()){ - throw std::runtime_error("rx subdev spec size inconsistent across all mboards"); - } + struct mboard_chan_pair{ + size_t mboard, chan; + mboard_chan_pair(void): mboard(0), chan(0){} + }; + + mboard_chan_pair rx_chan_to_mcp(size_t chan){ + mboard_chan_pair mcp; + mcp.chan = chan; + for (mcp.mboard = 0; mcp.mboard < get_num_mboards(); mcp.mboard++){ + size_t sss = get_rx_subdev_spec(mcp.mboard).size(); + if (mcp.chan < sss) break; + mcp.chan -= sss; } - return nchan; + return mcp; } - size_t tx_cpm(void){ //channels per mboard - size_t nchan = get_tx_subdev_spec(0).size(); - for (size_t m = 1; m < get_num_mboards(); m++){ - if (nchan != get_tx_subdev_spec(m).size()){ - throw std::runtime_error("tx subdev spec size inconsistent across all mboards"); - } + mboard_chan_pair tx_chan_to_mcp(size_t chan){ + mboard_chan_pair mcp; + mcp.chan = chan; + for (mcp.mboard = 0; mcp.mboard < get_num_mboards(); mcp.mboard++){ + size_t sss = get_tx_subdev_spec(mcp.mboard).size(); + if (mcp.chan < sss) break; + mcp.chan -= sss; } - return nchan; + return mcp; } wax::obj _mboard(size_t mboard){ std::string mb_name = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().at(mboard); return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, mb_name)]; } - wax::obj _rx_dsp(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_RX_DSP]; + wax::obj _rx_dsp(size_t chan){ + mboard_chan_pair mcp = rx_chan_to_mcp(chan); + prop_names_t dsp_names = _mboard(mcp.mboard)[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>(); + return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_RX_DSP, dsp_names.at(mcp.chan))]; } - wax::obj _tx_dsp(size_t mboard){ - return _mboard(mboard)[MBOARD_PROP_TX_DSP]; + wax::obj _tx_dsp(size_t chan){ + mboard_chan_pair mcp = tx_chan_to_mcp(chan); + prop_names_t dsp_names = _mboard(mcp.mboard)[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>(); + return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_TX_DSP, dsp_names.at(mcp.chan))]; } wax::obj _rx_dboard(size_t chan){ - std::string db_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).db_name; - return _mboard(chan/rx_cpm())[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + mboard_chan_pair mcp = rx_chan_to_mcp(chan); + std::string db_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).db_name; + return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; } wax::obj _tx_dboard(size_t chan){ - std::string db_name = get_tx_subdev_spec(chan/tx_cpm()).at(chan%tx_cpm()).db_name; - return _mboard(chan/tx_cpm())[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + mboard_chan_pair mcp = tx_chan_to_mcp(chan); + std::string db_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).db_name; + return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; } wax::obj _rx_subdev(size_t chan){ - std::string sd_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).sd_name; + mboard_chan_pair mcp = rx_chan_to_mcp(chan); + std::string sd_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; } wax::obj _tx_subdev(size_t chan){ - std::string sd_name = get_tx_subdev_spec(chan/tx_cpm()).at(chan%tx_cpm()).sd_name; + mboard_chan_pair mcp = tx_chan_to_mcp(chan); + std::string sd_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; } gain_group::sptr _rx_gain_group(size_t chan){ - std::string sd_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).sd_name; + mboard_chan_pair mcp = rx_chan_to_mcp(chan); + std::string sd_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); } gain_group::sptr _tx_gain_group(size_t chan){ - std::string sd_name = get_tx_subdev_spec(chan/tx_cpm()).at(chan%tx_cpm()).sd_name; + mboard_chan_pair mcp = tx_chan_to_mcp(chan); + std::string sd_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name; return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); } }; diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp index eccee7f4b..ced80c187 100644 --- a/host/lib/usrp/tune_helper.cpp +++ b/host/lib/usrp/tune_helper.cpp @@ -30,12 +30,11 @@ using namespace uhd::usrp; **********************************************************************/ static tune_result_t tune_xx_subdev_and_dsp( dboard_iface::unit_t unit, - wax::obj subdev, wax::obj dsp, size_t chan, + wax::obj subdev, wax::obj dsp, const tune_request_t &tune_request ){ wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; - std::string freq_name = dsp[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); - wax::obj dsp_freq_proxy = dsp[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)]; + wax::obj dsp_freq_proxy = dsp[DSP_PROP_FREQ_SHIFT]; //------------------------------------------------------------------ //-- calculate the LO offset, only used with automatic policy @@ -105,13 +104,11 @@ static tune_result_t tune_xx_subdev_and_dsp( } static double derive_freq_from_xx_subdev_and_dsp( - dboard_iface::unit_t unit, - wax::obj subdev, wax::obj dsp, size_t chan + dboard_iface::unit_t unit, wax::obj subdev, wax::obj dsp ){ //extract actual dsp and IF frequencies double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>(); - std::string freq_name = dsp[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); - double actual_dsp_freq = dsp[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>(); + double actual_dsp_freq = dsp[DSP_PROP_FREQ_SHIFT].as<double>(); //invert the sign on the dsp freq given the following conditions if (unit == dboard_iface::UNIT_TX) actual_dsp_freq *= -1.0; @@ -123,30 +120,28 @@ static double derive_freq_from_xx_subdev_and_dsp( * RX Tune **********************************************************************/ tune_result_t usrp::tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, size_t chan, - const tune_request_t &tune_request + wax::obj subdev, wax::obj ddc, const tune_request_t &tune_request ){ - return tune_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, chan, tune_request); + return tune_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, tune_request); } double usrp::derive_freq_from_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, size_t chan + wax::obj subdev, wax::obj ddc ){ - return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, chan); + return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc); } /*********************************************************************** * TX Tune **********************************************************************/ tune_result_t usrp::tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, size_t chan, - const tune_request_t &tune_request + wax::obj subdev, wax::obj duc, const tune_request_t &tune_request ){ - return tune_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, chan, tune_request); + return tune_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, tune_request); } double usrp::derive_freq_from_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, size_t chan + wax::obj subdev, wax::obj duc ){ - return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, chan); + return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc); } diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 370f4831f..8152c4e34 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -34,23 +34,25 @@ using namespace uhd::usrp; **********************************************************************/ void usrp1_impl::rx_dsp_init(void) { - _rx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_dsp_get, this, _1, _2), - boost::bind(&usrp1_impl::rx_dsp_set, this, _1, _2)); - - rx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16); + for (size_t i = 0; i < this->get_num_ddcs(); i++){ + _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_dsp_get, this, _1, _2, i), + boost::bind(&usrp1_impl::rx_dsp_set, this, _1, _2, i) + ); + rx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16, i); + } } /*********************************************************************** * RX DDC Get **********************************************************************/ -void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val){ +void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: - val = str(boost::format("usrp1 ddc %uX %s") - % this->get_num_ddcs() + val = str(boost::format("usrp1 ddc%d %s") + % which_dsp % (this->has_rx_halfband()? "+ hb" : "") ); return; @@ -60,16 +62,7 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val){ return; case DSP_PROP_FREQ_SHIFT: - val = _rx_dsp_freqs[key.name]; - return; - - case DSP_PROP_FREQ_SHIFT_NAMES:{ - prop_names_t names; - for(size_t i = 0; i < this->get_num_ddcs(); i++){ - names.push_back(boost::lexical_cast<std::string>(i)); - } - val = names; - } + val = _rx_dsp_freqs[which_dsp]; return; case DSP_PROP_CODEC_RATE: @@ -88,7 +81,7 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val){ /*********************************************************************** * RX DDC Set **********************************************************************/ -void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ +void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()) { @@ -97,16 +90,17 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update( new_freq, _clock_ctrl->get_master_clock_freq()); - static const uhd::dict<std::string, boost::uint32_t> - freq_name_to_reg_val = boost::assign::map_list_of - ("0", FR_RX_FREQ_0) ("1", FR_RX_FREQ_1) - ("2", FR_RX_FREQ_2) ("3", FR_RX_FREQ_3) - ; - _iface->poke32(freq_name_to_reg_val[key.name], ~reg_word + 1); - _rx_dsp_freqs[key.name] = new_freq; + static const boost::uint32_t dsp_index_to_reg_val[4] = { + FR_RX_FREQ_0, FR_RX_FREQ_1, FR_RX_FREQ_2, FR_RX_FREQ_3 + }; + _iface->poke32(dsp_index_to_reg_val[which_dsp], ~reg_word + 1); + _rx_dsp_freqs[which_dsp] = new_freq; return; } - case DSP_PROP_HOST_RATE: { + + case DSP_PROP_HOST_RATE: + if (which_dsp != 0) return; //only for dsp[0] as this is vectorized + { size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>()); if ((rate & 0x01) || (rate < 4) || (rate > 256)) { @@ -123,6 +117,11 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ } return; + case DSP_PROP_STREAM_CMD: + if (which_dsp != 0) return; //only for dsp[0] as this is vectorized + _soft_time_ctrl->issue_stream_cmd(val.as<stream_cmd_t>()); + return; + default: UHD_THROW_PROP_SET_ERROR(); } @@ -133,24 +132,25 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ **********************************************************************/ void usrp1_impl::tx_dsp_init(void) { - _tx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_dsp_get, this, _1, _2), - boost::bind(&usrp1_impl::tx_dsp_set, this, _1, _2)); - - //initial config and update - tx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() * 2 / 16); + for (size_t i = 0; i < this->get_num_ducs(); i++){ + _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_dsp_get, this, _1, _2, i), + boost::bind(&usrp1_impl::tx_dsp_set, this, _1, _2, i) + ); + tx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16, i); + } } /*********************************************************************** * TX DUC Get **********************************************************************/ -void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val){ +void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()) { case DSP_PROP_NAME: - val = str(boost::format("usrp1 duc %uX %s") - % this->get_num_ducs() + val = str(boost::format("usrp1 duc%d %s") + % which_dsp % (this->has_tx_halfband()? "+ hb" : "") ); return; @@ -160,16 +160,7 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val){ return; case DSP_PROP_FREQ_SHIFT: - val = _tx_dsp_freqs[key.name]; - return; - - case DSP_PROP_FREQ_SHIFT_NAMES:{ - prop_names_t names; - for(size_t i = 0; i < this->get_num_ducs(); i++){ - names.push_back(boost::lexical_cast<std::string>(i)); - } - val = names; - } + val = _tx_dsp_freqs[which_dsp]; return; case DSP_PROP_CODEC_RATE: @@ -188,7 +179,7 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val){ /*********************************************************************** * TX DUC Set **********************************************************************/ -void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){ +void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()) { @@ -197,15 +188,17 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){ double new_freq = val.as<double>(); //map the freq shift key to a subdev spec to a particular codec chip - std::string db_name = _tx_subdev_spec.at(boost::lexical_cast<size_t>(key.name)).db_name; + std::string db_name = _tx_subdev_spec.at(which_dsp).db_name; if (db_name == "A") _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); if (db_name == "B") _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); - _tx_dsp_freqs[key.name] = new_freq; + _tx_dsp_freqs[which_dsp] = new_freq; return; } - case DSP_PROP_HOST_RATE: { + case DSP_PROP_HOST_RATE: + if (which_dsp != 0) return; //only for dsp[0] as this is vectorized + { size_t rate = size_t(_clock_ctrl->get_master_clock_freq() * 2 / val.as<double>()); if ((rate & 0x01) || (rate < 8) || (rate > 512)) { diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 6d5bf466d..26d3e41d4 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -280,21 +280,19 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_dsp_proxy->get_link(); + val = _rx_dsp_proxies.get(key.name)->get_link(); return; case MBOARD_PROP_RX_DSP_NAMES: - val = prop_names_t(1, ""); + val = _rx_dsp_proxies.keys(); return; case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_dsp_proxy->get_link(); + val = _tx_dsp_proxies.get(key.name)->get_link(); return; case MBOARD_PROP_TX_DSP_NAMES: - val = prop_names_t(1, ""); + val = _tx_dsp_proxies.keys(); return; case MBOARD_PROP_CLOCK_CONFIG: @@ -342,10 +340,6 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) //handle the get request conditioned on the key switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_STREAM_CMD: - _soft_time_ctrl->issue_stream_cmd(val.as<stream_cmd_t>()); - return; - case MBOARD_PROP_RX_SUBDEV_SPEC: _rx_subdev_spec = val.as<subdev_spec_t>(); if (_rx_subdev_spec.size() > this->get_num_ddcs()){ diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 1d9f6709f..9755c466d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -182,19 +182,19 @@ private: //rx dsp functions and settings void rx_dsp_init(void); - void rx_dsp_get(const wax::obj &, wax::obj &); - void rx_dsp_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, double> _rx_dsp_freqs; + void rx_dsp_get(const wax::obj &, wax::obj &, size_t); + void rx_dsp_set(const wax::obj &, const wax::obj &, size_t); + uhd::dict<size_t, double> _rx_dsp_freqs; size_t _rx_dsp_decim; - wax_obj_proxy::sptr _rx_dsp_proxy; + uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies; //tx dsp functions and settings void tx_dsp_init(void); - void tx_dsp_get(const wax::obj &, wax::obj &); - void tx_dsp_set(const wax::obj &, const wax::obj &); - uhd::dict<std::string, double> _tx_dsp_freqs; + void tx_dsp_get(const wax::obj &, wax::obj &, size_t); + void tx_dsp_set(const wax::obj &, const wax::obj &, size_t); + uhd::dict<size_t, double> _tx_dsp_freqs; size_t _tx_dsp_interp; - wax_obj_proxy::sptr _tx_dsp_proxy; + uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies; //transports uhd::transport::usb_zero_copy::sptr _data_transport; diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 8340f7cdd..cdd559e94 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -28,12 +28,79 @@ using namespace uhd; using namespace uhd::usrp; -static const size_t default_decim = 16; -static const size_t default_interp = 16; - /*********************************************************************** - * DDC Helper Methods + * DSP impl and methods **********************************************************************/ +struct usrp2_mboard_impl::dsp_impl{ + uhd::dict<size_t, size_t> ddc_decim; + uhd::dict<size_t, double> ddc_freq; + uhd::dict<size_t, size_t> duc_interp; + uhd::dict<size_t, double> duc_freq; + std::vector<size_t> decim_and_interp_rates; + uhd::dict<size_t, bool> continuous_streaming; +}; + +void usrp2_mboard_impl::dsp_init(void){ + //create new dsp impl + _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ()); + + //load the allowed decim/interp rates + //range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) + for (size_t i = 4; i <= 128; i+=1){ + _dsp_impl->decim_and_interp_rates.push_back(i); + } + for (size_t i = 130; i <= 256; i+=2){ + _dsp_impl->decim_and_interp_rates.push_back(i); + } + for (size_t i = 260; i <= 512; i+=4){ + _dsp_impl->decim_and_interp_rates.push_back(i); + } + + //bind and initialize the rx dsps + for (size_t i = 0; i < NUM_RX_DSPS; i++){ + _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( + boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2, i), + boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2, i) + ); + + //initial config and update + ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i); + ddc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i); + + //setup the rx control registers + _iface->poke32(_iface->regs.rx_ctrl[i].clear_overrun, 1); //reset + _iface->poke32(_iface->regs.rx_ctrl[i].nsamps_per_pkt, _device.get_max_recv_samps_per_packet()); + _iface->poke32(_iface->regs.rx_ctrl[i].nchannels, 1); + _iface->poke32(_iface->regs.rx_ctrl[i].vrt_header, 0 + | (0x1 << 28) //if data with stream id + | (0x1 << 26) //has trailer + | (0x3 << 22) //integer time other + | (0x1 << 20) //fractional time sample count + ); + _iface->poke32(_iface->regs.rx_ctrl[i].vrt_stream_id, usrp2_impl::RECV_SID); + _iface->poke32(_iface->regs.rx_ctrl[i].vrt_trailer, 0); + _iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq())); + } + + //bind and initialize the tx dsps + for (size_t i = 0; i < NUM_TX_DSPS; i++){ + _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( + boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2, i), + boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2, i) + ); + + //initial config and update + duc_set(DSP_PROP_FREQ_SHIFT, double(0), i); + duc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i); + + //init the tx control registers + _iface->poke32(_iface->regs.tx_ctrl_clear_state, 1); //reset + _iface->poke32(_iface->regs.tx_ctrl_num_chan, 0); //1 channel + _iface->poke32(_iface->regs.tx_ctrl_report_sid, usrp2_impl::ASYNC_SID); + _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); + } +} + template <typename rate_type> static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_type> &rates){ unsigned closest_match = rates.front(); @@ -44,27 +111,28 @@ static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_typ return closest_match; } -void usrp2_mboard_impl::init_ddc_config(void){ - //create the ddc in the rx dsp dict - _rx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2), - boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2) - ); +void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, size_t which_dsp){ + _dsp_impl->continuous_streaming[which_dsp] = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS; + _iface->poke32(_iface->regs.rx_ctrl[which_dsp].stream_cmd, dsp_type1::calc_stream_cmd_word(stream_cmd)); + _iface->poke32(_iface->regs.rx_ctrl[which_dsp].time_secs, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); + _iface->poke32(_iface->regs.rx_ctrl[which_dsp].time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); +} - //initial config and update - ddc_set(DSP_PROP_FREQ_SHIFT, double(0)); - ddc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/default_decim)); +void usrp2_mboard_impl::handle_overflow(size_t which_dsp){ + if (_dsp_impl->continuous_streaming[which_dsp]){ //re-issue the stream command if already continuous + this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS, which_dsp); + } } /*********************************************************************** * DDC Properties **********************************************************************/ -void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: - val = _iface->get_cname() + " ddc0"; + val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp); return; case DSP_PROP_OTHERS: @@ -72,11 +140,7 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val){ return; case DSP_PROP_FREQ_SHIFT: - val = _ddc_freq; - return; - - case DSP_PROP_FREQ_SHIFT_NAMES: - val = prop_names_t(1, ""); + val = _dsp_impl->ddc_freq[which_dsp]; return; case DSP_PROP_CODEC_RATE: @@ -84,37 +148,41 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val){ return; case DSP_PROP_HOST_RATE: - val = get_master_clock_freq()/_ddc_decim; + val = get_master_clock_freq()/_dsp_impl->ddc_decim[which_dsp]; return; default: UHD_THROW_PROP_GET_ERROR(); } } -void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){ +void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()){ + case DSP_PROP_STREAM_CMD: + issue_ddc_stream_cmd(val.as<stream_cmd_t>(), which_dsp); + return; + case DSP_PROP_FREQ_SHIFT:{ double new_freq = val.as<double>(); - _iface->poke32(_iface->regs.dsp_rx_freq, + _iface->poke32(_iface->regs.dsp_rx[which_dsp].freq, dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq()) ); - _ddc_freq = new_freq; //shadow + _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow } return; case DSP_PROP_HOST_RATE:{ double extact_rate = get_master_clock_freq()/val.as<double>(); - _ddc_decim = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates); + _dsp_impl->ddc_decim[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates); //set the decimation - _iface->poke32(_iface->regs.dsp_rx_decim_rate, dsp_type1::calc_cic_filter_word(_ddc_decim)); + _iface->poke32(_iface->regs.dsp_rx[which_dsp].decim_rate, dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp])); //set the scaling static const boost::int16_t default_rx_scale_iq = 1024; - _iface->poke32(_iface->regs.dsp_rx_scale_iq, + _iface->poke32(_iface->regs.dsp_rx[which_dsp].scale_iq, dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) ); } @@ -125,29 +193,14 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){ } /*********************************************************************** - * DUC Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::init_duc_config(void){ - //create the duc in the tx dsp dict - _tx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2), - boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2) - ); - - //initial config and update - duc_set(DSP_PROP_FREQ_SHIFT, double(0)); - duc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/default_interp)); -} - -/*********************************************************************** * DUC Properties **********************************************************************/ -void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: - val = _iface->get_cname() + " duc0"; + val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp); return; case DSP_PROP_OTHERS: @@ -155,11 +208,7 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val){ return; case DSP_PROP_FREQ_SHIFT: - val = _duc_freq; - return; - - case DSP_PROP_FREQ_SHIFT_NAMES: - val = prop_names_t(1, ""); + val = _dsp_impl->duc_freq[which_dsp]; return; case DSP_PROP_CODEC_RATE: @@ -167,14 +216,14 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val){ return; case DSP_PROP_HOST_RATE: - val = get_master_clock_freq()/_duc_interp; + val = get_master_clock_freq()/_dsp_impl->duc_interp[which_dsp]; return; default: UHD_THROW_PROP_GET_ERROR(); } } -void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val){ +void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ named_prop_t key = named_prop_t::extract(key_); switch(key.as<dsp_prop_t>()){ @@ -196,19 +245,19 @@ void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val){ _iface->poke32(_iface->regs.dsp_tx_freq, dsp_type1::calc_cordic_word_and_update(new_freq, codec_rate) ); - _duc_freq = new_freq + dac_shift; //shadow + _dsp_impl->duc_freq[which_dsp] = new_freq + dac_shift; //shadow } return; case DSP_PROP_HOST_RATE:{ double extact_rate = get_master_clock_freq()/val.as<double>(); - _duc_interp = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates); + _dsp_impl->duc_interp[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates); //set the interpolation - _iface->poke32(_iface->regs.dsp_tx_interp_rate, dsp_type1::calc_cic_filter_word(_duc_interp)); + _iface->poke32(_iface->regs.dsp_tx_interp_rate, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp])); //set the scaling - _iface->poke32(_iface->regs.dsp_tx_scale_iq, dsp_type1::calc_iq_scale_word(_duc_interp)); + _iface->poke32(_iface->regs.dsp_tx_scale_iq, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp])); } return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index a22f805e1..6eb047454 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -30,8 +30,8 @@ extern "C" { #endif //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 4 -#define USRP2_FW_COMPAT_NUM 8 +#define USRP2_FPGA_COMPAT_NUM 5 +#define USRP2_FW_COMPAT_NUM 9 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 @@ -40,8 +40,9 @@ extern "C" { // Dynamic and/or private ports: 49152-65535 #define USRP2_UDP_CTRL_PORT 49152 //#define USRP2_UDP_UPDATE_PORT 49154 -#define USRP2_UDP_DATA_PORT 49156 +#define USRP2_UDP_DSP0_PORT 49156 #define USRP2_UDP_ERR0_PORT 49157 +#define USRP2_UDP_DSP1_PORT 49158 //////////////////////////////////////////////////////////////////////// // I2C addresses diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b20b6652e..b4f3e0873 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -18,6 +18,7 @@ #include "../../transport/vrt_packet_handler.hpp" #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" +#include <uhd/usrp/mboard_props.hpp> #include <uhd/utils/byteswap.hpp> #include <uhd/utils/thread_priority.hpp> #include <uhd/transport/bounded_buffer.hpp> @@ -119,27 +120,26 @@ private: **********************************************************************/ struct usrp2_impl::io_impl{ - io_impl(size_t send_frame_size, const std::vector<zero_copy_if::sptr> &xports): - xports(xports), + io_impl(std::vector<zero_copy_if::sptr> &dsp_xports): + dsp_xports(dsp_xports), //the assumption is that all data transports should be identical get_recv_buffs_fcn(boost::bind(&usrp2_impl::io_impl::get_recv_buffs, this, _1)), get_send_buffs_fcn(boost::bind(&usrp2_impl::io_impl::get_send_buffs, this, _1)), - packet_handler_recv_state(xports.size()), - packet_handler_send_state(xports.size()), async_msg_fifo(100/*messages deep*/) { - for (size_t i = 0; i < xports.size(); i++){ - fc_mons.push_back(flow_control_monitor::sptr( - new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size) - )); - //init empty packet infos - vrt::if_packet_info_t packet_info; - packet_info.packet_count = 0xf; - packet_info.has_tsi = true; - packet_info.tsi = 0; - packet_info.has_tsf = true; - packet_info.tsf = 0; - prev_infos.push_back(packet_info); + for (size_t i = 0; i < dsp_xports.size(); i++){ + fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor( + usrp2_impl::sram_bytes/dsp_xports.front()->get_send_frame_size() + )));; } + + //init empty packet infos + vrt::if_packet_info_t packet_info = vrt::if_packet_info_t(); + packet_info.packet_count = 0xf; + packet_info.has_tsi = true; + packet_info.tsi = 0; + packet_info.has_tsf = true; + packet_info.tsf = 0; + prev_infos.resize(dsp_xports.size(), packet_info); } ~io_impl(void){ @@ -149,15 +149,15 @@ struct usrp2_impl::io_impl{ } bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs){ - UHD_ASSERT_THROW(xports.size() == buffs.size()); + UHD_ASSERT_THROW(send_map.size() == buffs.size()); //calculate the flow control word const boost::uint32_t fc_word32 = packet_handler_send_state.next_packet_seq; //grab a managed buffer for each index for (size_t i = 0; i < buffs.size(); i++){ - if (not fc_mons[i]->check_fc_condition(fc_word32, send_timeout)) return false; - buffs[i] = xports[i]->get_send_buff(send_timeout); + if (not fc_mons[send_map[i]]->check_fc_condition(fc_word32, send_timeout)) return false; + buffs[i] = dsp_xports[send_map[i]]->get_send_buff(send_timeout); if (not buffs[i].get()) return false; buffs[i]->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_word32); } @@ -166,7 +166,10 @@ struct usrp2_impl::io_impl{ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs); - const std::vector<zero_copy_if::sptr> &xports; + std::vector<zero_copy_if::sptr> &dsp_xports; + + //mappings from channel index to dsp xport + std::vector<size_t> send_map, recv_map; //timeouts set on calls to recv/send (passed into get buffs methods) double recv_timeout, send_timeout; @@ -186,7 +189,7 @@ struct usrp2_impl::io_impl{ vrt_packet_handler::send_state packet_handler_send_state; //methods and variables for the pirate crew - void recv_pirate_loop(zero_copy_if::sptr, usrp2_mboard_impl::sptr, size_t); + void recv_pirate_loop(usrp2_mboard_impl::sptr, zero_copy_if::sptr, size_t); boost::thread_group recv_pirate_crew; bool recv_pirate_crew_raiding; bounded_buffer<async_metadata_t> async_msg_fifo; @@ -200,17 +203,18 @@ struct usrp2_impl::io_impl{ * - put async message packets into queue **********************************************************************/ void usrp2_impl::io_impl::recv_pirate_loop( - zero_copy_if::sptr zc_if_err0, - usrp2_mboard_impl::sptr mboard, - size_t index + usrp2_mboard_impl::sptr mboard, zero_copy_if::sptr err_xport, size_t index ){ set_thread_priority_safe(); recv_pirate_crew_raiding = true; spawn_mutex.unlock(); + //store a reference to the flow control monitor (offset by max dsps) + flow_control_monitor &fc_mon = *(this->fc_mons[index*usrp2_mboard_impl::MAX_NUM_DSPS]); + while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = zc_if_err0->get_recv_buff(); + managed_recv_buffer::sptr buff = err_xport->get_recv_buff(); if (not buff.get()) continue; //ignore timeout/error buffers try{ @@ -235,7 +239,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( //catch the flow control packets and react if (metadata.event_code == 0){ boost::uint32_t fc_word32 = (vrt_hdr + if_packet_info.num_header_words32)[1]; - this->fc_mons[index]->update_fc_condition(uhd::ntohx(fc_word32)); + fc_mon.update_fc_condition(uhd::ntohx(fc_word32)); continue; } @@ -258,27 +262,52 @@ void usrp2_impl::io_impl::recv_pirate_loop( **********************************************************************/ void usrp2_impl::io_init(void){ - //the assumption is that all data transports should be identical - const size_t send_frame_size = _data_transports.front()->get_send_frame_size(); - //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (send_frame_size, _data_transports)); + _io_impl = UHD_PIMPL_MAKE(io_impl, (dsp_xports)); //create a new pirate thread for each zc if (yarr!!) - for (size_t i = 0; i < _data_transports.size(); i++){ + for (size_t i = 0; i < _mboards.size(); i++){ //lock the unlocked mutex (non-blocking) _io_impl->spawn_mutex.lock(); //spawn a new pirate to plunder the recv booty _io_impl->recv_pirate_crew.create_thread(boost::bind( &usrp2_impl::io_impl::recv_pirate_loop, - _io_impl.get(), _err0_transports.at(i), - _mboards.at(i), i + _io_impl.get(), _mboards.at(i), err_xports.at(i), i )); //block here until the spawned thread unlocks _io_impl->spawn_mutex.lock(); //exit loop iteration in an unlocked condition _io_impl->spawn_mutex.unlock(); } + + //update mapping here since it didnt b4 when io init not called first + update_xport_channel_mapping(); +} + +void usrp2_impl::update_xport_channel_mapping(void){ + if (_io_impl.get() == NULL) return; //not inited yet + + _io_impl->recv_map.clear(); + _io_impl->send_map.clear(); + + for (size_t i = 0; i < _mboards.size(); i++){ + + subdev_spec_t rx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); + for (size_t j = 0; j < rx_subdev_spec.size(); j++){ + _io_impl->recv_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j); + //std::cout << "recv_map.back() " << _io_impl->recv_map.back() << std::endl; + } + + subdev_spec_t tx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); + for (size_t j = 0; j < tx_subdev_spec.size(); j++){ + _io_impl->send_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j); + //std::cout << "send_map.back() " << _io_impl->send_map.back() << std::endl; + } + + } + + _io_impl->packet_handler_recv_state = vrt_packet_handler::recv_state(_io_impl->recv_map.size()); + _io_impl->packet_handler_send_state = vrt_packet_handler::send_state(_io_impl->send_map.size()); } /*********************************************************************** @@ -300,7 +329,7 @@ size_t usrp2_impl::get_max_send_samps_per_packet(void) const{ + vrt_send_header_offset_words32*sizeof(boost::uint32_t) - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; - const size_t bpp = _data_transports.front()->get_send_frame_size() - hdr_size; + const size_t bpp = dsp_xports.front()->get_send_frame_size() - hdr_size; return bpp/_tx_otw_type.get_sample_size(); } @@ -383,14 +412,15 @@ UHD_INLINE bool usrp2_impl::io_impl::get_recv_buffs( vrt_packet_handler::managed_recv_buffs_t &buffs ){ if (buffs.size() == 1){ - buffs[0] = xports[0]->get_recv_buff(recv_timeout); + buffs[0] = dsp_xports[recv_map[0]]->get_recv_buff(recv_timeout); if (buffs[0].get() == NULL) return false; bool clear, msg; time_spec_t time; //unused variables //call extract_packet_info to handle printing the overflows - extract_packet_info(buffs[0], this->prev_infos[0], time, clear, msg); + extract_packet_info(buffs[0], this->prev_infos[recv_map[0]], time, clear, msg); return true; } //-------------------- begin alignment logic ---------------------// + UHD_ASSERT_THROW(recv_map.size() == buffs.size()); boost::system_time exit_time = boost::get_system_time() + to_time_dur(recv_timeout); managed_recv_buffer::sptr buff_tmp; alignment_indexes indexes_to_do; @@ -404,9 +434,9 @@ UHD_INLINE bool usrp2_impl::io_impl::get_recv_buffs( //do an initial pop to load an initial sequence id size_t index = indexes_to_do.front(); - buff_tmp = xports[index]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time())); + buff_tmp = dsp_xports[recv_map[index]]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time())); if (buff_tmp.get() == NULL) return false; - extract_packet_info(buff_tmp, this->prev_infos[index], expected_time, clear, msg); + extract_packet_info(buff_tmp, this->prev_infos[recv_map[index]], expected_time, clear, msg); if (clear) goto got_clear; buffs[index] = buff_tmp; if (msg) return handle_msg_packet(buffs, index); @@ -417,10 +447,10 @@ UHD_INLINE bool usrp2_impl::io_impl::get_recv_buffs( //pop an element off for this index index = indexes_to_do.front(); - buff_tmp = xports[index]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time())); + buff_tmp = dsp_xports[recv_map[index]]->get_recv_buff(from_time_dur(exit_time - boost::get_system_time())); if (buff_tmp.get() == NULL) return false; time_spec_t this_time; - extract_packet_info(buff_tmp, this->prev_infos[index], this_time, clear, msg); + extract_packet_info(buff_tmp, this->prev_infos[recv_map[index]], this_time, clear, msg); if (clear) goto got_clear; buffs[index] = buff_tmp; if (msg) return handle_msg_packet(buffs, index); @@ -458,13 +488,14 @@ size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - sizeof(vrt::if_packet_info_t().cid) //no class id ever used ; - const size_t bpp = _data_transports.front()->get_recv_frame_size() - hdr_size; + const size_t bpp = dsp_xports.front()->get_recv_frame_size() - hdr_size; return bpp/_rx_otw_type.get_sample_size(); } -static void handle_overflow(std::vector<usrp2_mboard_impl::sptr> &mboards, size_t chan){ +void usrp2_impl::handle_overflow(size_t chan){ std::cerr << "O" << std::flush; - mboards.at(chan/mboards.size())->handle_overflow(); + ldiv_t indexes = ldiv(chan, usrp2_mboard_impl::NUM_RX_DSPS); + _mboards.at(indexes.quot)->handle_overflow(indexes.rem); } size_t usrp2_impl::recv( @@ -481,6 +512,6 @@ size_t usrp2_impl::recv( _mboards.front()->get_master_clock_freq(), //master clock tick rate uhd::transport::vrt::if_hdr_unpack_be, _io_impl->get_recv_buffs_fcn, - boost::bind(&handle_overflow, boost::ref(_mboards), _1) + boost::bind(&usrp2_impl::handle_overflow, this, _1) ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 397fae636..34a2b7c69 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -21,8 +21,8 @@ #include <uhd/usrp/misc_utils.hpp> #include <uhd/usrp/dsp_utils.hpp> #include <uhd/usrp/mboard_props.hpp> -#include <uhd/utils/assert.hpp> #include <uhd/utils/byteswap.hpp> +#include <uhd/utils/assert.hpp> #include <uhd/utils/algorithm.hpp> #include <boost/bind.hpp> #include <iostream> @@ -33,35 +33,55 @@ static const size_t mimo_clock_sync_delay_cycles = 137; using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; /*********************************************************************** - * Structors + * Helpers **********************************************************************/ -usrp2_mboard_impl::usrp2_mboard_impl( - size_t index, - transport::udp_simple::sptr ctrl_transport, - transport::zero_copy_if::sptr data_transport, - transport::zero_copy_if::sptr err0_transport, - const device_addr_t &device_args, - size_t recv_samps_per_packet -): - _index(index), - _iface(usrp2_iface::make(ctrl_transport)) -{ +static void init_xport(zero_copy_if::sptr xport){ //Send a small data packet so the usrp2 knows the udp source port. //This setup must happen before further initialization occurs //or the async update packets will cause ICMP destination unreachable. - transport::managed_send_buffer::sptr send_buff; static const boost::uint32_t data[2] = { uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) }; - send_buff = data_transport->get_send_buff(); - std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); - send_buff = err0_transport->get_send_buff(); + + transport::managed_send_buffer::sptr send_buff = xport->get_send_buff(); std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); send_buff->commit(sizeof(data)); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +usrp2_mboard_impl::usrp2_mboard_impl( + const device_addr_t &device_addr, + size_t index, usrp2_impl &device +): + _index(index), _device(device), + _iface(usrp2_iface::make(udp_simple::make_connected( + device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT) + ))) +{ + //construct transports for dsp and async errors + std::cout << "Making transport for DSP0..." << std::endl; + device.dsp_xports.push_back(udp_zero_copy::make( + device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_DSP0_PORT), device_addr + )); + init_xport(device.dsp_xports.back()); + + std::cout << "Making transport for DSP1..." << std::endl; + device.dsp_xports.push_back(udp_zero_copy::make( + device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_DSP1_PORT), device_addr + )); + init_xport(device.dsp_xports.back()); + + std::cout << "Making transport for ERR0..." << std::endl; + device.err_xports.push_back(udp_zero_copy::make( + device_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_ERR0_PORT), device_addr_t() + )); + init_xport(device.err_xports.back()); //contruct the interfaces to mboard perifs _clock_ctrl = usrp2_clock_ctrl::make(_iface); @@ -72,66 +92,30 @@ usrp2_mboard_impl::usrp2_mboard_impl( //if(_gps_ctrl->gps_detected()) std::cout << "GPS time: " << _gps_ctrl->get_time() << std::endl; - //TODO move to dsp impl... - //load the allowed decim/interp rates - //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) - _allowed_decim_and_interp_rates.clear(); - for (size_t i = 4; i <= 128; i+=1){ - _allowed_decim_and_interp_rates.push_back(i); - } - for (size_t i = 130; i <= 256; i+=2){ - _allowed_decim_and_interp_rates.push_back(i); - } - for (size_t i = 260; i <= 512; i+=4){ - _allowed_decim_and_interp_rates.push_back(i); - } - - //setup the vrt rx registers - _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset - _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, recv_samps_per_packet); - _iface->poke32(_iface->regs.rx_ctrl_nchannels, 1); - _iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(_iface->regs.rx_ctrl_vrt_stream_id, usrp2_impl::RECV_SID); - _iface->poke32(_iface->regs.rx_ctrl_vrt_trailer, 0); - _iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq())); - - //init the tx control registers - _iface->poke32(_iface->regs.tx_ctrl_clear_state, 1); //reset - _iface->poke32(_iface->regs.tx_ctrl_num_chan, 0); //1 channel - _iface->poke32(_iface->regs.tx_ctrl_report_sid, usrp2_impl::ASYNC_SID); - _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); + //init the dsp stuff (before setting update packets) + dsp_init(); //setting the cycles per update (disabled by default) - const double ups_per_sec = device_args.cast<double>("ups_per_sec", 0.0); + const double ups_per_sec = device_addr.cast<double>("ups_per_sec", 0.0); if (ups_per_sec > 0.0){ const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec); _iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up); } //setting the packets per update (enabled by default) - const double ups_per_fifo = device_args.cast<double>("ups_per_fifo", 8.0); + size_t send_frame_size = device.dsp_xports[0]->get_send_frame_size(); + const double ups_per_fifo = device_addr.cast<double>("ups_per_fifo", 8.0); if (ups_per_fifo > 0.0){ - const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/data_transport->get_send_frame_size()); + const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/send_frame_size); _iface->poke32(_iface->regs.tx_ctrl_packets_per_up, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up); } - //init the ddc - init_ddc_config(); - - //init the duc - init_duc_config(); - //initialize the clock configuration - if (device_args.has_key("mimo_mode")){ - if (device_args["mimo_mode"] == "master"){ + if (device_addr.has_key("mimo_mode")){ + if (device_addr["mimo_mode"] == "master"){ _mimo_clocking_mode_is_master = true; } - else if (device_args["mimo_mode"] == "slave"){ + else if (device_addr["mimo_mode"] == "slave"){ _mimo_clocking_mode_is_master = false; } else throw std::runtime_error( @@ -158,13 +142,18 @@ usrp2_mboard_impl::usrp2_mboard_impl( (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t(); (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t(); + //------------------------------------------------------------------ //This is a hack/fix for the lingering packet problem. stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); - stream_cmd.num_samps = 1; - this->issue_ddc_stream_cmd(stream_cmd); - data_transport->get_recv_buff().get(); //recv with timeout for lingering - data_transport->get_recv_buff().get(); //recv with timeout for expected - _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //resets sequence + for (size_t i = 0; i < NUM_RX_DSPS; i++){ + size_t index = device.dsp_xports.size() - NUM_RX_DSPS + i; + stream_cmd.num_samps = 1; + this->issue_ddc_stream_cmd(stream_cmd, i); + device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for lingering + device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for expected + _iface->poke32(_iface->regs.rx_ctrl[i].clear_overrun, 1); //resets sequence + } + //------------------------------------------------------------------ } usrp2_mboard_impl::~usrp2_mboard_impl(void){ @@ -265,19 +254,6 @@ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ _iface->poke32(_iface->regs.time64_secs, boost::uint32_t(time_spec.get_full_secs())); } -void usrp2_mboard_impl::handle_overflow(void){ - if (_continuous_streaming){ //re-issue the stream command if already continuous - this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - } -} - -void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ - _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS; - _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word(stream_cmd)); - _iface->poke32(_iface->regs.rx_ctrl_time_secs, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(_iface->regs.rx_ctrl_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); -} - /*********************************************************************** * MBoard Get Properties **********************************************************************/ @@ -314,21 +290,19 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_dsp_proxy->get_link(); + val = _rx_dsp_proxies[key.name]->get_link(); return; case MBOARD_PROP_RX_DSP_NAMES: - val = prop_names_t(1, ""); + val = _rx_dsp_proxies.keys(); return; case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_dsp_proxy->get_link(); + val = _tx_dsp_proxies[key.name]->get_link(); return; case MBOARD_PROP_TX_DSP_NAMES: - val = prop_names_t(1, ""); + val = _tx_dsp_proxies.keys(); return; case MBOARD_PROP_CLOCK_CONFIG: @@ -391,30 +365,32 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ set_time_spec(val.as<time_spec_t>(), false); return; - case MBOARD_PROP_STREAM_CMD: - issue_ddc_stream_cmd(val.as<stream_cmd_t>()); - return; - case MBOARD_PROP_RX_SUBDEV_SPEC: _rx_subdev_spec = val.as<subdev_spec_t>(); verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); //sanity check - UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1); + UHD_ASSERT_THROW(_rx_subdev_spec.size() <= NUM_RX_DSPS); //set the mux - _iface->poke32(_iface->regs.dsp_rx_mux, dsp_type1::calc_rx_mux_word( - _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); + for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ + if (_rx_subdev_spec.size() >= 1) _iface->poke32(_iface->regs.dsp_rx[i].mux, dsp_type1::calc_rx_mux_word( + _dboard_manager->get_rx_subdev(_rx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() + )); + } + _device.update_xport_channel_mapping(); return; case MBOARD_PROP_TX_SUBDEV_SPEC: _tx_subdev_spec = val.as<subdev_spec_t>(); verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); //sanity check - UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1); + UHD_ASSERT_THROW(_tx_subdev_spec.size() <= NUM_TX_DSPS); //set the mux - _iface->poke32(_iface->regs.dsp_tx_mux, dsp_type1::calc_tx_mux_word( - _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() - )); + for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ + _iface->poke32(_iface->regs.dsp_tx_mux, dsp_type1::calc_tx_mux_word( + _dboard_manager->get_tx_subdev(_tx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() + )); + } + _device.update_xport_channel_mapping(); return; case MBOARD_PROP_EEPROM_MAP: diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 9ce0f7359..95031d211 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -22,14 +22,13 @@ #include <uhd/utils/assert.hpp> #include <uhd/utils/static.hpp> #include <uhd/utils/warning.hpp> -#include <boost/algorithm/string.hpp> //for split +#include <uhd/utils/byteswap.hpp> #include <boost/assign/list_of.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <boost/lexical_cast.hpp> -#include <boost/regex.hpp> #include <boost/bind.hpp> -#include <boost/asio.hpp> //htonl and ntohl +#include <boost/asio/ip/address_v4.hpp> #include <iostream> #include <vector> @@ -39,66 +38,11 @@ using namespace uhd::transport; namespace asio = boost::asio; /*********************************************************************** - * Helper Functions - **********************************************************************/ -template <class T> std::string num2str(T num){ - return boost::lexical_cast<std::string>(num); -} - -//! separate indexed device addresses into a vector of device addresses -device_addrs_t sep_indexed_dev_addrs(const device_addr_t &dev_addr){ - //------------ support old deprecated way and print warning -------- - if (dev_addr.has_key("addr") and not dev_addr["addr"].empty()){ - std::vector<std::string> addrs; boost::split(addrs, dev_addr["addr"], boost::is_any_of(" ")); - if (addrs.size() > 1){ - device_addr_t fixed_dev_addr = dev_addr; - fixed_dev_addr.pop("addr"); - for (size_t i = 0; i < addrs.size(); i++){ - fixed_dev_addr[str(boost::format("addr%d") % i)] = addrs[i]; - } - uhd::warning::post( - "addr = <space separated list of ip addresses> is deprecated.\n" - "To address a multi-device, use multiple <key><index> = <val>.\n" - "See the USRP-NXXX application notes. Two device example:\n" - " addr0 = 192.168.10.2\n" - " addr1 = 192.168.10.3\n" - ); - return sep_indexed_dev_addrs(fixed_dev_addr); - } - } - //------------------------------------------------------------------ - device_addrs_t dev_addrs; - BOOST_FOREACH(const std::string &key, dev_addr.keys()){ - boost::cmatch matches; - if (not boost::regex_match(key.c_str(), matches, boost::regex("^(\\D+)(\\d*)$"))){ - throw std::runtime_error("unknown key format: " + key); - } - std::string key_part(matches[1].first, matches[1].second); - std::string num_part(matches[2].first, matches[2].second); - size_t num = (num_part.empty())? 0 : boost::lexical_cast<size_t>(num_part); - dev_addrs.resize(std::max(num+1, dev_addrs.size())); - dev_addrs[num][key_part] = dev_addr[key]; - } - return dev_addrs; -} - -//! combine a vector in device addresses into an indexed device address -device_addr_t combine_dev_addr_vector(const device_addrs_t &dev_addrs){ - device_addr_t dev_addr; - for (size_t i = 0; i < dev_addrs.size(); i++){ - BOOST_FOREACH(const std::string &key, dev_addrs[i].keys()){ - dev_addr[str(boost::format("%s%d") % key % i)] = dev_addrs[i][key]; - } - } - return dev_addr; -} - -/*********************************************************************** * Discovery over the udp transport **********************************************************************/ static device_addrs_t usrp2_find(const device_addr_t &hint_){ //handle the multi-device discovery - device_addrs_t hints = sep_indexed_dev_addrs(hint_); + device_addrs_t hints = separate_device_addr(hint_); if (hints.size() > 1){ device_addrs_t found_devices; BOOST_FOREACH(const device_addr_t &hint_i, hints){ @@ -108,7 +52,7 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){ ) % hint_i.to_string())); found_devices.push_back(found_devices_i[0]); } - return device_addrs_t(1, combine_dev_addr_vector(found_devices)); + return device_addrs_t(1, combine_device_addrs(found_devices)); } //initialize the hint for a single device case @@ -147,8 +91,8 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){ //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; - ctrl_data_out.proto_ver = htonl(USRP2_FW_COMPAT_NUM); - ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO); + ctrl_data_out.proto_ver = uhd::htonx<boost::uint32_t>(USRP2_FW_COMPAT_NUM); + ctrl_data_out.id = uhd::htonx<boost::uint32_t>(USRP2_CTRL_ID_WAZZUP_BRO); udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); //loop and recieve until the timeout @@ -157,9 +101,9 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){ while(true){ size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem)); //std::cout << len << "\n"; - if (len > offsetof(usrp2_ctrl_data_t, data) and ntohl(ctrl_data_in->id) == USRP2_CTRL_ID_WAZZUP_DUDE){ + if (len > offsetof(usrp2_ctrl_data_t, data) and uhd::ntohx(ctrl_data_in->id) == USRP2_CTRL_ID_WAZZUP_DUDE){ //make a boost asio ipv4 with the raw addr in host byte order - boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr)); + boost::asio::ip::address_v4 ip_addr(uhd::ntohx(ctrl_data_in->data.ip_addr)); device_addr_t new_addr; new_addr["type"] = "usrp2"; new_addr["addr"] = ip_addr.to_string(); @@ -167,9 +111,9 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){ //This operation can throw due to compatibility mismatch. //In this case, the discovered device will be ignored. try{ - mboard_eeprom_t mb_eeprom = usrp2_iface::make( - udp_simple::make_connected(new_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)) - )->mb_eeprom; + mboard_eeprom_t mb_eeprom = usrp2_iface::make(udp_simple::make_connected( + new_addr["addr"], boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT) + ))->mb_eeprom; new_addr["name"] = mb_eeprom["name"]; new_addr["serial"] = mb_eeprom["serial"]; if ( @@ -197,40 +141,21 @@ static device_addrs_t usrp2_find(const device_addr_t &hint_){ /*********************************************************************** * Make **********************************************************************/ -static device::sptr usrp2_make(const device_addr_t &device_addr){ +static device::sptr usrp2_make(const device_addr_t &_device_addr){ + device_addr_t device_addr = _device_addr; //setup the dsp transport hints (default to a large recv buff) - device_addr_t dsp_xport_hints = device_addr; - if (not dsp_xport_hints.has_key("recv_buff_size")){ - //only enable on platforms that are happy with the large buffer resize - #if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32) + if (not device_addr.has_key("recv_buff_size")){ + #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + //limit buffer resize on macos or it will error + device_addr["recv_buff_size"] = "1e6"; + #elif defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32) //set to half-a-second of buffering at max rate - dsp_xport_hints["recv_buff_size"] = "50e6"; - #endif /*defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)*/ - } - - //create a ctrl and data transport for each address - std::vector<udp_simple::sptr> ctrl_transports; - std::vector<zero_copy_if::sptr> data_transports; - std::vector<zero_copy_if::sptr> err0_transports; - const device_addrs_t device_addrs = sep_indexed_dev_addrs(device_addr); - - BOOST_FOREACH(const device_addr_t &dev_addr_i, device_addrs){ - ctrl_transports.push_back(udp_simple::make_connected( - dev_addr_i["addr"], num2str(USRP2_UDP_CTRL_PORT) - )); - data_transports.push_back(udp_zero_copy::make( - dev_addr_i["addr"], num2str(USRP2_UDP_DATA_PORT), dsp_xport_hints - )); - err0_transports.push_back(udp_zero_copy::make( - dev_addr_i["addr"], num2str(USRP2_UDP_ERR0_PORT), device_addr_t() - )); + device_addr["recv_buff_size"] = "50e6"; + #endif } - //create the usrp2 implementation guts - return device::sptr(new usrp2_impl( - ctrl_transports, data_transports, err0_transports, device_addrs - )); + return device::sptr(new usrp2_impl(device_addr)); } UHD_STATIC_BLOCK(register_usrp2_device){ @@ -240,15 +165,9 @@ UHD_STATIC_BLOCK(register_usrp2_device){ /*********************************************************************** * Structors **********************************************************************/ -usrp2_impl::usrp2_impl( - std::vector<udp_simple::sptr> ctrl_transports, - std::vector<zero_copy_if::sptr> data_transports, - std::vector<zero_copy_if::sptr> err0_transports, - const device_addrs_t &device_args -): - _data_transports(data_transports), - _err0_transports(err0_transports) -{ +usrp2_impl::usrp2_impl(const device_addr_t &device_addr){ + device_addrs_t device_args = separate_device_addr(device_addr); + //setup rx otw type _rx_otw_type.width = 16; _rx_otw_type.shift = 0; @@ -263,13 +182,16 @@ usrp2_impl::usrp2_impl( //create a new mboard handler for each control transport for(size_t i = 0; i < device_args.size(); i++){ - _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl( - i, ctrl_transports[i], data_transports[i], - err0_transports[i], device_args[i], - this->get_max_recv_samps_per_packet() - ))); + device_addr_t dev_addr_i = device_args[i]; + BOOST_FOREACH(const std::string &key, device_addr.keys()){ + if (dev_addr_i.has_key(key)) continue; + dev_addr_i[key] = device_addr[key]; + } + _mboards.push_back(usrp2_mboard_impl::sptr( + new usrp2_mboard_impl(dev_addr_i, i, *this) + )); //use an empty name when there is only one mboard - std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : ""; + std::string name = (device_args.size() > 1)? boost::lexical_cast<std::string>(i) : ""; _mboard_dict[name] = _mboards.back(); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 337f842d6..0676cecf2 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -71,6 +71,8 @@ private: void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} }; +class usrp2_impl; + /*! * USRP2 mboard implementation guts: * The implementation details are encapsulated here. @@ -80,14 +82,14 @@ class usrp2_mboard_impl : public wax::obj{ public: typedef boost::shared_ptr<usrp2_mboard_impl> sptr; + static const size_t NUM_RX_DSPS = 2; + static const size_t NUM_TX_DSPS = 1; + static const size_t MAX_NUM_DSPS = 2; + //structors usrp2_mboard_impl( - size_t index, - uhd::transport::udp_simple::sptr, - uhd::transport::zero_copy_if::sptr, - uhd::transport::zero_copy_if::sptr, - const uhd::device_addr_t &device_args, - size_t recv_samps_per_packet + const uhd::device_addr_t &device_addr, + size_t index, usrp2_impl &device ); ~usrp2_mboard_impl(void); @@ -95,11 +97,11 @@ public: return _clock_ctrl->get_master_clock_rate(); } - void handle_overflow(void); + void handle_overflow(size_t); private: size_t _index; - bool _continuous_streaming; + usrp2_impl &_device; bool _mimo_clocking_mode_is_master; //interfaces @@ -147,27 +149,20 @@ private: wax_obj_proxy::sptr _tx_dboard_proxy; uhd::usrp::dboard_eeprom_t _tx_db_eeprom; - //methods and shadows for the ddc dsp - std::vector<size_t> _allowed_decim_and_interp_rates; - size_t _ddc_decim; - double _ddc_freq; - void init_ddc_config(void); - void issue_ddc_stream_cmd(const uhd::stream_cmd_t &stream_cmd); - - //methods and shadows for the duc dsp - size_t _duc_interp; - double _duc_freq; - void init_duc_config(void); + //methods and shadows for the dsps + UHD_PIMPL_DECL(dsp_impl) _dsp_impl; + void dsp_init(void); + void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t); //properties interface for ddc - void ddc_get(const wax::obj &, wax::obj &); - void ddc_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_dsp_proxy; + void ddc_get(const wax::obj &, wax::obj &, size_t); + void ddc_set(const wax::obj &, const wax::obj &, size_t); + uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies; //properties interface for duc - void duc_get(const wax::obj &, wax::obj &); - void duc_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _tx_dsp_proxy; + void duc_get(const wax::obj &, wax::obj &, size_t); + void duc_set(const wax::obj &, const wax::obj &, size_t); + uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies; }; @@ -182,19 +177,7 @@ public: static const boost::uint32_t RECV_SID = 1; static const boost::uint32_t ASYNC_SID = 2; - /*! - * Create a new usrp2 impl base. - * \param ctrl_transports the udp transports for control - * \param data_transports the udp transports for data - * \param err0_transports the udp transports for error - * \param device_args optional misc device parameters - */ - usrp2_impl( - std::vector<uhd::transport::udp_simple::sptr> ctrl_transports, - std::vector<uhd::transport::zero_copy_if::sptr> data_transports, - std::vector<uhd::transport::zero_copy_if::sptr> err0_transports, - const uhd::device_addrs_t &device_args - ); + usrp2_impl(const uhd::device_addr_t &); ~usrp2_impl(void); @@ -213,6 +196,14 @@ public: size_t get_max_recv_samps_per_packet(void) const; bool recv_async_msg(uhd::async_metadata_t &, double); + void update_xport_channel_mapping(void); + + //public frame sizes, set by mboard, used by io impl + size_t recv_frame_size, send_frame_size; + + std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports; + std::vector<uhd::transport::zero_copy_if::sptr> err_xports; + private: //device properties interface void get(const wax::obj &, wax::obj &); @@ -223,11 +214,10 @@ private: uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict; //io impl methods and members - std::vector<uhd::transport::zero_copy_if::sptr> _data_transports; - std::vector<uhd::transport::zero_copy_if::sptr> _err0_transports; uhd::otw_type_t _rx_otw_type, _tx_otw_type; UHD_PIMPL_DECL(io_impl) _io_impl; void io_init(void); + void handle_overflow(size_t); }; #endif /* INCLUDED_USRP2_IMPL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp index 84907c32e..66c3ac137 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.cpp +++ b/host/lib/usrp/usrp2/usrp2_regs.cpp @@ -38,8 +38,10 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) { x.sr_udp_sm = 96; x.sr_tx_dsp = 208; x.sr_tx_ctrl = 224; - x.sr_rx_dsp = 160; - x.sr_rx_ctrl = 176; + x.sr_rx_dsp0 = 160; + x.sr_rx_ctrl0 = 176; + x.sr_rx_dsp1 = 240; + x.sr_rx_ctrl1 = 32; x.sr_time64 = 192; x.sr_simtimer = 198; x.sr_last = 255; @@ -68,12 +70,18 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) { x.dsp_tx_scale_iq = sr_addr(misc_output_base, x.sr_tx_dsp + 1); x.dsp_tx_interp_rate = sr_addr(misc_output_base, x.sr_tx_dsp + 2); x.dsp_tx_mux = sr_addr(misc_output_base, x.sr_tx_dsp + 4); - x.dsp_rx_freq = sr_addr(misc_output_base, x.sr_rx_dsp + 0); - x.dsp_rx_scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp + 1); - x.dsp_rx_decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp + 2); - x.dsp_rx_dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp + 3); - x.dsp_rx_dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp + 4); - x.dsp_rx_mux = sr_addr(misc_output_base, x.sr_rx_dsp + 5); + x.dsp_rx[0].freq = sr_addr(misc_output_base, x.sr_rx_dsp0 + 0); + x.dsp_rx[0].scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp0 + 1); + x.dsp_rx[0].decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp0 + 2); + x.dsp_rx[0].dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp0 + 3); + x.dsp_rx[0].dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp0 + 4); + x.dsp_rx[0].mux = sr_addr(misc_output_base, x.sr_rx_dsp0 + 5); + x.dsp_rx[1].freq = sr_addr(misc_output_base, x.sr_rx_dsp1 + 0); + x.dsp_rx[1].scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp1 + 1); + x.dsp_rx[1].decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp1 + 2); + x.dsp_rx[1].dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp1 + 3); + x.dsp_rx[1].dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp1 + 4); + x.dsp_rx[1].mux = sr_addr(misc_output_base, x.sr_rx_dsp1 + 5); x.gpio_io = gpio_base + 0; x.gpio_ddr = gpio_base + 4; x.gpio_tx_sel = gpio_base + 8; @@ -86,15 +94,24 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) { x.atr_inrx_rxside = atr_base + 10; x.atr_full_txside = atr_base + 12; x.atr_full_rxside = atr_base + 14; - x.rx_ctrl_stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl + 0); - x.rx_ctrl_time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl + 1); - x.rx_ctrl_time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl + 2); - x.rx_ctrl_clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl + 3); - x.rx_ctrl_vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl + 4); - x.rx_ctrl_vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl + 5); - x.rx_ctrl_vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl + 6); - x.rx_ctrl_nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl + 7); - x.rx_ctrl_nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl + 8); + x.rx_ctrl[0].stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 0); + x.rx_ctrl[0].time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 1); + x.rx_ctrl[0].time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 2); + x.rx_ctrl[0].clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 3); + x.rx_ctrl[0].vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 4); + x.rx_ctrl[0].vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 5); + x.rx_ctrl[0].vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 6); + x.rx_ctrl[0].nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 7); + x.rx_ctrl[0].nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 8); + x.rx_ctrl[1].stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 0); + x.rx_ctrl[1].time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 1); + x.rx_ctrl[1].time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 2); + x.rx_ctrl[1].clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 3); + x.rx_ctrl[1].vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 4); + x.rx_ctrl[1].vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 5); + x.rx_ctrl[1].vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 6); + x.rx_ctrl[1].nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 7); + x.rx_ctrl[1].nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl1 + 8); x.tx_ctrl_num_chan = sr_addr(misc_output_base, x.sr_tx_ctrl + 0); x.tx_ctrl_clear_state = sr_addr(misc_output_base, x.sr_tx_ctrl + 1); x.tx_ctrl_report_sid = sr_addr(misc_output_base, x.sr_tx_ctrl + 2); diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 977b342cb..01f5ee65a 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -38,8 +38,10 @@ typedef struct { int sr_udp_sm; int sr_tx_dsp; int sr_tx_ctrl; - int sr_rx_dsp; - int sr_rx_ctrl; + int sr_rx_dsp0; + int sr_rx_ctrl0; + int sr_rx_dsp1; + int sr_rx_ctrl1; int sr_time64; int sr_simtimer; int sr_last; @@ -68,12 +70,14 @@ typedef struct { int dsp_tx_scale_iq; int dsp_tx_interp_rate; int dsp_tx_mux; - int dsp_rx_freq; - int dsp_rx_scale_iq; - int dsp_rx_decim_rate; - int dsp_rx_dcoffset_i; - int dsp_rx_dcoffset_q; - int dsp_rx_mux; + struct{ + int freq; + int scale_iq; + int decim_rate; + int dcoffset_i; + int dcoffset_q; + int mux; + } dsp_rx[2]; int gpio_base; int gpio_io; int gpio_ddr; @@ -88,15 +92,17 @@ typedef struct { int atr_inrx_rxside; int atr_full_txside; int atr_full_rxside; - int rx_ctrl_stream_cmd; - int rx_ctrl_time_secs; - int rx_ctrl_time_ticks; - int rx_ctrl_clear_overrun; - int rx_ctrl_vrt_header; - int rx_ctrl_vrt_stream_id; - int rx_ctrl_vrt_trailer; - int rx_ctrl_nsamps_per_pkt; - int rx_ctrl_nchannels; + struct{ + int stream_cmd; + int time_secs; + int time_ticks; + int clear_overrun; + int vrt_header; + int vrt_stream_id; + int vrt_trailer; + int nsamps_per_pkt; + int nchannels; + } rx_ctrl[2]; int tx_ctrl_num_chan; int tx_ctrl_clear_state; int tx_ctrl_report_sid; diff --git a/host/lib/usrp/usrp_e100/dsp_impl.cpp b/host/lib/usrp/usrp_e100/dsp_impl.cpp index 7d358a607..8d084f066 100644 --- a/host/lib/usrp/usrp_e100/dsp_impl.cpp +++ b/host/lib/usrp/usrp_e100/dsp_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -60,10 +60,6 @@ void usrp_e100_impl::rx_ddc_get(const wax::obj &key_, wax::obj &val){ val = _ddc_freq; return; - case DSP_PROP_FREQ_SHIFT_NAMES: - val = prop_names_t(1, ""); - return; - case DSP_PROP_CODEC_RATE: val = _clock_ctrl->get_fpga_clock_rate(); return; @@ -84,6 +80,10 @@ void usrp_e100_impl::rx_ddc_set(const wax::obj &key_, const wax::obj &val){ switch(key.as<dsp_prop_t>()){ + case DSP_PROP_STREAM_CMD: + issue_stream_cmd(val.as<stream_cmd_t>()); + return; + case DSP_PROP_FREQ_SHIFT:{ double new_freq = val.as<double>(); _iface->poke32(UE_REG_DSP_RX_FREQ, @@ -143,10 +143,6 @@ void usrp_e100_impl::tx_duc_get(const wax::obj &key_, wax::obj &val){ val = _duc_freq; return; - case DSP_PROP_FREQ_SHIFT_NAMES: - val = prop_names_t(1, ""); - return; - case DSP_PROP_CODEC_RATE: val = _clock_ctrl->get_fpga_clock_rate(); return; diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp index 0e08cd435..a4db53715 100644 --- a/host/lib/usrp/usrp_e100/mboard_impl.cpp +++ b/host/lib/usrp/usrp_e100/mboard_impl.cpp @@ -167,10 +167,6 @@ void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //handle the get request conditioned on the key switch(key.as<mboard_prop_t>()){ - case MBOARD_PROP_STREAM_CMD: - issue_stream_cmd(val.as<stream_cmd_t>()); - return; - case MBOARD_PROP_TIME_NOW: case MBOARD_PROP_TIME_PPS:{ time_spec_t time_spec = val.as<time_spec_t>(); diff --git a/host/tests/tune_helper_test.cpp b/host/tests/tune_helper_test.cpp index 735e7e948..aabaaaf6e 100644 --- a/host/tests/tune_helper_test.cpp +++ b/host/tests/tune_helper_test.cpp @@ -153,10 +153,6 @@ private: val = _freq_shift; return; - case DSP_PROP_FREQ_SHIFT_NAMES: - val = prop_names_t(1, ""); - return; - default: UHD_THROW_PROP_GET_ERROR(); } } @@ -190,12 +186,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx){ dummy_dsp dsp(100e6); std::cout << "Testing tune helper RX automatic IF offset" << std::endl; - tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9); + tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance); BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance); - double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0); + double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); } @@ -204,12 +200,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_tx){ dummy_dsp dsp(100e6); std::cout << "Testing tune helper TX automatic IF offset" << std::endl; - tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9); + tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance); BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance); - double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0); + double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); } @@ -218,12 +214,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){ dummy_dsp dsp(100e6); std::cout << "Testing tune helper RX dummy basic board" << std::endl; - tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 55e6); + tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 0.0, tolerance); BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance); - double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0); + double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance); } @@ -235,21 +231,21 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx_lo_off){ std::cout << "Testing tune helper RX automatic LO offset B >> fs" << std::endl; subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6); dsp[DSP_PROP_HOST_RATE] = double(4e6); - tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.45e9); + tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.45e9+4e6/2, tolerance); std::cout << "Testing tune helper RX automatic LO offset B > fs" << std::endl; subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6); dsp[DSP_PROP_HOST_RATE] = double(25e6); - tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.45e9); + tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.45e9+(40e6-25e6)/2, tolerance); std::cout << "Testing tune helper RX automatic LO offset B < fs" << std::endl; subdev[SUBDEV_PROP_BANDWIDTH] = double(20e6); dsp[DSP_PROP_HOST_RATE] = double(25e6); - tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.45e9); + tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); std::cout << tr.to_pp_string() << std::endl; BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.45e9, tolerance); } |