diff options
218 files changed, 4866 insertions, 8029 deletions
| diff --git a/firmware/microblaze/.gitignore b/firmware/microblaze/.gitignore index 068f01838..e867fe87c 100644 --- a/firmware/microblaze/.gitignore +++ b/firmware/microblaze/.gitignore @@ -5,6 +5,8 @@  /*.log  /*.rom  /.deps +/*.guess +/*.sub  /Makefile  /Makefile.in  /aclocal.m4 diff --git a/firmware/microblaze/Makefile.am b/firmware/microblaze/Makefile.am index 676c4fe42..6316b31a2 100644 --- a/firmware/microblaze/Makefile.am +++ b/firmware/microblaze/Makefile.am @@ -22,6 +22,5 @@ include $(top_srcdir)/Makefile.common  EXTRA_DIST = \  	u2_flash_tool -SUBDIRS = include lib apps - - +SUBDIRS = \ +	usrp2 diff --git a/firmware/microblaze/Makefile.common b/firmware/microblaze/Makefile.common index 3d0f540d8..ceb6a553a 100644 --- a/firmware/microblaze/Makefile.common +++ b/firmware/microblaze/Makefile.common @@ -17,6 +17,8 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  # +include $(top_srcdir)/lib/Makefile.inc +  ########################################################################  # lwIP header include dirs  ######################################################################## @@ -29,21 +31,12 @@ LWIP_INCLUDES = \  	-I$(LWIPDIR)/src/include/ipv4  ######################################################################## -# local include dirs -######################################################################## -LOCAL_INCLUDES = \ -	-I$(top_srcdir)/include \ -	-I$(top_srcdir)/lib - -########################################################################  # misc flags for the mb-gcc compiler  ########################################################################  MBGCC_CFLAGS = \  	--std=gnu99 -Wall -Werror-implicit-function-declaration \  	-mxl-soft-div -msoft-float -mxl-soft-mul -mxl-barrel-shift -MBGCC_LFLAGS = -Wl,-defsym -Wl,_STACK_SIZE=3072 -  ########################################################################  # define for the hal io (FIXME move?)  ######################################################################## @@ -51,31 +44,39 @@ MBGCC_LFLAGS = -Wl,-defsym -Wl,_STACK_SIZE=3072  HAL_IO = -DHAL_IO_USES_UART   ######################################################################## -# set the cflags and ldflags +# common cflags and ldflags  ######################################################################## -AM_CFLAGS = $(MBGCC_CFLAGS) $(LOCAL_INCLUDES) $(LWIP_INCLUDES) $(HAL_IO) +COMMON_CFLAGS = \ +	-I$(top_srcdir)/../../host/lib/usrp \ +	-I$(top_srcdir)/lib \ +	$(MBGCC_CFLAGS) \ +	$(LWIP_INCLUDES) \ +	$(HAL_IO) -AM_LDFLAGS = $(MBGCC_LFLAGS) +COMMON_LFLAGS = \ +	-Wl,-Map -Wl,$(@:.elf=.map)  ########################################################################  # Common stuff for building top level microblaze images  ######################################################################## -AM_LDFLAGS += -Wl,-Map -Wl,$(@:.elf=.map) - -%.bin : %.elf +.elf.bin:  	$(MB_OBJCOPY) -O binary $< $@ -%.dump : %.elf +.elf.dump:  	$(MB_OBJDUMP) -DSC $< > $@ -%.rom : %.bin +.bin.rom:  	$(HEXDUMP) -v -e'1/1 "%.2X\n"' $< > $@ +.elf.ihx: +	$(MB_OBJCOPY) -O ihex $(COMMON_IHX_ARGS) $< $@ +  _generated_from_elf = \  	$(noinst_PROGRAMS:.elf=.map) \  	$(noinst_PROGRAMS:.elf=.bin) \  	$(noinst_PROGRAMS:.elf=.dump) \ -	$(noinst_PROGRAMS:.elf=.rom) +	$(noinst_PROGRAMS:.elf=.rom) \ +	$(noinst_PROGRAMS:.elf=.ihx)  noinst_DATA = $(_generated_from_elf) diff --git a/firmware/microblaze/apps/burnrev40.c b/firmware/microblaze/apps/burnrev40.c deleted file mode 100644 index 362270961..000000000 --- a/firmware/microblaze/apps/burnrev40.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2007,2008 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "u2_init.h" -#include "memory_map.h" -#include "spi.h" -#include "hal_io.h" -#include "buffer_pool.h" -#include "pic.h" -#include <stdbool.h> -#include "ethernet.h" -#include "nonstdio.h" -#include "usrp2_eth_packet.h" -#include "dbsm.h" -#include "app_common_v2.h" -#include "memcpy_wa.h" -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <i2c.h> -#include <usrp2_i2c_addr.h> -#include <clocks.h> -#include "sd.h" -#include "mdelay.h" - -#define HW_REV_MAJOR 4 -#define HW_REV_MINOR 0 - -int test_ram() -{ -  int i,j,k; -  output_regs->ram_page = 1<<10; -   -  extram[0] = 0xDEADBEEF; -  extram[1] = 0xF00D1234; -  extram[7] = 0x76543210; -   -  output_regs->ram_page = 2<<10; -  extram[7] = 0x55555555; -  extram[1] = 0xaaaaaaaa; -  extram[0] = 0xeeeeeeee; -   -  output_regs->ram_page = 1<<10; -   -  i = extram[0]; -  k = extram[1]; -  j = extram[7]; -   -  if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { -    puts("RAM FAIL1!\n"); -    puthex32_nl(i); -    puthex32_nl(j); -    puthex32_nl(k); -    return 0; -  } -   -  output_regs->ram_page = 2<<10; - -  j = extram[7]; -  k = extram[1]; -  i = extram[0]; - -  if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { -    puts("RAM FAIL2!\n"); -    puthex32_nl(i); -    puthex32_nl(j); -    puthex32_nl(k); -    return 0; -  } -  return 1; -} - -int test_sd() -{ -  int i = sd_init(); -  if(i==0) { -    puts("FAILED INIT of Card\n"); -    return 0; -  } -   -  unsigned char buf[512]; -  i = sd_read_block(2048,buf); -  if(i == 0) { -    puts("READ Command Rejected\n"); -    return 0; -  } -  if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) -    ; -  else { -    puts("Read bad data from SD Card\n"); -    return 0; -  } -  return 1; -} - -int -main(void) -{ -  u2_init(); - -  putstr("\nFactory Test, Board Rev 4.0\n"); - -  bool ok = true; -  unsigned char maj = HW_REV_MAJOR; -  unsigned char min = HW_REV_MINOR; -  ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); -  ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); - -  putstr("\nset_hw_rev\n"); -  if (ok) -    printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); -  else { -    printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); -    hal_finish(); -    return 0; -  } - -  if(test_sd()) -    puts("SD OK\n"); -  else { -    puts("SD FAIL\n"); -    //hal_finish(); -    //return 0; -  } -  if(test_ram()) -    puts("RAM OK\n"); -  else { -    puts("RAM FAIL\n"); -    hal_finish(); -    return 0; -  } - -  print_mac_addr(ethernet_mac_addr()->addr); -  newline(); - -  clocks_mimo_config(MC_WE_LOCK_TO_SMA); - -  while (!clocks_lock_detect()) { -    puts("No Lock"); -    mdelay(1000); -  } -  puts("Clock Locked\n"); - -} diff --git a/firmware/microblaze/apps/Makefile.am b/firmware/microblaze/apps/cruft/Makefile.am index a4f79935b..a4f79935b 100644 --- a/firmware/microblaze/apps/Makefile.am +++ b/firmware/microblaze/apps/cruft/Makefile.am diff --git a/firmware/microblaze/apps/app_passthru_v2.c b/firmware/microblaze/apps/cruft/app_passthru_v2.c index 406c56b3b..406c56b3b 100644 --- a/firmware/microblaze/apps/app_passthru_v2.c +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.c diff --git a/firmware/microblaze/apps/app_passthru_v2.h b/firmware/microblaze/apps/cruft/app_passthru_v2.h index 3904c670f..3904c670f 100644 --- a/firmware/microblaze/apps/app_passthru_v2.h +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.h diff --git a/firmware/microblaze/apps/blink_leds.c b/firmware/microblaze/apps/cruft/blink_leds.c index 682ca8db2..682ca8db2 100644 --- a/firmware/microblaze/apps/blink_leds.c +++ b/firmware/microblaze/apps/cruft/blink_leds.c diff --git a/firmware/microblaze/apps/blink_leds2.c b/firmware/microblaze/apps/cruft/blink_leds2.c index 13e78afb3..13e78afb3 100644 --- a/firmware/microblaze/apps/blink_leds2.c +++ b/firmware/microblaze/apps/cruft/blink_leds2.c diff --git a/firmware/microblaze/apps/buf_ram_test.c b/firmware/microblaze/apps/cruft/buf_ram_test.c index 1aca2aec5..1aca2aec5 100644 --- a/firmware/microblaze/apps/buf_ram_test.c +++ b/firmware/microblaze/apps/cruft/buf_ram_test.c diff --git a/firmware/microblaze/apps/burn_dbsrx_eeprom.c b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c index 116d4d8d0..116d4d8d0 100644 --- a/firmware/microblaze/apps/burn_dbsrx_eeprom.c +++ b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c diff --git a/firmware/microblaze/apps/burnrev30.c b/firmware/microblaze/apps/cruft/burnrev30.c index 40fa53e34..40fa53e34 100644 --- a/firmware/microblaze/apps/burnrev30.c +++ b/firmware/microblaze/apps/cruft/burnrev30.c diff --git a/firmware/microblaze/apps/burnrev31.c b/firmware/microblaze/apps/cruft/burnrev31.c index f6b08d187..f6b08d187 100644 --- a/firmware/microblaze/apps/burnrev31.c +++ b/firmware/microblaze/apps/cruft/burnrev31.c diff --git a/firmware/microblaze/apps/can_i_sub.c b/firmware/microblaze/apps/cruft/can_i_sub.c index ed49791f0..ed49791f0 100644 --- a/firmware/microblaze/apps/can_i_sub.c +++ b/firmware/microblaze/apps/cruft/can_i_sub.c diff --git a/firmware/microblaze/apps/double_buffer_fragment.c b/firmware/microblaze/apps/cruft/double_buffer_fragment.c index cfc061247..cfc061247 100644 --- a/firmware/microblaze/apps/double_buffer_fragment.c +++ b/firmware/microblaze/apps/cruft/double_buffer_fragment.c diff --git a/firmware/microblaze/apps/echo.c b/firmware/microblaze/apps/cruft/echo.c index 89108ee80..89108ee80 100644 --- a/firmware/microblaze/apps/echo.c +++ b/firmware/microblaze/apps/cruft/echo.c diff --git a/firmware/microblaze/apps/eth_serdes.c b/firmware/microblaze/apps/cruft/eth_serdes.c index 2d2ddc1ca..2d2ddc1ca 100644 --- a/firmware/microblaze/apps/eth_serdes.c +++ b/firmware/microblaze/apps/cruft/eth_serdes.c diff --git a/firmware/microblaze/apps/factory_test.c b/firmware/microblaze/apps/cruft/factory_test.c index e1fbb0e40..e1fbb0e40 100644 --- a/firmware/microblaze/apps/factory_test.c +++ b/firmware/microblaze/apps/cruft/factory_test.c diff --git a/firmware/microblaze/apps/gen_eth_packets.c b/firmware/microblaze/apps/cruft/gen_eth_packets.c index 4d521f6bf..4d521f6bf 100644 --- a/firmware/microblaze/apps/gen_eth_packets.c +++ b/firmware/microblaze/apps/cruft/gen_eth_packets.c diff --git a/firmware/microblaze/apps/gen_pause_frames.c b/firmware/microblaze/apps/cruft/gen_pause_frames.c index 0f81dafff..0f81dafff 100644 --- a/firmware/microblaze/apps/gen_pause_frames.c +++ b/firmware/microblaze/apps/cruft/gen_pause_frames.c diff --git a/firmware/microblaze/apps/hello.c b/firmware/microblaze/apps/cruft/hello.c index bce843093..bce843093 100644 --- a/firmware/microblaze/apps/hello.c +++ b/firmware/microblaze/apps/cruft/hello.c diff --git a/firmware/microblaze/apps/ibs_rx_test.c b/firmware/microblaze/apps/cruft/ibs_rx_test.c index bdc04747e..bdc04747e 100644 --- a/firmware/microblaze/apps/ibs_rx_test.c +++ b/firmware/microblaze/apps/cruft/ibs_rx_test.c diff --git a/firmware/microblaze/apps/ibs_tx_test.c b/firmware/microblaze/apps/cruft/ibs_tx_test.c index ff9446d92..ff9446d92 100644 --- a/firmware/microblaze/apps/ibs_tx_test.c +++ b/firmware/microblaze/apps/cruft/ibs_tx_test.c diff --git a/firmware/microblaze/apps/mimo_app_common_v2.c b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c index 5dbecb0d0..5dbecb0d0 100644 --- a/firmware/microblaze/apps/mimo_app_common_v2.c +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c diff --git a/firmware/microblaze/apps/mimo_app_common_v2.h b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h index 1e62ced37..1e62ced37 100644 --- a/firmware/microblaze/apps/mimo_app_common_v2.h +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h diff --git a/firmware/microblaze/apps/mimo_tx.c b/firmware/microblaze/apps/cruft/mimo_tx.c index e0f8aa6fa..e0f8aa6fa 100644 --- a/firmware/microblaze/apps/mimo_tx.c +++ b/firmware/microblaze/apps/cruft/mimo_tx.c diff --git a/firmware/microblaze/apps/mimo_tx_slave.c b/firmware/microblaze/apps/cruft/mimo_tx_slave.c index cdf9c03c2..cdf9c03c2 100644 --- a/firmware/microblaze/apps/mimo_tx_slave.c +++ b/firmware/microblaze/apps/cruft/mimo_tx_slave.c diff --git a/firmware/microblaze/apps/rcv_eth_packets.c b/firmware/microblaze/apps/cruft/rcv_eth_packets.c index 03fc94354..03fc94354 100644 --- a/firmware/microblaze/apps/rcv_eth_packets.c +++ b/firmware/microblaze/apps/cruft/rcv_eth_packets.c diff --git a/firmware/microblaze/apps/read_dbids.c b/firmware/microblaze/apps/cruft/read_dbids.c index 24c6d9ab4..24c6d9ab4 100644 --- a/firmware/microblaze/apps/read_dbids.c +++ b/firmware/microblaze/apps/cruft/read_dbids.c diff --git a/firmware/microblaze/apps/sd_bounce.c b/firmware/microblaze/apps/cruft/sd_bounce.c index c1b48f170..c1b48f170 100644 --- a/firmware/microblaze/apps/sd_bounce.c +++ b/firmware/microblaze/apps/cruft/sd_bounce.c diff --git a/firmware/microblaze/apps/sd_gentest.c b/firmware/microblaze/apps/cruft/sd_gentest.c index 35e912615..35e912615 100644 --- a/firmware/microblaze/apps/sd_gentest.c +++ b/firmware/microblaze/apps/cruft/sd_gentest.c diff --git a/firmware/microblaze/apps/serdes_to_dsp.c b/firmware/microblaze/apps/cruft/serdes_to_dsp.c index 4994e0a69..4994e0a69 100644 --- a/firmware/microblaze/apps/serdes_to_dsp.c +++ b/firmware/microblaze/apps/cruft/serdes_to_dsp.c diff --git a/firmware/microblaze/apps/serdes_txrx.c b/firmware/microblaze/apps/cruft/serdes_txrx.c index 2c47c9628..2c47c9628 100644 --- a/firmware/microblaze/apps/serdes_txrx.c +++ b/firmware/microblaze/apps/cruft/serdes_txrx.c diff --git a/firmware/microblaze/apps/set_hw_rev.c b/firmware/microblaze/apps/cruft/set_hw_rev.c index d4ac8ff81..d4ac8ff81 100644 --- a/firmware/microblaze/apps/set_hw_rev.c +++ b/firmware/microblaze/apps/cruft/set_hw_rev.c diff --git a/firmware/microblaze/apps/test1.c b/firmware/microblaze/apps/cruft/test1.c index c3cc3be56..c3cc3be56 100644 --- a/firmware/microblaze/apps/test1.c +++ b/firmware/microblaze/apps/cruft/test1.c diff --git a/firmware/microblaze/apps/test_db_spi.c b/firmware/microblaze/apps/cruft/test_db_spi.c index f4fa98ef1..f4fa98ef1 100644 --- a/firmware/microblaze/apps/test_db_spi.c +++ b/firmware/microblaze/apps/cruft/test_db_spi.c diff --git a/firmware/microblaze/apps/test_i2c.c b/firmware/microblaze/apps/cruft/test_i2c.c index f349ead88..f349ead88 100644 --- a/firmware/microblaze/apps/test_i2c.c +++ b/firmware/microblaze/apps/cruft/test_i2c.c diff --git a/firmware/microblaze/apps/test_lsadc.c b/firmware/microblaze/apps/cruft/test_lsadc.c index 5fda29cd7..5fda29cd7 100644 --- a/firmware/microblaze/apps/test_lsadc.c +++ b/firmware/microblaze/apps/cruft/test_lsadc.c diff --git a/firmware/microblaze/apps/test_lsdac.c b/firmware/microblaze/apps/cruft/test_lsdac.c index 8c1bf333b..8c1bf333b 100644 --- a/firmware/microblaze/apps/test_lsdac.c +++ b/firmware/microblaze/apps/cruft/test_lsdac.c diff --git a/firmware/microblaze/apps/test_phy_comm.c b/firmware/microblaze/apps/cruft/test_phy_comm.c index d312ca4cc..d312ca4cc 100644 --- a/firmware/microblaze/apps/test_phy_comm.c +++ b/firmware/microblaze/apps/cruft/test_phy_comm.c diff --git a/firmware/microblaze/apps/test_ram.c b/firmware/microblaze/apps/cruft/test_ram.c index 77ee693f6..77ee693f6 100644 --- a/firmware/microblaze/apps/test_ram.c +++ b/firmware/microblaze/apps/cruft/test_ram.c diff --git a/firmware/microblaze/apps/test_sd.c b/firmware/microblaze/apps/cruft/test_sd.c index 494432d7f..494432d7f 100644 --- a/firmware/microblaze/apps/test_sd.c +++ b/firmware/microblaze/apps/cruft/test_sd.c diff --git a/firmware/microblaze/apps/timer_test.c b/firmware/microblaze/apps/cruft/timer_test.c index 44e80b5f1..44e80b5f1 100644 --- a/firmware/microblaze/apps/timer_test.c +++ b/firmware/microblaze/apps/cruft/timer_test.c diff --git a/firmware/microblaze/apps/tx_standalone.c b/firmware/microblaze/apps/cruft/tx_standalone.c index 1645fa8ba..1645fa8ba 100644 --- a/firmware/microblaze/apps/tx_standalone.c +++ b/firmware/microblaze/apps/cruft/tx_standalone.c diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index b81d32b2d..f0a9702be 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -41,7 +41,6 @@  #include <stdlib.h>  #include <string.h>  #include "clocks.h" -#include <vrt/bits.h>  #include "usrp2/fw_common.h"  #include <i2c.h>  #include <ethertype.h> @@ -97,6 +96,12 @@ static const uint32_t rx_ctrl_word = 1 << 16;  // DSP Rx writes ethernet header words  #define DSP_RX_FIRST_LINE sizeof(rx_ctrl_word)/sizeof(uint32_t) +static bool dbsm_rx_inspector(dbsm_t *sm, int buf_this){ +    size_t num_lines = buffer_pool_status->last_line[buf_this]-DSP_RX_FIRST_LINE; +    ((uint32_t*)buffer_ram(buf_this))[0] = (num_lines*sizeof(uint32_t)) | (1 << 16); +    return false; +} +  // receive from DSP  buf_cmd_args_t dsp_rx_recv_args = {    PORT_DSP, @@ -176,9 +181,9 @@ void handle_udp_ctrl_packet(      uint32_t ctrl_data_in_id = ctrl_data_in->id;      //ensure that the protocol versions match -    if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_PROTO_VERSION){ -        printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", -            USRP2_PROTO_VERSION, ctrl_data_in->proto_ver +    if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ +        printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", +            USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver          );          ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO;      } @@ -193,7 +198,7 @@ void handle_udp_ctrl_packet(      //setup the output data      usrp2_ctrl_data_t ctrl_data_out = { -        .proto_ver = USRP2_PROTO_VERSION, +        .proto_ver = USRP2_FW_COMPAT_NUM,          .id=USRP2_CTRL_ID_HUH_WHAT,          .seq=ctrl_data_in->seq      }; @@ -260,7 +265,7 @@ void handle_udp_ctrl_packet(       * Peek and Poke Register       ******************************************************************/      case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO: -        if (ctrl_data_in->data.poke_args.addr < 0xC000){ +        if (0){//ctrl_data_in->data.poke_args.addr < 0xC000){              printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr);          }          else switch(ctrl_data_in->data.poke_args.num_bytes){ @@ -436,7 +441,8 @@ main(void)    print_mac_addr(ethernet_mac_addr()->addr);    newline();    print_ip_addr(get_ip_addr()); newline(); -  printf("Control protocol version: %d\n", USRP2_PROTO_VERSION); +  printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM); +  printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM);    ethernet_register_link_changed_callback(link_changed_callback);    ethernet_init(); @@ -458,15 +464,12 @@ main(void)      dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0,  	      &dsp_rx_recv_args, &dsp_rx_send_args, -	      dbsm_nop_inspector); +	      dbsm_rx_inspector);    sr_tx_ctrl->clear_state = 1;    bp_clear_buf(DSP_TX_BUF_0);    bp_clear_buf(DSP_TX_BUF_1); -  buffer_ram(DSP_RX_BUF_0)[0] = rx_ctrl_word; -  buffer_ram(DSP_RX_BUF_0)[1] = rx_ctrl_word; -    // kick off the state machine    dbsm_start(&dsp_tx_sm); @@ -481,7 +484,7 @@ main(void)      int pending = pic_regs->pending;		// poll for under or overrun      if (pending & PIC_UNDERRUN_INT){ -      dbsm_handle_tx_underrun(&dsp_tx_sm); +      //dbsm_handle_tx_underrun(&dsp_tx_sm);        pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt        putchar('U');      } diff --git a/firmware/microblaze/bootstrap b/firmware/microblaze/bootstrap index 2343025cc..5786c1624 100755 --- a/firmware/microblaze/bootstrap +++ b/firmware/microblaze/bootstrap @@ -17,6 +17,7 @@  #  rm -rf *.cache +rm -rf libusrp2/.deps  aclocal  autoconf diff --git a/firmware/microblaze/config.guess b/firmware/microblaze/config.guess deleted file mode 120000 index 405bc3235..000000000 --- a/firmware/microblaze/config.guess +++ /dev/null @@ -1 +0,0 @@ -/usr/share/automake-1.11/config.guess
\ No newline at end of file diff --git a/firmware/microblaze/config.sub b/firmware/microblaze/config.sub deleted file mode 120000 index 4d47fbcbc..000000000 --- a/firmware/microblaze/config.sub +++ /dev/null @@ -1 +0,0 @@ -/usr/share/automake-1.11/config.sub
\ No newline at end of file diff --git a/firmware/microblaze/configure.ac b/firmware/microblaze/configure.ac index 46968b7fb..e27bcb557 100644 --- a/firmware/microblaze/configure.ac +++ b/firmware/microblaze/configure.ac @@ -32,6 +32,7 @@ m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.64],       [m4_define([_AC_LANG_IO_PROGRAM(]_GCC_LANG[)], m4_defn([AC_LANG_PROGRAM(]_GCC_LANG[)]))])])   AC_PROG_CC([mb-gcc]) +AM_PROG_CC_C_O  LT_INIT  ################################################## @@ -46,9 +47,6 @@ AC_PATH_PROG([HEXDUMP],    [hexdump])  ##################################################  AC_CONFIG_FILES([ \      Makefile \ -    apps/Makefile \ -    include/Makefile \ -    include/net/Makefile \ -    lib/Makefile \ +    usrp2/Makefile \  ])  AC_OUTPUT diff --git a/firmware/microblaze/include/.gitignore b/firmware/microblaze/include/.gitignore deleted file mode 100644 index b336cc7ce..000000000 --- a/firmware/microblaze/include/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile -/Makefile.in diff --git a/firmware/microblaze/include/net/Makefile.am b/firmware/microblaze/include/net/Makefile.am deleted file mode 100644 index 32b0bf9dc..000000000 --- a/firmware/microblaze/include/net/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright 2010 Ettus Research LLC -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. -# - -include $(top_srcdir)/Makefile.common - -noinst_HEADERS = \ -	eth_mac_addr.h \ -	padded_eth_hdr.h \ -	socket_address.h diff --git a/firmware/microblaze/include/usrp2_fpga_regs.h b/firmware/microblaze/include/usrp2_fpga_regs.h deleted file mode 100644 index b0f83df60..000000000 --- a/firmware/microblaze/include/usrp2_fpga_regs.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef INCLUDED_USRP2_FPGA_REGS_H -#define INCLUDED_USSRP2_FPGA_REGS_H - -#include "usrp2_cdefs.h" - -__U2_BEGIN_DECLS - -// ---------------------------------------------------------------- - -#define	DSP_CORE_TX_BASE	128 - -// DUC center frequency tuning word (phase increment) -#define FR_TX_FREQ_0		(0 + DSP_CORE_TX_BASE) - -// I & Q output scaling, 16.0 format ((I_SCALE << 16) | Q_SCALE) -#define FR_TX_SCALE_0		(1 + DSP_CORE_TX_BASE) - -// Tx interpolation rate (set to 1 less than desired rate) -#define FR_TX_INTERP_RATE_0	(2 + DSP_CORE_TX_BASE) - -// Write 1 (actually anything) to clear tx state -#define FR_TX_CLEAR_STATE_0	(3 + DSP_CORE_TX_BASE) - -// ---------------------------------------------------------------- - -#define	DSP_CORE_RX_BASE	160 - -// DDC center frequency tuning word (phase increment) -#define FR_RX_FREQ_0		(0 + DSP_CORE_RX_BASE) - -// I & Q input scaling, 16.0 format ((I_SCALE << 16) | Q_SCALE) -#define FR_RX_SCALE_0		(1 + DSP_CORE_RX_BASE) - -// Rx decimation rate (set to 1 less than desired rate) -#define FR_RX_DECIM_RATE_0	(2 + DSP_CORE_RX_BASE) - -// The next two registers concatenated are the Rx command register. -// -// Writing FR_RX_TIME_TO_RX_0 writes the concatenated value into the -// cmd queue.  Thus, if you're writing both, be sure to write -// FR_RX_QTY_0 first. -// -//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -//   |                          Timestamp                            | -//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -#define FR_RX_TIME_TO_RX	(3 + DSP_CORE_RX_BASE) - -//                          23-bits                       9-bits -//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -//   |                number_of_lines              | lines_per_frame | -//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -#define FR_RX_QTY_0		(4 + DSP_CORE_RX_BASE) - -// write a 1 (anything actually) to clear the overrun  -#define FR_RX_CLR_OVERRUN_0	(5 + DSP_CORE_RX_BASE) - - -__U2_END_DECLS - -#endif /* INCLUDED_USRP2_FPGA_REGS_H */ diff --git a/firmware/microblaze/include/usrp2_i2c_addr.h b/firmware/microblaze/include/usrp2_i2c_addr.h deleted file mode 100644 index 46f5a7556..000000000 --- a/firmware/microblaze/include/usrp2_i2c_addr.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2007 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef INCLUDED_USRP2_I2C_ADDR_H -#define INCLUDED_USRP2_I2C_ADDR_H - -// I2C addresses - -#define I2C_DEV_EEPROM	0x50		// 24LC02[45]:  7-bits 1010xxx - -#define	I2C_ADDR_MBOARD	(I2C_DEV_EEPROM	| 0x0) -#define	I2C_ADDR_TX_A	(I2C_DEV_EEPROM | 0x4) -#define	I2C_ADDR_RX_A	(I2C_DEV_EEPROM | 0x5) - - -// format of USRP2 motherboard rom -//	00: 0x00	h/w rev (LSB) -//	01: 0x00	h/w rev (MSB) -//	02: 0x00	MAC addr 0 -//	03: 0x50	MAC addr 1 -//	04: 0xC2	MAC addr 2 -//	05: 0x85	MAC addr 3 -//	06: 0x3.	MAC addr 4 -//	07: 0x..	MAC addr 5 - -#define MBOARD_REV_LSB	0x00 -#define	MBOARD_REV_MSB  0x01 -#define	MBOARD_MAC_ADDR 0x02 -#define MBOARD_IP_ADDR  0x0C - - -// format of daughterboard EEPROM -//	00: 0xDB	code for ``I'm a daughterboard'' -//	01:   ..	Daughterboard ID (LSB) -//	02:   ..	Daughterboard ID (MSB) -//	03:   ..	io bits  7-0 direction (bit set if it's an output from m'board) -//	04:   ..	io bits 15-8 direction (bit set if it's an output from m'board) -//	05:   ..	ADC0 DC offset correction (LSB) -//	06:   ..	ADC0 DC offset correction (MSB) -//	07:   ..	ADC1 DC offset correction (LSB) -//	08:   ..	ADC1 DC offset correction (MSB) -// 	... -//	1f:   ..	negative of the sum of bytes [0x00, 0x1e] - -#define	DB_EEPROM_MAGIC		0x00 -#define	  DB_EEPROM_MAGIC_VALUE			0xDB -#define	DB_EEPROM_ID_LSB		0x01 -#define	DB_EEPROM_ID_MSB		0x02 -#define	DB_EEPROM_OE_LSB		0x03 -#define	DB_EEPROM_OE_MSB		0x04 -#define	DB_EEPROM_OFFSET_0_LSB		0x05	// offset correction for ADC or DAC 0 -#define	DB_EEPROM_OFFSET_0_MSB		0x06 -#define	DB_EEPROM_OFFSET_1_LSB		0x07	// offset correction for ADC or DAC 1 -#define	DB_EEPROM_OFFSET_1_MSB		0x08 -#define	DB_EEPROM_CHKSUM		0x1f - -#define	DB_EEPROM_CLEN			0x20	// length of common portion of eeprom - -#define	DB_EEPROM_CUSTOM_BASE		DB_EEPROM_CLEN	// first avail offset for -							//   daughterboard specific use - -#endif /* INCLUDED_USRP2_I2C_ADDR_H */ - diff --git a/firmware/microblaze/include/usrp2_types.h b/firmware/microblaze/include/usrp2_types.h deleted file mode 100644 index fe45936f0..000000000 --- a/firmware/microblaze/include/usrp2_types.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef INCLUDED_USRP2_TYPES_H -#define INCLUDED_USRP2_TYPES_H - -#include <stdint.h> - -/*! - * \brief Fixed point representation of a frequency in Hertz (VITA-49 compatible) - * - * 64-bit two's complement, with the radix point 20 bits up from the bottom.  - * Q44.20 format (20 bits to the right of the radix point) - * - * Values range from +/- 8.79 terahertz with a resolution of 0.95 microhertz. - */ -typedef int64_t	u2_fxpt_freq_t; - -#define U2_FPF_RP	20	// location of radix point in u2_fxpt_freq_t - -// macro so we can init structs at compile time -#define U2_DOUBLE_TO_FXPT_FREQ(f) (int64_t)((f) * (1LL << U2_FPF_RP)) - -static inline u2_fxpt_freq_t -u2_double_to_fxpt_freq(double f) -{ -  return U2_DOUBLE_TO_FXPT_FREQ(f); -} - -static inline int -u2_fxpt_freq_round_to_int(u2_fxpt_freq_t fx) -{ -  return (int)((fx+(1<<(U2_FPF_RP-1)))>>U2_FPF_RP); -} - -static inline double -u2_fxpt_freq_to_double(u2_fxpt_freq_t fx) -{ -  return ((double) fx) * 1.0/(1 << U2_FPF_RP); -} - -static inline uint32_t -u2_fxpt_freq_hi(u2_fxpt_freq_t f) -{ -  return ((f >> 32) & 0xffffffff); -} - -static inline uint32_t -u2_fxpt_freq_lo(u2_fxpt_freq_t f) -{ -  return (f & 0xffffffff); -} - -static inline u2_fxpt_freq_t -u2_fxpt_freq_from_hilo(uint32_t hi, uint32_t lo) -{ -  return (((u2_fxpt_freq_t) hi) << 32) | lo; -} - -/*! - * \brief Fixed point representation of a gain in dB (VITA-49 compatible) - * - * 16-bit two's complement, with the radix point 7 bits up from the bottom.  - * Q9.7 format (7 bits to the right of the radix point) - */ -typedef int16_t u2_fxpt_gain_t; - -#define U2_FPG_RP	7	// location of radix point in u2_fxpt_gain_t - -// macro so we can init structs at compile time -#define U2_DOUBLE_TO_FXPT_GAIN(g) (int16_t)((g) * (1 << U2_FPG_RP)) - -static inline u2_fxpt_gain_t -u2_double_to_fxpt_gain(double g) -{ -  return U2_DOUBLE_TO_FXPT_GAIN(g); -} - -static inline float -u2_fxpt_gain_to_double(u2_fxpt_gain_t fx) -{ -  return ((double) fx) * 1.0/(1 << U2_FPG_RP); -} - -static inline int -u2_fxpt_gain_round_to_int(u2_fxpt_gain_t fx) -{  -  return (int)((fx+(1<<(U2_FPG_RP-1)))>>U2_FPG_RP); -} - -#endif /* INCLUDED_USRP2_TYPES_H */ diff --git a/firmware/microblaze/include/vrt/bits.h b/firmware/microblaze/include/vrt/bits.h deleted file mode 100644 index 54eeec7b4..000000000 --- a/firmware/microblaze/include/vrt/bits.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef INCLUDED_VRT_BITS_H -#define INCLUDED_VRT_BITS_H - -#include <stdint.h> - - -/* VRT Header bits */ - -#define	VRTH_PT_MASK		  (0xf << 28) -#define	VRTH_PT_IF_DATA_NO_SID	  (0x0 << 28)	// IF-Data, no stream id -#define	VRTH_PT_IF_DATA_WITH_SID  (0x1 << 28)	// IF-Data, w/ stream id -#define VRTH_PT_EXT_DATA_NO_SID	  (0x2 << 28) -#define	VRTH_PT_EXT_DATA_WITH_SID (0x3 << 28) -#define	VRTH_PT_IF_CONTEXT	  (0x4 << 28) -#define	VRTH_PT_EXT_CONTEXT	  (0x5 << 28) - -#define	VRTH_HAS_CLASSID	  (1 << 27) -#define	VRTH_HAS_TRAILER	  (1 << 26)	// Data pkts only -#define	VRTH_START_OF_BURST	  (1 << 25)	// Data (Tx) pkts only -#define	VRTH_END_OF_BURST	  (1 << 24)	// Data (Tx) pkts only -#define	VRTH_TSM		  (1 << 24)	// Context pkts only - -#define	VRTH_TSI_MASK		  (0x3 << 22) -#define	VRTH_TSI_NONE		  (0x0 << 22) -#define	VRTH_TSI_UTC		  (0x1 << 22) -#define	VRTH_TSI_GPS		  (0x2 << 22) -#define VRTH_TSI_OTHER		  (0x3 << 22) - -#define	VRTH_TSF_MASK		  (0x3 << 20) -#define	VRTH_TSF_NONE		  (0x0 << 20) -#define	VRTH_TSF_SAMPLE_CNT	  (0x1 << 20) -#define	VRTH_TSF_REAL_TIME_PS	  (0x2 << 20) -#define	VRTH_TSF_FREE_RUNNING	  (0x3 << 20) - -#define	VRTH_PKT_CNT_SHIFT	  16 -#define	VRTH_PKT_CNT_MASK	  (0xf << 16) - -#define	VRTH_PKT_SIZE_MASK	  0xffff		     - - -static inline int -vrth_pkt_cnt(uint32_t h) -{ -  return (h & VRTH_PKT_CNT_MASK) >> 16; -} - -static inline int -vrth_pkt_size(uint32_t h) -{ -  return h & VRTH_PKT_SIZE_MASK; -} - -/* - * Trailer bits - */ -#define	TR_E		      (1 << 8) - -#define TR_ENABLE(x) ((x) << 20) -#define	TR_STATE(x)  ((x) <<  8) - -// Use these with TR_ENABLE and TR_STATE -#define	TR_CAL_TIME	      (1 << 11) -#define	TR_VALID_DATA	      (1 << 10) -#define TR_REF_LOCK	      (1 <<  9) -#define	TR_AGC		      (1 <<  8) -#define TR_DETECTED_SIG	      (1 <<  7) -#define	TR_SPECTRAL_INVERSION (1 <<  6) -#define	TR_OVER_RANGE	      (1 <<  5) -#define	TR_SAMPLE_LOSS	      (1 <<  4) -#define TR_USER_3	      (1 <<  3) -#define TR_USER_2	      (1 <<  2) -#define TR_USER_1	      (1 <<  1) -#define TR_USER_0	      (1 <<  0) - -#endif /* INCLUDED_VRT_BITS_H */ diff --git a/firmware/microblaze/include/vrt/types.h b/firmware/microblaze/include/vrt/types.h deleted file mode 100644 index edfa4ec37..000000000 --- a/firmware/microblaze/include/vrt/types.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef INCLUDED_VRT_TYPES_H -#define INCLUDED_VRT_TYPES_H - -#include <stdint.h> - -/* macros for dealing with fixed point numbers */ -#define _FXPT_C(_type, _x, _rp) ((_type)((_x)*(1ll << _rp))) -#define _FXPT_TO_INT(_x, _one) (((_x) + ((_one)/2))/(_one)) -#define _FXPT_TO_DOUBLE(_x, _one) ((double)(_x) * (1.0/(_one))) - -/*********************************************************************** - * The VRT Altitude Type (meters) - **********************************************************************/ -typedef int32_t vrt_altitude_t; -#define VRT_ALTITUDE_RP 5 -#define VRT_ALTITUDE_C(_x) _FXPT_C(vrt_altitude_t, _x, VRT_ALTITUDE_RP) - -static inline vrt_altitude_t -double_to_vrt_altitude(double num){ -  return VRT_ALTITUDE_C(num); -} - -static inline int32_t -vrt_altitude_round_to_int(vrt_altitude_t fx){ -  return _FXPT_TO_INT(fx, VRT_ALTITUDE_C(1)); -} - -static inline double -vrt_altitude_to_double(vrt_altitude_t fx){ -  return _FXPT_TO_DOUBLE(fx, VRT_ALTITUDE_C(1)); -} - -/*********************************************************************** - * The VRT Geolocation Angle Type (degrees) - **********************************************************************/ -typedef int32_t vrt_geo_angle_t; -#define VRT_GEO_ANGLE_RP 22 -#define VRT_GEO_ANGLE_C(_x) _FXPT_C(vrt_geo_angle_t, _x, VRT_GEO_ANGLE_RP) - -static inline vrt_geo_angle_t -double_to_vrt_geo_angle(double num){ -  return VRT_GEO_ANGLE_C(num); -} - -static inline int16_t -vrt_geo_angle_round_to_int(vrt_geo_angle_t fx){ -  return _FXPT_TO_INT(fx, VRT_GEO_ANGLE_C(1)); -} - -static inline double -vrt_geo_angle_to_double(vrt_geo_angle_t fx){ -  return _FXPT_TO_DOUBLE(fx, VRT_GEO_ANGLE_C(1)); -} - -/*********************************************************************** - * The VRT Frequency Type (Hz) - **********************************************************************/ -typedef int64_t vrt_freq_t; -#define VRT_FREQ_RP 20 -#define VRT_FREQ_C(_x) _FXPT_C(vrt_freq_t, _x, VRT_FREQ_RP) - -static inline vrt_freq_t -double_to_vrt_freq(double num){ -  return VRT_FREQ_C(num); -} - -static inline int64_t -vrt_freq_round_to_int(vrt_freq_t fx){ -  return _FXPT_TO_INT(fx, VRT_FREQ_C(1)); -} - -static inline double -vrt_freq_to_double(vrt_freq_t fx){ -  return _FXPT_TO_DOUBLE(fx, VRT_FREQ_C(1)); -} - -/*********************************************************************** - * The VRT Gain Type (dB) - **********************************************************************/ -typedef int16_t vrt_gain_t; -#define VRT_GAIN_RP 7 -#define VRT_GAIN_C(_x) _FXPT_C(vrt_gain_t, _x, VRT_GAIN_RP) - -static inline vrt_gain_t -double_to_vrt_gain(double num){ -  return VRT_GAIN_C(num); -} - -static inline int16_t -vrt_gain_round_to_int(vrt_gain_t fx){ -  return _FXPT_TO_INT(fx, VRT_GAIN_C(1)); -} - -static inline double -vrt_gain_to_double(vrt_gain_t fx){ -  return _FXPT_TO_DOUBLE(fx, VRT_GAIN_C(1)); -} - -/*********************************************************************** - * The VRT Temperature Type (Celcius) - **********************************************************************/ -typedef int16_t vrt_temp_t; -#define VRT_TEMP_RP 6 -#define VRT_TEMP_C(_x) _FXPT_C(vrt_temp_t, _x, VRT_TEMP_RP) - -static inline vrt_temp_t -double_to_vrt_temp(double num){ -  return VRT_TEMP_C(num); -} - -static inline int16_t -vrt_temp_round_to_int(vrt_temp_t fx){ -  return _FXPT_TO_INT(fx, VRT_TEMP_C(1)); -} - -static inline double -vrt_temp_to_double(vrt_temp_t fx){ -  return _FXPT_TO_DOUBLE(fx, VRT_TEMP_C(1)); -} - -#endif /* INCLUDED_VRT_TYPES_H */ diff --git a/firmware/microblaze/lib/.gitignore b/firmware/microblaze/lib/.gitignore deleted file mode 100644 index 5d838bf6c..000000000 --- a/firmware/microblaze/lib/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -*~ -/*-stamp -/*.a -/*.bin -/*.dump -/*.log -/*.rom -/.deps -/Makefile -/Makefile.in -/aclocal.m4 -/autom4te.cache -/blink_leds -/blink_leds2 -/build -/compile -/config.h -/config.h.in -/config.log -/config.status -/configure -/depcomp -/eth_test -/gen_eth_packets -/ibs_rx_test -/ibs_tx_test -/install-sh -/libtool -/ltmain.sh -/missing -/py-compile -/rcv_eth_packets -/run_tests.sh -/stamp-h1 -/test1 -/test_phy_comm -/timer_test -/buf_ram_test -/buf_ram_zero -/hello diff --git a/firmware/microblaze/lib/Makefile.am b/firmware/microblaze/lib/Makefile.am deleted file mode 100644 index b51d74463..000000000 --- a/firmware/microblaze/lib/Makefile.am +++ /dev/null @@ -1,87 +0,0 @@ -# -# Copyright 2010 Ettus Research LLC -# -# Copyright 2007 Free Software Foundation, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. -# - -include $(top_srcdir)/Makefile.common - -noinst_LIBRARIES = \ -	libu2fw.a - -libu2fw_a_SOURCES = \ -	abort.c \ -	ad9510.c \ -	bsm12.c \ -	buffer_pool.c \ -	clocks.c \ -	dbsm.c \ -	eeprom.c \ -	ethernet.c \ -	eth_mac.c \ -	_exit.c \ -	exit.c \ -	hal_io.c \ -	hal_uart.c \ -	i2c.c \ -	mdelay.c \ -	memcpy_wa.c \ -	memset_wa.c \ -	nonstdio.c \ -	pic.c \ -	print_mac_addr.c \ -	print_rmon_regs.c \ -	print_buffer.c \ -	printf.c \ -	sd.c \ -	spi.c \ -	u2_init.c \ -	net_common.c \ -	arp_cache.c \ -	banal.c - -noinst_HEADERS = \ -	ad9510.h \ -	bsm12.h \ -	buffer_pool.h \ -	clocks.h \ -	dbsm.h \ -	eth_mac.h \ -	eth_mac_regs.h \ -	eth_phy.h \ -	ethernet.h \ -	hal_io.h \ -	hal_uart.h \ -	i2c.h \ -	mdelay.h \ -	memcpy_wa.h \ -	memory_map.h \ -	memset_wa.h \ -	nonstdio.h \ -	pic.h \ -	print_rmon_regs.h \ -	sd.h \ -	spi.h \ -	stdint.h \ -	stdio.h \ -	u2_init.h \ -	usrp2_bytesex.h \ -	wb16550.h \ -	net_common.h \ -	if_arp.h \ -	arp_cache.h \ -	banal.h \ -	ethertype.h diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc new file mode 100644 index 000000000..a576d1ccb --- /dev/null +++ b/firmware/microblaze/lib/Makefile.inc @@ -0,0 +1,47 @@ +# +# Copyright 2010 Ettus Research LLC +# +# Copyright 2007 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +COMMON_SRCS = \ +	$(top_srcdir)/lib/u2_init.c \ +	$(top_srcdir)/lib/abort.c \ +	$(top_srcdir)/lib/ad9510.c \ +	$(top_srcdir)/lib/bsm12.c \ +	$(top_srcdir)/lib/buffer_pool.c \ +	$(top_srcdir)/lib/clocks.c \ +	$(top_srcdir)/lib/dbsm.c \ +	$(top_srcdir)/lib/eeprom.c \ +	$(top_srcdir)/lib/eth_mac.c \ +	$(top_srcdir)/lib/_exit.c \ +	$(top_srcdir)/lib/exit.c \ +	$(top_srcdir)/lib/hal_io.c \ +	$(top_srcdir)/lib/hal_uart.c \ +	$(top_srcdir)/lib/i2c.c \ +	$(top_srcdir)/lib/mdelay.c \ +	$(top_srcdir)/lib/memcpy_wa.c \ +	$(top_srcdir)/lib/memset_wa.c \ +	$(top_srcdir)/lib/nonstdio.c \ +	$(top_srcdir)/lib/pic.c \ +	$(top_srcdir)/lib/print_mac_addr.c \ +	$(top_srcdir)/lib/print_rmon_regs.c \ +	$(top_srcdir)/lib/print_buffer.c \ +	$(top_srcdir)/lib/printf.c \ +	$(top_srcdir)/lib/spi.c \ +	$(top_srcdir)/lib/net_common.c \ +	$(top_srcdir)/lib/arp_cache.c \ +	$(top_srcdir)/lib/banal.c diff --git a/firmware/microblaze/include/usrp2_clock_bits.h b/firmware/microblaze/lib/clock_bits.h index d2052e941..d2052e941 100644 --- a/firmware/microblaze/include/usrp2_clock_bits.h +++ b/firmware/microblaze/lib/clock_bits.h diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c index ccc4a7cc7..2b352a385 100644 --- a/firmware/microblaze/lib/clocks.c +++ b/firmware/microblaze/lib/clocks.c @@ -25,40 +25,60 @@  #include "ad9510.h"  #include "spi.h"  #include "u2_init.h" -#include "nonstdio.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 + +//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.  void   clocks_init(void)  {    // Set up basic clocking functions in AD9510 -  ad9510_write_reg(0x45, 0x00); // CLK2 drives distribution +  ad9510_write_reg(0x45, 0x01); // CLK2 drives distribution +  //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 +//  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 +//  ad9510_write_reg(0x5A, 0x01); // Update Regs    // Primary clock configuration -  clocks_mimo_config(MC_WE_DONT_LOCK); +//  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); +//  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)  { @@ -86,7 +106,7 @@ clocks_mimo_config(int flags)    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 @@ -103,18 +123,17 @@ clocks_mimo_config(int flags)    }    // 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);  +//  if (flags & MC_PROVIDE_CLK_TO_MIMO) +//    clocks_enable_clkexp_out(true,10); +//  else +//    clocks_enable_clkexp_out(false,0);   } +*/  bool   clocks_lock_detect()  { -  if(pic_regs->pending & PIC_CLKSTATUS) -    return true; -  return false; +    return (pic_regs->pending & PIC_CLKSTATUS);  }  int inline @@ -136,21 +155,23 @@ clocks_gen_div(int divisor)  #define CLOCK_MODE_LVDS 2  #define CLOCK_MODE_CMOS 3 +//CHANGED: set to PECL for default behavior  void   clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode)  {    int enable_word, div_word, div_en_word;    switch(mode) { -  case CLOCK_MODE_PECL : -    enable_word = enable ? 0x08 : 0x0A; -    break;    case CLOCK_MODE_LVDS :      enable_word = enable ? 0x02 : 0x03;      break;    case CLOCK_MODE_CMOS :      enable_word = enable ? 0x08 : 0x09;      break; +  case CLOCK_MODE_PECL : +	default: +    enable_word = enable ? 0x08 : 0x0A; +    break;    }    if(enable && (divisor>1)) {      div_word = clocks_gen_div(divisor); @@ -180,8 +201,8 @@ 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 2 on Rev 3, Clock 5 on Rev 4, Clock 6 on USRP2+  void  clocks_enable_clkexp_out(bool enable, int divisor)  { @@ -192,13 +213,19 @@ clocks_enable_clkexp_out(bool enable, int divisor)      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: Invalid Rev\n"); +    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 +*/ +/* +// Clock 5 on Rev 3, none (was 2) on Rev 4, none on USRP2+  void  clocks_enable_eth_phyclk(bool enable, int divisor)  { @@ -207,9 +234,9 @@ clocks_enable_eth_phyclk(bool enable, int divisor)    else if(u2_hw_rev_major == 4)      clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL);    else -    putstr("ERR: Invalid Rev\n"); +    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) diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h index 43d5a05c2..28d1d542f 100644 --- a/firmware/microblaze/lib/clocks.h +++ b/firmware/microblaze/lib/clocks.h @@ -26,7 +26,7 @@   */  #include <stdbool.h> -#include <usrp2_clock_bits.h> +#include "clock_bits.h"  /*! @@ -43,7 +43,7 @@ void clocks_init(void);   * 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); +//void clocks_mimo_config(int flags);  /*!   * \brief Lock Detect -- Return True if our PLL is locked @@ -63,12 +63,12 @@ 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); +//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); +//void clocks_enable_eth_phyclk(bool enable, int divisor);  /*!   * \brief Enable or disable clock to DAC diff --git a/firmware/microblaze/include/compiler.h b/firmware/microblaze/lib/compiler.h index 4fa9b49f8..4fa9b49f8 100644 --- a/firmware/microblaze/include/compiler.h +++ b/firmware/microblaze/lib/compiler.h diff --git a/firmware/microblaze/lib/eth_mac.c b/firmware/microblaze/lib/eth_mac.c index 375d3f4d4..034a4d494 100644 --- a/firmware/microblaze/lib/eth_mac.c +++ b/firmware/microblaze/lib/eth_mac.c @@ -83,14 +83,6 @@ eth_mac_read_rmon(int addr)  int  eth_mac_miim_read(int addr)  { -  if (hwconfig_simulation_p()){ -    switch(addr){ -    case PHY_LINK_AN: -      return LANSR_MASTER | LANSR_LINK_GOOD | LANSR_SPEED_1000; -    default: -      return 0; -    } -  }    int phy_addr = PHY_ADDR;    eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr; @@ -112,7 +104,7 @@ eth_mac_miim_write(int addr, int value)    eth_mac->miitx_data = value;    eth_mac->miicommand = MIIC_WCTRLDATA; -  //printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value); +//  printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value);    while((eth_mac->miistatus & MIIS_BUSY) != 0)      ;  } diff --git a/firmware/microblaze/lib/hal_io.c b/firmware/microblaze/lib/hal_io.c index 0afd6a2cc..58b1e681e 100644 --- a/firmware/microblaze/lib/hal_io.c +++ b/firmware/microblaze/lib/hal_io.c @@ -193,3 +193,13 @@ puts(const char *s)    putchar('\n');    return 0;  } + +char * +gets(char * const s) +{ +	char *x = s; +	while((*x=(char)hal_uart_getc()) != '\n') x++; +	*x = 0; +	return s; +} + diff --git a/firmware/microblaze/lib/hal_io.h b/firmware/microblaze/lib/hal_io.h index d8967f063..c67d96c62 100644 --- a/firmware/microblaze/lib/hal_io.h +++ b/firmware/microblaze/lib/hal_io.h @@ -23,6 +23,7 @@  void hal_io_init(void);  void hal_finish(); +char *gets(char * const s);  /*   * ------------------------------------------------------------------------ diff --git a/firmware/microblaze/lib/hal_uart.c b/firmware/microblaze/lib/hal_uart.c index 75b12b432..fe3b7515a 100644 --- a/firmware/microblaze/lib/hal_uart.c +++ b/firmware/microblaze/lib/hal_uart.c @@ -39,16 +39,25 @@ divisor_table[MAX_WB_DIV+1][NSPEEDS] = {  #define u uart_regs +static char uart_mode = UART_MODE_ONLCR; + +void +hal_uart_set_mode(int mode) +{ +  uart_mode = mode; +} +  void  hal_uart_init(void)  { +	hal_uart_set_mode(UART_MODE_ONLCR);    u->clkdiv = 217;  // 230400 bps  }  void  hal_uart_putc(int ch)  { -  if (ch == '\n')		// FIXME for now map \n -> \r\n +  if (ch == '\n')// && (uart_mode == UART_MODE_ONLCR))		//map \n->\r\n if necessary      hal_uart_putc('\r');    while (u->txlevel == 0)	 // wait for fifo to have space @@ -60,7 +69,7 @@ hal_uart_putc(int ch)  void  hal_uart_putc_nowait(int ch)  { -  if (ch == '\n')		// FIXME for now map \n -> \r\n +  if (ch == '\n')// && (uart_mode == UART_MODE_ONLCR))		//map \n->\r\n if necessary      hal_uart_putc('\r');    if(u->txlevel)   // If fifo has space diff --git a/firmware/microblaze/lib/hal_uart.h b/firmware/microblaze/lib/hal_uart.h index 2ddfa6259..dfd73c323 100644 --- a/firmware/microblaze/lib/hal_uart.h +++ b/firmware/microblaze/lib/hal_uart.h @@ -19,6 +19,16 @@  #ifndef INCLUDED_HAL_UART_H  #define INCLUDED_HAL_UART_H +/*! + * \brief uart mode flags + */ +#define	UART_MODE_RAW		0x0000	// no mapping on input or output +#define	UART_MODE_ONLCR	0x0001	// map \n to \r\n on output (default) + +/* + * \brief Set uart mode + */ +void hal_uart_set_mode(int flags);  /*!   * \brief one-time call to init diff --git a/firmware/microblaze/include/net/.gitignore b/firmware/microblaze/lib/net/.gitignore index 282522db0..282522db0 100644 --- a/firmware/microblaze/include/net/.gitignore +++ b/firmware/microblaze/lib/net/.gitignore diff --git a/firmware/microblaze/include/net/eth_mac_addr.h b/firmware/microblaze/lib/net/eth_mac_addr.h index b44fb68f7..b44fb68f7 100644 --- a/firmware/microblaze/include/net/eth_mac_addr.h +++ b/firmware/microblaze/lib/net/eth_mac_addr.h diff --git a/firmware/microblaze/include/net/padded_eth_hdr.h b/firmware/microblaze/lib/net/padded_eth_hdr.h index df816734f..df816734f 100644 --- a/firmware/microblaze/include/net/padded_eth_hdr.h +++ b/firmware/microblaze/lib/net/padded_eth_hdr.h diff --git a/firmware/microblaze/include/net/socket_address.h b/firmware/microblaze/lib/net/socket_address.h index 336f30a0c..336f30a0c 100644 --- a/firmware/microblaze/include/net/socket_address.h +++ b/firmware/microblaze/lib/net/socket_address.h diff --git a/firmware/microblaze/lib/nonstdio.c b/firmware/microblaze/lib/nonstdio.c index 1c991afee..4b5fa4123 100644 --- a/firmware/microblaze/lib/nonstdio.c +++ b/firmware/microblaze/lib/nonstdio.c @@ -78,3 +78,46 @@ puthex32_nl(unsigned long x)    puthex32(x);    newline();  } +/* +void reverse(char s[]) +{ +    int c, i, j; + +    for (i = 0, j = strlen(s)-1; i<j; i++, j--) { +        c = s[i]; +        s[i] = s[j]; +        s[j] = c; +    } +} + +int abs(signed long value) { +	return (value >= 0) ? value : 0-value; +} + +//we'll keep the puthex functions above because they're way more lightweight. but sometimes you just want to print in decimal, you know? +char *itoa(signed long value, char *result, int base) +{ +	// check that the base if valid +	if (base < 2 || base > 16) { *result = 0; return result; } + +	char* out = result; +	signed long quotient = value; + +	do { +		*out = hex[ abs(quotient % base) ]; +		++out; +		quotient /= base; +	} while ( quotient ); + +	// Only apply negative sign for base 10 +	if ( value < 0 && base == 10) *out++ = '-'; + +	*out = 0; +	reverse( result ); + +	return result; + +} +*/ + + diff --git a/firmware/microblaze/lib/nonstdio.h b/firmware/microblaze/lib/nonstdio.h index 3fd9e39bb..62ebfa46d 100644 --- a/firmware/microblaze/lib/nonstdio.h +++ b/firmware/microblaze/lib/nonstdio.h @@ -1,4 +1,6 @@ -/* -*- c -*- */ +// +// Copyright 2010 Ettus Research LLC +//  /*   * Copyright 2007 Free Software Foundation, Inc.   * @@ -20,7 +22,7 @@  #define INCLUDED_NONSTDIO_H  #include <stdio.h> -#include <usrp2_types.h> +#include <stdint.h>  #include <stddef.h>  void putstr(const char *s);		// cf puts, no added newline @@ -37,10 +39,10 @@ void puthex32_nl(unsigned long x);  void newline();				// putchar('\n')  void print_mac_addr(const unsigned char addr[6]); -void print_fxpt_freq(u2_fxpt_freq_t v); -void print_fxpt_gain(u2_fxpt_gain_t v);  void print_uint64(uint64_t v);  void print_buffer(uint32_t *buf, size_t n); +//char *itoa(signed long value, char *result, int base); +//void reverse(char s[]);  #endif /* INCLUDED_NONSTDIO_H */ diff --git a/firmware/microblaze/lib/pic.c b/firmware/microblaze/lib/pic.c index 4575bd775..e89d2b755 100644 --- a/firmware/microblaze/lib/pic.c +++ b/firmware/microblaze/lib/pic.c @@ -44,7 +44,7 @@ pic_init(void)    // uP is level triggered    pic_regs->mask = ~0;				       // mask all interrupts -  pic_regs->edge_enable = PIC_ONETIME_INT | PIC_PHY_INT; +  pic_regs->edge_enable = PIC_ONETIME_INT;    pic_regs->polarity = ~0 & ~PIC_PHY_INT;	       // rising edge    pic_regs->pending = ~0;			       // clear all pending ints  } diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c index 937397df6..bef808e57 100644 --- a/firmware/microblaze/lib/spi.c +++ b/firmware/microblaze/lib/spi.c @@ -43,7 +43,7 @@ spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags    spi_wait();    // Tell it which SPI slave device to access -  spi_regs->ss = slave & 0xff; +  spi_regs->ss = slave & 0xffff;    // Data we will send    spi_regs->txrx0 = data; diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h index f5b69b270..01e4d26fd 100644 --- a/firmware/microblaze/lib/spi.h +++ b/firmware/microblaze/lib/spi.h @@ -48,5 +48,23 @@ void spi_wait(void);  uint32_t  spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); +// ---------------------------------------------------------------- +// Routines that manipulate the FLASH SPI BUS +// ---------------------------------------------------------------- + +/*! + * \brief One time call to initialize SPI + */ +void spif_init(void); + +/*!  + * \brief Wait for last SPI transaction to complete. + * Unless you need to know it completed, it's not necessary to call this. + */ +void spif_wait(void); + +uint32_t +spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags); +  #endif /* INCLUDED_SPI_H */ diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index 6809101c0..75bc40859 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -25,9 +25,8 @@  #include "i2c.h"  #include "mdelay.h"  #include "clocks.h" -#include "usrp2_i2c_addr.h" - -//#include "nonstdio.h" +#include "usrp2/fw_common.h" +#include "nonstdio.h"  unsigned char u2_hw_rev_major;  unsigned char u2_hw_rev_minor; @@ -35,8 +34,8 @@ unsigned char u2_hw_rev_minor;  static inline void  get_hw_rev(void)  { -  bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &u2_hw_rev_minor, 1); -  ok &= eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &u2_hw_rev_major, 1); +  bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, &u2_hw_rev_minor, 1); +  ok &= eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, &u2_hw_rev_major, 1);  }  /* @@ -68,7 +67,7 @@ u2_init(void)    mdelay(100);    hal_set_leds(0x1f, 0x1f);    mdelay(100); -  hal_set_leds(0x1, 0x1f);  // Leave the first one on +  hal_set_leds(LED_D, 0x1f);  // Leave one on  #if 0    // test register readback diff --git a/firmware/microblaze/apps/.gitignore b/firmware/microblaze/usrp2/.gitignore index 968b04cd7..18f715618 100644 --- a/firmware/microblaze/apps/.gitignore +++ b/firmware/microblaze/usrp2/.gitignore @@ -1,8 +1,9 @@ -/*.elf +/Makefile +/Makefile.in +/*.a  /*.bin  /*.dump -/*.log +/*.ihx +/*.elf  /*.rom  /*.map -/Makefile -/Makefile.in diff --git a/firmware/microblaze/include/Makefile.am b/firmware/microblaze/usrp2/Makefile.am index 6afbbcd12..8da013980 100644 --- a/firmware/microblaze/include/Makefile.am +++ b/firmware/microblaze/usrp2/Makefile.am @@ -1,8 +1,6 @@  #  # Copyright 2010 Ettus Research LLC  # -# Copyright 2008 Free Software Foundation, Inc. -#  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU General Public License as published by  # the Free Software Foundation, either version 3 of the License, or @@ -19,12 +17,27 @@  include $(top_srcdir)/Makefile.common -SUBDIRS = net +AM_CFLAGS = \ +	$(COMMON_CFLAGS) + +AM_LDFLAGS = \ +	$(COMMON_LFLAGS) \ +	libusrp2.a \ +	-Wl,-defsym -Wl,_TEXT_START_ADDR=0x0050 \ +	-Wl,-defsym -Wl,_STACK_SIZE=3072 + +######################################################################## +# USRP2 specific library and programs +######################################################################## +noinst_LIBRARIES = libusrp2.a + +libusrp2_a_SOURCES = \ +	$(COMMON_SRCS) \ +	sd.c \ +	ethernet.c + +noinst_PROGRAMS = \ +	usrp2_txrx_uhd.elf -noinst_HEADERS = \ -    usrp2_fpga_regs.h \ -    usrp2_i2c_addr.h \ -    usrp2_clock_bits.h \ -    usrp2_types.h \ -    vrt/bits.h \ -    vrt/types.h +usrp2_txrx_uhd_elf_SOURCES = \ +	$(top_srcdir)/apps/txrx_uhd.c diff --git a/firmware/microblaze/lib/eth_phy.h b/firmware/microblaze/usrp2/eth_phy.h index 6c16f97b7..6c16f97b7 100644 --- a/firmware/microblaze/lib/eth_phy.h +++ b/firmware/microblaze/usrp2/eth_phy.h diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/usrp2/ethernet.c index 34a3ad7c1..d60d7dc4c 100644 --- a/firmware/microblaze/lib/ethernet.c +++ b/firmware/microblaze/usrp2/ethernet.c @@ -25,10 +25,9 @@  #include "nonstdio.h"  #include <stdbool.h>  #include "i2c.h" -#include "usrp2_i2c_addr.h" +#include "usrp2/fw_common.h" - -#define VERBOSE 0 +#define VERBOSE 1  static ethernet_t ed_state;  static ethernet_link_changed_callback_t ed_callback = 0; @@ -302,7 +301,7 @@ ethernet_mac_addr(void)        return &src_mac_addr;      eth_mac_addr_t tmp; -    bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp));      if (!ok || unprogrammed(&tmp, sizeof(tmp))){        // use the default      } @@ -316,7 +315,7 @@ ethernet_mac_addr(void)  bool  ethernet_set_mac_addr(const eth_mac_addr_t *t)  { -  bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t));    if (ok){      src_mac_addr = *t;      src_mac_addr_initialized = true; @@ -344,7 +343,7 @@ const struct ip_addr *get_ip_addr(void)        return &src_ip_addr;      struct ip_addr tmp; -    bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, &tmp, sizeof(tmp)); +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp));      if (!ok || unprogrammed(&tmp, sizeof(tmp))){        // use the default      } @@ -356,7 +355,7 @@ const struct ip_addr *get_ip_addr(void)  }  bool set_ip_addr(const struct ip_addr *t){ -  bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr));    if (ok){      src_ip_addr = *t;      src_ip_addr_initialized = true; diff --git a/firmware/microblaze/lib/memory_map.h b/firmware/microblaze/usrp2/memory_map.h index cdf3dd338..41a2820bc 100644 --- a/firmware/microblaze/lib/memory_map.h +++ b/firmware/microblaze/usrp2/memory_map.h @@ -89,6 +89,7 @@ typedef struct {  #define SPI_SS_TX_DAC   32  #define SPI_SS_TX_ADC   64  #define SPI_SS_TX_DB   128 +#define SPI_SS_ADS64P44 256  // Masks for different parts of CTRL reg  #define SPI_CTRL_ASS      (1<<13) @@ -374,6 +375,10 @@ typedef struct {    volatile uint32_t     led_src;        // HW or SW control for LEDs  } output_regs_t; +#define CLK_RESET  (1<<4) +#define CLK_ENABLE (1<<3) | (1<<2) +#define CLK_SEL    (1<<1) | (1<<0) +  #define SERDES_ENABLE 8  #define SERDES_PRBSEN 4  #define SERDES_LOOPEN 2 diff --git a/firmware/microblaze/lib/sd.c b/firmware/microblaze/usrp2/sd.c index d000b28ae..d000b28ae 100644 --- a/firmware/microblaze/lib/sd.c +++ b/firmware/microblaze/usrp2/sd.c diff --git a/firmware/microblaze/lib/sd.h b/firmware/microblaze/usrp2/sd.h index e2d0ae38e..e2d0ae38e 100644 --- a/firmware/microblaze/lib/sd.h +++ b/firmware/microblaze/usrp2/sd.h diff --git a/fpga/usrp2/control_lib/Makefile.srcs b/fpga/usrp2/control_lib/Makefile.srcs index 5e2a96a53..bc8e4d5bc 100644 --- a/fpga/usrp2/control_lib/Makefile.srcs +++ b/fpga/usrp2/control_lib/Makefile.srcs @@ -20,6 +20,7 @@ mux8.v \  nsgpio.v \  ram_2port.v \  ram_harv_cache.v \ +ram_harvard.v \  ram_loader.v \  setting_reg.v \  settings_bus.v \ diff --git a/fpga/usrp2/control_lib/ram_harvard.v b/fpga/usrp2/control_lib/ram_harvard.v new file mode 100644 index 000000000..948f9b36f --- /dev/null +++ b/fpga/usrp2/control_lib/ram_harvard.v @@ -0,0 +1,69 @@ + + +// Dual ported, Harvard architecture, cached ram + +module ram_harvard +  #(parameter AWIDTH=15, +    parameter RAM_SIZE=16384, +    parameter ICWIDTH=6, +    parameter DCWIDTH=6) +    +    (input wb_clk_i,  +     input wb_rst_i, +     // Firmware download port. +     input [AWIDTH-1:0] ram_loader_adr_i, +     input [31:0] ram_loader_dat_i, +     input [3:0] ram_loader_sel_i, +     input ram_loader_stb_i, +     input ram_loader_we_i, +     input ram_loader_done_i,     +     // Instruction fetch port. +     input [AWIDTH-1:0] if_adr, +     output [31:0] if_data, +     // Data access port. +     input [AWIDTH-1:0] dwb_adr_i, +     input [31:0] dwb_dat_i,  +     output [31:0] dwb_dat_o, +     input dwb_we_i, +     output dwb_ack_o, +     input dwb_stb_i, +     input [3:0] dwb_sel_i, + +     input flush_icache ); + +   reg 	   ack_d1; +   reg 	   stb_d1; +    +   dpram32 #(.AWIDTH(AWIDTH),.RAM_SIZE(RAM_SIZE))  +   sys_ram +     (.clk(wb_clk_i), +      .adr1_i(ram_loader_done_i ? if_adr : ram_loader_adr_i), +      .dat1_i(ram_loader_dat_i), +      .dat1_o(if_data), +      .we1_i(ram_loader_done_i ? 1'b0 : ram_loader_we_i), +      .en1_i(ram_loader_done_i ? 1'b1 : ram_loader_stb_i), +      //.sel1_i(ram_loader_done_i ? 4'hF : ram_loader_sel_i), +      .sel1_i(ram_loader_sel_i), // Sel is only for writes anyway +      .adr2_i(dwb_adr_i), +      .dat2_i(dwb_dat_i), +      .dat2_o(dwb_dat_o), +      .we2_i(dwb_we_i), +      .en2_i(dwb_stb_i), +      .sel2_i(dwb_sel_i)  +      ); + +   assign dwb_ack_o = dwb_stb_i & (dwb_we_i | (stb_d1 & ~ack_d1)); + +   always @(posedge wb_clk_i)  +     if(wb_rst_i) +       ack_d1 <= 1'b0; +     else  +       ack_d1 <= dwb_ack_o; + +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       stb_d1 <= 0; +     else +       stb_d1 <= dwb_stb_i; + +endmodule // ram_harvard diff --git a/fpga/usrp2/control_lib/ram_loader.v b/fpga/usrp2/control_lib/ram_loader.v index cb67de739..c53ea7aa7 100644 --- a/fpga/usrp2/control_lib/ram_loader.v +++ b/fpga/usrp2/control_lib/ram_loader.v @@ -1,225 +1,261 @@ +module ram_loader +  #(parameter AWIDTH=16, RAM_SIZE=16384) +    ( +     // Wishbone I/F and clock domain +     input wb_clk, +     input dsp_clk, +     input ram_loader_rst, +     output wire [31:0] wb_dat, +     output wire [AWIDTH-1:0] wb_adr, +     output wb_stb, +     output reg [3:0] wb_sel, +     output wb_we, +     output reg ram_loader_done, +     // CPLD signals and clock domain +     input cpld_clk, +     input cpld_din, +     output reg cpld_start, +     output reg cpld_mode, +     output reg cpld_done, +     input cpld_detached +     ); -// Adapted from VHDL code in spi_boot by Arnim Legauer -//  Added a full wishbone master interface (32-bit) - -module ram_loader #(parameter AWIDTH=16, RAM_SIZE=16384) -  (input clk_i, input rst_i, -   // CPLD Interface -   input cfg_clk_i, input cfg_data_i, -   output start_o, output mode_o, output done_o, -   input detached_i, -   // Wishbone interface -   output wire [31:0] wb_dat_o, -   output reg [AWIDTH-1:0] wb_adr_o, -   output wb_stb_o, -   output wb_cyc_o, -   output reg [3:0] wb_sel_o, -   output reg wb_we_o, -   input wb_ack_i, -   output ram_loader_done_o); +   localparam S0 = 0; +   localparam S1 = 1; +   localparam S2 = 2; +   localparam S3 = 3; +   localparam S4 = 4; +   localparam S5 = 5; +   localparam S6 = 6; +   localparam RESET = 7; -   //  FSM to control start signal, clocked on main clock -   localparam FSM1_WAIT_DETACH = 2'b00; -   localparam FSM1_CHECK_NO_DONE = 2'b01; -   localparam FSM1_WAIT_DONE = 2'b10; -    -   reg [1:0]  start_fsm_q, start_fsm_s; -   reg 	      start_q, enable_q, start_s, enable_s; -   reg 	      done_q, done_s; +   localparam WB_IDLE = 0; +   localparam WB_WRITE = 1; +   + +   reg [AWIDTH+2:0] count;       // 3 LSB's count bits in, the MSB's generate the Wishbone address +   reg [6:0] 	    shift_reg; +   reg [7:0] 	    data_reg; +   reg 		    sampled_clk; +   reg 		    sampled_clk_meta; +   reg 		    sampled_din; +   reg 		    inc_count; +   reg 		    load_data_reg; +   reg 		    shift;   +   reg 		    wb_state, wb_next_state; +   reg [2:0] 	    state, next_state; +     +   // +   // CPLD clock doesn't free run and is approximately 12.5MHz. +   // Use 50MHz Wishbone clock to sample it as a signal and avoid having +   // an extra clock domain for no reason. +   // + +   always @(posedge dsp_clk or posedge ram_loader_rst) +      if (ram_loader_rst) +	begin +	   sampled_clk_meta <= 1'b0; +	   sampled_clk <= 1'b0; +	   sampled_din <= 1'b0; +	   count <= 'h7FFF8;  // Initialize so that address will be 0 when first byte fully received. +	   data_reg <= 0; +	   shift_reg <= 0; +	end +      else  +	begin +	   sampled_clk_meta <= cpld_clk; +	   sampled_clk <= sampled_clk_meta; +	   sampled_din <= cpld_din; +	   if (inc_count) +	     count <= count + 1'b1; +	   if (load_data_reg) +	     data_reg <= {shift_reg,sampled_din}; +	   if (shift) +	     shift_reg <= {shift_reg[5:0],sampled_din};	    +	end // else: !if(ram_loader_rst) -   always @(posedge clk_i or posedge rst_i) -     if(rst_i) -       begin -	  start_fsm_q <= FSM1_WAIT_DETACH; -	  start_q <= 1'b0; -	  enable_q <= 1'b0; -       end +	    +   always @(posedge dsp_clk or posedge ram_loader_rst) +     if (ram_loader_rst) +       state <= RESET;       else -       begin -	  start_fsm_q <= start_fsm_s; -	  enable_q <= enable_s; -	  start_q <= start_s; -       end // else: !if(rst_i) -    +       state <= next_state; + +     always @* -     case(start_fsm_q) -       FSM1_WAIT_DETACH: -	 if(detached_i == 1'b1) -	   begin -	      start_fsm_s <= FSM1_CHECK_NO_DONE; -	      enable_s <= 1'b1; -	      start_s <= 1'b1; -	   end -	 else -	   begin -	      start_fsm_s <= FSM1_WAIT_DETACH; -	      enable_s <= enable_q; -	      start_s <= start_q; -	   end // else: !if(detached_i == 1'b1) -       FSM1_CHECK_NO_DONE: -	 if(~done_q) -	   begin -	      start_fsm_s  <= FSM1_WAIT_DONE; -	      enable_s <= enable_q; -	      start_s <= start_q; -	   end -	 else -	   begin -	      start_fsm_s  <= FSM1_CHECK_NO_DONE; -	      enable_s <= enable_q; -	      start_s <= start_q; -	   end // else: !if(~done_q) -       FSM1_WAIT_DONE: -	 if(done_q) -	   begin -	      start_fsm_s  <= FSM1_WAIT_DETACH; -	      enable_s <= 1'b0; -	      start_s <= 1'b0; -	   end -	 else -	   begin -	      start_fsm_s  <= FSM1_WAIT_DONE; -	      enable_s <= enable_q; -	      start_s <= start_q; -	   end // else: !if(done_q) -       default: -	 begin -	    start_fsm_s  <= FSM1_WAIT_DETACH; -	    enable_s <= enable_q; -	    start_s <= start_q; -	 end // else: !if(done_q) -     endcase // case(start_fsm_q) -    -   //  FSM running on data clock - -   localparam FSM2_IDLE = 3'b000; -   localparam FSM2_WE_ON = 3'b001; -   localparam FSM2_WE_OFF = 3'b010; -   localparam FSM2_INC_ADDR1 = 3'b011; -   localparam FSM2_INC_ADDR2 = 3'b100; -   localparam FSM2_FINISHED = 3'b101; -    -   reg [AWIDTH-1:0] addr_q; -   reg [7:0] 	    shift_dat_q, ser_dat_q; -   reg [2:0] 	    bit_q, fsm_q, fsm_s; -   reg 		    bit_ovfl_q, ram_we_s, ram_we_q, mode_q, mode_s, inc_addr_s; -    -   always @(posedge cfg_clk_i or posedge rst_i) -     if(rst_i) -       begin -	  addr_q <= 0; -	  shift_dat_q <= 8'd0; -	  ser_dat_q <= 8'd0; -	  bit_q <= 3'd0; -	  bit_ovfl_q <= 1'b0; -	  fsm_q <= FSM2_IDLE; -	  ram_we_q <= 1'b0; -	  done_q <= 1'b0; -	  mode_q <= 1'b0; -       end +     begin +	// Defaults +	next_state = state; +	cpld_start = 1'b0; +	shift = 1'b0; +	inc_count = 0; +	load_data_reg = 1'b0; +	ram_loader_done = 1'b0; +	cpld_mode = 1'b0; +	cpld_done = 1'b1; +	 +	 +	 +	case (state) //synthesis parallel_case full_case +	  // After reset wait until CPLD indicates its detached. +	  RESET: begin		      +	     if (cpld_detached) +	       next_state = S0; +	     else +	       next_state = RESET; +	  end + +	  // Assert cpld_start to signal the CPLD its to start sending serial clock and data. +	  // Assume cpld_clk is low as we transition into search for first rising edge +	  S0: begin +	     cpld_start = 1'b1;	  +	     cpld_done = 1'b0;	  +	     if (~cpld_detached) +	       next_state = S2; +	     else +	       next_state = S0;    +	  end +	   +	  // +	  S1: begin +	     cpld_start = 1'b1;	    +	     cpld_done = 1'b0;	  +	     if (sampled_clk) +	       begin +		  // Found rising edge on cpld_clk. +		  if (count[2:0] == 3'b111) +		    // Its the last bit of a byte, send it out to the Wishbone bus. +		    begin +		       load_data_reg = 1'b1; +		       inc_count = 1'b1; +		    end +		  else  +	          // Shift databit into LSB of shift register and increment count +		     begin +		       shift = 1'b1; +		       inc_count = 1'b1; +		     end // else: !if(count[2:0] == 3'b111) +		  next_state = S2; +	       end // if (sampled_clk) +	     else +	       next_state = S1; +	  end // case: S1 +	   +	  // +	  S2: begin +	     cpld_start = 1'b1;	     +	     cpld_done = 1'b0; +	     if (~sampled_clk) +	       // Found negative edge of clock +	       if (count[AWIDTH+2:3] == RAM_SIZE-1) // NOTE need to change this constant +		 // All firmware now downloaded +		 next_state = S3; +	       else +		 next_state = S1; +	     else +	       next_state = S2; +	  end // case: S2 +	   +	  // Now that terminal count is reached and all firmware is downloaded signal CPLD that download is done  +	  // and that mode is now SPI mode. +	  S3: begin +	     if (sampled_clk) +	       begin +		  cpld_mode = 1'b1; +		  cpld_done = 1'b1; +		  next_state = S4; +	       end +	     else +	       next_state = S3;	      +	  end + +	  // Search for negedge of cpld_clk whilst keeping done sequence asserted. +	  // Keep done assserted  +	  S4: begin +	     cpld_mode = 1'b1; +	     cpld_done = 1'b1; +	     if (~sampled_clk) +	       next_state = S5; +	     else +	       next_state = S4; +	  end + +	  // Search for posedge of cpld_clk whilst keeping done sequence asserted. +	  S5: begin +	     cpld_mode = 1'b1; +	     cpld_done = 1'b1; +	     if (sampled_clk) +	       next_state = S6; +	     else	       +	       next_state = S5;	        +	  end + +	  // Stay in this state until reset/power down +	  S6: begin +	     ram_loader_done = 1'b1; +	     cpld_done = 1'b1; +	     cpld_mode = 1'b1; +	     next_state = S6; +	  end + +	endcase // case(state) +     end + +   always @(posedge dsp_clk or posedge ram_loader_rst) +     if (ram_loader_rst) +       wb_state <= WB_IDLE;       else -       begin -	  if(inc_addr_s) -	    addr_q <= addr_q + 1; -	  if(enable_q) -	    begin -	       bit_q <= bit_q + 1; -	       bit_ovfl_q <= (bit_q == 3'd7); -	       shift_dat_q[0] <= cfg_data_i; -	       shift_dat_q[7:1] <= shift_dat_q[6:0]; -	    end -	  if(bit_ovfl_q) -	    ser_dat_q <= shift_dat_q; - -	  fsm_q <= fsm_s; - -	  ram_we_q <= ram_we_s; - -	  if(done_s) -	    done_q <= 1'b1; -	  mode_q <= mode_s; -       end // else: !if(rst_i) +       wb_state <= wb_next_state; +   reg do_write; +   wire empty, full; +        always @*       begin -	inc_addr_s <= 1'b0; -	ram_we_s <= 1'b0; -	done_s <= 1'b0; -	fsm_s <= FSM2_IDLE; -	mode_s <= 1'b0; - -	case(fsm_q) -	  FSM2_IDLE : -	    if(start_q) -	      if(bit_ovfl_q) -		fsm_s <= FSM2_WE_ON; -	  FSM2_WE_ON: -	    begin -	       ram_we_s <= 1'b1; -	       fsm_s <= FSM2_WE_OFF; -	    end -	  FSM2_WE_OFF: -	    begin -	       ram_we_s <= 1'b1; -	       fsm_s <= FSM2_INC_ADDR1; -	    end -	  FSM2_INC_ADDR1: -	    fsm_s <= FSM2_INC_ADDR2; -	  FSM2_INC_ADDR2: -	    if(addr_q == (RAM_SIZE-1)) -	    //if(&addr_q) -	      begin -		 fsm_s <= FSM2_FINISHED; -		 done_s <= 1'b1; -		 mode_s <= 1'b1; -	      end -	    else -	      begin -		 inc_addr_s <= 1'b1; -		 fsm_s <= FSM2_IDLE; -	      end // else: !if(&addr_q) -	  FSM2_FINISHED: -	    begin -	       fsm_s <= FSM2_FINISHED; -	       mode_s <= 1'b1; -	    end -	endcase // case(fsm_q) +	wb_next_state = wb_state; +	do_write = 1'b0; +	 +	case (wb_state) //synthesis full_case parallel_case +	  // +	  WB_IDLE: begin +	     if (load_data_reg) +	       // Data reg will load ready to write wishbone @ next clock edge +	       wb_next_state  =  WB_WRITE; +	     else +	       wb_next_state = WB_IDLE; +	  end + +	  // Drive address and data onto wishbone. +	  WB_WRITE: begin +      	     do_write = 1'b1; +	     if (~full)	        +	       wb_next_state =  WB_IDLE;		       +	     else +	       wb_next_state = WB_WRITE;	        +	  end + +	endcase // case(wb_state)       end // always @ * -   assign start_o = start_q; -   assign mode_o = mode_q; -   assign done_o = start_q ? done_q : 1'b1; -   wire [AWIDTH-1:0] ram_addr = addr_q; -   wire [7:0] ram_data = ser_dat_q; -   assign ram_loader_done_o = (fsm_q == FSM2_FINISHED); -    -   // wishbone master, only writes -   reg [7:0] dat_holder; -   assign    wb_dat_o = {4{dat_holder}}; -   assign    wb_stb_o = wb_we_o; -   assign    wb_cyc_o = wb_we_o; +   wire [1:0] count_out; +   wire [7:0] data_out; + +   fifo_xlnx_16x40_2clk crossclk +     (.rst(ram_loader_rst), +      .wr_clk(dsp_clk), .din({count[4:3],count[AWIDTH+2:3],data_reg}), .wr_en(do_write), .full(full), +      .rd_clk(wb_clk), .dout({count_out,wb_adr,data_out}), .rd_en(~empty), .empty(empty)); + +   assign wb_dat = {4{data_out}}; + +   always @* +     case(count_out[1:0]) //synthesis parallel_case full_case +       2'b00 : wb_sel = 4'b1000; +       2'b01 : wb_sel = 4'b0100; +       2'b10 : wb_sel = 4'b0010; +       2'b11 : wb_sel = 4'b0001; +     endcase + +   assign wb_we = ~empty; +   assign wb_stb = ~empty; -   always @(posedge clk_i or posedge rst_i) -     if(rst_i) -       begin -	  dat_holder <= 8'd0; -	  wb_adr_o <= 0; -	  wb_sel_o <= 4'b0000; -	  wb_we_o <= 1'b0; -       end -     else if(ram_we_q) -       begin -	  dat_holder <= ram_data; -	  wb_adr_o <= ram_addr; -	  wb_we_o <= 1'b1; -	  case(ram_addr[1:0])   // Big Endian -	    2'b00 : wb_sel_o <= 4'b1000; -	    2'b01 : wb_sel_o <= 4'b0100; -	    2'b10 : wb_sel_o <= 4'b0010; -	    2'b11 : wb_sel_o <= 4'b0001; -	  endcase // case(ram_addr[1:0]) -       end // if (ram_we_q) -     else if(wb_ack_i) -       wb_we_o <= 1'b0; -        endmodule // ram_loader diff --git a/fpga/usrp2/fifo/Makefile.srcs b/fpga/usrp2/fifo/Makefile.srcs index 22867da7e..c66979132 100644 --- a/fpga/usrp2/fifo/Makefile.srcs +++ b/fpga/usrp2/fifo/Makefile.srcs @@ -20,4 +20,6 @@ fifo19_to_ll8.v \  ll8_to_fifo19.v \  fifo36_to_fifo19.v \  fifo19_to_fifo36.v \ +fifo36_mux.v \ +fifo36_demux.v \  )) diff --git a/fpga/usrp2/fifo/fifo36_demux.v b/fpga/usrp2/fifo/fifo36_demux.v new file mode 100644 index 000000000..a54759d4d --- /dev/null +++ b/fpga/usrp2/fifo/fifo36_demux.v @@ -0,0 +1,50 @@ + +// Demux packets from a fifo based on the contents of the first line +//  If first line matches the parameter and mask, send to data1, otherwise send to data0 + +module fifo36_demux +  #(parameter match_data = 0, +    parameter match_mask = 0) +   (input clk, input reset, input clear, +    input [35:0] data_i, input src_rdy_i, output dst_rdy_o, +    output [35:0] data0_o, output src0_rdy_o, input dst0_rdy_i, +    output [35:0] data1_o, output src1_rdy_o, input dst1_rdy_i); + +   localparam DMX_IDLE = 0; +   localparam DMX_DATA0 = 1; +   localparam DMX_DATA1 = 2; +    +   reg [1:0] 	  state; + +   wire 	  match = |( (data_i ^ match_data) & match_mask ); +   wire 	  eof = data_i[33]; +    +   always @(posedge clk) +     if(reset | clear) +       state <= DMX_IDLE; +     else +       case(state) +	 DMX_IDLE : +	   if(src_rdy_i) +	     if(match) +	       state <= DMX_DATA1; +	     else +	       state <= DMX_DATA0; +	 DMX_DATA0 : +	   if(src_rdy_i & dst0_rdy_i & eof) +	     state <= DMX_IDLE; +	 DMX_DATA1 : +	   if(src_rdy_i & dst1_rdy_i & eof) +	     state <= DMX_IDLE; +	 default : +	   state <= DMX_IDLE; +       endcase // case (state) + +   assign dst_rdy_o = (state==DMX_IDLE) ? 0 : (state==DMX_DATA0) ? dst0_rdy_i : dst1_rdy_i; +   assign src0_rdy_o = (state==DMX_DATA0) ? src_rdy_i : 0; +   assign src1_rdy_o = (state==DMX_DATA1) ? src_rdy_i : 0; + +   assign data0_o = data_i; +   assign data1_o = data_i; +    +endmodule // fifo36_demux diff --git a/fpga/usrp2/fifo/fifo36_mux.v b/fpga/usrp2/fifo/fifo36_mux.v new file mode 100644 index 000000000..92bf13ff9 --- /dev/null +++ b/fpga/usrp2/fifo/fifo36_mux.v @@ -0,0 +1,57 @@ + +// Mux packets from multiple FIFO interfaces onto a single one. +//  Can alternate or give priority to one port (port 0) +//  In prio mode, port 1 will never get access if port 0 is always busy + +module fifo36_mux +  #(parameter prio = 0) +   (input clk, input reset, input clear, +    input [35:0] data0_i, input src0_rdy_i, output dst0_rdy_o, +    input [35:0] data1_i, input src1_rdy_i, output dst1_rdy_o, +    output [35:0] data_o, output src_rdy_o, input dst_rdy_i); + +   localparam MUX_IDLE0 = 0; +   localparam MUX_DATA0 = 1; +   localparam MUX_IDLE1 = 2; +   localparam MUX_DATA1 = 3; +    +   reg [1:0] 	  state; + +   wire 	  eof0 = data0_i[33]; +   wire 	  eof1 = data1_i[33]; +    +   always @(posedge clk) +     if(reset | clear) +       state <= MUX_IDLE0; +     else +       case(state) +	 MUX_IDLE0 : +	   if(src0_rdy_i) +	     state <= MUX_DATA0; +	   else if(src1_rdy_i) +	     state <= MUX_DATA1; + +	 MUX_DATA0 : +	   if(src0_rdy_i & dst_rdy_i & eof0) +	     state <= prio ? MUX_IDLE0 : MUX_IDLE1; + +	 MUX_IDLE1 : +	   if(src1_rdy_i) +	     state <= MUX_DATA1; +	   else if(src0_rdy_i) +	     state <= MUX_DATA0; +	    +	 MUX_DATA1 : +	   if(src1_rdy_i & dst_rdy_i & eof1) +	     state <= MUX_IDLE0; +	  +	 default : +	   state <= MUX_IDLE0; +       endcase // case (state) + +   assign dst0_rdy_o = (state==MUX_DATA0) ? dst_rdy_i : 0; +   assign dst1_rdy_o = (state==MUX_DATA1) ? dst_rdy_i : 0; +   assign src_rdy_o = (state==MUX_DATA0) ? src0_rdy_i : (state==MUX_DATA1) ? src1_rdy_i : 0; +   assign data_o = (state==MUX_DATA0) ? data0_i : data1_i; +    +endmodule // fifo36_demux diff --git a/fpga/usrp2/fifo/fifo_new_tb.vcd b/fpga/usrp2/fifo/fifo_new_tb.vcd deleted file mode 100644 index 796889e7d..000000000 --- a/fpga/usrp2/fifo/fifo_new_tb.vcd +++ /dev/null @@ -1,5506 +0,0 @@ -$date -	Thu Mar 19 17:21:11 2009 -$end -$version -	Icarus Verilog -$end -$timescale -	1ps -$end -$scope module fifo_new_tb $end -$var wire 1 ! dst_rdy_f36i $end -$var wire 36 " f36_in [35:0] $end -$var wire 36 # i1 [35:0] $end -$var wire 1 $ i1_dr $end -$var wire 1 % i1_sr $end -$var wire 19 & i2 [18:0] $end -$var wire 1 ' i2_dr $end -$var wire 1 ( i2_sr $end -$var wire 19 ) i3 [18:0] $end -$var wire 1 * i3_dr $end -$var wire 1 + i3_sr $end -$var wire 36 , i4 [35:0] $end -$var wire 1 - i4_sr $end -$var wire 8 . ll_data [7:0] $end -$var wire 1 / ll_dst_rdy_n $end -$var wire 1 0 ll_eof_n $end -$var wire 1 1 ll_sof_n $end -$var wire 1 2 ll_src_rdy_n $end -$var reg 1 3 clear $end -$var reg 1 4 clk $end -$var reg 16 5 count [15:0] $end -$var reg 1 6 dst_rdy_f36o $end -$var reg 32 7 f36_data [31:0] $end -$var reg 1 8 f36_eof $end -$var reg 2 9 f36_occ [1:0] $end -$var reg 1 : f36_sof $end -$var reg 1 ; i4_dr $end -$var reg 1 < rst $end -$var reg 1 = src_rdy_f36i $end -$scope module fifo_short1 $end -$var wire 1 > clear $end -$var wire 1 ? clk $end -$var wire 36 @ datain [35:0] $end -$var wire 36 A dataout [35:0] $end -$var wire 1 $ dst_rdy_i $end -$var wire 1 ! dst_rdy_o $end -$var wire 1 B read $end -$var wire 1 C reset $end -$var wire 1 D src_rdy_i $end -$var wire 1 % src_rdy_o $end -$var wire 1 E write $end -$var reg 4 F a [3:0] $end -$var reg 1 G empty $end -$var reg 1 H full $end -$var reg 5 I occupied [4:0] $end -$var reg 5 J space [4:0] $end -$scope begin gen_srl16[0] $end -$scope module srl16e $end -$var wire 1 K A0 $end -$var wire 1 L A1 $end -$var wire 1 M A2 $end -$var wire 1 N A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 O D $end -$var wire 1 P Q $end -$var reg 16 Q data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[1] $end -$scope module srl16e $end -$var wire 1 R A0 $end -$var wire 1 S A1 $end -$var wire 1 T A2 $end -$var wire 1 U A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 V D $end -$var wire 1 W Q $end -$var reg 16 X data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[2] $end -$scope module srl16e $end -$var wire 1 Y A0 $end -$var wire 1 Z A1 $end -$var wire 1 [ A2 $end -$var wire 1 \ A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 ] D $end -$var wire 1 ^ Q $end -$var reg 16 _ data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[3] $end -$scope module srl16e $end -$var wire 1 ` A0 $end -$var wire 1 a A1 $end -$var wire 1 b A2 $end -$var wire 1 c A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 d D $end -$var wire 1 e Q $end -$var reg 16 f data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[4] $end -$scope module srl16e $end -$var wire 1 g A0 $end -$var wire 1 h A1 $end -$var wire 1 i A2 $end -$var wire 1 j A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 k D $end -$var wire 1 l Q $end -$var reg 16 m data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[5] $end -$scope module srl16e $end -$var wire 1 n A0 $end -$var wire 1 o A1 $end -$var wire 1 p A2 $end -$var wire 1 q A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 r D $end -$var wire 1 s Q $end -$var reg 16 t data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[6] $end -$scope module srl16e $end -$var wire 1 u A0 $end -$var wire 1 v A1 $end -$var wire 1 w A2 $end -$var wire 1 x A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 y D $end -$var wire 1 z Q $end -$var reg 16 { data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[7] $end -$scope module srl16e $end -$var wire 1 | A0 $end -$var wire 1 } A1 $end -$var wire 1 ~ A2 $end -$var wire 1 !" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 "" D $end -$var wire 1 #" Q $end -$var reg 16 $" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[8] $end -$scope module srl16e $end -$var wire 1 %" A0 $end -$var wire 1 &" A1 $end -$var wire 1 '" A2 $end -$var wire 1 (" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 )" D $end -$var wire 1 *" Q $end -$var reg 16 +" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[9] $end -$scope module srl16e $end -$var wire 1 ," A0 $end -$var wire 1 -" A1 $end -$var wire 1 ." A2 $end -$var wire 1 /" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 0" D $end -$var wire 1 1" Q $end -$var reg 16 2" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[10] $end -$scope module srl16e $end -$var wire 1 3" A0 $end -$var wire 1 4" A1 $end -$var wire 1 5" A2 $end -$var wire 1 6" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 7" D $end -$var wire 1 8" Q $end -$var reg 16 9" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[11] $end -$scope module srl16e $end -$var wire 1 :" A0 $end -$var wire 1 ;" A1 $end -$var wire 1 <" A2 $end -$var wire 1 =" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 >" D $end -$var wire 1 ?" Q $end -$var reg 16 @" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[12] $end -$scope module srl16e $end -$var wire 1 A" A0 $end -$var wire 1 B" A1 $end -$var wire 1 C" A2 $end -$var wire 1 D" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 E" D $end -$var wire 1 F" Q $end -$var reg 16 G" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[13] $end -$scope module srl16e $end -$var wire 1 H" A0 $end -$var wire 1 I" A1 $end -$var wire 1 J" A2 $end -$var wire 1 K" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 L" D $end -$var wire 1 M" Q $end -$var reg 16 N" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[14] $end -$scope module srl16e $end -$var wire 1 O" A0 $end -$var wire 1 P" A1 $end -$var wire 1 Q" A2 $end -$var wire 1 R" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 S" D $end -$var wire 1 T" Q $end -$var reg 16 U" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[15] $end -$scope module srl16e $end -$var wire 1 V" A0 $end -$var wire 1 W" A1 $end -$var wire 1 X" A2 $end -$var wire 1 Y" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 Z" D $end -$var wire 1 [" Q $end -$var reg 16 \" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[16] $end -$scope module srl16e $end -$var wire 1 ]" A0 $end -$var wire 1 ^" A1 $end -$var wire 1 _" A2 $end -$var wire 1 `" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 a" D $end -$var wire 1 b" Q $end -$var reg 16 c" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[17] $end -$scope module srl16e $end -$var wire 1 d" A0 $end -$var wire 1 e" A1 $end -$var wire 1 f" A2 $end -$var wire 1 g" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 h" D $end -$var wire 1 i" Q $end -$var reg 16 j" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[18] $end -$scope module srl16e $end -$var wire 1 k" A0 $end -$var wire 1 l" A1 $end -$var wire 1 m" A2 $end -$var wire 1 n" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 o" D $end -$var wire 1 p" Q $end -$var reg 16 q" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[19] $end -$scope module srl16e $end -$var wire 1 r" A0 $end -$var wire 1 s" A1 $end -$var wire 1 t" A2 $end -$var wire 1 u" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 v" D $end -$var wire 1 w" Q $end -$var reg 16 x" data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[20] $end -$scope module srl16e $end -$var wire 1 y" A0 $end -$var wire 1 z" A1 $end -$var wire 1 {" A2 $end -$var wire 1 |" A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 }" D $end -$var wire 1 ~" Q $end -$var reg 16 !# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[21] $end -$scope module srl16e $end -$var wire 1 "# A0 $end -$var wire 1 ## A1 $end -$var wire 1 $# A2 $end -$var wire 1 %# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 &# D $end -$var wire 1 '# Q $end -$var reg 16 (# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[22] $end -$scope module srl16e $end -$var wire 1 )# A0 $end -$var wire 1 *# A1 $end -$var wire 1 +# A2 $end -$var wire 1 ,# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 -# D $end -$var wire 1 .# Q $end -$var reg 16 /# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[23] $end -$scope module srl16e $end -$var wire 1 0# A0 $end -$var wire 1 1# A1 $end -$var wire 1 2# A2 $end -$var wire 1 3# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 4# D $end -$var wire 1 5# Q $end -$var reg 16 6# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[24] $end -$scope module srl16e $end -$var wire 1 7# A0 $end -$var wire 1 8# A1 $end -$var wire 1 9# A2 $end -$var wire 1 :# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 ;# D $end -$var wire 1 <# Q $end -$var reg 16 =# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[25] $end -$scope module srl16e $end -$var wire 1 ># A0 $end -$var wire 1 ?# A1 $end -$var wire 1 @# A2 $end -$var wire 1 A# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 B# D $end -$var wire 1 C# Q $end -$var reg 16 D# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[26] $end -$scope module srl16e $end -$var wire 1 E# A0 $end -$var wire 1 F# A1 $end -$var wire 1 G# A2 $end -$var wire 1 H# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 I# D $end -$var wire 1 J# Q $end -$var reg 16 K# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[27] $end -$scope module srl16e $end -$var wire 1 L# A0 $end -$var wire 1 M# A1 $end -$var wire 1 N# A2 $end -$var wire 1 O# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 P# D $end -$var wire 1 Q# Q $end -$var reg 16 R# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[28] $end -$scope module srl16e $end -$var wire 1 S# A0 $end -$var wire 1 T# A1 $end -$var wire 1 U# A2 $end -$var wire 1 V# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 W# D $end -$var wire 1 X# Q $end -$var reg 16 Y# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[29] $end -$scope module srl16e $end -$var wire 1 Z# A0 $end -$var wire 1 [# A1 $end -$var wire 1 \# A2 $end -$var wire 1 ]# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 ^# D $end -$var wire 1 _# Q $end -$var reg 16 `# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[30] $end -$scope module srl16e $end -$var wire 1 a# A0 $end -$var wire 1 b# A1 $end -$var wire 1 c# A2 $end -$var wire 1 d# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 e# D $end -$var wire 1 f# Q $end -$var reg 16 g# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[31] $end -$scope module srl16e $end -$var wire 1 h# A0 $end -$var wire 1 i# A1 $end -$var wire 1 j# A2 $end -$var wire 1 k# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 l# D $end -$var wire 1 m# Q $end -$var reg 16 n# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[32] $end -$scope module srl16e $end -$var wire 1 o# A0 $end -$var wire 1 p# A1 $end -$var wire 1 q# A2 $end -$var wire 1 r# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 s# D $end -$var wire 1 t# Q $end -$var reg 16 u# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[33] $end -$scope module srl16e $end -$var wire 1 v# A0 $end -$var wire 1 w# A1 $end -$var wire 1 x# A2 $end -$var wire 1 y# A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 z# D $end -$var wire 1 {# Q $end -$var reg 16 |# data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[34] $end -$scope module srl16e $end -$var wire 1 }# A0 $end -$var wire 1 ~# A1 $end -$var wire 1 !$ A2 $end -$var wire 1 "$ A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 #$ D $end -$var wire 1 $$ Q $end -$var reg 16 %$ data [15:0] $end -$upscope $end -$upscope $end -$scope begin gen_srl16[35] $end -$scope module srl16e $end -$var wire 1 &$ A0 $end -$var wire 1 '$ A1 $end -$var wire 1 ($ A2 $end -$var wire 1 )$ A3 $end -$var wire 1 E CE $end -$var wire 1 ? CLK $end -$var wire 1 *$ D $end -$var wire 1 +$ Q $end -$var reg 16 ,$ data [15:0] $end -$upscope $end -$upscope $end -$upscope $end -$scope module fifo36_to_fifo19 $end -$var wire 1 > clear $end -$var wire 1 ? clk $end -$var wire 19 -$ f19_dataout [18:0] $end -$var wire 1 ' f19_dst_rdy_i $end -$var wire 1 ( f19_src_rdy_o $end -$var wire 1 .$ f19_xfer $end -$var wire 36 /$ f36_datain [35:0] $end -$var wire 1 $ f36_dst_rdy_o $end -$var wire 1 0$ f36_eof $end -$var wire 1 1$ f36_occ $end -$var wire 1 2$ f36_sof $end -$var wire 1 % f36_src_rdy_i $end -$var wire 1 3$ f36_xfer $end -$var wire 1 4$ half_line $end -$var wire 1 C reset $end -$var reg 1 5$ phase $end -$upscope $end -$scope module fifo19_to_ll8 $end -$var wire 1 6$ advance $end -$var wire 1 > clear $end -$var wire 1 ? clk $end -$var wire 19 7$ f19_data [18:0] $end -$var wire 1 ' f19_dst_rdy_o $end -$var wire 1 8$ f19_eof $end -$var wire 1 9$ f19_occ $end -$var wire 1 :$ f19_sof $end -$var wire 1 ( f19_src_rdy_i $end -$var wire 1 ;$ ll_dst_rdy $end -$var wire 1 / ll_dst_rdy_n $end -$var wire 1 <$ ll_eof $end -$var wire 1 0 ll_eof_n $end -$var wire 1 =$ ll_sof $end -$var wire 1 1 ll_sof_n $end -$var wire 1 >$ ll_src_rdy $end -$var wire 1 2 ll_src_rdy_n $end -$var wire 1 C reset $end -$var reg 8 ?$ ll_data [7:0] $end -$var reg 1 @$ state $end -$upscope $end -$scope module ll8_to_fifo19 $end -$var wire 1 > clear $end -$var wire 1 ? clk $end -$var wire 19 A$ f19_data [18:0] $end -$var wire 1 * f19_dst_rdy_i $end -$var wire 1 + f19_src_rdy_o $end -$var wire 8 B$ ll_data [7:0] $end -$var wire 1 C$ ll_dst_rdy $end -$var wire 1 / ll_dst_rdy_n $end -$var wire 1 D$ ll_eof $end -$var wire 1 0 ll_eof_n $end -$var wire 1 E$ ll_sof $end -$var wire 1 1 ll_sof_n $end -$var wire 1 F$ ll_src_rdy $end -$var wire 1 2 ll_src_rdy_n $end -$var wire 1 C reset $end -$var wire 1 G$ xfer_out $end -$var reg 8 H$ dat0 [7:0] $end -$var reg 8 I$ dat1 [7:0] $end -$var reg 1 J$ f19_eof $end -$var reg 1 K$ f19_occ $end -$var reg 1 L$ f19_sof $end -$var reg 2 M$ state [1:0] $end -$upscope $end -$scope module fifo19_to_fifo36 $end -$var wire 1 > clear $end -$var wire 1 ? clk $end -$var wire 19 N$ f19_datain [18:0] $end -$var wire 1 * f19_dst_rdy_o $end -$var wire 1 O$ f19_eof $end -$var wire 1 P$ f19_occ $end -$var wire 1 Q$ f19_sof $end -$var wire 1 + f19_src_rdy_i $end -$var wire 36 R$ f36_dataout [35:0] $end -$var wire 1 S$ f36_dst_rdy_i $end -$var wire 1 - f36_src_rdy_o $end -$var wire 1 C reset $end -$var wire 1 T$ xfer_out $end -$var reg 16 U$ dat0 [15:0] $end -$var reg 16 V$ dat1 [15:0] $end -$var reg 1 W$ f36_eof $end -$var reg 1 X$ f36_occ $end -$var reg 1 Y$ f36_sof $end -$var reg 2 Z$ state [1:0] $end -$upscope $end -$scope task PutPacketInFIFO36 $end -$var reg 32 [$ data_len [31:0] $end -$var reg 32 \$ data_start [31:0] $end -$upscope $end -$scope task ReadFromFIFO36 $end -$upscope $end -$upscope $end -$enddefinitions $end -#0 -$dumpvars -bx \$ -bx [$ -bx Z$ -xY$ -xX$ -xW$ -bx V$ -bx U$ -0T$ -0S$ -b0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx R$ -xQ$ -xP$ -xO$ -bx N$ -bx M$ -xL$ -xK$ -xJ$ -bx I$ -bx H$ -xG$ -xF$ -xE$ -xD$ -xC$ -bx B$ -bx A$ -x@$ -bx ?$ -x>$ -x=$ -x<$ -x;$ -x:$ -x9$ -x8$ -bx 7$ -x6$ -x5$ -x4$ -x3$ -x2$ -x1$ -x0$ -bx /$ -x.$ -bx -$ -b0 ,$ -x+$ -0*$ -x)$ -x($ -x'$ -x&$ -b0 %$ -x$$ -0#$ -x"$ -x!$ -x~# -x}# -b0 |# -x{# -0z# -xy# -xx# -xw# -xv# -b0 u# -xt# -0s# -xr# -xq# -xp# -xo# -b0 n# -xm# -0l# -xk# -xj# -xi# -xh# -b0 g# -xf# -0e# -xd# -xc# -xb# -xa# -b0 `# -x_# -0^# -x]# -x\# -x[# -xZ# -b0 Y# -xX# -0W# -xV# -xU# -xT# -xS# -b0 R# -xQ# -0P# -xO# -xN# -xM# -xL# -b0 K# -xJ# -0I# -xH# -xG# -xF# -xE# -b0 D# -xC# -0B# -xA# -x@# -x?# -x># -b0 =# -x<# -0;# -x:# -x9# -x8# -x7# -b0 6# -x5# -04# -x3# -x2# -x1# -x0# -b0 /# -x.# -0-# -x,# -x+# -x*# -x)# -b0 (# -x'# -0&# -x%# -x$# -x## -x"# -b0 !# -x~" -0}" -x|" -x{" -xz" -xy" -b0 x" -xw" -0v" -xu" -xt" -xs" -xr" -b0 q" -xp" -0o" -xn" -xm" -xl" -xk" -b0 j" -xi" -0h" -xg" -xf" -xe" -xd" -b0 c" -xb" -0a" -x`" -x_" -x^" -x]" -b0 \" -x[" -0Z" -xY" -xX" -xW" -xV" -b0 U" -xT" -0S" -xR" -xQ" -xP" -xO" -b0 N" -xM" -0L" -xK" -xJ" -xI" -xH" -b0 G" -xF" -0E" -xD" -xC" -xB" -xA" -b0 @" -x?" -0>" -x=" -x<" -x;" -x:" -b0 9" -x8" -07" -x6" -x5" -x4" -x3" -b0 2" -x1" -00" -x/" -x." -x-" -x," -b0 +" -x*" -0)" -x(" -x'" -x&" -x%" -b0 $" -x#" -0"" -x!" -x~ -x} -x| -b0 { -xz -0y -xx -xw -xv -xu -b0 t -xs -0r -xq -xp -xo -xn -b0 m -xl -0k -xj -xi -xh -xg -b0 f -xe -0d -xc -xb -xa -x` -b0 _ -x^ -0] -x\ -x[ -xZ -xY -b0 X -xW -0V -xU -xT -xS -xR -b0 Q -xP -0O -xN -xM -xL -xK -bx J -bx I -xH -xG -bx F -0E -0D -1C -xB -bx A -b0 @ -0? -0> -0= -1< -0; -0: -b0 9 -08 -b0 7 -06 -bx 5 -04 -03 -x2 -x1 -x0 -x/ -bx . -x- -b0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx , -x+ -x* -bx ) -x( -x' -bx & -x% -x$ -bx # -b0 " -x! -$end -#50000000000000 -0D$ -10 -0E$ -0<$ -11 -08$ -09$ -0=$ -0$ -b0 ?$ -b0 . -b0 B$ -0:$ -0' -0F$ -04$ -01$ -b0 & -b0 -$ -b0 7$ -1;$ -0.$ -06$ -12 -03$ -0B -02$ -00$ -0/ -1! -0>$ -0( -0% -0K -0P -0L -0M -0N -0R -0W -0S -0T -0U -0Y -0^ -0Z -0[ -0\ -0` -0e -0a -0b -0c -0g -0l -0h -0i -0j -0n -0s -0o -0p -0q -0u -0z -0v -0w -0x -0| -0#" -0} -0~ -0!" -0%" -0*" -0&" -0'" -0(" -0," -01" -0-" -0." -0/" -03" -08" -04" -05" -06" -0:" -0?" -0;" -0<" -0=" -0A" -0F" -0B" -0C" -0D" -0H" -0M" -0I" -0J" -0K" -0O" -0T" -0P" -0Q" -0R" -0V" -0[" -0W" -0X" -0Y" -0]" -0b" -0^" -0_" -0`" -0d" -0i" -0e" -0f" -0g" -0k" -0p" -0l" -0m" -0n" -0r" -0w" -0s" -0t" -0u" -0y" -0~" -0z" -0{" -0|" -0"# -0'# -0## -0$# -0%# -0)# -0.# -0*# -0+# -0,# -00# -05# -01# -02# -03# -07# -0<# -08# -09# -0:# -0># -0C# -0?# -0@# -0A# -0E# -0J# -0F# -0G# -0H# -0L# -0Q# -0M# -0N# -0O# -0S# -0X# -0T# -0U# -0V# -0Z# -0_# -0[# -0\# -0]# -0a# -0f# -0b# -0c# -0d# -0h# -0m# -0i# -0j# -0k# -0o# -0t# -0p# -0q# -0r# -0v# -0{# -0w# -0x# -0y# -0}# -0$$ -0~# -0!$ -0"$ -0&$ -0+$ -b0 # -b0 A -b0 /$ -0'$ -0($ -0)$ -0P$ -1C$ -0G$ -1* -0H -1G -b0 F -b10000 J -b0 I -05$ -0@$ -0K$ -b0xxxxxxxxxxxxxxxxxx ) -b0xxxxxxxxxxxxxxxxxx A$ -b0xxxxxxxxxxxxxxxxxx N$ -b0 M$ -0+ -0X$ -b0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx , -b0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx R$ -b0 Z$ -0- -14 -1? -#100000000000000 -04 -0? -#150000000000000 -14 -1? -#200000000000000 -04 -0? -#250000000000000 -14 -1? -#300000000000000 -04 -0? -#350000000000000 -14 -1? -#400000000000000 -04 -0? -#450000000000000 -14 -1? -#500000000000000 -04 -0? -#550000000000000 -14 -1? -#600000000000000 -04 -0? -#650000000000000 -14 -1? -#700000000000000 -04 -0? -#750000000000000 -14 -1? -#800000000000000 -04 -0? -#850000000000000 -14 -1? -#900000000000000 -04 -0? -#950000000000000 -14 -1? -#1000000000000000 -04 -0? -0< -0C -#1050000000000000 -14 -1? -#1100000000000000 -04 -0? -#1150000000000000 -1k -1y -1"" -1S" -1Z" -1}" -1&# -14# -1^# -1l# -1s# -1E -1: -b10100000101100001100000011010000 7 -b110100000101100001100000011010000 " -b110100000101100001100000011010000 @ -1= -1D -b100 5 -b1100 [$ -b10100000101100001100000011010000 \$ -14 -1? -#1200000000000000 -04 -0? -#1250000000000000 -1F$ -16$ -02 -1>$ -1( -1% -1O -1)" -1a" -1;# -0s# -0G -b1111 J -b1 I -b1000 5 -b10100001101100011100000111010001 7 -0: -b10100001101100011100000111010001 " -b10100001101100011100000111010001 @ -14 -1? -#1250000000000100 -1E$ -01 -1=$ -b10100000 ?$ -b10100000 . -b10100000 B$ -1:$ -b11010000010110000 & -b11010000010110000 -$ -b11010000010110000 7$ -12$ -b1 m -1l -b1 { -1z -b1 $" -1#" -b1 U" -1T" -b1 \" -1[" -b1 !# -1~" -b1 (# -1'# -b1 6# -15# -b1 `# -1_# -b1 n# -1m# -b1 u# -1t# -b110100000101100001100000011010000 # -b110100000101100001100000011010000 A -b110100000101100001100000011010000 /$ -#1300000000000000 -04 -0? -#1350000000000000 -0E$ -0:$ -1.$ -11 -b0 & -b0 -$ -b0 7$ -1' -0=$ -02$ -0O -1V -0)" -10" -0a" -1h" -0;# -1B# -1z# -1Q$ -0O$ -b0 ?$ -b0 . -b0 B$ -1K -1R -1Y -1` -1g -0l -1n -1u -0z -1| -0#" -1%" -1," -13" -1:" -1A" -1H" -1O" -0T" -1V" -0[" -1]" -1d" -1k" -1r" -1y" -0~" -1"# -0'# -1)# -10# -05# -17# -1># -1E# -1L# -1S# -1Z# -0_# -1a# -1h# -0m# -1o# -0t# -b0 # -b0 A -b0 /$ -1v# -1}# -1&$ -18 -b10100010101100101100001011010010 7 -b1010100010101100101100001011010010 " -b1010100010101100101100001011010010 @ -b10100000 H$ -b1 M$ -0J$ -1L$ -b110100000xxxxxxxx ) -b110100000xxxxxxxx A$ -b110100000xxxxxxxx N$ -1@$ -b10 I -b1110 J -b1 F -14 -1? -#1350000000000100 -b10110000 ?$ -b10110000 . -b10110000 B$ -1:$ -b11010000010110000 & -b11010000010110000 -$ -b11010000010110000 7$ -12$ -b10 u# -1t# -b11 n# -1m# -b11 `# -1_# -b1 =# -b11 6# -15# -b11 (# -1'# -b11 !# -1~" -b1 c" -b11 \" -1[" -b11 U" -1T" -b1 +" -b11 $" -1#" -b11 { -1z -b11 m -1l -b110100000101100001100000011010000 # -b110100000101100001100000011010000 A -b110100000101100001100000011010000 /$ -b1 Q -#1351000000000000 -1; -1S$ -#1400000000000000 -04 -0? -#1450000000000000 -0E$ -0.$ -11 -02$ -0:$ -0' -0=$ -0K -1L -0R -1S -0Y -1Z -0` -1a -0g -1h -0l -0n -1o -0u -1v -0z -0| -1} -0#" -0%" -1&" -0," -1-" -03" -14" -0:" -1;" -0A" -1B" -0H" -1I" -0O" -1P" -0T" -0V" -1W" -0[" -0]" -1^" -0d" -1e" -0k" -1l" -0r" -1s" -0y" -1z" -0~" -0"# -1## -0'# -0)# -1*# -00# -11# -05# -07# -18# -0># -1?# -0E# -1F# -0L# -1M# -0S# -1T# -0Z# -1[# -0_# -0a# -1b# -0h# -1i# -0m# -0o# -1p# -0t# -b0 # -b0 A -b0 /$ -0v# -1w# -0}# -1~# -0&$ -1'$ -b0 & -b0 -$ -b0 7$ -b0 ?$ -b0 . -b0 B$ -1G$ -0E -0V -0k -0y -0"" -00" -0S" -0Z" -0h" -0}" -0&# -04# -0B# -0^# -0l# -0z# -b10 F -b1101 J -b11 I -15$ -0@$ -b10 M$ -1+ -b10110000 I$ -b11010000010110000 ) -b11010000010110000 A$ -b11010000010110000 N$ -0= -0D -b0 7 -08 -b0 " -b0 @ -14 -1? -#1450000000000100 -b11000000 ?$ -b11000000 . -b11000000 B$ -b1100000011010000 & -b1100000011010000 -$ -b1100000011010000 7$ -12$ -b10 Q -b1 X -b111 m -1l -b111 { -1z -b111 $" -1#" -b10 +" -b1 2" -b111 U" -1T" -b111 \" -1[" -b10 c" -b1 j" -b111 !# -1~" -b111 (# -1'# -b111 6# -15# -b10 =# -b1 D# -b111 `# -1_# -b111 n# -1m# -b100 u# -1t# -b110100000101100001100000011010000 # -b110100000101100001100000011010000 A -b110100000101100001100000011010000 /$ -b1 |# -#1500000000000000 -04 -0? -#1550000000000000 -13$ -1B -1.$ -1$ -1' -0G$ -0Q$ -b11010000 ?$ -b11010000 . -b11010000 B$ -b1010000010110000 U$ -b1 Z$ -0W$ -1Y$ -b11010000010110000xxxxxxxxxxxxxxxx , -b11010000010110000xxxxxxxxxxxxxxxx R$ -b11000000 H$ -b1 M$ -0+ -0L$ -b1100000010110000 ) -b1100000010110000 A$ -b1100000010110000 N$ -1@$ -14 -1? -#1600000000000000 -04 -0? -#1650000000000000 -0E$ -11 -0=$ -03$ -0B -0.$ -02$ -0:$ -0$ -0' -1K -1P -0L -1R -0S -0W -1Y -0Z -1` -0a -1g -0h -1n -0o -1u -0v -1| -0} -1%" -1*" -0&" -1," -0-" -01" -13" -04" -1:" -0;" -1A" -0B" -1H" -0I" -1O" -0P" -1V" -0W" -1]" -1b" -0^" -1d" -0e" -0i" -1k" -0l" -1r" -0s" -1y" -0z" -1"# -0## -1)# -0*# -10# -01# -17# -1<# -08# -1># -0?# -0C# -1E# -0F# -1L# -0M# -1S# -0T# -1Z# -0[# -1a# -0b# -1h# -0i# -1o# -0p# -0t# -1v# -0w# -0{# -b10100001101100011100000111010001 # -b10100001101100011100000111010001 A -b10100001101100011100000111010001 /$ -1}# -0~# -1&$ -0'$ -b1010000110110001 & -b1010000110110001 -$ -b1010000110110001 7$ -b10100001 ?$ -b10100001 . -b10100001 B$ -1G$ -b1 F -b1110 J -b10 I -05$ -0@$ -b10 M$ -1+ -b11010000 I$ -b1100000011010000 ) -b1100000011010000 A$ -b1100000011010000 N$ -14 -1? -#1700000000000000 -04 -0? -#1750000000000000 -1.$ -1' -1T$ -0G$ -b10110001 ?$ -b10110001 . -b10110001 B$ -b1100000011010000 V$ -b110100000101100001100000011010000 , -b110100000101100001100000011010000 R$ -b10 Z$ -1- -b10100001 H$ -b1010000111010000 ) -b1010000111010000 A$ -b1010000111010000 N$ -b1 M$ -0+ -1@$ -14 -1? -#1800000000000000 -04 -0? -#1850000000000000 -0.$ -0' -b1100000111010001 & -b1100000111010001 -$ -b1100000111010001 7$ -b11000001 ?$ -b11000001 . -b11000001 B$ -1G$ -0T$ -15$ -0@$ -b10 M$ -1+ -b10110001 I$ -b1010000110110001 ) -b1010000110110001 A$ -b1010000110110001 N$ -b0 Z$ -0- -14 -1? -#1900000000000000 -04 -0? -#1950000000000000 -13$ -1B -1.$ -1$ -1' -0G$ -b11010001 ?$ -b11010001 . -b11010001 B$ -b1010000110110001 U$ -b1 Z$ -0Y$ -b10100001101100011100000011010000 , -b10100001101100011100000011010000 R$ -b11000001 H$ -b1100000110110001 ) -b1100000110110001 A$ -b1100000110110001 N$ -b1 M$ -0+ -1@$ -14 -1? -#2000000000000000 -04 -0? -#2050000000000000 -03$ -0B -0.$ -10$ -0$ -0' -0K -0P -0R -1W -0Y -0` -0g -0n -0u -0| -0%" -0*" -0," -11" -03" -0:" -0A" -0H" -0O" -0V" -0]" -0b" -0d" -1i" -0k" -0r" -0y" -0"# -0)# -00# -07# -0<# -0># -1C# -0E# -0L# -0S# -0Z# -0a# -0h# -0o# -0v# -1{# -b1010100010101100101100001011010010 # -b1010100010101100101100001011010010 A -b1010100010101100101100001011010010 /$ -0}# -0&$ -b1010001010110010 & -b1010001010110010 -$ -b1010001010110010 7$ -b10100010 ?$ -b10100010 . -b10100010 B$ -1G$ -b0 F -b1111 J -b1 I -05$ -0@$ -b10 M$ -1+ -b11010001 I$ -b1100000111010001 ) -b1100000111010001 A$ -b1100000111010001 N$ -14 -1? -#2100000000000000 -04 -0? -#2150000000000000 -1.$ -1' -1T$ -0G$ -b10110010 ?$ -b10110010 . -b10110010 B$ -b1100000111010001 V$ -b10100001101100011100000111010001 , -b10100001101100011100000111010001 R$ -b10 Z$ -1- -b10100010 H$ -b1010001011010001 ) -b1010001011010001 A$ -b1010001011010001 N$ -b1 M$ -0+ -1@$ -14 -1? -#2200000000000000 -04 -0? -#2250000000000000 -0.$ -18$ -0' -b101100001011010010 & -b101100001011010010 -$ -b101100001011010010 7$ -b11000010 ?$ -b11000010 . -b11000010 B$ -1G$ -0T$ -15$ -0@$ -b10 M$ -1+ -b10110010 I$ -b1010001010110010 ) -b1010001010110010 A$ -b1010001010110010 N$ -b0 Z$ -0- -14 -1? -#2300000000000000 -04 -0? -#2350000000000000 -1D$ -13$ -1B -00 -1.$ -1$ -1<$ -1' -0G$ -b11010010 ?$ -b11010010 . -b11010010 B$ -b1010001010110010 U$ -b10100010101100101100000111010001 , -b10100010101100101100000111010001 R$ -b1 Z$ -b11000010 H$ -b1100001010110010 ) -b1100001010110010 A$ -b1100001010110010 N$ -b1 M$ -0+ -1@$ -14 -1? -#2400000000000000 -04 -0? -#2450000000000000 -0D$ -0' -0F$ -10 -0.$ -06$ -12 -03$ -0B -08$ -0$ -0<$ -0>$ -0( -0% -b1010001010110010 & -b1010001010110010 -$ -b1010001010110010 7$ -b10100010 ?$ -b10100010 . -b10100010 B$ -1G$ -1O$ -1G -b10000 J -b0 I -05$ -0@$ -1J$ -b10 M$ -1+ -b11010010 I$ -b101100001011010010 ) -b101100001011010010 A$ -b101100001011010010 N$ -14 -1? -#2500000000000000 -04 -0? -#2550000000000000 -1T$ -0G$ -b1100001011010010 V$ -b10 Z$ -1- -1W$ -b1010100010101100101100001011010010 , -b1010100010101100101100001011010010 R$ -b0 M$ -0+ -14 -1? -#2600000000000000 -04 -0? -#2650000000000000 -0T$ -b0 Z$ -0- -14 -1? -#2700000000000000 -04 -0? -#2750000000000000 -14 -1? -#2800000000000000 -04 -0? -#2850000000000000 -14 -1? -#2900000000000000 -04 -0? -#2950000000000000 -14 -1? -#3000000000000000 -04 -0? -#3050000000000000 -14 -1? -#3100000000000000 -04 -0? -#3150000000000000 -14 -1? -#3200000000000000 -04 -0? -#3250000000000000 -14 -1? -#3300000000000000 -04 -0? -#3350000000000000 -14 -1? -#3400000000000000 -04 -0? -#3450000000000000 -14 -1? -#3500000000000000 -04 -0? -#3550000000000000 -14 -1? -#3600000000000000 -04 -0? -#3650000000000000 -14 -1? -#3700000000000000 -04 -0? -#3750000000000000 -14 -1? -#3800000000000000 -04 -0? -#3850000000000000 -14 -1? -#3900000000000000 -04 -0? -#3950000000000000 -14 -1? -#4000000000000000 -04 -0? -#4050000000000000 -14 -1? -#4100000000000000 -04 -0? -#4150000000000000 -14 -1? -#4200000000000000 -04 -0? -#4250000000000000 -14 -1? -#4300000000000000 -04 -0? -#4350000000000000 -14 -1? -#4400000000000000 -04 -0? -#4450000000000000 -14 -1? -#4500000000000000 -04 -0? -#4550000000000000 -14 -1? -#4600000000000000 -04 -0? -#4650000000000000 -14 -1? -#4700000000000000 -04 -0? -#4750000000000000 -14 -1? -#4800000000000000 -04 -0? -#4850000000000000 -14 -1? -#4900000000000000 -04 -0? -#4950000000000000 -14 -1? -#5000000000000000 -04 -0? -#5050000000000000 -14 -1? -#5100000000000000 -04 -0? -#5150000000000000 -14 -1? -#5200000000000000 -04 -0? -#5250000000000000 -14 -1? -#5300000000000000 -04 -0? -#5350000000000000 -14 -1? -#5400000000000000 -04 -0? -#5450000000000000 -14 -1? -#5500000000000000 -04 -0? -#5550000000000000 -14 -1? -#5600000000000000 -04 -0? -#5650000000000000 -14 -1? -#5700000000000000 -04 -0? -#5750000000000000 -14 -1? -#5800000000000000 -04 -0? -#5850000000000000 -14 -1? -#5900000000000000 -04 -0? -#5950000000000000 -14 -1? -#6000000000000000 -04 -0? -#6050000000000000 -14 -1? -#6100000000000000 -04 -0? -#6150000000000000 -14 -1? -#6200000000000000 -04 -0? -#6250000000000000 -14 -1? -#6300000000000000 -04 -0? -#6350000000000000 -14 -1? -#6400000000000000 -04 -0? -#6450000000000000 -14 -1? -#6500000000000000 -04 -0? -#6550000000000000 -14 -1? -#6600000000000000 -04 -0? -#6650000000000000 -14 -1? -#6700000000000000 -04 -0? -#6750000000000000 -14 -1? -#6800000000000000 -04 -0? -#6850000000000000 -14 -1? -#6900000000000000 -04 -0? -#6950000000000000 -14 -1? -#7000000000000000 -04 -0? -#7050000000000000 -14 -1? -#7100000000000000 -04 -0? -#7150000000000000 -14 -1? -#7200000000000000 -04 -0? -#7250000000000000 -14 -1? -#7300000000000000 -04 -0? -#7350000000000000 -14 -1? -#7400000000000000 -04 -0? -#7450000000000000 -14 -1? -#7500000000000000 -04 -0? -#7550000000000000 -14 -1? -#7600000000000000 -04 -0? -#7650000000000000 -14 -1? -#7700000000000000 -04 -0? -#7750000000000000 -14 -1? -#7800000000000000 -04 -0? -#7850000000000000 -14 -1? -#7900000000000000 -04 -0? -#7950000000000000 -14 -1? -#8000000000000000 -04 -0? -#8050000000000000 -14 -1? -#8100000000000000 -04 -0? -#8150000000000000 -14 -1? -#8200000000000000 -04 -0? -#8250000000000000 -14 -1? -#8300000000000000 -04 -0? -#8350000000000000 -14 -1? -#8400000000000000 -04 -0? -#8450000000000000 -14 -1? -#8500000000000000 -04 -0? -#8550000000000000 -14 -1? -#8600000000000000 -04 -0? -#8650000000000000 -14 -1? -#8700000000000000 -04 -0? -#8750000000000000 -14 -1? -#8800000000000000 -04 -0? -#8850000000000000 -14 -1? -#8900000000000000 -04 -0? -#8950000000000000 -14 -1? -#9000000000000000 -04 -0? -#9050000000000000 -14 -1? -#9100000000000000 -04 -0? -#9150000000000000 -14 -1? -#9200000000000000 -04 -0? -#9250000000000000 -14 -1? -#9300000000000000 -04 -0? -#9350000000000000 -14 -1? -#9400000000000000 -04 -0? -#9450000000000000 -14 -1? -#9500000000000000 -04 -0? -#9550000000000000 -14 -1? -#9600000000000000 -04 -0? -#9650000000000000 -14 -1? -#9700000000000000 -04 -0? -#9750000000000000 -14 -1? -#9800000000000000 -04 -0? -#9850000000000000 -14 -1? -#9900000000000000 -04 -0? -#9950000000000000 -14 -1? -#10000000000000000 -04 -0? -#10050000000000000 -14 -1? -#10100000000000000 -04 -0? -#10150000000000000 -14 -1? -#10200000000000000 -04 -0? -#10250000000000000 -14 -1? -#10300000000000000 -04 -0? -#10350000000000000 -14 -1? -#10400000000000000 -04 -0? -#10450000000000000 -14 -1? -#10500000000000000 -04 -0? -#10550000000000000 -14 -1? -#10600000000000000 -04 -0? -#10650000000000000 -14 -1? -#10700000000000000 -04 -0? -#10750000000000000 -14 -1? -#10800000000000000 -04 -0? -#10850000000000000 -14 -1? -#10900000000000000 -04 -0? -#10950000000000000 -14 -1? -#11000000000000000 -04 -0? -#11050000000000000 -14 -1? -#11100000000000000 -04 -0? -#11150000000000000 -14 -1? -#11200000000000000 -04 -0? -#11250000000000000 -14 -1? -#11300000000000000 -04 -0? -#11350000000000000 -14 -1? -#11400000000000000 -04 -0? -#11450000000000000 -14 -1? -#11500000000000000 -04 -0? -#11550000000000000 -14 -1? -#11600000000000000 -04 -0? -#11650000000000000 -1k -1r -1"" -1L" -1Z" -1}" -1&# -1-# -14# -1^# -1e# -1l# -1s# -1E -1: -b11100000111100001010000010110000 7 -b111100000111100001010000010110000 " -b111100000111100001010000010110000 @ -1= -1D -b100 5 -b100100 [$ -b11100000111100001010000010110000 \$ -14 -1? -#11700000000000000 -04 -0? -#11750000000000000 -1F$ -16$ -02 -1>$ -1( -1% -1O -1)" -1a" -1;# -0s# -b1 I -b1111 J -0G -b1000 5 -b11100001111100011010000110110001 7 -0: -b11100001111100011010000110110001 " -b11100001111100011010000110110001 @ -14 -1? -#11750000000000100 -1E$ -01 -1=$ -b11100000 ?$ -b11100000 . -b11100000 B$ -1:$ -b11110000011110000 & -b11110000011110000 -$ -b11110000011110000 7$ -12$ -00$ -b10 |# -0{# -b1001 u# -1t# -b1111 n# -b1 g# -1f# -b1111 `# -b10 D# -0C# -b100 =# -b1111 6# -b1 /# -1.# -b1111 (# -b1111 !# -b10 j" -0i" -b100 c" -b1111 \" -b1110 U" -0T" -b1 N" -1M" -b10 2" -01" -b100 +" -b1111 $" -b1110 { -0z -b1 t -1s -b1111 m -b10 X -0W -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -b100 Q -#11800000000000000 -04 -0? -#11850000000000000 -0:$ -0E$ -b1010001010110010 & -b1010001010110010 -$ -b1010001010110010 7$ -1.$ -11 -02$ -10$ -1' -0=$ -0O -1V -0)" -10" -0a" -1h" -0;# -1B# -1K -1R -1W -1Y -1` -1g -1n -0s -1u -1z -1| -1%" -1," -11" -13" -1:" -1A" -1H" -0M" -1O" -1T" -1V" -1]" -1d" -1i" -1k" -1r" -1y" -1"# -1)# -0.# -10# -17# -1># -1C# -1E# -1L# -1S# -1Z# -1a# -0f# -1h# -1o# -0t# -1v# -1{# -b1010100010101100101100001011010010 # -b1010100010101100101100001011010010 A -b1010100010101100101100001011010010 /$ -1}# -1&$ -b10110010 ?$ -b10110010 . -b10110010 B$ -1Q$ -0O$ -b1100 5 -b11100010111100101010001010110010 7 -b11100010111100101010001010110010 " -b11100010111100101010001010110010 @ -b1 F -b1110 J -b10 I -1@$ -1L$ -0J$ -b1 M$ -b11100000 H$ -b11110000011010010 ) -b11110000011010010 A$ -b11110000011010010 N$ -14 -1? -#11850000000000100 -b11110000 ?$ -b11110000 . -b11110000 B$ -1:$ -b11110000011110000 & -b11110000011110000 -$ -b11110000011110000 7$ -12$ -00$ -b1001 Q -b100 X -0W -b11111 m -b11 t -1s -b11100 { -0z -b11111 $" -b1001 +" -b100 2" -01" -b11 N" -1M" -b11100 U" -0T" -b11111 \" -b1001 c" -b100 j" -0i" -b11111 !# -b11111 (# -b11 /# -1.# -b11111 6# -b1001 =# -b100 D# -0C# -b11111 `# -b11 g# -1f# -b11111 n# -b10010 u# -1t# -b100 |# -0{# -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -#11900000000000000 -04 -0? -#11950000000000000 -18$ -0.$ -03$ -0B -0' -0:$ -0$ -02$ -10$ -1G$ -b11000010 ?$ -b11000010 . -b11000010 B$ -b101100001011010010 & -b101100001011010010 -$ -b101100001011010010 7$ -0K -1L -0P -0R -1W -1S -0Y -1Z -0` -1a -0g -1h -0n -1o -0s -0u -1v -1z -0| -1} -0%" -1&" -0*" -0," -11" -1-" -03" -14" -0:" -1;" -0A" -1B" -0H" -1I" -0M" -0O" -1P" -1T" -0V" -1W" -0]" -1^" -0b" -0d" -1i" -1e" -0k" -1l" -0r" -1s" -0y" -1z" -0"# -1## -0)# -1*# -0.# -00# -11# -07# -18# -0<# -0># -1C# -1?# -0E# -1F# -0L# -1M# -0S# -1T# -0Z# -1[# -0a# -1b# -0f# -0h# -1i# -0o# -1p# -0t# -0v# -1{# -b1010100010101100101100001011010010 # -b1010100010101100101100001011010010 A -b1010100010101100101100001011010010 /$ -1w# -0}# -1~# -0&$ -1'$ -1O -1)" -1a" -1;# -b11110000 I$ -b11110000011110000 ) -b11110000011110000 A$ -b11110000011110000 N$ -b10 M$ -1+ -0@$ -15$ -b11 I -b1101 J -b10 F -b10000 5 -b11100011111100111010001110110011 7 -b11100011111100111010001110110011 " -b11100011111100111010001110110011 @ -14 -1? -#11950000000000100 -b10100000 ?$ -b10100000 . -b10100000 B$ -08$ -b1010000010110000 & -b1010000010110000 -$ -b1010000010110000 7$ -12$ -00$ -b1000 |# -0{# -b100100 u# -1t# -b111111 n# -b111 g# -1f# -b111111 `# -b1001 D# -0C# -b10010 =# -b111111 6# -b111 /# -1.# -b111111 (# -b111111 !# -b1001 j" -0i" -b10010 c" -b111111 \" -b111000 U" -0T" -b111 N" -1M" -b1001 2" -01" -b10010 +" -b111111 $" -b111000 { -0z -b111 t -1s -b111111 m -b1001 X -0W -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -b10010 Q -#12000000000000000 -04 -0? -#12050000000000000 -1D$ -00 -1<$ -18$ -13$ -1B -b101100001011010010 & -b101100001011010010 -$ -b101100001011010010 7$ -1.$ -1$ -02$ -10$ -1' -0O -0V -1] -0)" -00" -17" -0a" -0h" -1o" -0;# -0B# -1I# -1K -1R -1W -1Y -1` -1g -1n -0s -1u -1z -1| -1%" -1," -11" -13" -1:" -1A" -1H" -0M" -1O" -1T" -1V" -1]" -1d" -1i" -1k" -1r" -1y" -1"# -1)# -0.# -10# -17# -1># -1C# -1E# -1L# -1S# -1Z# -1a# -0f# -1h# -1o# -0t# -1v# -1{# -b1010100010101100101100001011010010 # -b1010100010101100101100001011010010 A -b1010100010101100101100001011010010 /$ -1}# -1&$ -b11010010 ?$ -b11010010 . -b11010010 B$ -0G$ -0Q$ -b10100 5 -b11100100111101001010010010110100 7 -b11100100111101001010010010110100 " -b11100100111101001010010010110100 @ -b11 F -b1100 J -b100 I -1@$ -0L$ -b1 M$ -0+ -b10100000 H$ -b1010000011110000 ) -b1010000011110000 A$ -b1010000011110000 N$ -1Y$ -0W$ -b1 Z$ -b1110000011110000 U$ -b111100000111100001100001011010010 , -b111100000111100001100001011010010 R$ -14 -1? -#12050000000000100 -0D$ -10 -0<$ -b10110000 ?$ -b10110000 . -b10110000 B$ -08$ -b1010000010110000 & -b1010000010110000 -$ -b1010000010110000 7$ -12$ -00$ -b100101 Q -b10011 X -0W -b1111111 m -b1111 t -1s -b1110000 { -0z -b1111111 $" -b100101 +" -b10011 2" -01" -b1111 N" -1M" -b1110000 U" -0T" -b1111111 \" -b100101 c" -b10011 j" -0i" -b1111111 !# -b1111111 (# -b1111 /# -1.# -b1111111 6# -b100101 =# -b10011 D# -0C# -b1111111 `# -b1111 g# -1f# -b1111111 n# -b1001000 u# -1t# -b10000 |# -0{# -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -#12100000000000000 -04 -0? -#12150000000000000 -1E$ -0.$ -01 -03$ -0B -0' -1=$ -1:$ -0$ -1G$ -b11100000 ?$ -b11100000 . -b11100000 B$ -b11110000011110000 & -b11110000011110000 -$ -b11110000011110000 7$ -1O -1)" -1a" -1;# -b10110000 I$ -b1010000010110000 ) -b1010000010110000 A$ -b1010000010110000 N$ -b10 M$ -1+ -0@$ -05$ -b11000 5 -b11100101111101011010010110110101 7 -b11100101111101011010010110110101 " -b11100101111101011010010110110101 @ -14 -1? -#12150000000000100 -0E$ -11 -0=$ -b11100001 ?$ -b11100001 . -b11100001 B$ -0:$ -b1110000111110001 & -b1110000111110001 -$ -b1110000111110001 7$ -02$ -b100000 |# -b10010000 u# -0t# -b11111111 n# -b11111 g# -b11111111 `# -b1 K# -b100110 D# -b1001010 =# -1<# -b11111111 6# -b11111 /# -b11111111 (# -b11111111 !# -b1 q" -b100110 j" -b1001010 c" -1b" -b11111111 \" -b11100000 U" -b11111 N" -b1 9" -b100110 2" -b1001010 +" -1*" -b11111111 $" -b11100000 { -b11111 t -b11111111 m -b1 _ -b100110 X -b1001010 Q -1P -b11100001111100011010000110110001 # -b11100001111100011010000110110001 A -b11100001111100011010000110110001 /$ -#12200000000000000 -04 -0? -#12250000000000000 -1:$ -b11110000011110000 & -b11110000011110000 -$ -b11110000011110000 7$ -1.$ -12$ -1' -0O -1V -0)" -10" -0a" -1h" -0;# -1B# -0K -0L -1M -0P -0R -0S -0W -1T -0Y -0Z -1[ -0` -0a -1b -0g -0h -1i -0n -0o -1p -1s -0u -0v -1w -0z -0| -0} -1~ -0%" -0&" -1'" -0*" -0," -0-" -01" -1." -03" -04" -15" -0:" -0;" -1<" -0A" -0B" -1C" -0H" -0I" -1J" -1M" -0O" -0P" -1Q" -0T" -0V" -0W" -1X" -0]" -0^" -1_" -0b" -0d" -0e" -0i" -1f" -0k" -0l" -1m" -0r" -0s" -1t" -0y" -0z" -1{" -0"# -0## -1$# -0)# -0*# -1+# -1.# -00# -01# -12# -07# -08# -19# -0<# -0># -0?# -0C# -1@# -0E# -0F# -1G# -0L# -0M# -1N# -0S# -0T# -1U# -0Z# -0[# -1\# -0a# -0b# -1c# -1f# -0h# -0i# -1j# -0o# -0p# -1q# -1t# -0v# -0w# -0{# -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -1x# -0}# -0~# -1!$ -0&$ -0'$ -1($ -b11110000 ?$ -b11110000 . -b11110000 B$ -0G$ -1T$ -b11100 5 -b11100110111101101010011010110110 7 -b11100110111101101010011010110110 " -b11100110111101101010011010110110 @ -b100 F -b1011 J -b101 I -1@$ -b1 M$ -0+ -b11100001 H$ -b1110000110110000 ) -b1110000110110000 A$ -b1110000110110000 N$ -b10 Z$ -1- -b1010000010110000 V$ -b111100000111100001010000010110000 , -b111100000111100001010000010110000 R$ -14 -1? -#12250000000000100 -b11110001 ?$ -b11110001 . -b11110001 B$ -0:$ -b1110000111110001 & -b1110000111110001 -$ -b1110000111110001 7$ -02$ -b10010101 Q -1P -b1001100 X -b11 _ -b111111111 m -b111111 t -b111000000 { -b111111111 $" -b10010101 +" -1*" -b1001100 2" -b11 9" -b111111 N" -b111000000 U" -b111111111 \" -b10010101 c" -1b" -b1001100 j" -b11 q" -b111111111 !# -b111111111 (# -b111111 /# -b111111111 6# -b10010101 =# -1<# -b1001100 D# -b11 K# -b111111111 `# -b111111 g# -b111111111 n# -b100100000 u# -0t# -b11100001111100011010000110110001 # -b11100001111100011010000110110001 A -b11100001111100011010000110110001 /$ -b1000000 |# -#12300000000000000 -04 -0? -#12350000000000000 -0.$ -03$ -0B -0' -0$ -12$ -0T$ -1G$ -b10100000 ?$ -b10100000 . -b10100000 B$ -b1010000010110000 & -b1010000010110000 -$ -b1010000010110000 7$ -1K -0P -1R -1Y -1` -1g -1n -1u -1| -1%" -0*" -1," -13" -1:" -1A" -1H" -1O" -1V" -1]" -0b" -1d" -1k" -1r" -1y" -1"# -1)# -10# -17# -0<# -1># -1E# -1L# -1S# -1Z# -1a# -1h# -1o# -1t# -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -1v# -1}# -1&$ -1O -1)" -1a" -1;# -b0 Z$ -0- -b11110001 I$ -b1110000111110001 ) -b1110000111110001 A$ -b1110000111110001 N$ -b10 M$ -1+ -0@$ -15$ -b110 I -b1010 J -b101 F -b100000 5 -b11100111111101111010011110110111 7 -b11100111111101111010011110110111 " -b11100111111101111010011110110111 @ -14 -1? -#12350000000000100 -b10100001 ?$ -b10100001 . -b10100001 B$ -b1010000110110001 & -b1010000110110001 -$ -b1010000110110001 7$ -02$ -b10000000 |# -b1001000000 u# -0t# -b1111111111 n# -b1111111 g# -b1111111111 `# -b111 K# -b10011001 D# -b100101010 =# -1<# -b1111111111 6# -b1111111 /# -b1111111111 (# -b1111111111 !# -b111 q" -b10011001 j" -b100101010 c" -1b" -b1111111111 \" -b1110000000 U" -b1111111 N" -b111 9" -b10011001 2" -b100101010 +" -1*" -b1111111111 $" -b1110000000 { -b1111111 t -b1111111111 m -b111 _ -b10011001 X -b100101010 Q -1P -b11100001111100011010000110110001 # -b11100001111100011010000110110001 A -b11100001111100011010000110110001 /$ -#12400000000000000 -04 -0? -#12450000000000000 -13$ -1B -b1010000010110000 & -b1010000010110000 -$ -b1010000010110000 7$ -1.$ -1$ -12$ -1' -0O -0V -0] -1d -0)" -00" -07" -1>" -0a" -0h" -0o" -1v" -0;# -0B# -0I# -1P# -1z# -0K -1L -0P -0R -1S -0W -0Y -1Z -0` -1a -0g -1h -0n -1o -1s -0u -1v -0z -0| -1} -0%" -1&" -0*" -0," -1-" -01" -03" -14" -0:" -1;" -0A" -1B" -0H" -1I" -1M" -0O" -1P" -0T" -0V" -1W" -0]" -1^" -0b" -0d" -1e" -0i" -0k" -1l" -0r" -1s" -0y" -1z" -0"# -1## -0)# -1*# -1.# -00# -11# -07# -18# -0<# -0># -1?# -0C# -0E# -1F# -0L# -1M# -0S# -1T# -0Z# -1[# -0a# -1b# -1f# -0h# -1i# -0o# -1t# -1p# -0v# -1w# -0{# -b111100000111100001010000010110000 # -b111100000111100001010000010110000 A -b111100000111100001010000010110000 /$ -0}# -1~# -0&$ -1'$ -b10110000 ?$ -b10110000 . -b10110000 B$ -0G$ -18 -b11101000111110001010100010111000 7 -b1011101000111110001010100010111000 " -b1011101000111110001010100010111000 @ -b110 F -b1001 J -b111 I -1@$ -b1 M$ -0+ -b10100001 H$ -b1010000111110001 ) -b1010000111110001 A$ -b1010000111110001 N$ -0Y$ -b1 Z$ -b1110000111110001 U$ -b11100001111100011010000010110000 , -b11100001111100011010000010110000 R$ -14 -1? -#12450000000000100 -b10110001 ?$ -b10110001 . -b10110001 B$ -b1010000110110001 & -b1010000110110001 -$ -b1010000110110001 7$ -02$ -b1001010101 Q -1P -b100110011 X -b1111 _ -b11111111111 m -b11111111 t -b11100000000 { -b11111111111 $" -b1001010101 +" -1*" -b100110011 2" -b1111 9" -b11111111 N" -b11100000000 U" -b11111111111 \" -b1001010101 c" -1b" -b100110011 j" -b1111 q" -b11111111111 !# -b11111111111 (# -b11111111 /# -b11111111111 6# -b1001010101 =# -1<# -b100110011 D# -b1111 K# -b11111111111 `# -b11111111 g# -b11111111111 n# -b10010000000 u# -0t# -b11100001111100011010000110110001 # -b11100001111100011010000110110001 A -b11100001111100011010000110110001 /$ -b100000000 |# -#12500000000000000 -04 -0? -#12550000000000000 -0.$ -03$ -0B -0' -0$ -1G$ -b11100001 ?$ -b11100001 . -b11100001 B$ -b1110000111110001 & -b1110000111110001 -$ -b1110000111110001 7$ -0E -0d -0k -0r -0"" -0>" -0L" -0Z" -0v" -0}" -0&# -0-# -04# -0P# -0^# -0e# -0l# -0z# -b10110001 I$ -b1010000110110001 ) -b1010000110110001 A$ -b1010000110110001 N$ -b10 M$ -1+ -0@$ -05$ -0= -0D -b0 7 -08 -b0 " -b0 @ -14 -1? -#12550000000000100 -b11100010 ?$ -b11100010 . -b11100010 B$ -b1110001011110010 & -b1110001011110010 -$ -b1110001011110010 7$ -b1000000001 |# -b100100000000 u# -b111111111111 n# -b111111111 g# -b111111111111 `# -b1 R# -b11110 K# -b1001100110 D# -1C# -b10010101010 =# -0<# -b111111111111 6# -b111111111 /# -b111111111111 (# -b111111111111 !# -b1 x" -b11110 q" -b1001100110 j" -1i" -b10010101010 c" -0b" -b111111111111 \" -b111000000000 U" -b111111111 N" -b1 @" -b11110 9" -b1001100110 2" -11" -b10010101010 +" -0*" -b111111111111 $" -b111000000000 { -b111111111 t -b111111111111 m -b1 f -b11110 _ -b1001100110 X -1W -b10010101010 Q -0P -b11100010111100101010001010110010 # -b11100010111100101010001010110010 A -b11100010111100101010001010110010 /$ -#12600000000000000 -04 -0? -#12650000000000000 -1.$ -1' -b11110010 ?$ -b11110010 . -b11110010 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11100010 H$ -b1110001010110001 ) -b1110001010110001 A$ -b1110001010110001 N$ -b10 Z$ -1- -b1010000110110001 V$ -b11100001111100011010000110110001 , -b11100001111100011010000110110001 R$ -14 -1? -#12700000000000000 -04 -0? -#12750000000000000 -0.$ -03$ -0B -0' -0$ -0T$ -1G$ -b10100010 ?$ -b10100010 . -b10100010 B$ -b1010001010110010 & -b1010001010110010 -$ -b1010001010110010 7$ -b0 Z$ -0- -b11110010 I$ -b1110001011110010 ) -b1110001011110010 A$ -b1110001011110010 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#12800000000000000 -04 -0? -#12850000000000000 -13$ -1B -1.$ -1$ -1' -b10110010 ?$ -b10110010 . -b10110010 B$ -0G$ -1@$ -b1 M$ -0+ -b10100010 H$ -b1010001011110010 ) -b1010001011110010 A$ -b1010001011110010 N$ -b1 Z$ -b1110001011110010 U$ -b11100010111100101010000110110001 , -b11100010111100101010000110110001 R$ -14 -1? -#12900000000000000 -04 -0? -#12950000000000000 -0.$ -03$ -0B -0' -0$ -1G$ -b11100011 ?$ -b11100011 . -b11100011 B$ -b1110001111110011 & -b1110001111110011 -$ -b1110001111110011 7$ -1K -1P -0L -1R -0S -1W -1Y -0Z -0^ -1` -0a -1g -0h -1n -0o -1u -0v -1| -0} -1%" -1*" -0&" -1," -0-" -11" -13" -04" -08" -1:" -0;" -1A" -0B" -1H" -0I" -1O" -0P" -1V" -0W" -1]" -1b" -0^" -1d" -0e" -1i" -1k" -0l" -0p" -1r" -0s" -1y" -0z" -1"# -0## -1)# -0*# -10# -01# -17# -1<# -08# -1># -0?# -1C# -1E# -0F# -0J# -b11100011111100111010001110110011 # -b11100011111100111010001110110011 A -b11100011111100111010001110110011 /$ -1L# -0M# -1S# -0T# -1Z# -0[# -1a# -0b# -1h# -0i# -1o# -0p# -1v# -0w# -1}# -0~# -1&$ -0'$ -b10110010 I$ -b1010001010110010 ) -b1010001010110010 A$ -b1010001010110010 N$ -b10 M$ -1+ -0@$ -05$ -b110 I -b1010 J -b101 F -14 -1? -#13000000000000000 -04 -0? -#13050000000000000 -1.$ -1' -b11110011 ?$ -b11110011 . -b11110011 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11100011 H$ -b1110001110110010 ) -b1110001110110010 A$ -b1110001110110010 N$ -b10 Z$ -1- -b1010001010110010 V$ -b11100010111100101010001010110010 , -b11100010111100101010001010110010 R$ -14 -1? -#13100000000000000 -04 -0? -#13150000000000000 -0.$ -03$ -0B -0' -0$ -0T$ -1G$ -b10100011 ?$ -b10100011 . -b10100011 B$ -b1010001110110011 & -b1010001110110011 -$ -b1010001110110011 7$ -b0 Z$ -0- -b11110011 I$ -b1110001111110011 ) -b1110001111110011 A$ -b1110001111110011 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#13200000000000000 -04 -0? -#13250000000000000 -13$ -1B -1.$ -1$ -1' -b10110011 ?$ -b10110011 . -b10110011 B$ -0G$ -1@$ -b1 M$ -0+ -b10100011 H$ -b1010001111110011 ) -b1010001111110011 A$ -b1010001111110011 N$ -b1 Z$ -b1110001111110011 U$ -b11100011111100111010001010110010 , -b11100011111100111010001010110010 R$ -14 -1? -#13300000000000000 -04 -0? -#13350000000000000 -0.$ -03$ -0B -0' -0$ -1G$ -b11100100 ?$ -b11100100 . -b11100100 B$ -b1110010011110100 & -b1110010011110100 -$ -b1110010011110100 7$ -0K -0P -0R -0W -0Y -1^ -0` -0g -0n -0u -0| -0%" -0*" -0," -01" -03" -18" -0:" -0A" -0H" -0O" -0V" -0]" -0b" -0d" -0i" -0k" -1p" -0r" -0y" -0"# -0)# -00# -07# -0<# -0># -0C# -0E# -1J# -b11100100111101001010010010110100 # -b11100100111101001010010010110100 A -b11100100111101001010010010110100 /$ -0L# -0S# -0Z# -0a# -0h# -0o# -0v# -0}# -0&$ -b10110011 I$ -b1010001110110011 ) -b1010001110110011 A$ -b1010001110110011 N$ -b10 M$ -1+ -0@$ -05$ -b101 I -b1011 J -b100 F -14 -1? -#13400000000000000 -04 -0? -#13450000000000000 -1.$ -1' -b11110100 ?$ -b11110100 . -b11110100 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11100100 H$ -b1110010010110011 ) -b1110010010110011 A$ -b1110010010110011 N$ -b10 Z$ -1- -b1010001110110011 V$ -b11100011111100111010001110110011 , -b11100011111100111010001110110011 R$ -14 -1? -#13500000000000000 -04 -0? -#13550000000000000 -0.$ -03$ -0B -0' -0$ -0T$ -1G$ -b10100100 ?$ -b10100100 . -b10100100 B$ -b1010010010110100 & -b1010010010110100 -$ -b1010010010110100 7$ -b0 Z$ -0- -b11110100 I$ -b1110010011110100 ) -b1110010011110100 A$ -b1110010011110100 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#13600000000000000 -04 -0? -#13650000000000000 -13$ -1B -1.$ -1$ -1' -b10110100 ?$ -b10110100 . -b10110100 B$ -0G$ -1@$ -b1 M$ -0+ -b10100100 H$ -b1010010011110100 ) -b1010010011110100 A$ -b1010010011110100 N$ -b1 Z$ -b1110010011110100 U$ -b11100100111101001010001110110011 , -b11100100111101001010001110110011 R$ -14 -1? -#13700000000000000 -04 -0? -#13750000000000000 -0.$ -03$ -0B -0' -0$ -1G$ -b11100101 ?$ -b11100101 . -b11100101 B$ -b1110010111110101 & -b1110010111110101 -$ -b1110010111110101 7$ -1K -1P -1L -0M -1R -1S -0W -0T -1Y -1Z -0[ -1^ -1` -1a -0b -0e -1g -1h -0i -1n -1o -0p -1u -1v -0w -1| -1} -0~ -1%" -1*" -1&" -0'" -1," -1-" -01" -0." -13" -14" -05" -18" -1:" -1;" -0<" -0?" -1A" -1B" -0C" -1H" -1I" -0J" -1O" -1P" -0Q" -1V" -1W" -0X" -1]" -1b" -1^" -0_" -1d" -1e" -0i" -0f" -1k" -1l" -0m" -1p" -1r" -1s" -0t" -0w" -1y" -1z" -0{" -1"# -1## -0$# -1)# -1*# -0+# -10# -11# -02# -17# -1<# -18# -09# -1># -1?# -0C# -0@# -1E# -1F# -0G# -1J# -1L# -1M# -0N# -0Q# -1S# -1T# -0U# -1Z# -1[# -0\# -1a# -1b# -0c# -1h# -1i# -0j# -1o# -1p# -0q# -1v# -1w# -0x# -0{# -b11100101111101011010010110110101 # -b11100101111101011010010110110101 A -b11100101111101011010010110110101 /$ -1}# -1~# -0!$ -1&$ -1'$ -0($ -b10110100 I$ -b1010010010110100 ) -b1010010010110100 A$ -b1010010010110100 N$ -b10 M$ -1+ -0@$ -05$ -b100 I -b1100 J -b11 F -14 -1? -#13800000000000000 -04 -0? -#13850000000000000 -1.$ -1' -b11110101 ?$ -b11110101 . -b11110101 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11100101 H$ -b1110010110110100 ) -b1110010110110100 A$ -b1110010110110100 N$ -b10 Z$ -1- -b1010010010110100 V$ -b11100100111101001010010010110100 , -b11100100111101001010010010110100 R$ -14 -1? -#13900000000000000 -04 -0? -#13950000000000000 -0.$ -03$ -0B -0' -0$ -0T$ -1G$ -b10100101 ?$ -b10100101 . -b10100101 B$ -b1010010110110101 & -b1010010110110101 -$ -b1010010110110101 7$ -b0 Z$ -0- -b11110101 I$ -b1110010111110101 ) -b1110010111110101 A$ -b1110010111110101 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#14000000000000000 -04 -0? -#14050000000000000 -13$ -1B -1.$ -1$ -1' -b10110101 ?$ -b10110101 . -b10110101 B$ -0G$ -1@$ -b1 M$ -0+ -b10100101 H$ -b1010010111110101 ) -b1010010111110101 A$ -b1010010111110101 N$ -b1 Z$ -b1110010111110101 U$ -b11100101111101011010010010110100 , -b11100101111101011010010010110100 R$ -14 -1? -#14100000000000000 -04 -0? -#14150000000000000 -0.$ -03$ -0B -0' -0$ -1G$ -b11100110 ?$ -b11100110 . -b11100110 B$ -b1110011011110110 & -b1110011011110110 -$ -b1110011011110110 7$ -0K -0P -0R -1W -0Y -0` -0g -0n -0u -0| -0%" -0*" -0," -11" -03" -0:" -0A" -0H" -0O" -0V" -0]" -0b" -0d" -1i" -0k" -0r" -0y" -0"# -0)# -00# -07# -0<# -0># -1C# -b11100110111101101010011010110110 # -b11100110111101101010011010110110 A -b11100110111101101010011010110110 /$ -0E# -0L# -0S# -0Z# -0a# -0h# -0o# -0v# -0}# -0&$ -b10110101 I$ -b1010010110110101 ) -b1010010110110101 A$ -b1010010110110101 N$ -b10 M$ -1+ -0@$ -05$ -b11 I -b1101 J -b10 F -14 -1? -#14200000000000000 -04 -0? -#14250000000000000 -1.$ -1' -b11110110 ?$ -b11110110 . -b11110110 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11100110 H$ -b1110011010110101 ) -b1110011010110101 A$ -b1110011010110101 N$ -b10 Z$ -1- -b1010010110110101 V$ -b11100101111101011010010110110101 , -b11100101111101011010010110110101 R$ -14 -1? -#14300000000000000 -04 -0? -#14350000000000000 -0.$ -03$ -0B -0' -0$ -0T$ -1G$ -b10100110 ?$ -b10100110 . -b10100110 B$ -b1010011010110110 & -b1010011010110110 -$ -b1010011010110110 7$ -b0 Z$ -0- -b11110110 I$ -b1110011011110110 ) -b1110011011110110 A$ -b1110011011110110 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#14400000000000000 -04 -0? -#14450000000000000 -13$ -1B -1.$ -1$ -1' -b10110110 ?$ -b10110110 . -b10110110 B$ -0G$ -1@$ -b1 M$ -0+ -b10100110 H$ -b1010011011110110 ) -b1010011011110110 A$ -b1010011011110110 N$ -b1 Z$ -b1110011011110110 U$ -b11100110111101101010010110110101 , -b11100110111101101010010110110101 R$ -14 -1? -#14500000000000000 -04 -0? -#14550000000000000 -0.$ -03$ -0B -0' -0$ -1G$ -b11100111 ?$ -b11100111 . -b11100111 B$ -b1110011111110111 & -b1110011111110111 -$ -b1110011111110111 7$ -1K -1P -0L -1R -0S -1W -1Y -0Z -1^ -1` -0a -0e -1g -0h -1n -0o -1u -0v -1| -0} -1%" -1*" -0&" -1," -0-" -11" -13" -04" -18" -1:" -0;" -0?" -1A" -0B" -1H" -0I" -1O" -0P" -1V" -0W" -1]" -1b" -0^" -1d" -0e" -1i" -1k" -0l" -1p" -1r" -0s" -0w" -1y" -0z" -1"# -0## -1)# -0*# -10# -01# -17# -1<# -08# -1># -0?# -1C# -1E# -0F# -1J# -1L# -0M# -0Q# -1S# -0T# -1Z# -0[# -1a# -0b# -1h# -0i# -1o# -0p# -1v# -0w# -0{# -b11100111111101111010011110110111 # -b11100111111101111010011110110111 A -b11100111111101111010011110110111 /$ -1}# -0~# -1&$ -0'$ -b10110110 I$ -b1010011010110110 ) -b1010011010110110 A$ -b1010011010110110 N$ -b10 M$ -1+ -0@$ -05$ -b10 I -b1110 J -b1 F -14 -1? -#14600000000000000 -04 -0? -#14650000000000000 -1.$ -1' -b11110111 ?$ -b11110111 . -b11110111 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11100111 H$ -b1110011110110110 ) -b1110011110110110 A$ -b1110011110110110 N$ -b10 Z$ -1- -b1010011010110110 V$ -b11100110111101101010011010110110 , -b11100110111101101010011010110110 R$ -14 -1? -#14700000000000000 -04 -0? -#14750000000000000 -0.$ -03$ -0B -0' -0$ -0T$ -1G$ -b10100111 ?$ -b10100111 . -b10100111 B$ -b1010011110110111 & -b1010011110110111 -$ -b1010011110110111 7$ -b0 Z$ -0- -b11110111 I$ -b1110011111110111 ) -b1110011111110111 A$ -b1110011111110111 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#14800000000000000 -04 -0? -#14850000000000000 -13$ -1B -1.$ -1$ -1' -b10110111 ?$ -b10110111 . -b10110111 B$ -0G$ -1@$ -b1 M$ -0+ -b10100111 H$ -b1010011111110111 ) -b1010011111110111 A$ -b1010011111110111 N$ -b1 Z$ -b1110011111110111 U$ -b11100111111101111010011010110110 , -b11100111111101111010011010110110 R$ -14 -1? -#14900000000000000 -04 -0? -#14950000000000000 -0.$ -03$ -0B -0' -0$ -10$ -1G$ -b11101000 ?$ -b11101000 . -b11101000 B$ -b1110100011111000 & -b1110100011111000 -$ -b1110100011111000 7$ -0K -0P -0R -0W -0Y -0^ -0` -1e -0g -0n -0u -0| -0%" -0*" -0," -01" -03" -08" -0:" -1?" -0A" -0H" -0O" -0V" -0]" -0b" -0d" -0i" -0k" -0p" -0r" -1w" -0y" -0"# -0)# -00# -07# -0<# -0># -0C# -0E# -0J# -0L# -1Q# -0S# -0Z# -0a# -0h# -0o# -0v# -1{# -b1011101000111110001010100010111000 # -b1011101000111110001010100010111000 A -b1011101000111110001010100010111000 /$ -0}# -0&$ -b10110111 I$ -b1010011110110111 ) -b1010011110110111 A$ -b1010011110110111 N$ -b10 M$ -1+ -0@$ -05$ -b1 I -b1111 J -b0 F -14 -1? -#15000000000000000 -04 -0? -#15050000000000000 -1.$ -1' -b11111000 ?$ -b11111000 . -b11111000 B$ -0G$ -1T$ -1@$ -b1 M$ -0+ -b11101000 H$ -b1110100010110111 ) -b1110100010110111 A$ -b1110100010110111 N$ -b10 Z$ -1- -b1010011110110111 V$ -b11100111111101111010011110110111 , -b11100111111101111010011110110111 R$ -14 -1? -#15100000000000000 -04 -0? -#15150000000000000 -0.$ -03$ -0B -0' -18$ -0$ -0T$ -1G$ -b10101000 ?$ -b10101000 . -b10101000 B$ -b101010100010111000 & -b101010100010111000 -$ -b101010100010111000 7$ -b0 Z$ -0- -b11111000 I$ -b1110100011111000 ) -b1110100011111000 A$ -b1110100011111000 N$ -b10 M$ -1+ -0@$ -15$ -14 -1? -#15200000000000000 -04 -0? -#15250000000000000 -1D$ -13$ -1B -00 -1.$ -1$ -1<$ -1' -b10111000 ?$ -b10111000 . -b10111000 B$ -0G$ -1@$ -b1 M$ -0+ -b10101000 H$ -b1010100011111000 ) -b1010100011111000 A$ -b1010100011111000 N$ -b1 Z$ -b1110100011111000 U$ -b11101000111110001010011110110111 , -b11101000111110001010011110110111 R$ -14 -1? -#15300000000000000 -04 -0? -#15350000000000000 -0D$ -10 -0' -0F$ -0<$ -08$ -0$ -0.$ -06$ -12 -03$ -0B -1G$ -1O$ -b11101000 ?$ -b11101000 . -b11101000 B$ -b1110100011111000 & -b1110100011111000 -$ -b1110100011111000 7$ -0>$ -0( -0% -b10111000 I$ -b10 M$ -1+ -1J$ -b101010100010111000 ) -b101010100010111000 A$ -b101010100010111000 N$ -0@$ -05$ -b0 I -b10000 J -1G -14 -1? -#15400000000000000 -04 -0? -#15450000000000000 -0G$ -1T$ -b0 M$ -0+ -1W$ -b10 Z$ -1- -b1010100010111000 V$ -b1011101000111110001010100010111000 , -b1011101000111110001010100010111000 R$ -14 -1? -#15500000000000000 -04 -0? -#15550000000000000 -0T$ -b0 Z$ -0- -14 -1? -#15600000000000000 -04 -0? -#15650000000000000 -14 -1? -#15700000000000000 -04 -0? -#15750000000000000 -14 -1? -#15800000000000000 -04 -0? -#15850000000000000 -14 -1? -#15900000000000000 -04 -0? -#15950000000000000 -14 -1? -#16000000000000000 -04 -0? -#16050000000000000 -14 -1? -#16100000000000000 -04 -0? -#16150000000000000 -14 -1? -#16200000000000000 -04 -0? -#16250000000000000 -14 -1? -#16300000000000000 -04 -0? -#16350000000000000 -14 -1? -#16400000000000000 -04 -0? -#16450000000000000 -14 -1? -#16500000000000000 -04 -0? -#16550000000000000 -14 -1? -#16600000000000000 -04 -0? -#16650000000000000 -14 -1? -#16700000000000000 -04 -0? -#16750000000000000 -14 -1? -#16800000000000000 -04 -0? -#16850000000000000 -14 -1? -#16900000000000000 -04 -0? -#16950000000000000 -14 -1? -#17000000000000000 -04 -0? -#17050000000000000 -14 -1? -#17100000000000000 -04 -0? -#17150000000000000 -14 -1? -#17200000000000000 -04 -0? -#17250000000000000 -14 -1? -#17300000000000000 -04 -0? -#17350000000000000 -14 -1? -#17400000000000000 -04 -0? -#17450000000000000 -14 -1? -#17500000000000000 -04 -0? -#17550000000000000 -14 -1? -#17600000000000000 -04 -0? -#17650000000000000 -14 -1? -#17700000000000000 -04 -0? -#17750000000000000 -14 -1? -#17800000000000000 -04 -0? -#17850000000000000 -14 -1? -#17900000000000000 -04 -0? -#17950000000000000 -14 -1? -#18000000000000000 -04 -0? -#18050000000000000 -14 -1? -#18100000000000000 -04 -0? -#18150000000000000 -14 -1? -#18200000000000000 -04 -0? -#18250000000000000 -14 -1? -#18300000000000000 -04 -0? -#18350000000000000 -14 -1? -#18400000000000000 -04 -0? -#18450000000000000 -14 -1? -#18500000000000000 -04 -0? -#18550000000000000 -14 -1? -#18600000000000000 -04 -0? -#18650000000000000 -14 -1? -#18700000000000000 -04 -0? -#18750000000000000 -14 -1? -#18800000000000000 -04 -0? -#18850000000000000 -14 -1? -#18900000000000000 -04 -0? -#18950000000000000 -14 -1? -#19000000000000000 -04 -0? -#19050000000000000 -14 -1? -#19100000000000000 -04 -0? -#19150000000000000 -14 -1? -#19200000000000000 -04 -0? -#19250000000000000 -14 -1? -#19300000000000000 -04 -0? -#19350000000000000 -14 -1? -#19400000000000000 -04 -0? -#19450000000000000 -14 -1? -#19500000000000000 -04 -0? -#19550000000000000 -14 -1? -#19600000000000000 -04 -0? -#19650000000000000 -14 -1? -#19700000000000000 -04 -0? -#19750000000000000 -14 -1? -#19800000000000000 -04 -0? -#19850000000000000 -14 -1? -#19900000000000000 -04 -0? -#19950000000000000 -14 -1? -#20000000000000000 -04 -0? diff --git a/fpga/usrp2/fifo/fifo_tb.v b/fpga/usrp2/fifo/fifo_tb.v index f561df7fa..327da4700 100644 --- a/fpga/usrp2/fifo/fifo_tb.v +++ b/fpga/usrp2/fifo/fifo_tb.v @@ -24,20 +24,39 @@ module fifo_new_tb();     wire i1_sr, i1_dr;     wire i2_sr, i2_dr;     wire i3_sr, i3_dr; +   wire i7_sr, i7_dr; +        reg i4_dr = 0;     wire i4_sr; -   wire [35:0] i1, i4; +   wire [35:0] i1, i4, i7;     wire [18:0] i2, i3;     wire [7:0] ll_data;     wire ll_src_rdy_n, ll_dst_rdy_n, ll_sof_n, ll_eof_n; +   wire [35:0] err_dat; +   wire        err_src_rdy, err_dst_rdy; + +   reg 	       trigger = 0; +   initial #10000 trigger = 1;     fifo_short #(.WIDTH(36)) fifo_short1       (.clk(clk),.reset(rst),.clear(clear),        .datain(f36_in),.src_rdy_i(src_rdy_f36i),.dst_rdy_o(dst_rdy_f36i), -      .dataout(i1),.src_rdy_o(i1_sr),.dst_rdy_i(i1_dr) ); +      .dataout(i7),.src_rdy_o(i7_sr),.dst_rdy_i(i7_dr) ); +   gen_context_pkt #(.PROT_ENG_FLAGS(1)) gcp +     (.clk(clk),.reset(rst),.clear(clear), +      .trigger(trigger), .sent(), +      .streamid(32'hDEAD_F00D), .vita_time(64'h01234567_89ABCDEF), .message(32'hBEEF_2940), +      .data_o(err_dat), .src_rdy_o(err_src_rdy), .dst_rdy_i(err_dst_rdy)); +    +   fifo36_mux #(.prio(0)) fifo36_mux +     (.clk(clk), .reset(rst), .clear(clear), +      .data0_i(i7), .src0_rdy_i(i7_sr), .dst0_rdy_o(i7_dr), +      .data1_i(err_dat), .src1_rdy_i(err_src_rdy), .dst1_rdy_o(err_dst_rdy), +      .data_o(i1), .src_rdy_o(i1_sr), .dst_rdy_i(i1_dr)); +        fifo36_to_fifo19 fifo36_to_fifo19       (.clk(clk),.reset(rst),.clear(clear),        .f36_datain(i1),.f36_src_rdy_i(i1_sr),.f36_dst_rdy_o(i1_dr), @@ -59,7 +78,7 @@ module fifo_new_tb();       (.clk(clk),.reset(rst),.clear(clear),        .f19_datain(i3),.f19_src_rdy_i(i3_sr),.f19_dst_rdy_o(i3_dr),        .f36_dataout(i4),.f36_src_rdy_o(i4_sr),.f36_dst_rdy_i(i4_dr) ); -      +     task ReadFromFIFO36;        begin  	 $display("Read from FIFO36"); diff --git a/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_bpcu.v b/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_bpcu.v index a7c686e7e..81587e25c 100644 --- a/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_bpcu.v +++ b/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_bpcu.v @@ -125,7 +125,7 @@ module aeMB_bpcu (/*AUTOARG*/     reg [31:2] 	   rPC, xPC;     reg [31:2] 	   rPCLNK, xPCLNK; -   assign 	   iwb_adr_o = rIPC[IW-1:2]; +   assign 	   iwb_adr_o = gena ? xIPC[IW-1:2] :  rIPC[IW-1:2]; //IJB     always @(/*AUTOSENSE*/rBRA or rIPC or rPC or rRESULT) begin        //xPCLNK <= (^rATOM) ? rPC : rPC; @@ -168,7 +168,8 @@ module aeMB_bpcu (/*AUTOARG*/  	rATOM <= 2'h0;  	rBRA <= 1'h0;  	rDLY <= 1'h0; -	rIPC <= 30'h0; +//	rIPC <= 30'h0; +	rIPC <= 30'h3fffffff; // DWORD aligned address   	rPC <= 30'h0;  	rPCLNK <= 30'h0;  	// End of automatics diff --git a/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_core_BE.v b/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_core_BE.v index 9ffa20ff2..38ca3a023 100644 --- a/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_core_BE.v +++ b/fpga/usrp2/opencores/aemb/rtl/verilog/aeMB_core_BE.v @@ -10,12 +10,10 @@ module aeMB_core_BE      parameter MUL=0, parameter BSF=0)      (input sys_clk_i,       input sys_rst_i, - -     output iwb_stb_o, -     output [ISIZ-1:0] iwb_adr_o, -     input [31:0] iwb_dat_i, -     input iwb_ack_i, - +     // Instruction port +     output [14:0] if_adr, +     input [31:0] if_dat, +     // Data port       output dwb_we_o,       output dwb_stb_o,       output [DSIZ-1:0] dwb_adr_o, @@ -28,17 +26,28 @@ module aeMB_core_BE       input sys_int_i,        input sys_exc_i); -   assign  dwb_cyc_o = dwb_stb_o; +   wire [ISIZ-1:0] iwb_adr_o; +   wire [31:0] 	   iwb_dat_i; +   wire 	   iwb_ack_i; +   wire 	   iwb_stb_o; +    +   assign dwb_cyc_o = dwb_stb_o; +   assign iwb_ack_i = 1'b1; +   assign if_adr = iwb_adr_o[14:0]; +   assign iwb_dat_i = if_dat; + +   // Note some "wishbone" instruction fetch signals pruned on external interface +   // but not propogated change deep into aeMB.     aeMB_edk32 #(.IW(ISIZ),.DW(DSIZ),.MUL(MUL),.BSF(BSF))       aeMB_edk32 (.sys_clk_i(sys_clk_i),   		 .sys_rst_i(sys_rst_i), -		  +		 // Instruction Port  		 .iwb_stb_o(iwb_stb_o),  		 .iwb_adr_o(iwb_adr_o[ISIZ-1:2]),  		 .iwb_ack_i(iwb_ack_i),  		 .iwb_dat_i(iwb_dat_i), -		  +		 // Data port  		 .dwb_wre_o(dwb_we_o),  		 .dwb_stb_o(dwb_stb_o),  		 .dwb_adr_o(dwb_adr_o[DSIZ-1:2]), diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/dsp_core_tx.v index 22d3d44a3..79d92c9b3 100644 --- a/fpga/usrp2/sdr_lib/dsp_core_tx.v +++ b/fpga/usrp2/sdr_lib/dsp_core_tx.v @@ -29,11 +29,11 @@ module dsp_core_tx       (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),        .in(set_data),.out({scale_i,scale_q}),.changed()); -   setting_reg #(.my_addr(BASE+2)) sr_2 +   setting_reg #(.my_addr(BASE+2), .width(10)) sr_2       (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),        .in(set_data),.out({enable_hb1, enable_hb2, interp_rate}),.changed()); -   setting_reg #(.my_addr(BASE+4)) sr_4 +   setting_reg #(.my_addr(BASE+4), .width(8)) sr_4       (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),        .in(set_data),.out({dacmux_b,dacmux_a}),.changed()); diff --git a/fpga/usrp2/top/Makefile.common b/fpga/usrp2/top/Makefile.common index d0435fa1e..4da64ac28 100644 --- a/fpga/usrp2/top/Makefile.common +++ b/fpga/usrp2/top/Makefile.common @@ -47,7 +47,7 @@ $(ISE_FILE): $$(SOURCES) $$(MAKEFILE_LIST)  	@echo $@  	$(ISE_HELPER) "" -$(BIN_FILE): $(ISE_FILE) +$(BIN_FILE): $(ISE_FILE) $$(SOURCES) $$(MAKEFILE_LIST)  	@echo $@  	$(ISE_HELPER) "Generate Programming File"  	touch $@ diff --git a/fpga/usrp2/top/u2_rev3/u2_core.v b/fpga/usrp2/top/u2_rev3/u2_core.v index b67d8edd6..9ba3cc136 100644..100755 --- a/fpga/usrp2/top/u2_rev3/u2_core.v +++ b/fpga/usrp2/top/u2_rev3/u2_core.v @@ -277,33 +277,33 @@ module u2_core     // ///////////////////////////////////////////////////////////////////     // RAM Loader -   wire [31:0] 	 ram_loader_dat, iwb_dat; -   wire [15:0] 	 ram_loader_adr, iwb_adr; +   wire [31:0] 	 ram_loader_dat, if_dat; +   wire [15:0] 	 ram_loader_adr; +   wire [14:0] 	 if_adr;     wire [3:0] 	 ram_loader_sel; -   wire 	 ram_loader_stb, ram_loader_we, ram_loader_ack; +   wire 	 ram_loader_stb, ram_loader_we;     wire 	 iwb_ack, iwb_stb;     ram_loader #(.AWIDTH(16),.RAM_SIZE(RAM_SIZE)) -     ram_loader (.clk_i(wb_clk),.rst_i(ram_loader_rst), +     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), +		 .wb_we(ram_loader_we), +		 .ram_loader_done(ram_loader_done),  		 // CPLD Interface -		 .cfg_clk_i(cpld_clk), -		 .cfg_data_i(cpld_din), -		 .start_o(cpld_start_int), -		 .mode_o(cpld_mode_int), -		 .done_o(cpld_done_int), -		 .detached_i(cpld_detached), -		 // Wishbone Interface -		 .wb_dat_o(ram_loader_dat),.wb_adr_o(ram_loader_adr), -		 .wb_stb_o(ram_loader_stb),.wb_cyc_o(),.wb_sel_o(ram_loader_sel), -		 .wb_we_o(ram_loader_we),.wb_ack_i(ram_loader_ack), -		 .ram_loader_done_o(ram_loader_done)); - +		 .cpld_clk(cpld_clk), +		 .cpld_din(cpld_din), +		 .cpld_start(cpld_start_int), +		 .cpld_mode(cpld_mode_int), +		 .cpld_done(cpld_done_int), +		 .cpld_detached(cpld_detached)); +        // /////////////////////////////////////////////////////////////////////////     // Processor     aeMB_core_BE #(.ISIZ(16),.DSIZ(16),.MUL(0),.BSF(1))       aeMB (.sys_clk_i(wb_clk), .sys_rst_i(wb_rst),  	   // Instruction Wishbone bus to I-RAM -	   .iwb_stb_o(iwb_stb),.iwb_adr_o(iwb_adr), -	   .iwb_dat_i(iwb_dat),.iwb_ack_i(iwb_ack), +	   .if_adr(if_adr), +	   .if_dat(if_dat),  	   // Data Wishbone bus to system bus fabric  	   .dwb_we_o(m0_we),.dwb_stb_o(m0_stb),.dwb_dat_o(m0_dat_i),.dwb_adr_o(m0_adr),  	   .dwb_dat_i(m0_dat_o),.dwb_ack_i(m0_ack),.dwb_sel_o(m0_sel),.dwb_cyc_o(m0_cyc), @@ -317,16 +317,16 @@ module u2_core     // I-port connects directly to processor and ram loader     wire 	 flush_icache; -   ram_harv_cache #(.AWIDTH(15),.RAM_SIZE(RAM_SIZE),.ICWIDTH(7),.DCWIDTH(6)) +   ram_harvard #(.AWIDTH(15),.RAM_SIZE(RAM_SIZE),.ICWIDTH(7),.DCWIDTH(6))       sys_ram(.wb_clk_i(wb_clk),.wb_rst_i(wb_rst),  	     .ram_loader_adr_i(ram_loader_adr[14: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_ack_o(ram_loader_ack), +	     .ram_loader_we_i(ram_loader_we),  	     .ram_loader_done_i(ram_loader_done), -	     .iwb_adr_i(iwb_adr[14:0]), .iwb_stb_i(iwb_stb), -	     .iwb_dat_o(iwb_dat), .iwb_ack_o(iwb_ack), +	     .if_adr(if_adr),  +	     .if_data(if_dat),   	     .dwb_adr_i(s0_adr[14: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), @@ -622,7 +622,7 @@ module u2_core     // ///////////////////////////////////////////////////////////////////////////////////     // External RAM Interface - +/*     localparam PAGE_SIZE = 10;  // PAGE SIZE is in bytes, 10 = 1024 bytes     wire [15:0] bus2ram, ram2bus; @@ -650,6 +650,7 @@ module u2_core        .sram_bw(),.sram_adv(RAM_LDn),.sram_ce(RAM_CENn),.sram_oe(RAM_OEn),        .sram_mode(),.sram_zz() ); +*/     assign      RAM_CE1n = 0;     assign      RAM_D[17:16] = 2'bzz; @@ -700,7 +701,8 @@ module u2_core  			     { wr2_flags, rd2_flags },  			     { GMII_TX_EN,3'd0, wr2_ready_i, wr2_ready_o, rd2_ready_i, rd2_ready_o } }; -   assign  debug_gpio_0 = debug_mac; //eth_mac_debug; +   assign  debug_gpio_0 = 0; + //debug_mac; //eth_mac_debug;     assign  debug_gpio_1 = 0;  endmodule // u2_core diff --git a/fpga/usrp2/top/u2_rev3/u2_core_udp.v b/fpga/usrp2/top/u2_rev3/u2_core_udp.v index cb0ed78c7..124930c23 100644 --- a/fpga/usrp2/top/u2_rev3/u2_core_udp.v +++ b/fpga/usrp2/top/u2_rev3/u2_core_udp.v @@ -180,6 +180,11 @@ module u2_core     wire [31:0] 	irq;     wire [63:0] 	vita_time; +   wire 	 run_rx, run_tx; +   reg 		 run_rx_d1; +   always @(posedge dsp_clk) +     run_rx_d1 <= run_rx; +        // ///////////////////////////////////////////////////////////////////////////////////////////////     // Wishbone Single Master INTERCON     localparam 	dw = 32;  // Data bus width @@ -279,33 +284,33 @@ module u2_core     // ///////////////////////////////////////////////////////////////////     // RAM Loader -   wire [31:0] 	 ram_loader_dat, iwb_dat; -   wire [15:0] 	 ram_loader_adr, iwb_adr; +   wire [31:0] 	 ram_loader_dat, if_dat; +   wire [15:0] 	 ram_loader_adr; +   wire [14:0] 	 if_adr;     wire [3:0] 	 ram_loader_sel; -   wire 	 ram_loader_stb, ram_loader_we, ram_loader_ack; +   wire 	 ram_loader_stb, ram_loader_we;     wire 	 iwb_ack, iwb_stb;     ram_loader #(.AWIDTH(16),.RAM_SIZE(RAM_SIZE)) -     ram_loader (.clk_i(wb_clk),.rst_i(ram_loader_rst), +     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), +		 .wb_we(ram_loader_we), +		 .ram_loader_done(ram_loader_done),  		 // CPLD Interface -		 .cfg_clk_i(cpld_clk), -		 .cfg_data_i(cpld_din), -		 .start_o(cpld_start_int), -		 .mode_o(cpld_mode_int), -		 .done_o(cpld_done_int), -		 .detached_i(cpld_detached), -		 // Wishbone Interface -		 .wb_dat_o(ram_loader_dat),.wb_adr_o(ram_loader_adr), -		 .wb_stb_o(ram_loader_stb),.wb_cyc_o(),.wb_sel_o(ram_loader_sel), -		 .wb_we_o(ram_loader_we),.wb_ack_i(ram_loader_ack), -		 .ram_loader_done_o(ram_loader_done)); - +		 .cpld_clk(cpld_clk), +		 .cpld_din(cpld_din), +		 .cpld_start(cpld_start_int), +		 .cpld_mode(cpld_mode_int), +		 .cpld_done(cpld_done_int), +		 .cpld_detached(cpld_detached)); +        // /////////////////////////////////////////////////////////////////////////     // Processor     aeMB_core_BE #(.ISIZ(16),.DSIZ(16),.MUL(0),.BSF(1))       aeMB (.sys_clk_i(wb_clk), .sys_rst_i(wb_rst),  	   // Instruction Wishbone bus to I-RAM -	   .iwb_stb_o(iwb_stb),.iwb_adr_o(iwb_adr), -	   .iwb_dat_i(iwb_dat),.iwb_ack_i(iwb_ack), +	   .if_adr(if_adr), +	   .if_dat(if_dat),  	   // Data Wishbone bus to system bus fabric  	   .dwb_we_o(m0_we),.dwb_stb_o(m0_stb),.dwb_dat_o(m0_dat_i),.dwb_adr_o(m0_adr),  	   .dwb_dat_i(m0_dat_o),.dwb_ack_i(m0_ack),.dwb_sel_o(m0_sel),.dwb_cyc_o(m0_cyc), @@ -319,16 +324,16 @@ module u2_core     // I-port connects directly to processor and ram loader     wire 	 flush_icache; -   ram_harv_cache #(.AWIDTH(15),.RAM_SIZE(RAM_SIZE),.ICWIDTH(7),.DCWIDTH(6)) +   ram_harvard #(.AWIDTH(15),.RAM_SIZE(RAM_SIZE),.ICWIDTH(7),.DCWIDTH(6))       sys_ram(.wb_clk_i(wb_clk),.wb_rst_i(wb_rst),  	     .ram_loader_adr_i(ram_loader_adr[14: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_ack_o(ram_loader_ack), +	     .ram_loader_we_i(ram_loader_we),  	     .ram_loader_done_i(ram_loader_done), -	     .iwb_adr_i(iwb_adr[14:0]), .iwb_stb_i(iwb_stb), -	     .iwb_dat_o(iwb_dat), .iwb_ack_o(iwb_ack), +	     .if_adr(if_adr),  +	     .if_data(if_dat),   	     .dwb_adr_i(s0_adr[14: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), @@ -418,7 +423,10 @@ module u2_core         cycle_count <= 0;       else         cycle_count <= cycle_count + 1; -    + +   //compatibility number -> increment when the fpga has been sufficiently altered +   localparam compat_num = 32'd1; +     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), @@ -426,7 +434,7 @@ module u2_core        .word00(status_b0),.word01(status_b1),.word02(status_b2),.word03(status_b3),        .word04(status_b4),.word05(status_b5),.word06(status_b6),.word07(status_b7),        .word08(status),.word09({sim_mode,27'b0,clock_divider[3:0]}),.word10(vita_time[63:32]), -      .word11(vita_time[31:0]),.word12(32'b0),.word13(irq),.word14(status_enc),.word15(cycle_count) +      .word11(vita_time[31:0]),.word12(compat_num),.word13(irq),.word14(status_enc),.word15(cycle_count)        );     // ///////////////////////////////////////////////////////////////////////// @@ -461,11 +469,20 @@ module u2_core        .tx_f36_data(udp_tx_data), .tx_f36_src_rdy_i(udp_tx_src_rdy), .tx_f36_dst_rdy_o(udp_tx_dst_rdy),        .debug(debug_udp) ); +   wire [35:0] 	 tx_err_data, udp1_tx_data; +   wire 	 tx_err_src_rdy, tx_err_dst_rdy, udp1_tx_src_rdy, udp1_tx_dst_rdy; +        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), -      .dataout(udp_tx_data), .src_rdy_o(udp_tx_src_rdy), .dst_rdy_i(udp_tx_dst_rdy)); +      .dataout(udp1_tx_data), .src_rdy_o(udp1_tx_src_rdy), .dst_rdy_i(udp1_tx_dst_rdy)); +   fifo36_mux #(.prio(0)) mux_err_stream +     (.clk(dsp_clk), .reset(dsp_reset), .clear(0), +      .data0_i(udp1_tx_data), .src0_rdy_i(udp1_tx_src_rdy), .dst0_rdy_o(udp1_tx_dst_rdy), +      .data1_i(tx_err_data), .src1_rdy_i(tx_err_src_rdy), .dst1_rdy_o(tx_err_dst_rdy), +      .data_o(udp_tx_data), .src_rdy_o(udp_tx_src_rdy), .dst_rdy_i(udp_tx_dst_rdy)); +        fifo_cascade #(.WIDTH(36), .SIZE(ETH_RX_FIFOSIZE)) rx_eth_fifo       (.clk(dsp_clk), .reset(dsp_rst), .clear(0),        .datain(udp_rx_data), .src_rdy_i(udp_rx_src_rdy), .dst_rdy_o(udp_rx_dst_rdy), @@ -509,12 +526,13 @@ 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 = {clk_status,serdes_link_up}; +   wire [7:0] 	 led_hw = {run_tx, run_rx, 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),  				      .in(set_data),.out(led_sw),.changed()); -   setting_reg #(.my_addr(8),.width(8)) sr_led_src (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr), -					  .in(set_data),.out(led_src),.changed()); + +   setting_reg #(.my_addr(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); @@ -565,11 +583,6 @@ module u2_core     // /////////////////////////////////////////////////////////////////////////     // ATR Controller, Slave #11 -   wire 	 run_rx, run_tx; -   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), @@ -638,40 +651,26 @@ module u2_core     // DSP TX     wire [35:0] 	 tx_data; -   wire [99:0] 	 tx1_data; -   wire 	 tx_src_rdy, tx_dst_rdy, tx1_src_rdy, tx1_dst_rdy; - -   wire [31:0] 	 debug_vtc, debug_vtd, debug_vt; +   wire 	 tx_src_rdy, tx_dst_rdy; +   wire [31:0] 	 debug_vt;     fifo_cascade #(.WIDTH(36), .SIZE(DSP_TX_FIFOSIZE)) tx_fifo_cascade       (.clk(dsp_clk), .reset(dsp_rst), .clear(0),        .datain({rd1_flags,rd1_dat}), .src_rdy_i(rd1_ready_o), .dst_rdy_o(rd1_ready_i),        .dataout(tx_data), .src_rdy_o(tx_src_rdy), .dst_rdy_i(tx_dst_rdy) ); -   vita_tx_deframer #(.BASE(SR_TX_CTRL), .MAXCHAN(1)) vita_tx_deframer -     (.clk(dsp_clk), .reset(dsp_rst), .clear(0), -      .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), -      .data_i(tx_data), .src_rdy_i(tx_src_rdy), .dst_rdy_o(tx_dst_rdy), -      .sample_fifo_o(tx1_data), .sample_fifo_src_rdy_o(tx1_src_rdy), .sample_fifo_dst_rdy_i(tx1_dst_rdy), -      .debug(debug_vtd) ); - -   vita_tx_control #(.BASE(SR_TX_CTRL), .WIDTH(32)) vita_tx_control -     (.clk(dsp_clk), .reset(dsp_rst), .clear(0), -      .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), -      .vita_time(vita_time),.underrun(underrun), -      .sample_fifo_i(tx1_data), .sample_fifo_src_rdy_i(tx1_src_rdy), .sample_fifo_dst_rdy_o(tx1_dst_rdy), -      .sample(sample_tx), .run(run_tx), .strobe(strobe_tx), -      .debug(debug_vtc) ); -    -   assign debug_vt = debug_vtc | debug_vtd; -    -   dsp_core_tx #(.BASE(SR_TX_DSP)) dsp_core_tx -     (.clk(dsp_clk),.rst(dsp_rst), +   vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),  +		   .REPORT_ERROR(1), .PROT_ENG_FLAGS(1))  +   vita_tx_chain +     (.clk(dsp_clk), .reset(dsp_rst),        .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp), -      .sample(sample_tx), .run(run_tx), .strobe(strobe_tx), +      .vita_time(vita_time), +      .tx_data_i(tx_data), .tx_src_rdy_i(tx_src_rdy), .tx_dst_rdy_o(tx_dst_rdy), +      .err_data_o(tx_err_data), .err_src_rdy_o(tx_err_src_rdy), .err_dst_rdy_i(tx_err_dst_rdy),        .dac_a(dac_a),.dac_b(dac_b), -      .debug(debug_tx_dsp) ); - +      .underrun(underrun), .run(run_tx), +      .debug(debug_vt)); +        assign dsp_rst = wb_rst;     // /////////////////////////////////////////////////////////////////////////////////// @@ -773,8 +772,7 @@ endmodule // u2_core  			     { s6_adr[15:8] },  			     { s6_adr[7:0] },  			     { 6'd0, mdio_cpy, MDC } }; -*/ -/* +     assign debug 	 = { { GMII_TXD },  			     { 5'd0, GMII_TX_EN, GMII_TX_ER, GMII_GTX_CLK },  			     { wr2_flags, rd2_flags }, @@ -783,7 +781,6 @@ endmodule // u2_core  			     { 5'd0, GMII_RX_DV, GMII_RX_ER, GMII_RX_CLK },  			     { wr2_flags, rd2_flags },  			     { GMII_TX_EN,3'd0, wr2_ready_i, wr2_ready_o, rd2_ready_i, rd2_ready_o } }; - */  //   assign debug = debug_udp;    // assign debug = vrc_debug; @@ -794,9 +791,8 @@ endmodule // u2_core  			   {wr1_ready_i, wr1_ready_o, rx1_src_rdy, rx1_dst_rdy, rx1_data[35:32]}};  */  //   assign debug_gpio_1 = {vita_time[63:32] }; -    -/* -    assign debug_gpio_1 = { { tx_f19_data[15:8] }, +/*    +   assign debug_gpio_1 = { { tx_f19_data[15:8] },  			   { tx_f19_data[7:0] },  			   { 3'd0, tx_f19_src_rdy, tx_f19_dst_rdy, tx_f19_data[18:16] },  			   { 2'b0, rd2_ready_i, rd2_ready_o, rd2_flags } }; diff --git a/fpga/usrp2/udp/prot_eng_tx.v b/fpga/usrp2/udp/prot_eng_tx.v index 9031011f7..a18eb73ae 100644 --- a/fpga/usrp2/udp/prot_eng_tx.v +++ b/fpga/usrp2/udp/prot_eng_tx.v @@ -40,11 +40,16 @@ module prot_eng_tx     // Store header values in a small dual-port (distributed) ram     reg [HDR_WIDTH-1:0] header_ram[0:HDR_LEN-1];     wire [HDR_WIDTH-1:0] header_word; +   reg [15:0]  chk_precompute;     always @(posedge clk)       if(set_stb & ((set_addr & 8'hE0) == BASE)) -       header_ram[set_addr[4:0]] <= set_data; - +       begin +	  header_ram[set_addr[4:0]] <= set_data; +	  if(set_data[18]) +	    chk_precompute <= set_data[15:0]; +       end +        assign header_word = header_ram[state];     wire last_hdr_line  = header_word[19]; @@ -56,7 +61,7 @@ module prot_eng_tx     reg [15:0] length;     wire [15:0] ip_length = length + 28;  // IP HDR + UDP HDR     wire [15:0] udp_length = length + 8;  //  UDP HDR - +      always @(posedge clk)       if(reset)         begin @@ -101,12 +106,16 @@ module prot_eng_tx     wire [15:0] checksum;     add_onescomp #(.WIDTH(16)) add_onescomp  -     (.A(header_word[15:0]),.B(ip_length),.SUM(checksum)); +     (.A(chk_precompute),.B(ip_length),.SUM(checksum)); +   reg [15:0]  checksum_reg; +   always @(posedge clk) +     checksum_reg <= checksum; +        always @*       if(ip_chk)         //dataout_int 	<= header_word[15:0] ^ ip_length; -       dataout_int 	<= 16'hFFFF ^ checksum; +       dataout_int 	<= 16'hFFFF ^ checksum_reg;       else if(ip_len)         dataout_int 	<= ip_length;       else if(udp_len) diff --git a/fpga/usrp2/vrt/Makefile.srcs b/fpga/usrp2/vrt/Makefile.srcs index 07c62224b..dc4bd8c96 100644 --- a/fpga/usrp2/vrt/Makefile.srcs +++ b/fpga/usrp2/vrt/Makefile.srcs @@ -10,4 +10,6 @@ vita_rx_control.v \  vita_rx_framer.v \  vita_tx_control.v \  vita_tx_deframer.v \ +vita_tx_chain.v \ +gen_context_pkt.v \  )) diff --git a/fpga/usrp2/vrt/gen_context_pkt.v b/fpga/usrp2/vrt/gen_context_pkt.v new file mode 100644 index 000000000..780a027ba --- /dev/null +++ b/fpga/usrp2/vrt/gen_context_pkt.v @@ -0,0 +1,72 @@ + + +module gen_context_pkt +  #(parameter PROT_ENG_FLAGS=1) +   (input clk, input reset, input clear, +    input trigger, output sent, +    input [31:0] streamid, +    input [63:0] vita_time, +    input [31:0] message, +    output [35:0] data_o, output src_rdy_o, input dst_rdy_i); +    +   localparam CTXT_IDLE = 0; +   localparam CTXT_PROT_ENG = 1; +   localparam CTXT_HEADER = 2; +   localparam CTXT_STREAMID = 3; +   localparam CTXT_SECS = 4; +   localparam CTXT_TICS = 5; +   localparam CTXT_TICS2 = 6; +   localparam CTXT_MESSAGE = 7; +   localparam CTXT_DONE = 8; + +   reg [33:0] 	 data_int; +   wire 	 src_rdy_int, dst_rdy_int; +   wire [3:0] 	 seqno = 0; +   reg [3:0] 	 ctxt_state; +   reg [63:0] 	 err_time; +    +   always @(posedge clk) +     if(reset | clear) +       ctxt_state <= CTXT_IDLE; +     else +       case(ctxt_state) +	 CTXT_IDLE : +	   if(trigger) +	     begin +		err_time <= vita_time; +		if(PROT_ENG_FLAGS) +		  ctxt_state <= CTXT_PROT_ENG; +		else +		  ctxt_state <= CTXT_HEADER; +	     end +	  +	 CTXT_DONE : +	   if(~trigger) +	     ctxt_state <= CTXT_IDLE; + +	 default : +	   if(dst_rdy_int) +	     ctxt_state <= ctxt_state + 1; +       endcase // case (ctxt_state) + +   assign src_rdy_int = ~( (ctxt_state == CTXT_IDLE) | (ctxt_state == CTXT_DONE) ); +    +   always @* +     case(ctxt_state) +       CTXT_PROT_ENG : data_int <= { 2'b01, 16'd1, 16'd24 }; +       CTXT_HEADER : data_int <= { 1'b0, (PROT_ENG_FLAGS ? 1'b0 : 1'b1), 12'b010100001101, seqno, 16'd6 }; +       CTXT_STREAMID : data_int <= { 2'b00, streamid }; +       CTXT_SECS : data_int <= { 2'b00, err_time[63:32] }; +       CTXT_TICS : data_int <= { 2'b00, 32'd0 }; +       CTXT_TICS2 : data_int <= { 2'b00, err_time[31:0] }; +       CTXT_MESSAGE : data_int <= { 2'b10, message }; +       default : data_int <= {2'b00, 32'b00}; +     endcase // case (ctxt_state) + +   fifo_short #(.WIDTH(34)) ctxt_fifo +     (.clk(clk), .reset(reset), .clear(clear), +      .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int), +      .dataout(data_o[33:0]), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i)); +   assign data_o[35:34] = 2'b00; +    +endmodule // gen_context_pkt diff --git a/fpga/usrp2/vrt/vita_rx.build b/fpga/usrp2/vrt/vita_rx.build index f6d2d75a3..010d1be6e 100755 --- a/fpga/usrp2/vrt/vita_rx.build +++ b/fpga/usrp2/vrt/vita_rx.build @@ -1 +1 @@ -iverilog -Wimplict -Wportbind -y ../models -y . -y ../control_lib/ -y ../control_lib/newfifo -y ../coregen -y /opt/Xilinx/10.1/ISE/verilog/src/XilinxCoreLib -y /opt/Xilinx/10.1/ISE/verilog/src/unisims/ -y ../timing -o vita_rx_tb vita_rx_tb.v +iverilog -Wimplict -Wportbind -y ../models -y . -y ../control_lib/ -y ../fifo -y ../coregen -y /opt/Xilinx/10.1/ISE/verilog/src/XilinxCoreLib -y /opt/Xilinx/10.1/ISE/verilog/src/unisims/ -y ../timing -o vita_rx_tb vita_rx_tb.v diff --git a/fpga/usrp2/vrt/vita_rx_control.v b/fpga/usrp2/vrt/vita_rx_control.v index 742dd47e0..93673d292 100644 --- a/fpga/usrp2/vrt/vita_rx_control.v +++ b/fpga/usrp2/vrt/vita_rx_control.v @@ -67,7 +67,7 @@ module vita_rx_control     shortfifo #(.WIDTH(96)) commandfifo       (.clk(clk),.rst(reset),.clear(clear_int),        .datain({new_command,new_time}), .write(write_ctrl&~full_ctrl), .full(full_ctrl), -      .dataout({send_imm_pre,chain_pre,reload_pre,numlines_pre,rcvtime_pre}),  +      .dataout({send_imm_pre,chain_pre,reload_pre,numlines_pre,rcvtime_pre}),        .read(read_ctrl), .empty(empty_ctrl),        .occupied(command_queue_len), .space() ); @@ -98,7 +98,7 @@ module vita_rx_control        .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i),        .space(), .occupied() ); -   // Inband Signallling State Machine +   // Inband Signalling State Machine     time_compare        time_compare (.time_now(vita_time), .trigger_time(rcvtime), .now(now), .early(early), .late(late)); @@ -189,4 +189,3 @@ module vita_rx_control  		       { 2'b0, overrun, chain_pre, sample_fifo_in_rdy, attempt_sample_write, sample_fifo_src_rdy_o,sample_fifo_dst_rdy_i} };  endmodule // rx_control - diff --git a/fpga/usrp2/vrt/vita_rx_framer.v b/fpga/usrp2/vrt/vita_rx_framer.v index f3a81664a..fd82263d0 100644 --- a/fpga/usrp2/vrt/vita_rx_framer.v +++ b/fpga/usrp2/vrt/vita_rx_framer.v @@ -99,7 +99,7 @@ module vita_rx_framer     localparam VITA_ERR_TICS 	 = 12;     localparam VITA_ERR_TICS2 	 = 13;     localparam VITA_ERR_PAYLOAD 	 = 14; -   localparam VITA_ERR_TRAILER 	 = 15; +   localparam VITA_ERR_TRAILER 	 = 15; // Extension context packets have no trailer     always @(posedge clk)       if(reset | clear_pkt_count) @@ -107,17 +107,30 @@ module vita_rx_framer       else if((vita_state == VITA_TRAILER) & pkt_fifo_rdy)         pkt_count <= pkt_count + 1; +   wire 	  has_streamid = vita_header[28]; +   wire 	  has_trailer = vita_header[26]; +   reg 		  trl_eob; +        always @*       case(vita_state) -       VITA_HEADER, VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,vita_header[31:20],pkt_count,vita_pkt_len}; -       VITA_STREAMID, VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; -       VITA_SECS, VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; -       VITA_TICS, VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0}; -       VITA_TICS2, VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; +       // Data packets are IF Data packets with or w/o streamid, no classid, with trailer +       VITA_HEADER : pkt_fifo_line <= {2'b01,3'b000,vita_header[28],2'b01,vita_header[25:20],pkt_count,vita_pkt_len}; +       VITA_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; +       VITA_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; +       VITA_TICS : pkt_fifo_line <= {2'b00,32'd0}; +       VITA_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]};         VITA_PAYLOAD : pkt_fifo_line <= {2'b00,data_fifo_o}; -       VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b00,28'd0,flags_fifo_o}; -       VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer}; -       VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer}; +       VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer[31:21],1'b1,vita_trailer[19:9],trl_eob,8'd0}; + +       // Error packets are Extension Context packets, which have no trailer +       VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,4'b0101,4'b0000,vita_header[23:20],pkt_count,16'd6}; +       VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; +       VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; +       VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0}; +       VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; +       VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b11,28'd0,flags_fifo_o}; +       //VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer}; +                default : pkt_fifo_line <= 34'h0_FFFF_FFFF;         endcase // case (vita_state) @@ -141,6 +154,11 @@ module vita_rx_framer  	 end         else if(pkt_fifo_rdy)  	 case(vita_state) +	   VITA_HEADER : +	     if(has_streamid) +	       vita_state <= VITA_STREAMID; +	     else +	       vita_state <= VITA_SECS;  	   VITA_PAYLOAD :  	     if(sample_fifo_src_rdy_i)  	       begin @@ -148,6 +166,7 @@ module vita_rx_framer  		    begin  		       sample_phase <= 0;  		       sample_ctr   <= sample_ctr + 1; +		       trl_eob <= flags_fifo_o[0];  		       if(sample_ctr == samples_per_packet)  			 vita_state <= VITA_TRAILER;  		       if(|flags_fifo_o)   // end early if any flag is set @@ -155,8 +174,10 @@ module vita_rx_framer  		    end  		  else  		    sample_phase <= sample_phase + 1; -	       end -	   VITA_TRAILER, VITA_ERR_TRAILER : +	       end // if (sample_fifo_src_rdy_i) +	   VITA_ERR_PAYLOAD : +	     vita_state <= VITA_IDLE; +	   VITA_TRAILER :  	     vita_state <= VITA_IDLE;  	   default :  	     vita_state 	   <= vita_state + 1; @@ -172,7 +193,7 @@ module vita_rx_framer         VITA_PAYLOAD :  	 // Write if sample ready and no error flags       	 req_write_pkt_fifo <= (sample_fifo_src_rdy_i & ~|flags_fifo_o[3:1]); -       VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_SECS, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD, VITA_ERR_TRAILER : +       VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_SECS, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD :  	 req_write_pkt_fifo <= 1;         default :  	 req_write_pkt_fifo <= 0; @@ -192,7 +213,7 @@ module vita_rx_framer  				   ( ((vita_state==VITA_PAYLOAD) &   				      (sample_phase == (numchan-4'd1)) &   				      ~|flags_fifo_o[3:1]) | -				     (vita_state==VITA_ERR_TRAILER)); +				     (vita_state==VITA_ERR_PAYLOAD));     assign debug_rx  = vita_state; diff --git a/fpga/usrp2/vrt/vita_rx_tb.v b/fpga/usrp2/vrt/vita_rx_tb.v index b4fda9622..3e01e2ee2 100644 --- a/fpga/usrp2/vrt/vita_rx_tb.v +++ b/fpga/usrp2/vrt/vita_rx_tb.v @@ -3,8 +3,8 @@  module vita_rx_tb;     localparam DECIM  = 8'd4; -   localparam MAXCHAN=4; -   localparam NUMCHAN=4; +   localparam MAXCHAN=1; +   localparam NUMCHAN=1;     reg clk 	     = 0;     reg reset 	     = 1; @@ -94,7 +94,7 @@ module vita_rx_tb;  	@(posedge clk);  	write_setting(4,32'hDEADBEEF);  // VITA header  	write_setting(5,32'hF00D1234);  // VITA streamid -	write_setting(6,32'h98765432);  // VITA trailer +	write_setting(6,32'hF0000000);  // VITA trailer  	write_setting(7,8);  // Samples per VITA packet  	write_setting(8,NUMCHAN);  // Samples per VITA packet  	queue_rx_cmd(1,0,8,32'h0,32'h0);  // send imm, single packet @@ -111,8 +111,13 @@ module vita_rx_tb;  	queue_rx_cmd(0,0,8,32'h0,32'h340);  // send at, on time  	queue_rx_cmd(0,0,8,32'h0,32'h100);  // send at, but late +	#100000; +	$display("\nChained, break chain\n");  	queue_rx_cmd(1,1,8,32'h0,32'h0);  // chained, but break chain  	#100000; +	$display("\nSingle packet\n"); +	queue_rx_cmd(1,0,8,32'h0,32'h0);  // send imm, single packet +	#100000;  	$display("\nEnd chain with zero samples, shouldn't error\n");  	queue_rx_cmd(1,1,8,32'h0,32'h0);  // chained  	queue_rx_cmd(0,0,0,32'h0,32'h0);  // end chain with zero samples, should keep us out of error diff --git a/fpga/usrp2/vrt/vita_tx_chain.v b/fpga/usrp2/vrt/vita_tx_chain.v new file mode 100644 index 000000000..662cdca62 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_chain.v @@ -0,0 +1,71 @@ + +module vita_tx_chain +  #(parameter BASE_CTRL=0, +    parameter BASE_DSP=0, +    parameter REPORT_ERROR=0, +    parameter PROT_ENG_FLAGS=0) +   (input clk, input reset, +    input set_stb, input [7:0] set_addr, input [31:0] set_data, +    input [63:0] vita_time, +    input [35:0] tx_data_i, input tx_src_rdy_i, output tx_dst_rdy_o, +    output [35:0] err_data_o, output err_src_rdy_o, input err_dst_rdy_i, +    output [15:0] dac_a, output [15:0] dac_b, +    output underrun, output run, +    output [31:0] debug); + +   localparam MAXCHAN = 1; +   localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN); + +   wire [FIFOWIDTH-1:0] tx1_data; +   wire 		tx1_src_rdy, tx1_dst_rdy; +   wire 		clear_vita; +   wire [31:0] 		sample_tx; +   wire [31:0] 		streamid, message; +   wire 		trigger, sent; +   wire [31:0] 		debug_vtc, debug_vtd, debug_tx_dsp; + +   wire 		error; +   wire [31:0] 		error_code; +   wire 		clear_seqnum; +    +   assign underrun = error; +   assign message = error_code; +       +   setting_reg #(.my_addr(BASE_CTRL+2), .at_reset(0)) sr_streamid +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(streamid),.changed(clear_seqnum)); + +   vita_tx_deframer #(.BASE(BASE_CTRL), .MAXCHAN(MAXCHAN)) vita_tx_deframer +     (.clk(clk), .reset(reset), .clear(clear_vita), .clear_seqnum(clear_seqnum), +      .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), +      .data_i(tx_data_i), .src_rdy_i(tx_src_rdy_i), .dst_rdy_o(tx_dst_rdy_o), +      .sample_fifo_o(tx1_data), .sample_fifo_src_rdy_o(tx1_src_rdy), .sample_fifo_dst_rdy_i(tx1_dst_rdy), +      .debug(debug_vtd) ); + +   vita_tx_control #(.BASE(BASE_CTRL), .WIDTH(32*MAXCHAN)) vita_tx_control +     (.clk(clk), .reset(reset), .clear(clear_vita), +      .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), +      .vita_time(vita_time),.error(error),.error_code(error_code), +      .sample_fifo_i(tx1_data), .sample_fifo_src_rdy_i(tx1_src_rdy), .sample_fifo_dst_rdy_o(tx1_dst_rdy), +      .sample(sample_tx), .run(run), .strobe(strobe_tx), +      .debug(debug_vtc) ); +    +   dsp_core_tx #(.BASE(BASE_DSP)) dsp_core_tx +     (.clk(clk),.rst(reset), +      .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), +      .sample(sample_tx), .run(run), .strobe(strobe_tx), +      .dac_a(dac_a),.dac_b(dac_b), +      .debug(debug_tx_dsp) ); + +   generate +      if(REPORT_ERROR==1) +	gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS)) gen_tx_err_pkt +	  (.clk(clk), .reset(reset), .clear(clear_vita), +	   .trigger(error), .sent(),  +	   .streamid(streamid), .vita_time(vita_time), .message(message), +	   .data_o(err_data_o), .src_rdy_o(err_src_rdy_o), .dst_rdy_i(err_dst_rdy_i)); +   endgenerate +    +   assign debug = debug_vtc | debug_vtd; +    +endmodule // vita_tx_chain diff --git a/fpga/usrp2/vrt/vita_tx_control.v b/fpga/usrp2/vrt/vita_tx_control.v index bffc64e52..d0516bec8 100644 --- a/fpga/usrp2/vrt/vita_tx_control.v +++ b/fpga/usrp2/vrt/vita_tx_control.v @@ -6,10 +6,11 @@ module vita_tx_control      input set_stb, input [7:0] set_addr, input [31:0] set_data,      input [63:0] vita_time, -    output underrun, +    output error, +    output reg [31:0] error_code,      // From vita_tx_deframer -    input [4+64+WIDTH-1:0] sample_fifo_i, +    input [5+64+16+WIDTH-1:0] sample_fifo_i,      input sample_fifo_src_rdy_i,      output sample_fifo_dst_rdy_o, @@ -20,14 +21,17 @@ module vita_tx_control      output [31:0] debug      ); -    -   assign sample = sample_fifo_i[4+64+WIDTH-1:4+64]; + +   assign sample = sample_fifo_i[5+64+16+WIDTH-1:5+64+16];     wire [63:0] send_time = sample_fifo_i[63:0]; -   wire        eop = sample_fifo_i[64]; -   wire        eob = sample_fifo_i[65]; -   wire        sob = sample_fifo_i[66]; -   wire        send_at = sample_fifo_i[67]; +   wire [15:0] seqnum = sample_fifo_i[79:64]; +   wire        eop = sample_fifo_i[80]; +   wire        eob = sample_fifo_i[81]; +   wire        sob = sample_fifo_i[82]; +   wire        send_at = sample_fifo_i[83]; +   wire        seqnum_err = sample_fifo_i[84]; +        wire        now, early, late, too_early;     // FIXME ignore too_early for now for timing reasons @@ -40,8 +44,15 @@ module vita_tx_control     localparam IBS_IDLE = 0;     localparam IBS_RUN = 1;  // FIXME do we need this?     localparam IBS_CONT_BURST = 2; -   localparam IBS_UNDERRUN = 3; -   localparam IBS_UNDERRUN_DONE = 4; +   localparam IBS_ERROR = 3; +   localparam IBS_ERROR_DONE = 4; +   localparam IBS_ERROR_WAIT = 5; + +   wire [31:0] CODE_UNDERRUN = {seqnum,16'd2}; +   wire [31:0] CODE_SEQ_ERROR = {seqnum,16'd4}; +   wire [31:0] CODE_TIME_ERROR = {seqnum,16'd8}; +   wire [31:0] CODE_UNDERRUN_MIDPKT = {seqnum,16'd16}; +   wire [31:0] CODE_SEQ_ERROR_MIDBURST = {seqnum,16'd32};     reg [2:0] ibs_state; @@ -50,22 +61,49 @@ module vita_tx_control       (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),        .in(set_data),.out(),.changed(clear_state)); +   wire [31:0] error_policy; +   setting_reg #(.my_addr(BASE+3)) sr_error_policy +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(error_policy),.changed()); + +   wire        policy_wait = error_policy[0]; +   wire        policy_next_packet = error_policy[1]; +   wire        policy_next_burst = error_policy[2]; +   reg 	       send_error; +        always @(posedge clk)       if(reset | clear_state) -       ibs_state <= 0; +       begin +	  ibs_state <= IBS_IDLE; +	  send_error <= 0; +       end       else         case(ibs_state)  	 IBS_IDLE :  	   if(sample_fifo_src_rdy_i) -	     if(~send_at | now) +	     if(seqnum_err) +	       begin +		  ibs_state <= IBS_ERROR; +		  error_code <= CODE_SEQ_ERROR; +		  send_error <= 1; +	       end +	     else if(~send_at | now)  	       ibs_state <= IBS_RUN;  	     else if(late | too_early) -	       ibs_state <= IBS_UNDERRUN; +	       begin +		  ibs_state <= IBS_ERROR; +		  error_code <= CODE_TIME_ERROR; +		  send_error <= 1; +	       end  	 IBS_RUN :  	   if(strobe)  	     if(~sample_fifo_src_rdy_i) -	       ibs_state <= IBS_UNDERRUN; +	       begin +		  ibs_state <= IBS_ERROR; +		  error_code <= CODE_UNDERRUN_MIDPKT; +		  send_error <= 1; +	       end  	     else if(eop)  	       if(eob)  		 ibs_state <= IBS_IDLE; @@ -74,24 +112,53 @@ module vita_tx_control  	 IBS_CONT_BURST :  	   if(strobe) -	     ibs_state <= IBS_UNDERRUN_DONE; +	     begin +		if(policy_next_packet) +		  ibs_state <= IBS_ERROR_DONE; +		else if(policy_wait) +		  ibs_state <= IBS_ERROR_WAIT; +		else +		  ibs_state <= IBS_ERROR; +		error_code <= CODE_UNDERRUN; +		send_error <= 1; +	     end  	   else if(sample_fifo_src_rdy_i) -	     ibs_state <= IBS_RUN; +	     if(seqnum_err) +	       begin +		  ibs_state <= IBS_ERROR; +		  error_code <= CODE_SEQ_ERROR_MIDBURST; +		  send_error <= 1; +	       end +	     else +	       ibs_state <= IBS_RUN; -	 IBS_UNDERRUN : -	   if(sample_fifo_src_rdy_i & eop) -	     ibs_state <= IBS_UNDERRUN_DONE; +	 IBS_ERROR : +	   begin +	      send_error <= 0; +	      if(sample_fifo_src_rdy_i & eop) +		if(policy_next_packet | (policy_next_burst & eob)) +		  ibs_state <= IBS_IDLE; +		else if(policy_wait) +		  ibs_state <= IBS_ERROR_WAIT; +	   end -	 IBS_UNDERRUN_DONE : -	   ; +	 IBS_ERROR_DONE : +	   begin +	      send_error <= 0; +	      ibs_state <= IBS_IDLE; +	   end +	  +	 IBS_ERROR_WAIT : +	   send_error <= 0;         endcase // case (ibs_state) -   assign sample_fifo_dst_rdy_o = (ibs_state == IBS_UNDERRUN) | (strobe & (ibs_state == IBS_RUN));  // FIXME also cleanout +   assign sample_fifo_dst_rdy_o = (ibs_state == IBS_ERROR) | (strobe & (ibs_state == IBS_RUN));  // FIXME also cleanout     assign run = (ibs_state == IBS_RUN) | (ibs_state == IBS_CONT_BURST); -   assign underrun = (ibs_state == IBS_UNDERRUN_DONE); +   //assign error = (ibs_state == IBS_ERROR_DONE); +   assign error = send_error;     assign debug = { { now,early,late,too_early,eop,eob,sob,send_at }, -		    { sample_fifo_src_rdy_i, sample_fifo_dst_rdy_o, strobe, run, underrun, ibs_state[2:0] }, +		    { sample_fifo_src_rdy_i, sample_fifo_dst_rdy_o, strobe, run, error, ibs_state[2:0] },  		    { 8'b0 },  		    { 8'b0 } }; diff --git a/fpga/usrp2/vrt/vita_tx_deframer.v b/fpga/usrp2/vrt/vita_tx_deframer.v index 220d3b061..f9cd7d00d 100644 --- a/fpga/usrp2/vrt/vita_tx_deframer.v +++ b/fpga/usrp2/vrt/vita_tx_deframer.v @@ -2,7 +2,7 @@  module vita_tx_deframer    #(parameter BASE=0,      parameter MAXCHAN=1) -   (input clk, input reset, input clear, +   (input clk, input reset, input clear, input clear_seqnum,      input set_stb, input [7:0] set_addr, input [31:0] set_data,      // To FIFO interface of Buffer Pool @@ -10,7 +10,7 @@ module vita_tx_deframer      input src_rdy_i,      output dst_rdy_o, -    output [4+64+(32*MAXCHAN)-1:0] sample_fifo_o, +    output [5+64+16+(32*MAXCHAN)-1:0] sample_fifo_o,      output sample_fifo_src_rdy_o,      input sample_fifo_dst_rdy_i, @@ -21,8 +21,10 @@ module vita_tx_deframer      output [31:0] debug      ); +   localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN); +        wire [1:0] numchan; -   setting_reg #(.my_addr(BASE), .at_reset(0)) sr_numchan +   setting_reg #(.my_addr(BASE), .at_reset(0), .width(2)) sr_numchan       (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),        .in(set_data),.out(numchan),.changed()); @@ -36,14 +38,18 @@ module vita_tx_deframer     assign is_sob = data_i[25];     assign is_eob = data_i[24];     wire      eof = data_i[33]; -        reg 	     has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg;     reg 	     has_trailer_reg, is_sob_reg, is_eob_reg; - +        reg [15:0] pkt_len;     reg [1:0]  vector_phase;     wire       line_done; +   reg 	      seqnum_err; +   reg [3:0]  seqnum_reg; +   wire [3:0] seqnum = data_i[19:16]; +   wire [3:0] next_seqnum = seqnum_reg + 4'd1; +        // Output FIFO for packetized data     localparam VITA_HEADER 	 = 0;     localparam VITA_STREAMID 	 = 1; @@ -61,6 +67,13 @@ module vita_tx_deframer     wire        eop = eof | (pkt_len==hdr_len);  // FIXME would ignoring eof allow larger VITA packets?     wire        fifo_space; + +   always @(posedge clk) +     if(reset | clear_seqnum) +       seqnum_reg <= 4'hF; +     else +       if((vita_state==VITA_HEADER) & src_rdy_i) +	 seqnum_reg <= seqnum;     always @(posedge clk)       if(reset | clear) @@ -68,6 +81,7 @@ module vita_tx_deframer  	  vita_state 		<= VITA_HEADER;  	  {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg}   	    <= 0; +	  seqnum_err <= 0;         end       else          if((vita_state == VITA_STORE) & fifo_space) @@ -99,6 +113,7 @@ module vita_tx_deframer  		  vita_state <= VITA_TICS;  		else  		  vita_state <= VITA_PAYLOAD; +		seqnum_err <= ~(seqnum == next_seqnum);  	     end // case: VITA_HEADER  	   VITA_STREAMID :  	     if(has_classid_reg) @@ -145,7 +160,7 @@ module vita_tx_deframer     assign line_done = (vector_phase == numchan); -   wire [4+64+32*MAXCHAN-1:0] fifo_i; +   wire [FIFOWIDTH-1:0] fifo_i;     reg [63:0] 		      send_time;     reg [31:0] 		      sample_a, sample_b, sample_c, sample_d; @@ -169,13 +184,14 @@ module vita_tx_deframer         endcase // case (vector_phase)     wire 		      store = (vita_state == VITA_STORE); -   fifo_short #(.WIDTH(4+64+32*MAXCHAN)) short_tx_q +   fifo_short #(.WIDTH(FIFOWIDTH)) short_tx_q       (.clk(clk), .reset(reset), .clear(clear),        .datain(fifo_i), .src_rdy_i(store), .dst_rdy_o(fifo_space),        .dataout(sample_fifo_o), .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i) );     // sob, eob, has_secs (send_at) ignored on all lines except first -   assign fifo_i = {sample_d,sample_c,sample_b,sample_a,has_secs_reg,is_sob_reg,is_eob_reg,eop,send_time}; +   assign fifo_i = {sample_d,sample_c,sample_b,sample_a,seqnum_err,has_secs_reg,is_sob_reg,is_eob_reg,eop, +		    12'd0,seqnum_reg,send_time};     assign dst_rdy_o = ~(vita_state == VITA_PAYLOAD) & ~((vita_state==VITA_STORE)& ~fifo_space) ; diff --git a/host/AUTHORS b/host/AUTHORS index d0fe52768..137eba0e6 100644 --- a/host/AUTHORS +++ b/host/AUTHORS @@ -1 +1,17 @@ +Matt Ettus - matt@ettus.com +    USRP1/USRP2 FPGA code +  Josh Blum - josh@ettus.com +    driver framework +    USRP2 firmware +    USRP2 host code +    Basic/LF host code +    XCVR2450 host code +    RFX Series host code + +Jason Abele - jason@ettus.com +    RFX Series host code +    WBX host code + +Eric Blossom - eb@comsec.com +    USRP2 firmware diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index e26ec03d2..ceea5d024 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -20,14 +20,11 @@ PROJECT(UHD CXX)  ENABLE_TESTING()  ######################################################################## -# Setup CPack +# Config Files (include order is important)  ######################################################################## -SET(CPACK_PACKAGE_VERSION_MAJOR 0) -SET(CPACK_PACKAGE_VERSION_MINOR 0) -SET(CPACK_PACKAGE_VERSION_PATCH 0) -SET(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_SOURCE_DIR}/README) -SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE) -INCLUDE(CPack) #include after setting vars +INCLUDE(${CMAKE_SOURCE_DIR}/config/Python.cmake) +INCLUDE(${CMAKE_SOURCE_DIR}/config/Version.cmake) +INCLUDE(${CMAKE_SOURCE_DIR}/config/CPack.cmake)  ########################################################################  # Install Dirs @@ -42,7 +39,7 @@ MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")  ########################################################################  # Local Include Dir  ######################################################################## -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)  ########################################################################  # Optional Compiler Flags @@ -62,10 +59,10 @@ IF(NOT CMAKE_BUILD_TYPE)  ENDIF(NOT CMAKE_BUILD_TYPE)  IF(CMAKE_COMPILER_IS_GNUCXX) -    UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall      HAVE_WALL) -    UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra    HAVE_WEXTRA) -    UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic  HAVE_PEDANTIC) -    UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi      HAVE_ANSI) +    ADD_DEFINITIONS(-Wall) +    ADD_DEFINITIONS(-Wextra) +    ADD_DEFINITIONS(-pedantic) +    ADD_DEFINITIONS(-ansi)      #only export symbols that are declared to be part of the uhd api:      UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)  ENDIF(CMAKE_COMPILER_IS_GNUCXX) @@ -81,12 +78,12 @@ ENDIF(MSVC)  ########################################################################  # Setup Boost  ######################################################################## -IF(EXISTS "/usr/lib64") +IF(UNIX AND EXISTS "/usr/lib64")      LIST(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix -ENDIF(EXISTS "/usr/lib64") +ENDIF(UNIX AND EXISTS "/usr/lib64") -SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42 1.43.0" "1.43") -FIND_PACKAGE(Boost 1.36 REQUIRED COMPONENTS +SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42" "1.43.0" "1.43") +FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} REQUIRED COMPONENTS      date_time      filesystem      program_options @@ -103,7 +100,7 @@ LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})  # Create Uninstall Target  ########################################################################  CONFIGURE_FILE( -    ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in +    ${CMAKE_SOURCE_DIR}/config/cmake_uninstall.cmake.in      ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake  @ONLY) diff --git a/host/README b/host/README index 6eaf6bb42..5018ef541 100644 --- a/host/README +++ b/host/README @@ -18,6 +18,7 @@ LF TX  RFX Series  XCVR 2450  WBX Series +DBSRX  ########################################################################  # Documentation diff --git a/host/config/CPack.cmake b/host/config/CPack.cmake new file mode 100644 index 000000000..a86f452f9 --- /dev/null +++ b/host/config/CPack.cmake @@ -0,0 +1,42 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# Setup CPack +######################################################################## +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ettus Research - Universal Hardware Driver") +SET(CPACK_PACKAGE_VENDOR              "Ettus Research LLC") +SET(CPACK_PACKAGE_CONTACT             "support@ettus.com") +SET(CPACK_PACKAGE_VERSION_MAJOR ${UHD_VERSION_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${UHD_VERSION_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH ${UHD_VERSION_PATCH}) +SET(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/README) +SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE) +SET(BOOST_MIN_VERSION 1.36) #used in setup for boost +STRING(REPLACE "," ", " CPACK_DEBIAN_PACKAGE_DEPENDS +    "libboost-date-time-dev          (>= ${BOOST_MIN_VERSION})," +    "libboost-filesystem-dev         (>= ${BOOST_MIN_VERSION})," +    "libboost-program-options-dev    (>= ${BOOST_MIN_VERSION})," +    "libboost-regex-dev              (>= ${BOOST_MIN_VERSION})," +    "libboost-system-dev             (>= ${BOOST_MIN_VERSION})," +    "libboost-test-dev               (>= ${BOOST_MIN_VERSION})," +    "libboost-thread-dev             (>= ${BOOST_MIN_VERSION})" +) +SET(CPACK_DEBIAN_PACKAGE_RECOMMENDS "python, python-tk") +SET(CPACK_RPM_PACKAGE_REQUIRES "boost-devel >= ${BOOST_MIN_VERSION}") +INCLUDE(CPack) #include after setting vars +MESSAGE(STATUS "Version: ${CPACK_PACKAGE_VERSION}") diff --git a/host/config/Python.cmake b/host/config/Python.cmake new file mode 100644 index 000000000..55ef6acca --- /dev/null +++ b/host/config/Python.cmake @@ -0,0 +1,49 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# Setup Python +######################################################################## +INCLUDE(FindPythonInterp) + +IF(NOT PYTHONINTERP_FOUND) +    MESSAGE(FATAL_ERROR "Error: Python interpretor required by the build system.") +ENDIF(NOT PYTHONINTERP_FOUND) + +MACRO(PYTHON_CHECK_MODULE module have) +    MESSAGE(STATUS "Checking for python module ${module}") +    EXECUTE_PROCESS( +        COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}" +        RESULT_VARIABLE ${have} +    ) +    IF(${have} EQUAL 0) +        MESSAGE(STATUS "Checking for python module ${module} - found") +        SET(${have} TRUE) +    ELSE(${have} EQUAL 0) +        MESSAGE(STATUS "Checking for python module ${module} - not found") +        SET(${have} FALSE) +    ENDIF(${have} EQUAL 0) +ENDMACRO(PYTHON_CHECK_MODULE) + +######################################################################## +# Check Modules +######################################################################## +PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH) + +IF(NOT HAVE_PYTHON_MODULE_CHEETAH) +    MESSAGE(FATAL_ERROR "Error: Cheetah Templates required by the build system.") +ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH) diff --git a/host/config/Version.cmake b/host/config/Version.cmake new file mode 100644 index 000000000..a592a4565 --- /dev/null +++ b/host/config/Version.cmake @@ -0,0 +1,71 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# Setup Version Numbers +######################################################################## +SET(UHD_VERSION_MAJOR 0) +SET(UHD_VERSION_MINOR 0) +SET(UHD_VERSION_PATCH 0) + +######################################################################## +# Find GIT to get repo information +######################################################################## +MESSAGE(STATUS "Checking for git") +FIND_PROGRAM(GIT git) +IF(${GIT} STREQUAL "GIT-NOTFOUND") +    MESSAGE(STATUS "Checking for git - not found") +ELSE(${GIT} STREQUAL "GIT-NOTFOUND") +    MESSAGE(STATUS "Checking for git - found") + +    #grab the git log entry for the current head +    EXECUTE_PROCESS( +        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +        COMMAND ${GIT} log HEAD~..HEAD --date=raw +        OUTPUT_VARIABLE _git_log OUTPUT_STRIP_TRAILING_WHITESPACE +    ) + +    #extract the timestamp from the git log entry +    EXECUTE_PROCESS( +        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +        COMMAND ${PYTHON_EXECUTABLE} -c "import re; print re.match('^.*Date:\\s*(\\d*).*$', '''${_git_log}''', re.MULTILINE | re.DOTALL).groups()[0]" +        OUTPUT_VARIABLE _git_timestamp OUTPUT_STRIP_TRAILING_WHITESPACE +    ) + +    #format the timestamp into YYYY-MM-DD +    EXECUTE_PROCESS( +        COMMAND ${PYTHON_EXECUTABLE} -c "import time; print time.strftime('%Y%m%d', time.gmtime(${_git_timestamp}))" +        OUTPUT_VARIABLE _git_date OUTPUT_STRIP_TRAILING_WHITESPACE +    ) +    SET(UHD_VERSION_MAJOR ${_git_date}) + +    #format the timestamp into HH-MM-SS +    EXECUTE_PROCESS( +        COMMAND ${PYTHON_EXECUTABLE} -c "import time; print time.strftime('%H%M%S', time.gmtime(${_git_timestamp}))" +        OUTPUT_VARIABLE _git_time OUTPUT_STRIP_TRAILING_WHITESPACE +    ) +    SET(UHD_VERSION_MINOR ${_git_time}) + +    #grab the git ref id for the current head +    EXECUTE_PROCESS( +        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +        COMMAND ${GIT} rev-parse --short HEAD +        OUTPUT_VARIABLE _git_rev OUTPUT_STRIP_TRAILING_WHITESPACE +    ) +    SET(UHD_VERSION_PATCH ${_git_rev}) + +ENDIF(${GIT} STREQUAL "GIT-NOTFOUND") diff --git a/host/cmake_uninstall.cmake.in b/host/config/cmake_uninstall.cmake.in index 6031a6ca9..6031a6ca9 100644 --- a/host/cmake_uninstall.cmake.in +++ b/host/config/cmake_uninstall.cmake.in diff --git a/host/docs/build.rst b/host/docs/build.rst index 6f0afdb6e..8f0d0db59 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -147,6 +147,12 @@ Build the project in MSVC  **Note:** you may not have permission to build the install target.  You need to be an administrator or to run MSVC as administrator. +** alternative command line instructions ** + +* Open the Visual Studio Command Prompt Shorcut +* DevEnv <uhd-repo-path>\host\build\ALL_BUILD.vcproj /Build Release +* DevEnv <uhd-repo-path>\host\build\INSTALL.vcproj /Build Release +  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Setup the PATH environment variable  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 9c496ebee..b66fd2069 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -32,7 +32,20 @@ The Basic TX and LFTX boards have 1 quadrature subdevice using both antennas.  The boards have no tunable elements or programmable gains.  Though the magic of aliasing, you can up-convert signals -greater than the nyquist rate of the DAC. +greater than the Nyquist rate of the DAC. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +DBSRX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The DBSRX board has 1 quadrature subdevice. + +Receive Antennas: **J3** + +The board has no user selectable antenna setting + +Recieve Gains:  +    **GC1**, Range: 0-56dB +    **GC2**, Range: 0-24dB  ^^^^^^^^^^^^^^^^^^^^^^^^^^^  RFX Series @@ -45,7 +58,7 @@ The user may set the receive antenna to be TX/RX or RX2.  However, when using an RFX board in full-duplex mode,  the receive antenna will always be set to RX2, regardless of the settings. -Recieve Gains: **PGA0**, Range: 0-45dB +Recieve Gains: **PGA0**, Range: 0-70dB (except RFX400 range is 0-45dB)  ^^^^^^^^^^^^^^^^^^^^^^^^^^^  XCVR 2450 @@ -87,3 +100,44 @@ the receive antenna will always be set to RX2, regardless of the settings.  Transmit Gains: **PGA0**, Range: 0-25dB  Recieve Gains: **PGA0**, Range: 0-31.5dB + +------------------------------------------------------------------------ +Daughterboard Modifications +------------------------------------------------------------------------ + +Sometimes, daughterboards will require modification +to work on certain frequencies or to work with certain hardware. +Modification usually involves moving/removing a SMT component +and burning a new daughterboard id into the eeprom. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +DBSRX +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Due to different clocking capabilities, +the DBSRX will require modifications to operate on a non-USRP1 motherboard. +On a USRP1 motherboard, a divided clock is provided from an FPGA pin +because the standard daughterboard clock lines cannot provided a divided clock. +However, on other USRP motherboards, the divided clock is provided +over the standard daughterboard clock lines. + +**Step 1: Move the clock configuration resistor** + +Remove R193 (which is 10 ohms, 0603 size) and put it on R194, which is empty. +This is made somewhat more complicated by the fact that the silkscreen is not clear in that area. +R193 is on the back, immediately below the large beige connector, J2. +R194 is just below, and to the left of R193. +The silkscreen for R193 is ok, but for R194, +it is upside down, and partially cut off. +If you lose R193, you can use anything from 0 to 10 ohms there. + +**Step 2: Burn a new daughterboard id into the EEPROM** + +With the daughterboard plugged-in, run the following commands: +:: + +    cd <prefix>/share/uhd/utils +    ./usrp_burn_db_eeprom --id=0x000d --unit=RX --args=<args> --db=<db> + +* <args> are device address arguments (optional if only one USRP is on your machine) +* <db> is the name of the daughterboard slot (optional if the USRP has only one slot) diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 76b27fd31..bc4ea0e44 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -38,7 +38,7 @@ Run the following commands:      ./configure --host=mb      make -*The image file will be ./apps/txrx_uhd.bin* +*The image file will be ./usrp2/usrp2_txrx_uhd.bin*  ------------------------------------------------------------------------  Load the images onto the SD card @@ -161,7 +161,7 @@ The USRP2 will reply to icmp echo requests.  **Monitor the USRP2:**  You can read the serial port on the rear of the USRP2  to get debug verbose from the embedded microcontroller. -Use a standard USB to tty-level serial converter at 230400 baud. +Use a standard USB to 3.3v-level serial converter at 230400 baud.  The microcontroller prints useful information about IP addresses,  MAC addresses, control packets, and fast-path settings. diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 5071b114f..10a9a833a 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -15,6 +15,10 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  # + +ADD_EXECUTABLE(tx_continuous_samples tx_continuous_samples.cpp) +TARGET_LINK_LIBRARIES(tx_continuous_samples uhd) +  ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp)  TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd) @@ -25,6 +29,7 @@ ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)  TARGET_LINK_LIBRARIES(tx_timed_samples uhd)  INSTALL(TARGETS +    tx_continuous_samples      benchmark_rx_rate      rx_timed_samples      tx_timed_samples diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 752facb0d..8fae813cf 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -66,7 +66,7 @@ static inline void test_device(          //handle the error codes          switch(md.error_code){          case uhd::rx_metadata_t::ERROR_CODE_NONE: -        case uhd::rx_metadata_t::ERROR_CODE_OVERRUN: +        case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:              break;          default: diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index a72e1ec81..5fbf8b6c5 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -74,8 +74,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //setup streaming      std::cout << std::endl; -    std::cout << boost::format("Begin streaming %u samples, %d seconds in the future...") -        % total_num_samps % seconds_in_future << std::endl; +    std::cout << boost::format( +        "Begin streaming %u samples, %d seconds in the future..." +    ) % total_num_samps % seconds_in_future << std::endl;      uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);      stream_cmd.num_samps = total_num_samps;      stream_cmd.stream_now = false; @@ -102,7 +103,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              if (num_acc_samps == 0) continue;              std::cout << boost::format(                  "Got timeout before all samples received, possible packet loss, exiting loop..." -            ) % md.error_code << std::endl; +            ) << std::endl;              goto done_loop;          default: diff --git a/host/examples/tx_continuous_samples.cpp b/host/examples/tx_continuous_samples.cpp new file mode 100644 index 000000000..cf70b07fb --- /dev/null +++ b/host/examples/tx_continuous_samples.cpp @@ -0,0 +1,110 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/thread_priority.hpp> +#include <uhd/utils/safe_main.hpp> +#include <uhd/usrp/simple_usrp.hpp> +#include <boost/program_options.hpp> +#include <boost/thread/thread_time.hpp> //system time +#include <boost/format.hpp> +#include <iostream> +#include <complex> + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ +    uhd::set_thread_priority_safe(); + +    //variables to be set by po +    std::string args; +    size_t total_duration; +    size_t samps_per_packet; +    double tx_rate, freq; +    float ampl; + +    //setup the program options +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help", "help message") +        ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args") +        ("duration", po::value<size_t>(&total_duration)->default_value(3), "number of seconds to transmit") +        ("spp", po::value<size_t>(&samps_per_packet)->default_value(1000), "number of samples per packet") +        ("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") +        ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz") +        ("ampl", po::value<float>(&l)->default_value(float(0.3)), "amplitude of each sample") +        ("dilv", "specify to disable inner-loop verbose") +    ; +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    //print the help message +    if (vm.count("help")){ +        std::cout << boost::format("UHD TX Continuous Samples %s") % desc << std::endl; +        return ~0; +    } + +    bool verbose = vm.count("dilv") == 0; + +    //create a usrp device +    std::cout << std::endl; +    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; +    uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); +    uhd::device::sptr dev = sdev->get_device(); +    std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; + +    //set properties on the device +    std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; +    sdev->set_tx_rate(tx_rate); +    std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl; +    sdev->set_tx_freq(freq); + +    //allocate data to send +    std::vector<std::complex<float> > buff(samps_per_packet, std::complex<float>(ampl, ampl)); + +    //setup the metadata flags +    uhd::tx_metadata_t md; +    md.start_of_burst = true; //always SOB (good for continuous streaming) +    md.end_of_burst   = false; + +    //send the data in multiple packets +    boost::system_time end_time(boost::get_system_time() + boost::posix_time::seconds(total_duration)); +    while(end_time > boost::get_system_time()){ +        //send samples per packet (driver fragments internally) +        size_t num_tx_samps = dev->send( +            &buff.front(), samps_per_packet, md, +            uhd::io_type_t::COMPLEX_FLOAT32, +            uhd::device::SEND_MODE_FULL_BUFF +        ); +        if(verbose) std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; +    } + +    //send a mini EOB packet +    if(verbose) std::cout << std::endl << boost::format("Sending packet with end-of-burst") << std::endl; +    md.start_of_burst = false; +    md.end_of_burst   = true; +    dev->send( +        NULL, 0, md, +        uhd::io_type_t::COMPLEX_FLOAT32, +        uhd::device::SEND_MODE_FULL_BUFF +    ); + +    //finished +    std::cout << std::endl << "Done!" << std::endl << std::endl; + +    return 0; +} diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index c0339dbd3..ad528c9fb 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -25,6 +25,7 @@ INSTALL(FILES      config.hpp      device.hpp      device.ipp +    version.hpp      wax.hpp      DESTINATION ${INCLUDE_DIR}/uhd  ) diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index a19d22880..c48b3dfff 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -42,6 +42,9 @@ public:      typedef boost::function<device_addrs_t(const device_addr_t &)> find_t;      typedef boost::function<sptr(const device_addr_t &)> make_t; +    //! A reasonable default timeout for receive +    static const size_t default_recv_timeout_ms = 100; +      /*!       * Register a device into the discovery and factory system.       * @@ -158,12 +161,7 @@ public:       * See the rx metadata fragment flags and offset fields for details.       *       * This is a blocking call and will not return until the number -     * of samples returned have been written into each buffer. -     * However, a call to receive may timeout and return zero samples. -     * The timeout duration is decided by the underlying transport layer. -     * The caller should assume that the call to receive will not return -     * immediately when no packets are available to the transport layer, -     * and that the timeout duration is reasonably tuned for performance. +     * of samples returned have been written into each buffer or timeout.       *       * When using the full buffer recv mode, the metadata only applies       * to the first packet received and written into the recv buffers. @@ -174,6 +172,7 @@ public:       * \param metadata data to fill describing the buffer       * \param io_type the type of data to fill into the buffer       * \param recv_mode tells recv how to load the buffer +     * \param timeout_ms the timeout in milliseconds to wait for a packet       * \return the number of samples received or 0 on error       */      virtual size_t recv( @@ -181,7 +180,8 @@ public:          size_t nsamps_per_buff,          rx_metadata_t &metadata,          const io_type_t &io_type, -        recv_mode_t recv_mode +        recv_mode_t recv_mode, +        size_t timeout_ms = default_recv_timeout_ms      ) = 0;      /*! @@ -192,7 +192,8 @@ public:          size_t nsamps_per_buff,          rx_metadata_t &metadata,          const io_type_t &io_type, -        recv_mode_t recv_mode +        recv_mode_t recv_mode, +        size_t timeout_ms = default_recv_timeout_ms      );      //! Deprecated @@ -213,6 +214,17 @@ public:       */      virtual size_t get_max_recv_samps_per_packet(void) const = 0; +    /*! +     * Receive and asynchronous message from the device. +     * \param async_metadata the metadata to be filled in +     * \param timeout_ms the timeout in milliseconds to wait for a message +     * \return true when the async_metadata is valid, false for timeout +     */ +    virtual bool recv_async_msg( +        async_metadata_t &async_metadata, +        size_t timeout_ms = default_recv_timeout_ms +    ) = 0; +  };  } //namespace uhd diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp index c38a2e43e..603c52859 100644 --- a/host/include/uhd/device.ipp +++ b/host/include/uhd/device.ipp @@ -52,12 +52,13 @@ namespace uhd{          size_t nsamps_per_buff,          rx_metadata_t &metadata,          const io_type_t &io_type, -        recv_mode_t recv_mode +        recv_mode_t recv_mode, +        size_t timeout_ms      ){          return this->recv(              std::vector<void *>(1, buff),              nsamps_per_buff, metadata, -            io_type, recv_mode +            io_type, recv_mode, timeout_ms          );      } diff --git a/host/include/uhd/transport/alignment_buffer.ipp b/host/include/uhd/transport/alignment_buffer.ipp index ed7cfd26c..61b3b60f5 100644 --- a/host/include/uhd/transport/alignment_buffer.ipp +++ b/host/include/uhd/transport/alignment_buffer.ipp @@ -57,12 +57,15 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/              std::vector<elem_type> &elems,              const time_duration_t &time          ){ +            boost::system_time exit_time = boost::get_system_time() + time;              buff_contents_type buff_contents_tmp;              std::list<size_t> indexes_to_do(_all_indexes);              //do an initial pop to load an initial sequence id              size_t index = indexes_to_do.front(); -            if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; +            if (not _buffs[index]->pop_with_timed_wait( +                buff_contents_tmp, exit_time - boost::get_system_time() +            )) return false;              elems[index] = buff_contents_tmp.first;              seq_type expected_seq_id = buff_contents_tmp.second;              indexes_to_do.pop_front(); @@ -75,7 +78,9 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/                      _there_was_a_clear = false;                      indexes_to_do = _all_indexes;                      index = indexes_to_do.front(); -                    if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; +                    if (not _buffs[index]->pop_with_timed_wait( +                        buff_contents_tmp, exit_time - boost::get_system_time() +                    )) return false;                      elems[index] = buff_contents_tmp.first;                      expected_seq_id = buff_contents_tmp.second;                      indexes_to_do.pop_front(); @@ -83,7 +88,9 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/                  //pop an element off for this index                  index = indexes_to_do.front(); -                if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; +                if (not _buffs[index]->pop_with_timed_wait( +                    buff_contents_tmp, exit_time - boost::get_system_time() +                )) return false;                  //if the sequence id matches:                  //  store the popped element into the output, diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp index 98dca02f0..c84393ecf 100644 --- a/host/include/uhd/transport/udp_simple.hpp +++ b/host/include/uhd/transport/udp_simple.hpp @@ -73,9 +73,10 @@ public:       * Receive into the provided buffer.       * Blocks until data is received or a timeout occurs.       * \param buff a mutable buffer to receive into +     * \param timeout_ms the timeout in milliseconds       * \return the number of bytes received or zero on timeout       */ -    virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; +    virtual size_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms) = 0;  };  }} //namespace diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp index 50a2b5c3b..de96ea768 100644 --- a/host/include/uhd/types/dict.hpp +++ b/host/include/uhd/types/dict.hpp @@ -20,7 +20,10 @@  #include <uhd/config.hpp>  #include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp>  #include <stdexcept> +#include <typeinfo>  #include <vector>  #include <list> @@ -117,7 +120,10 @@ namespace uhd{              BOOST_FOREACH(const pair_t &p, _map){                  if (p.first == key) return p.second;              } -            throw std::invalid_argument("key not found in dict"); +            throw std::invalid_argument(str(boost::format( +                "key \"%s\" not found in dict(%s, %s)" +            ) % boost::lexical_cast<std::string>(key) +            % typeid(Key).name() % typeid(Val).name()));          }          /*! diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp index 039196250..65952941c 100644 --- a/host/include/uhd/types/metadata.hpp +++ b/host/include/uhd/types/metadata.hpp @@ -26,7 +26,7 @@ namespace uhd{      /*!       * RX metadata structure for describing sent IF data. -     * Includes stream ID, time specification, and fragmentation flags. +     * Includes time specification, fragmentation flags, burst flags, and error codes.       * The receive routines will convert IF data headers into metadata.       */      struct UHD_API rx_metadata_t{ @@ -62,7 +62,7 @@ namespace uhd{           * - timeout: no packet received, underlying code timed-out           * - late command: a stream command was issued in the past           * - broken chain: expected another stream command -         * - overrun: an internal receive buffer has overrun +         * - overflow: an internal receive buffer has filled           * - bad packet: the buffer was unrecognizable as a vrt packet           *           * Note: When an overrun occurs in continuous streaming mode, @@ -74,27 +74,21 @@ namespace uhd{           * - none           * - late command           * - broken chain -         * - overrun +         * - overflow           */          enum error_code_t {              ERROR_CODE_NONE         = 0x0,              ERROR_CODE_TIMEOUT      = 0x1,              ERROR_CODE_LATE_COMMAND = 0x2,              ERROR_CODE_BROKEN_CHAIN = 0x4, -            ERROR_CODE_OVERRUN      = 0x8, +            ERROR_CODE_OVERFLOW     = 0x8,              ERROR_CODE_BAD_PACKET   = 0xf          } error_code; - -        /*! -         * The default constructor: -         * Sets the fields to default values (flags set to false). -         */ -        rx_metadata_t(void);      };      /*!       * TX metadata structure for describing received IF data. -     * Includes stream ID, time specification, and burst flags. +     * Includes time specification, and start and stop burst flags.       * The send routines will convert the metadata to IF data headers.       */      struct UHD_API tx_metadata_t{ @@ -121,6 +115,38 @@ namespace uhd{          tx_metadata_t(void);      }; +    /*! +     * Async metadata structure for describing transmit related events. +     */ +    struct UHD_API async_metadata_t{ +        //! The channel number in a mimo configuration +        size_t channel; + +        /*! +         * Time specification: when the async event occurred. +         */ +        bool has_time_spec; +        time_spec_t time_spec; + +        /*! +         * Event codes: +         * - success: a packet was successfully transmitted +         * - underflow: an internal send buffer has emptied +         * - sequence error: packet loss between host and device +         * - time error: packet had time that was late (or too early) +         * - underflow in packet: underflow occurred inside a packet +         * - sequence error in burst: packet loss within a burst +         */ +        enum event_code_t { +            EVENT_CODE_SUCCESS    = 0x1, +            EVENT_CODE_UNDERFLOW  = 0x2, +            EVENT_CODE_SEQ_ERROR  = 0x4, +            EVENT_CODE_TIME_ERROR = 0x8, +            EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10, +            EVENT_CODE_SEQ_ERROR_IN_BURST  = 0x20 +        } event_code; +    }; +  } //namespace uhd  #endif /* INCLUDED_UHD_TYPES_METADATA_HPP */ diff --git a/host/include/uhd/types/tune_result.hpp b/host/include/uhd/types/tune_result.hpp index c428a7692..9eebc161a 100644 --- a/host/include/uhd/types/tune_result.hpp +++ b/host/include/uhd/types/tune_result.hpp @@ -19,6 +19,7 @@  #define INCLUDED_UHD_TYPES_TUNE_RESULT_HPP  #include <uhd/config.hpp> +#include <string>  namespace uhd{ @@ -28,15 +29,18 @@ namespace uhd{       * the target and actual intermediate frequency.       * The struct hold the result of tuning the DSP as       * the target and actual digital converter frequency. -     * It also tell us weather or not the spectrum is inverted.       */      struct UHD_API tune_result_t{          double target_inter_freq;          double actual_inter_freq;          double target_dsp_freq;          double actual_dsp_freq; -        bool spectrum_inverted; -        tune_result_t(void); + +        /*! +         * Create a pretty print string for this tune result struct. +         * \return the printable string +         */ +        std::string to_pp_string(void) const;      };  } //namespace uhd diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index 6f8c1a2d8..76ee24e5f 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -18,6 +18,7 @@  INSTALL(FILES      #### props headers ### +    codec_props.hpp      dboard_props.hpp      device_props.hpp      dsp_props.hpp @@ -32,6 +33,7 @@ INSTALL(FILES      dboard_manager.hpp      ### utilities ### +    subdev_spec.hpp      tune_helper.hpp      ### interfaces ### diff --git a/host/include/uhd/usrp/codec_props.hpp b/host/include/uhd/usrp/codec_props.hpp new file mode 100644 index 000000000..ab09b1703 --- /dev/null +++ b/host/include/uhd/usrp/codec_props.hpp @@ -0,0 +1,42 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_USRP_CODEC_PROPS_HPP +#define INCLUDED_UHD_USRP_CODEC_PROPS_HPP + +#include <uhd/utils/props.hpp> + +namespace uhd{ namespace usrp{ + +    /*! +    * Possible device codec properties: +    *   A codec is expected to have a rate and gain elements. +    *   Other properties can be discovered through the others prop. +    */ +    enum codec_prop_t{ +        CODEC_PROP_NAME           = 'n', //ro, std::string +        CODEC_PROP_OTHERS         = 'o', //ro, prop_names_t +        CODEC_PROP_GAIN_I         = 'i', //rw, float +        CODEC_PROP_GAIN_Q         = 'q', //rw, float +        CODEC_PROP_GAIN_RANGE     = 'r', //ro, gain_range_t +        CODEC_PROP_GAIN_NAMES     = 'G'  //ro, prop_names_t +    }; + + +}} //namespace + +#endif /* INCLUDED_UHD_USRP_CODEC_PROPS_HPP */ diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp index e88d39876..9b75d791f 100644 --- a/host/include/uhd/usrp/dboard_base.hpp +++ b/host/include/uhd/usrp/dboard_base.hpp @@ -40,7 +40,7 @@ public:       * Derived classes should pass the args into the base class,       * but should not deal with the internals of the args.       */ -    struct ctor_args_impl; typedef ctor_args_impl* ctor_args_t; +    typedef void * ctor_args_t;      //structors      dboard_base(ctor_args_t); diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index caf1e6ee6..fc7ea3052 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -22,6 +22,7 @@  #include <uhd/types/serial.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/cstdint.hpp> +#include <string>  #include <vector>  namespace uhd{ namespace usrp{ @@ -65,6 +66,12 @@ public:      };      /*! +     * Get the motherboard name of the form: usrp1, usrp2... +     * \return string representing the motherboard name +     */ +    virtual std::string get_mboard_name(void) = 0; + +    /*!       * Write to an aux dac.       *       * \param unit which unit rx or tx diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp index 4d5c5efbd..aab6c31ce 100644 --- a/host/include/uhd/usrp/dboard_props.hpp +++ b/host/include/uhd/usrp/dboard_props.hpp @@ -23,16 +23,18 @@  namespace uhd{ namespace usrp{      /*! -     * Possible device dboard properties +     * Possible device dboard properties: +     *    A dboard has an id, one or more subdevices, and a codec. +     *    A dboard is considered to be unidirectional (RX or TX).       */      enum dboard_prop_t{          DBOARD_PROP_NAME         = 'n', //ro, std::string          DBOARD_PROP_SUBDEV       = 's', //ro, wax::obj          DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t -        DBOARD_PROP_USED_SUBDEVS = 'u', //ro, prop_names_t          DBOARD_PROP_DBOARD_ID    = 'i', //rw, dboard_id_t -        DBOARD_PROP_DBOARD_IFACE = 'f'  //ro, dboard_iface::sptr -        //DBOARD_PROP_CODEC              //ro, wax::obj //----> not sure, dont have to deal with yet +        DBOARD_PROP_DBOARD_IFACE = 'f', //ro, dboard_iface::sptr +        DBOARD_PROP_CODEC        = 'c', //ro, wax::obj +        DBOARD_PROP_GAIN_GROUP   = 'g'  //ro, gain_group      };   }} //namespace diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp index 983bcb672..346eec179 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/include/uhd/usrp/device_props.hpp @@ -34,22 +34,6 @@ namespace uhd{ namespace usrp{          DEVICE_PROP_MBOARD_NAMES   = 'M'  //ro, prop_names_t      }; -    //////////////////////////////////////////////////////////////////////// -    /*! ------ not dealing with yet, commented out ------------ -    * Possible device codec properties: -    *   A codec is expected to have a rate and gain elements. -    *   Other properties can be discovered through the others prop. -    */ -    /*enum codec_prop_t{ -        CODEC_PROP_NAME,               //ro, std::string -        CODEC_PROP_OTHERS,             //ro, prop_names_t -        CODEC_PROP_GAIN,               //rw, gain_t -        CODEC_PROP_GAIN_RANGE,         //ro, gain_range_t -        CODEC_PROP_GAIN_NAMES,         //ro, prop_names_t -        //CODEC_PROP_CLOCK_RATE          //ro, freq_t //----> not sure we care to know -    };*/ - -  }} //namespace  #endif /* INCLUDED_UHD_USRP_DEVICE_PROPS_HPP */ diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp index a432ce50c..0f250f439 100644 --- a/host/include/uhd/usrp/mboard_props.hpp +++ b/host/include/uhd/usrp/mboard_props.hpp @@ -39,6 +39,8 @@ namespace uhd{ namespace usrp{          MBOARD_PROP_RX_DBOARD_NAMES = 'E', //ro, prop_names_t          MBOARD_PROP_TX_DBOARD       = 'v', //ro, wax::obj          MBOARD_PROP_TX_DBOARD_NAMES = 'V', //ro, prop_names_t +        MBOARD_PROP_RX_SUBDEV_SPEC  = 'r', //rw, subdev_spec_t +        MBOARD_PROP_TX_SUBDEV_SPEC  = 'R', //rw, subdev_spec_t          MBOARD_PROP_CLOCK_CONFIG    = 'C', //rw, clock_config_t          MBOARD_PROP_TIME_NOW        = 't', //rw, time_spec_t          MBOARD_PROP_TIME_NEXT_PPS   = 'T', //wo, time_spec_t diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 68a42cad8..10a404059 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -24,6 +24,7 @@  #include <uhd/types/stream_cmd.hpp>  #include <uhd/types/clock_config.hpp>  #include <uhd/types/tune_result.hpp> +#include <uhd/usrp/subdev_spec.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp>  #include <vector> @@ -119,11 +120,15 @@ public:      /*******************************************************************       * RX methods       ******************************************************************/ +    virtual void set_rx_subdev_spec(size_t chan, const uhd::usrp::subdev_spec_t &spec) = 0; +    virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(size_t chan) = 0; +      virtual void set_rx_rate_all(double rate) = 0;      virtual double get_rx_rate_all(void) = 0;      virtual tune_result_t set_rx_freq(size_t chan, double freq) = 0;      virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0; +    virtual double get_rx_freq(size_t chan) = 0;      virtual freq_range_t get_rx_freq_range(size_t chan) = 0;      virtual void set_rx_gain(size_t chan, float gain) = 0; @@ -147,11 +152,15 @@ public:      /*******************************************************************       * TX methods       ******************************************************************/ +    virtual void set_tx_subdev_spec(size_t chan, const uhd::usrp::subdev_spec_t &spec) = 0; +    virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(size_t chan) = 0; +      virtual void set_tx_rate_all(double rate) = 0;      virtual double get_tx_rate_all(void) = 0;      virtual tune_result_t set_tx_freq(size_t chan, double freq) = 0;      virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0; +    virtual double get_tx_freq(size_t chan) = 0;      virtual freq_range_t get_tx_freq_range(size_t chan) = 0;      virtual void set_tx_gain(size_t chan, float gain) = 0; diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 1d9136f08..4da63c929 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -24,6 +24,7 @@  #include <uhd/types/stream_cmd.hpp>  #include <uhd/types/clock_config.hpp>  #include <uhd/types/tune_result.hpp> +#include <uhd/usrp/subdev_spec.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp>  #include <vector> @@ -107,11 +108,15 @@ public:      /*******************************************************************       * RX methods       ******************************************************************/ +    virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; +    virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0; +      virtual void set_rx_rate(double rate) = 0;      virtual double get_rx_rate(void) = 0;      virtual tune_result_t set_rx_freq(double freq) = 0;      virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0; +    virtual double get_rx_freq(void) = 0;      virtual freq_range_t get_rx_freq_range(void) = 0;      virtual void set_rx_gain(float gain) = 0; @@ -134,11 +139,15 @@ public:      /*******************************************************************       * TX methods       ******************************************************************/ +    virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; +    virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0; +      virtual void set_tx_rate(double rate) = 0;      virtual double get_tx_rate(void) = 0;      virtual tune_result_t set_tx_freq(double freq) = 0;      virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0; +    virtual double get_tx_freq(void) = 0;      virtual freq_range_t get_tx_freq_range(void) = 0;      virtual void set_tx_gain(float gain) = 0; diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp index 1f8e91d68..cd07cb7a8 100644 --- a/host/include/uhd/usrp/subdev_props.hpp +++ b/host/include/uhd/usrp/subdev_props.hpp @@ -23,6 +23,22 @@  namespace uhd{ namespace usrp{      /*! +     * Possible subdev connection types: +     * +     * A complex subdevice is physically connected to both channels, +     * which may be connected in one of two ways: IQ or QI (swapped). +     * +     * A real subdevice is only physically connected one channel, +     * either only the I channel or only the Q channel. +     */ +    enum subdev_conn_t{ +        SUBDEV_CONN_COMPLEX_IQ = 'C', +        SUBDEV_CONN_COMPLEX_QI = 'c', +        SUBDEV_CONN_REAL_I     = 'R', +        SUBDEV_CONN_REAL_Q     = 'r' +    }; + +    /*!       * Possible device subdev properties       */      enum subdev_prop_t{ @@ -36,9 +52,7 @@ namespace uhd{ namespace usrp{          SUBDEV_PROP_ANTENNA           = 'a', //rw, std::string          SUBDEV_PROP_ANTENNA_NAMES     = 'A', //ro, prop_names_t          SUBDEV_PROP_LO_LOCKED         = 'L', //ro, bool -        SUBDEV_PROP_QUADRATURE        = 'q', //ro, bool -        SUBDEV_PROP_IQ_SWAPPED        = 'i', //ro, bool -        SUBDEV_PROP_SPECTRUM_INVERTED = 's', //ro, bool +        SUBDEV_PROP_CONNECTION        = 'c', //ro, subdev_conn_t          SUBDEV_PROP_USE_LO_OFFSET     = 'l', //ro, bool          SUBDEV_PROP_RSSI              = 'R', //ro, float          SUBDEV_PROP_BANDWIDTH         = 'B'  //rw, double diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp new file mode 100644 index 000000000..4d8f03b77 --- /dev/null +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -0,0 +1,95 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP +#define INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP + +#include <uhd/config.hpp> +#include <vector> +#include <string> + +namespace uhd{ namespace usrp{ + +    /*! +     * A subdevice specification (daughterboard, subdevice) name pairing. +     */ +    struct UHD_API subdev_spec_pair_t{ +        //! The daughterboard name +        std::string db_name; + +        //! The subdevice name +        std::string sd_name; + +        /*! +         * Create a new subdevice specification pair from dboard and subdev names. +         * \param db_name the name of a daughterboard slot +         * \param sd_name the name of a subdevice on that daughterboard +         */ +        subdev_spec_pair_t( +            const std::string &db_name, const std::string &sd_name +        ); +    }; + +    /*! +     * A list of (daughterboard name, subdevice name) pairs: +     * +     * A subdevice specification represents a list of subdevices on a motherboard. +     * The subdevices specified may span across multiple daughterboards; +     * Hence the need for a subdevice specification over a simple list of strings. +     * Typically, the user will pass a RX or TX subdevice specification into the API, +     * and the implementation will infer the channel configuration from the specification. +     * +     * The subdevice specification can be represented as a markup-string. +     * The markup-string is a whitespace separated list of dboard:subdev pairs. +     * The "dboard:" part is optional on boards with only one daughterboard slot. +     * The first pair represents the subdevice for channel zero, +     * the second pair represents the subdevice for channel one, and so on. +     * +     * Examples: +     * - Use subdevice AB on daughterboard A (USRP1): "A:AB" +     * - Use subdevice A on daughterboard A for channel zero and subdevice A on daughterboard B for channel one (USRP1): "A:A B:A" +     * - Use subdevice AB (USRP2): "AB" or ":AB" +     * +     * An empty subdevice specification can be used to automatically +     * select the first subdevice on the first present daughterboard. +     */ +    class UHD_API subdev_spec_t : public std::vector<subdev_spec_pair_t>{ +    public: + +        /*! +         * Create a subdev specification from a markup string. +         * \param markup the markup string +         */ +        subdev_spec_t(const std::string &markup = ""); + +        /*! +         * Convert a subdev specification into a pretty print string. +         * \return a printable string representing the subdev specification +         */ +        std::string to_pp_string(void) const; + +        /*! +         * Convert the subdevice specification into a markup string. +         * The markup string contains the delimiter symbols. +         * \return a string with delimiter markup +         */ +        std::string to_string(void) const; +    }; + +}} + +#endif /* INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP */ diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp index f1e276d4f..df3907b3e 100644 --- a/host/include/uhd/usrp/tune_helper.hpp +++ b/host/include/uhd/usrp/tune_helper.hpp @@ -24,55 +24,75 @@  namespace uhd{ namespace usrp{ -/*! - * Tune a rx chain to the desired frequency: - * The IF of the subdevice is set as close as possible to - * the given target frequency + the LO offset (when applicable). - * The ddc cordic is setup to bring the IF down to baseband. - * \param subdev the dboard subdevice object with properties - * \param ddc the ddc properties object (with "if_rate", "bb_rate", "freq") - * \param target_freq the desired center frequency - * \param lo_offset an offset for the subdevice IF from center - * \return a tune result struct - */ -UHD_API tune_result_t tune_rx_subdev_and_ddc( -    wax::obj subdev, wax::obj ddc, -    double target_freq, double lo_offset -); +    /*! +     * Tune a rx chain to the desired frequency: +     * The IF of the subdevice is set as close as possible to +     * the given target frequency + the LO offset (when applicable). +     * 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 target_freq the desired center frequency +     * \param lo_offset an offset for the subdevice IF from center +     * \return a tune result struct +     */ +    UHD_API tune_result_t tune_rx_subdev_and_dsp( +        wax::obj subdev, wax::obj ddc, +        double target_freq, double lo_offset +    ); -/*! - * Tune a rx chain to the desired frequency: - * Same as the above, except the LO offset - * is calculated based on the subdevice and BW. - */ -UHD_API tune_result_t tune_rx_subdev_and_ddc( -    wax::obj subdev, wax::obj ddc, double target_freq -); +    /*! +     * Tune a rx chain to the desired frequency: +     * Same as the above, except the LO offset +     * is calculated based on the subdevice and BW. +     */ +    UHD_API tune_result_t tune_rx_subdev_and_dsp( +        wax::obj subdev, wax::obj ddc, double target_freq +    ); -/*! - * Tune a tx chain to the desired frequency: - * The IF of the subdevice is set as close as possible to - * the given target frequency + the LO offset (when applicable). - * The duc cordic is setup to bring the baseband up to IF. - * \param subdev the dboard subdevice object with properties - * \param duc the duc properties object (with "if_rate", "bb_rate", "freq") - * \param target_freq the desired center frequency - * \param lo_offset an offset for the subdevice IF from center - * \return a tune result struct - */ -UHD_API tune_result_t tune_tx_subdev_and_duc( -    wax::obj subdev, wax::obj duc, -    double target_freq, double lo_offset -); +    /*! +     * 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 +     * \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 +    ); -/*! - * Tune a tx chain to the desired frequency: - * Same as the above, except the LO offset - * is calculated based on the subdevice and BW. - */ -UHD_API tune_result_t tune_tx_subdev_and_duc( -    wax::obj subdev, wax::obj duc, double target_freq -); +    /*! +     * Tune a tx chain to the desired frequency: +     * The IF of the subdevice is set as close as possible to +     * the given target frequency + the LO offset (when applicable). +     * 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 target_freq the desired center frequency +     * \param lo_offset an offset for the subdevice IF from center +     * \return a tune result struct +     */ +    UHD_API tune_result_t tune_tx_subdev_and_dsp( +        wax::obj subdev, wax::obj duc, +        double target_freq, double lo_offset +    ); + +    /*! +     * Tune a tx chain to the desired frequency: +     * Same as the above, except the LO offset +     * is calculated based on the subdevice and BW. +     */ +    UHD_API tune_result_t tune_tx_subdev_and_dsp( +        wax::obj subdev, wax::obj duc, double target_freq +    ); + +    /*! +     * 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 +     * \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 +    );  }} diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index d484788b2..ef8e64ce0 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -22,11 +22,12 @@ INSTALL(FILES      byteswap.hpp      byteswap.ipp      exception.hpp -    gain_handler.hpp +    gain_group.hpp      pimpl.hpp      props.hpp      safe_main.hpp      static.hpp      thread_priority.hpp +    warning.hpp      DESTINATION ${INCLUDE_DIR}/uhd/utils  ) diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp index b52edc6b5..1b5eacfa9 100644 --- a/host/include/uhd/utils/algorithm.hpp +++ b/host/include/uhd/utils/algorithm.hpp @@ -69,6 +69,31 @@ namespace std{      }      /*! +     * A wrapper around std::reverse that takes a range instead of an iterator. +     * +     * The elements are reversed into descending order using the less-than operator. +     * +     * \param range the range of elements to be reversed +     */ +    template<typename Range> inline void reverse(Range &range){ +        return std::reverse(boost::begin(range), boost::end(range)); +    } + +    /*! +     * A wrapper around std::reverse that takes a range instead of an iterator. +     * +     * The elements are reversed into descending order using the less-than operator. +     * This wrapper reverses the elements non-destructively into a new range. +     * Based on the builtin python function reversed(...) +     * +     * \param range the range of elements to be reversed +     * \return a new range with the elements reversed +     */ +    template<typename Range> inline Range reversed(const Range &range){ +        Range srange(range); std::reverse(srange); return srange; +    } + +    /*!       * Is the value found within the elements in this range?       *       * Uses std::find to search the iterable for an element. @@ -112,17 +137,6 @@ namespace std{      }      /*! -     * A templated signum implementation. -     * \param n the comparable to process -     * \return -1 when n negative, +1 when n positive, otherwise 0 -     */ -    template<typename T> inline int signum(T n){ -        if (n < 0) return -1; -        if (n > 0) return +1; -        return 0; -    } - -    /*!       * A templated clip implementation.       * \param val the value to clip between an upper and lower limit       * \param bound1 the upper or lower bound diff --git a/host/include/uhd/utils/gain_group.hpp b/host/include/uhd/utils/gain_group.hpp new file mode 100644 index 000000000..3955dfa9a --- /dev/null +++ b/host/include/uhd/utils/gain_group.hpp @@ -0,0 +1,85 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_GAIN_GROUP_HPP +#define INCLUDED_UHD_UTILS_GAIN_GROUP_HPP + +#include <uhd/config.hpp> +#include <uhd/types/ranges.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> +#include <boost/utility.hpp> + +namespace uhd{ + +/*! + * A set of function to control a gain element. + */ +struct UHD_API gain_fcns_t{ +    boost::function<gain_range_t(void)> get_range; +    boost::function<float(void)>        get_value; +    boost::function<void(float)>        set_value; +}; + +class UHD_API gain_group : boost::noncopyable{ +public: +    typedef boost::shared_ptr<gain_group> sptr; + +    /*! +     * Get the overall gain range for this group. +     * Overall step is defined as the minimum step size. +     * \return a gain range with overall min, max, step +     */ +    virtual gain_range_t get_range(void) = 0; + +    /*! +     * Get the overall gain value for this group. +     * \return a summation of all the gain values +     */ +    virtual float get_value(void) = 0; + +    /*! +     * Set the overall gain value for this group. +     * The power will be distributed across individual gain elements. +     * The semantics of how to do this are determined by the priority. +     * \param gain the gain to set across the group +     */ +    virtual void set_value(float gain) = 0; + +    /*! +     * Register a set of gain functions into this group. +     * Priority determines how power will be distributed +     * with higher priorities getting the power first, +     * and lower priorities getting the remainder power. +     * \param gain_fcns the set of gain functions +     * \param priority the priority of the gain element +     */ +    virtual void register_fcns( +        const gain_fcns_t &gain_fcns, size_t priority = 0 +    ) = 0; + +    /*! +     * Make a new empty gain group. +     * \return a gain group object. +     */ +    static sptr make(void); +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_GAIN_GROUP_HPP */ + diff --git a/host/include/uhd/utils/gain_handler.hpp b/host/include/uhd/utils/gain_handler.hpp deleted file mode 100644 index f4629e6a7..000000000 --- a/host/include/uhd/utils/gain_handler.hpp +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP -#define INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP - -#include <uhd/config.hpp> -#include <uhd/wax.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/function.hpp> - -namespace uhd{ - -class UHD_API gain_handler{ -public: -    typedef boost::shared_ptr<gain_handler> sptr; -    typedef boost::function<bool(const wax::obj &, const wax::obj &)> is_equal_t; - -    /*! -     * A set of properties for dealing with gains. -     */ -    struct UHD_API props_t{ -        wax::obj value, range, names; -        props_t(void); //default constructor -    }; - -    /*! -     * Make a new gain handler. -     * The construction arguments are agnostic to the property type. -     * It is up to the caller to provide an "is_equal" function that -     * can tell weather two properties (in a wax obj) are equal. -     * \param link a link to the wax obj with properties -     * \param props a struct of properties keys -     * \param is_equal the function that tests for equal properties -     */ -    static sptr make( -        const wax::obj &link, -        const props_t &props, -        is_equal_t is_equal -    ); - -    /*! -     * Intercept gets for overall gain, min, max, step. -     * Ensures that the gain name is valid. -     * \return true for handled, false to pass on -     */ -    virtual bool intercept_get(const wax::obj &key, wax::obj &val) = 0; - -    /*! -     * Intercept sets for overall gain. -     * Ensures that the gain name is valid. -     * Ensures that the new gain is within range. -     * \return true for handled, false to pass on -     */ -    virtual bool intercept_set(const wax::obj &key, const wax::obj &val) = 0; - -    /*! -     * Function template to test if two wax types are equal: -     * The constructor will bind an instance of this for a specific type. -     * This bound equals functions allows the intercept methods to be non-templated. -     */ -    template <class T> static bool is_equal(const wax::obj &a, const wax::obj &b){ -        try{ -            return a.as<T>() == b.as<T>(); -        } -        catch(const wax::bad_cast &){ -            return false; -        } -    } - -}; - -} //namespace uhd - -#endif /* INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP */ - diff --git a/host/include/uhd/utils/pimpl.hpp b/host/include/uhd/utils/pimpl.hpp index 09bf0c0a2..18454f0c4 100644 --- a/host/include/uhd/utils/pimpl.hpp +++ b/host/include/uhd/utils/pimpl.hpp @@ -20,6 +20,7 @@  #include <uhd/config.hpp>  #include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp>  /*! \file pimpl.hpp   * "Pimpl idiom" (pointer to implementation idiom). @@ -50,6 +51,6 @@   * \param _args the constructor args for the pimpl   */  #define UHD_PIMPL_MAKE(_name, _args) \ -    boost::shared_ptr<_name>(new _name _args) +    boost::make_shared<_name> _args  #endif /* INCLUDED_UHD_UTILS_PIMPL_HPP */ diff --git a/host/include/uhd/utils/warning.hpp b/host/include/uhd/utils/warning.hpp new file mode 100644 index 000000000..91d8400ab --- /dev/null +++ b/host/include/uhd/utils/warning.hpp @@ -0,0 +1,34 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_WARNING_HPP +#define INCLUDED_UHD_UTILS_WARNING_HPP + +#include <uhd/config.hpp> +#include <string> + +namespace uhd{ + +    /*! +     * Print a formatted warning string to stderr. +     * \param msg the multiline warning message +     */ +    UHD_API void print_warning(const std::string &msg); + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_WARNING_HPP */ diff --git a/host/include/uhd/version.hpp b/host/include/uhd/version.hpp new file mode 100644 index 000000000..19d672e65 --- /dev/null +++ b/host/include/uhd/version.hpp @@ -0,0 +1,28 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_VERSION_HPP +#define INCLUDED_UHD_VERSION_HPP + +#include <uhd/config.hpp> +#include <string> + +namespace uhd{ +    UHD_API std::string get_version_string(void); +} //namespace uhd + +#endif /* INCLUDED_UHD_VERSION_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 77b04af0c..48cfe742e 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -16,38 +16,16 @@  #  ######################################################################## -# Setup Python -######################################################################## -INCLUDE(FindPythonInterp) - -MACRO(PYTHON_CHECK_MODULE module have) -    MESSAGE(STATUS "Checking for python module ${module}") -    EXECUTE_PROCESS( -        COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}" -        RESULT_VARIABLE ${have} -    ) -    IF(${have} EQUAL 0) -        MESSAGE(STATUS "Checking for python module ${module} - found") -        SET(${have} TRUE) -    ELSE(${have} EQUAL 0) -        MESSAGE(STATUS "Checking for python module ${module} - not found") -        SET(${have} FALSE) -    ENDIF(${have} EQUAL 0) -ENDMACRO(PYTHON_CHECK_MODULE) - -PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH) - -IF(NOT HAVE_PYTHON_MODULE_CHEETAH) -    MESSAGE(FATAL_ERROR "Error: Cheetah Templates needed for pre-build generation.") -ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH) - -########################################################################  # Helpful Macros  ########################################################################  MACRO(LIBUHD_APPEND_SOURCES)      LIST(APPEND libuhd_sources ${ARGV})  ENDMACRO(LIBUHD_APPEND_SOURCES) +MACRO(LIBUHD_APPEND_LIBS) +    LIST(APPEND libuhd_libs ${ARGV}) +ENDMACRO(LIBUHD_APPEND_LIBS) +  MACRO(LIBUHD_PYTHON_GEN_SOURCE pyfile outfile)      #ensure that the directory exists for outfile      GET_FILENAME_COMPONENT(outfile_dir ${outfile} PATH) @@ -70,75 +48,22 @@ ENDMACRO(LIBUHD_PYTHON_GEN_SOURCE)  INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/CMakeLists.txt)  INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/transport/CMakeLists.txt)  INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/CMakeLists.txt) -INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/dboard/CMakeLists.txt) -INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp2/CMakeLists.txt) -INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp_e/CMakeLists.txt) - -######################################################################## -# Setup defines for process scheduling -######################################################################## -MESSAGE(STATUS "Configuring priority scheduling...") - -INCLUDE(CheckCXXSourceCompiles) -CHECK_CXX_SOURCE_COMPILES(" -    #include <pthread.h> -    int main(){ -        struct sched_param sp; -        pthread_setschedparam(pthread_self(), SCHED_RR, &sp); -        return 0; -    } -    " HAVE_PTHREAD_SETSCHEDPARAM -) - -CHECK_CXX_SOURCE_COMPILES(" -    #include <windows.h> -    int main(){ -        SetThreadPriority(GetCurrentThread(), 0); -        SetPriorityClass(GetCurrentProcess(), 0); -        return 0; -    } -    " HAVE_WIN_SETTHREADPRIORITY -) - -IF(HAVE_PTHREAD_SETSCHEDPARAM) -    MESSAGE(STATUS "  Priority scheduling supported through pthread_setschedparam.") -    ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM) -ELSEIF(HAVE_WIN_SETTHREADPRIORITY) -    MESSAGE(STATUS "  Priority scheduling supported through windows SetThreadPriority.") -    ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY) -ELSE(HAVE_PTHREAD_SETSCHEDPARAM) -    MESSAGE(STATUS "  Priority scheduling not supported.") -ENDIF(HAVE_PTHREAD_SETSCHEDPARAM) - -######################################################################## -# Setup defines for module loading -######################################################################## -MESSAGE(STATUS "Configuring module loading...") - -INCLUDE(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H) -CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H) - -IF(HAVE_DLFCN_H) -    MESSAGE(STATUS "  Module loading supported through dlopen.") -    ADD_DEFINITIONS(-DHAVE_DLFCN_H) -ELSEIF(HAVE_WINDOWS_H) -    MESSAGE(STATUS "  Module loading supported through LoadLibrary.") -    ADD_DEFINITIONS(-DHAVE_WINDOWS_H) -ELSE(HAVE_DLFCN_H) -    MESSAGE(STATUS "  Module loading not supported.") -ENDIF(HAVE_DLFCN_H) +INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/utils/CMakeLists.txt)  ########################################################################  # Append to the list of sources for lib uhd  ######################################################################## +CONFIGURE_FILE( +    ${CMAKE_CURRENT_SOURCE_DIR}/constants.hpp.in +    ${CMAKE_CURRENT_BINARY_DIR}/constants.hpp +@ONLY) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +  LIBUHD_APPEND_SOURCES( +    ${CMAKE_CURRENT_BINARY_DIR}/constants.hpp      ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/gain_handler.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp  ) @@ -146,9 +71,7 @@ LIBUHD_APPEND_SOURCES(  # Setup libuhd library  ########################################################################  ADD_LIBRARY(uhd SHARED ${libuhd_sources}) - -TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) - +TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${libuhd_libs})  SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS")  INSTALL(TARGETS uhd diff --git a/host/lib/constants.hpp.in b/host/lib/constants.hpp.in new file mode 100644 index 000000000..295c8f16c --- /dev/null +++ b/host/lib/constants.hpp.in @@ -0,0 +1,28 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_CONSTANTS_HPP +#define INCLUDED_LIBUHD_CONSTANTS_HPP + +#include <uhd/config.hpp> +#include <string> + +static const std::string UHD_VERSION_STRING = "@CPACK_PACKAGE_VERSION@"; +static const std::string UHD_INSTALL_PREFIX = "@CMAKE_INSTALL_PREFIX@"; +static const std::string UHD_PKG_DATA_DIR = "@PKG_DATA_DIR@"; + +#endif /* INCLUDED_LIBUHD_CONSTANTS_HPP */ diff --git a/host/lib/device.cpp b/host/lib/device.cpp index 431595c4f..d575ebaab 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -12,7 +12,7 @@  // GNU General Public License for more details.  //  // You should have received a copy of the GNU General Public License -// asize_t with this program.  If not, see <http://www.gnu.org/licenses/>. +// along with this program.  If not, see <http://www.gnu.org/licenses/>.  //  #include <uhd/device.hpp> diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp deleted file mode 100644 index 36e2e8ed3..000000000 --- a/host/lib/gain_handler.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/utils/gain_handler.hpp> -#include <uhd/utils/assert.hpp> -#include <uhd/types/ranges.hpp> -#include <uhd/utils/props.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <cmath> -#include <vector> - -using namespace uhd; - -/*********************************************************************** - * gain handler implementation interface - **********************************************************************/ -class gain_handler_impl : public gain_handler{ -public: -    gain_handler_impl( -        const wax::obj &link, -        const props_t &props, -        is_equal_t is_equal -    ); -    ~gain_handler_impl(void); -    bool intercept_get(const wax::obj &key, wax::obj &val); -    bool intercept_set(const wax::obj &key, const wax::obj &val); - -private: -    wax::obj     _link; -    props_t _props; -    is_equal_t   _is_equal; - -    prop_names_t get_gain_names(void); -    float get_overall_gain_val(void); -    gain_range_t get_overall_gain_range(void); -    template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){ -        return _link[named_prop_t(prop, name)].as<T>(); -    } -}; - -/*********************************************************************** - * the make function - **********************************************************************/ -gain_handler::sptr gain_handler::make( -    const wax::obj &link, -    const props_t &props, -    is_equal_t is_equal -){ -    return sptr(new gain_handler_impl(link, props, is_equal)); -} - -/*********************************************************************** - * gain handler implementation methods - **********************************************************************/ -gain_handler::props_t::props_t(void){ -    /* NOP */ -} - -gain_handler_impl::gain_handler_impl( -    const wax::obj &link, -    const props_t &props, -    is_equal_t is_equal -){ -    _link = link; -    _props = props; -    _is_equal = is_equal; -} - -gain_handler_impl::~gain_handler_impl(void){ -    /* NOP */ -} - -prop_names_t gain_handler_impl::get_gain_names(void){ -    return _link[_props.names].as<prop_names_t>(); -} - -float gain_handler_impl::get_overall_gain_val(void){ -    float gain_val = 0; -    BOOST_FOREACH(std::string name, get_gain_names()){ -        gain_val += get_named_prop<float>(_props.value, name); -    } -    return gain_val; -} - -gain_range_t gain_handler_impl::get_overall_gain_range(void){ -    float gain_min = 0, gain_max = 0, gain_step = 0; -    BOOST_FOREACH(std::string name, get_gain_names()){ -        gain_range_t floatmp = get_named_prop<gain_range_t>(_props.range, name); -        gain_min += floatmp.min; -        gain_max += floatmp.max; -        gain_step = std::max(gain_step, floatmp.step); -    } -    return gain_range_t(gain_min, gain_max, gain_step); -} - -/*********************************************************************** - * gain handler implementation get method - **********************************************************************/ -bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){ -    wax::obj key; std::string name; -    boost::tie(key, name) = extract_named_prop(key_); - -    //not a wildcard... dont handle (but check name) -    if (name != ""){ -        assert_has(get_gain_names(), name, "gain name"); -        return false; -    } - -    if (_is_equal(key, _props.value)){ -        val = get_overall_gain_val(); -        return true; -    } - -    if (_is_equal(key, _props.range)){ -        val = get_overall_gain_range(); -        return true; -    } - -    return false; //not handled -} - -/*********************************************************************** - * gain handler implementation set method - **********************************************************************/ -bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){ -    wax::obj key; std::string name; -    boost::tie(key, name) = extract_named_prop(key_); - -    //not a gain value key... dont handle -    if (not _is_equal(key, _props.value)) return false; - -    float gain_val = val.as<float>(); - -    //not a wildcard... dont handle (but check name and range) -    if (name != ""){ -        assert_has(get_gain_names(), name, "gain name"); -        gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name); -        if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str( -            boost::format("A value of %f for gain %s is out of range of (%f, %f)") -            % gain_val % name % gain.min % gain.max -        )); -        return false; -    } - -    //set the overall gain -    BOOST_FOREACH(std::string name, get_gain_names()){ -        //get the min, max, step for this gain name -        gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name); - -        //clip g to be within the allowed range -        float g = std::min(std::max(gain_val, gain.min), gain.max); -        //set g to be a multiple of the step size -        g -= std::fmod(g, gain.step); -        //set g to be the new gain -        _link[named_prop_t(_props.value, name)] = g; -        //subtract g out of the total gain left to apply -        gain_val -= g; -    } - -    return true; -} diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index ba1bbc9f0..f8e15c13d 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -55,6 +55,11 @@ LIBUHD_PYTHON_GEN_SOURCE(  )  LIBUHD_PYTHON_GEN_SOURCE( +    ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_max2118_regs.py +    ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/max2118_regs.hpp +) + +LIBUHD_PYTHON_GEN_SOURCE(      ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9862_regs.py      ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9862_regs.hpp  ) diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py index 47325a7e3..986093004 100644 --- a/host/lib/ic_reg_maps/common.py +++ b/host/lib/ic_reg_maps/common.py @@ -173,7 +173,7 @@ class mreg:      def get_type(self):          return 'boost::uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8) -def generate(name, regs_tmpl, body_tmpl='', file=__file__): +def generate(name, regs_tmpl, body_tmpl='', file=__file__, append=False):      #evaluate the regs template and parse each line into a register      regs = list(); mregs = list()      for entry in parse_tmpl(regs_tmpl).splitlines(): @@ -193,4 +193,4 @@ def generate(name, regs_tmpl, body_tmpl='', file=__file__):      )      #write the generated code to file specified by argv1 -    open(sys.argv[1], 'w').write(code) +    open(sys.argv[1], 'a' if append else 'w').write(code) diff --git a/host/lib/ic_reg_maps/gen_max2118_regs.py b/host/lib/ic_reg_maps/gen_max2118_regs.py new file mode 100644 index 000000000..506fbaec8 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_max2118_regs.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# Template for raw text data describing write registers +# name addr[bit range inclusive] default optional enums +######################################################################## +WRITE_REGS_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## +######################################################################## +## N-Divider MSB (0) Write +######################################################################## +div2                  0[7]          0       div4, div2 +n_divider_msb         0[0:6]        3 +######################################################################## +## N-Divider LSB (1) Write +######################################################################## +n_divider_lsb         1[0:7]        0xB6 +~n_divider            n_divider_lsb, n_divider_msb +######################################################################## +## R, Charge Pump, and VCO (2) Write +######################################################################## +#set $r_divider_names = ', '.join(map(lambda x: 'div' + str(2**(x+1)), range(0,8))) +r_divider             2[5:7]        1       $r_divider_names  +#set $cp_current_bias = ', '.join(map(lambda x: 'i_cp_%dua'%(50*2**x), range(0,4))) +cp_current            2[3:4]        3       $cp_current_bias +osc_band              2[0:2]        5 +######################################################################## +## I/Q Filter DAC (3) Write +######################################################################## +##unused              3[7]          0 +f_dac                 3[0:6]        0x7F    ## filter tuning dac, depends on m +######################################################################## +## LPF Divider DAC (4) Write +######################################################################## +adl_vco_adc_latch     4[7]          0       disabled, enabled +ade_vco_ade_read      4[6]          0       disabled, enabled +dl_output_drive       4[5]          0       iq_590m_vpp, iq_1_vpp +m_divider             4[0:4]        2       ## filter tuning counter +######################################################################## +## GC2 and Diag (5) Write +######################################################################## +diag                  5[5:7]        0       normal, cp_i_source, cp_i_sink, cp_high_z, unused, n_and_filt, r_and_gc2, m_div +gc2                   5[0:4]        0x1F    ## Step Size: 0-1: 0dB, 2-22: 1dB, 23-31: 0.5dB +""" + +######################################################################## +# Template for raw text data describing read registers +# name addr[bit range inclusive] default optional enums +######################################################################## +READ_REGS_TMPL="""\ +######################################################################## +## Status (0) Read +######################################################################## +pwr                   0[6]          0       not_reset, reset +adc                   0[2:4]        0       ## VCO tuning voltage, Lock Status +######################################################################## +## I/Q Filter DAC (1) Read +######################################################################## +filter_dac            1[0:6]        0       ## I/Q Filter tuning DAC, current +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ +    boost::uint8_t reg = 0; +    switch(addr){ +    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) +    case $addr: +        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); +        #end for +        break; +    #end for +    } +    return boost::uint8_t(reg); +} + +void set_reg(boost::uint8_t addr, boost::uint8_t reg){ +    switch(addr){ +    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) +    case $addr: +        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); +        #end for +        break; +    #end for +    } +} +""" + +if __name__ == '__main__': +    import common; common.generate( +        name='max2118_write_regs', +        regs_tmpl=WRITE_REGS_TMPL, +        body_tmpl=BODY_TMPL, +        file=__file__, +    ) + +    import common; common.generate( +        name='max2118_read_regs', +        regs_tmpl=READ_REGS_TMPL, +        body_tmpl=BODY_TMPL, +        file=__file__, +        append=True, +    ) diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index f339127ad..89750f99d 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -34,12 +34,13 @@ using namespace uhd::transport;   * This is okay bacause this is the slow-path implementation.   *   * \param socket the asio socket + * \param timeout_ms the timeout in milliseconds   */  static void reasonable_recv_timeout( -    boost::asio::ip::udp::socket &socket +    boost::asio::ip::udp::socket &socket, size_t timeout_ms  ){      boost::asio::deadline_timer timer(socket.get_io_service()); -    timer.expires_from_now(boost::posix_time::milliseconds(100)); +    timer.expires_from_now(boost::posix_time::milliseconds(timeout_ms));      while (not (socket.available() or timer.expires_from_now().is_negative())){          boost::this_thread::sleep(boost::posix_time::milliseconds(1));      } @@ -55,8 +56,8 @@ public:      ~udp_connected_impl(void);      //send/recv -    size_t send(const boost::asio::const_buffer &buff); -    size_t recv(const boost::asio::mutable_buffer &buff); +    size_t send(const boost::asio::const_buffer &); +    size_t recv(const boost::asio::mutable_buffer &, size_t);  private:      boost::asio::ip::udp::socket   *_socket; @@ -85,8 +86,8 @@ size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){      return _socket->send(boost::asio::buffer(buff));  } -size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){ -    reasonable_recv_timeout(*_socket); +size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){ +    reasonable_recv_timeout(*_socket, timeout_ms);      if (not _socket->available()) return 0;      return _socket->receive(boost::asio::buffer(buff));  } @@ -101,8 +102,8 @@ public:      ~udp_broadcast_impl(void);      //send/recv -    size_t send(const boost::asio::const_buffer &buff); -    size_t recv(const boost::asio::mutable_buffer &buff); +    size_t send(const boost::asio::const_buffer &); +    size_t recv(const boost::asio::mutable_buffer &, size_t);  private:      boost::asio::ip::udp::socket   *_socket; @@ -136,8 +137,8 @@ size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){      return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint);  } -size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){ -    reasonable_recv_timeout(*_socket); +size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){ +    reasonable_recv_timeout(*_socket, timeout_ms);      if (not _socket->available()) return 0;      boost::asio::ip::udp::endpoint sender_endpoint;      return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint); diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index bfbcf62d8..ee989ee2b 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -18,6 +18,7 @@  #include <uhd/transport/udp_zero_copy.hpp>  #include <uhd/transport/udp_simple.hpp> //mtu  #include <uhd/utils/assert.hpp> +#include <uhd/utils/warning.hpp>  #include <boost/cstdint.hpp>  #include <boost/asio.hpp>  #include <boost/format.hpp> @@ -29,7 +30,11 @@ using namespace uhd::transport;   * Constants   **********************************************************************/  //enough buffering for half a second of samples at full rate on usrp2 -static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); +static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); +//Large buffers cause more underflow at high rates. +//Perhaps this is due to the kernel scheduling, +//but may change with host-based flow control. +static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3);  static const double RECV_TIMEOUT = 0.1; //100 ms  /*********************************************************************** @@ -143,6 +148,10 @@ template<typename Opt> static void resize_buff_helper(      size_t target_size,      const std::string &name  ){ +    size_t min_sock_buff_size = 0; +    if (name == "recv") min_sock_buff_size = MIN_RECV_SOCK_BUFF_SIZE; +    if (name == "send") min_sock_buff_size = MIN_SEND_SOCK_BUFF_SIZE; +      //resize the buffer if size was provided      if (target_size > 0){          size_t actual_size = udp_trans->resize_buff<Opt>(target_size); @@ -153,19 +162,18 @@ template<typename Opt> static void resize_buff_helper(          else std::cout << boost::format(              "Current %s sock buff size: %d bytes"          ) % name % actual_size << std::endl; -        if (actual_size < target_size) std::cerr << boost::format( -            "Warning:\n" -            "    The %s buffer is smaller than the requested size.\n" -            "    The minimum recommended buffer size is %d bytes.\n" -            "    See the USRP2 application notes on buffer resizing.\n" -        ) % name % MIN_SOCK_BUFF_SIZE << std::endl; +        if (actual_size < target_size) uhd::print_warning(str(boost::format( +            "The %s buffer is smaller than the requested size.\n" +            "The minimum recommended buffer size is %d bytes.\n" +            "See the USRP2 application notes on buffer resizing.\n" +        ) % name % min_sock_buff_size));      }      //only enable on platforms that are happy with the large buffer resize      #if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)      //otherwise, ensure that the buffer is at least the minimum size -    else if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){ -        resize_buff_helper<Opt>(udp_trans, MIN_SOCK_BUFF_SIZE, name); +    else if (udp_trans->get_buff_size<Opt>() < min_sock_buff_size){ +        resize_buff_helper<Opt>(udp_trans, min_sock_buff_size, name);      }      #endif /*defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)*/  } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index bd76cbb8f..7e0588f03 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -35,14 +35,25 @@  namespace vrt_packet_handler{ +template <typename T> UHD_INLINE T get_context_code( +    const boost::uint32_t *vrt_hdr, +    const uhd::transport::vrt::if_packet_info_t &if_packet_info +){ +    //extract the context word (we dont know the endianness so mirror the bytes) +    boost::uint32_t word0 = vrt_hdr[if_packet_info.num_header_words32] | +              uhd::byteswap(vrt_hdr[if_packet_info.num_header_words32]); +    return T(word0 & 0xff); +} +  /***********************************************************************   * vrt packet handler for recv   **********************************************************************/      typedef std::vector<uhd::transport::managed_recv_buffer::sptr> managed_recv_buffs_t;      typedef boost::function<bool(managed_recv_buffs_t &)> get_recv_buffs_t; -    typedef boost::function<void(size_t /*which channel*/)> handle_overrun_t; +    typedef boost::function<void(size_t /*which channel*/)> handle_overflow_t; +    typedef boost::function<void(const boost::uint32_t *, uhd::transport::vrt::if_packet_info_t &)> vrt_unpacker_t; -    static inline void handle_overrun_nop(size_t){} +    static inline void handle_overflow_nop(size_t){}      struct recv_state{          //width of the receiver in channels @@ -69,13 +80,12 @@ namespace vrt_packet_handler{       * Unpack a received vrt header and set the copy buffer.       *  - helper function for vrt_packet_handler::_recv1       ******************************************************************/ -    template<typename vrt_unpacker_type>      static UHD_INLINE void _recv1_helper(          recv_state &state,          uhd::rx_metadata_t &metadata,          double tick_rate, -        vrt_unpacker_type vrt_unpacker, -        const handle_overrun_t &handle_overrun, +        const vrt_unpacker_t &vrt_unpacker, +        const handle_overflow_t &handle_overflow,          size_t vrt_header_offset_words32      ){          //vrt unpack each managed buffer @@ -92,22 +102,19 @@ namespace vrt_packet_handler{              const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast<const boost::uint32_t *>() + vrt_header_offset_words32;              if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32;              vrt_unpacker(vrt_hdr, if_packet_info); -            const boost::uint32_t *vrt_data = vrt_hdr + if_packet_info.num_header_words32;              //handle the non-data packet case and parse its contents              if (if_packet_info.packet_type != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA){ -                //extract the context word (we dont know the endianness so mirror the bytes) -                boost::uint32_t word0 = vrt_data[0] | uhd::byteswap(vrt_data[0]); -                if (word0 & uhd::rx_metadata_t::ERROR_CODE_OVERRUN) handle_overrun(i); -                metadata.error_code = uhd::rx_metadata_t::error_code_t(word0 & 0xf); +                metadata.error_code = get_context_code<uhd::rx_metadata_t::error_code_t>(vrt_hdr, if_packet_info); +                if (metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) handle_overflow(i);                  //break to exit loop and store metadata below                  state.size_of_copy_buffs = 0; break;              }              //setup the buffer to point to the data -            state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_data); +            state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_hdr + if_packet_info.num_header_words32);              //store the minimum payload length into the copy buffer length              size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t); @@ -131,7 +138,6 @@ namespace vrt_packet_handler{       * Recv data, unpack a vrt header, and copy-convert the data.       *  - helper function for vrt_packet_handler::recv       ******************************************************************/ -    template<typename vrt_unpacker_type>      static UHD_INLINE size_t _recv1(          recv_state &state,          const std::vector<void *> &buffs, @@ -141,9 +147,9 @@ namespace vrt_packet_handler{          const uhd::io_type_t &io_type,          const uhd::otw_type_t &otw_type,          double tick_rate, -        vrt_unpacker_type vrt_unpacker, +        const vrt_unpacker_t &vrt_unpacker,          const get_recv_buffs_t &get_recv_buffs, -        const handle_overrun_t &handle_overrun, +        const handle_overflow_t &handle_overflow,          size_t vrt_header_offset_words32      ){          metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE; @@ -158,7 +164,7 @@ namespace vrt_packet_handler{              try{                  _recv1_helper(                      state, metadata, tick_rate, -                    vrt_unpacker, handle_overrun, +                    vrt_unpacker, handle_overflow,                      vrt_header_offset_words32                  );              }catch(const std::exception &e){ @@ -206,7 +212,6 @@ namespace vrt_packet_handler{      /*******************************************************************       * Recv vrt packets and copy convert the samples into the buffer.       ******************************************************************/ -    template<typename vrt_unpacker_type>      static UHD_INLINE size_t recv(          recv_state &state,          const std::vector<void *> &buffs, @@ -216,9 +221,9 @@ namespace vrt_packet_handler{          const uhd::io_type_t &io_type,          const uhd::otw_type_t &otw_type,          double tick_rate, -        vrt_unpacker_type vrt_unpacker, +        const vrt_unpacker_t &vrt_unpacker,          const get_recv_buffs_t &get_recv_buffs, -        const handle_overrun_t &handle_overrun = &handle_overrun_nop, +        const handle_overflow_t &handle_overflow = &handle_overflow_nop,          size_t vrt_header_offset_words32 = 0      ){          switch(recv_mode){ @@ -235,7 +240,7 @@ namespace vrt_packet_handler{                  tick_rate,                  vrt_unpacker,                  get_recv_buffs, -                handle_overrun, +                handle_overflow,                  vrt_header_offset_words32              );          } @@ -255,7 +260,7 @@ namespace vrt_packet_handler{                      tick_rate,                      vrt_unpacker,                      get_recv_buffs, -                    handle_overrun, +                    handle_overflow,                      vrt_header_offset_words32                  );                  if (num_samps == 0) break; //had a recv timeout or error, break loop @@ -273,6 +278,7 @@ namespace vrt_packet_handler{   **********************************************************************/      typedef std::vector<uhd::transport::managed_send_buffer::sptr> managed_send_buffs_t;      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;      struct send_state{          //init the expected seq number @@ -287,7 +293,6 @@ namespace vrt_packet_handler{       * Pack a vrt header, copy-convert the data, and send it.       *  - helper function for vrt_packet_handler::send       ******************************************************************/ -    template<typename vrt_packer_type>      static UHD_INLINE void _send1(          send_state &state,          const std::vector<const void *> &buffs, @@ -296,7 +301,7 @@ namespace vrt_packet_handler{          uhd::transport::vrt::if_packet_info_t &if_packet_info,          const uhd::io_type_t &io_type,          const uhd::otw_type_t &otw_type, -        vrt_packer_type vrt_packer, +        const vrt_packer_t &vrt_packer,          const get_send_buffs_t &get_send_buffs,          size_t vrt_header_offset_words32      ){ @@ -334,7 +339,6 @@ namespace vrt_packet_handler{      /*******************************************************************       * Send vrt packets and copy convert the samples into the buffer.       ******************************************************************/ -    template<typename vrt_packer_type>      static UHD_INLINE size_t send(          send_state &state,          const std::vector<const void *> &buffs, @@ -344,7 +348,7 @@ namespace vrt_packet_handler{          const uhd::io_type_t &io_type,          const uhd::otw_type_t &otw_type,          double tick_rate, -        vrt_packer_type vrt_packer, +        const vrt_packer_t &vrt_packer,          const get_send_buffs_t &get_send_buffs,          size_t max_samples_per_packet,          size_t vrt_header_offset_words32 = 0 diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp index 42f69d77b..8a1cde694 100644 --- a/host/lib/transport/zero_copy.cpp +++ b/host/lib/transport/zero_copy.cpp @@ -54,12 +54,14 @@ private:  //! phony zero-copy recv interface implementation  struct phony_zero_copy_recv_if::impl{ +    impl(size_t max_buff_size) : max_buff_size(max_buff_size){ +        /* NOP */ +    }      size_t max_buff_size;  };  phony_zero_copy_recv_if::phony_zero_copy_recv_if(size_t max_buff_size){ -    _impl = UHD_PIMPL_MAKE(impl, ()); -    _impl->max_buff_size = max_buff_size; +    _impl = UHD_PIMPL_MAKE(impl, (max_buff_size));  }  phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){ diff --git a/host/lib/types.cpp b/host/lib/types.cpp index e0ce61058..5c0fb1f42 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -36,6 +36,7 @@  #include <boost/thread.hpp>  #include <stdexcept>  #include <complex> +#include <sstream>  using namespace uhd; @@ -60,14 +61,17 @@ freq_range_t::freq_range_t(double min, double max):  /***********************************************************************   * tune result   **********************************************************************/ -tune_result_t::tune_result_t(void): -    target_inter_freq(0.0), -    actual_inter_freq(0.0), -    target_dsp_freq(0.0), -    actual_dsp_freq(0.0), -    spectrum_inverted(false) -{ -    /* NOP */ +std::string tune_result_t::to_pp_string(void) const{ +    return str(boost::format( +        "Tune Result:\n" +        "    Target Intermediate Freq: %f (MHz)\n" +        "    Actual Intermediate Freq: %f (MHz)\n" +        "    Target DSP Freq Shift:    %f (MHz)\n" +        "    Actual DSP Freq Shift:    %f (MHz)\n" +    ) +        % (target_inter_freq/1e6) % (actual_inter_freq/1e6) +        % (target_dsp_freq/1e6)   % (actual_dsp_freq/1e6) +    );  }  /*********************************************************************** @@ -95,18 +99,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):  /***********************************************************************   * metadata   **********************************************************************/ -rx_metadata_t::rx_metadata_t(void): -    has_time_spec(false), -    time_spec(time_spec_t()), -    more_fragments(false), -    fragment_offset(0), -    start_of_burst(false), -    end_of_burst(false), -    error_code(ERROR_CODE_NONE) -{ -    /* NOP */ -} -  tx_metadata_t::tx_metadata_t(void):      has_time_spec(false),      time_spec(time_spec_t()), @@ -199,7 +191,7 @@ device_addr_t::device_addr_t(const std::string &args){          std::vector<std::string> key_val;          boost::split(key_val, pair, boost::is_any_of(pair_delim));          if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); -        (*this)[trim(key_val[0])] = trim(key_val[1]); +        (*this)[trim(key_val.front())] = trim(key_val.back());      }  } @@ -207,16 +199,18 @@ std::string device_addr_t::to_pp_string(void) const{      if (this->size() == 0) return "Empty Device Address";      std::stringstream ss; +    ss << "Device Address:" << std::endl;      BOOST_FOREACH(std::string key, this->keys()){ -        ss << boost::format("%s: %s") % key % (*this)[key] << std::endl; +        ss << boost::format("    %s: %s") % key % (*this)[key] << std::endl;      }      return ss.str();  }  std::string device_addr_t::to_string(void) const{      std::string args_str; +    size_t count = 0;      BOOST_FOREACH(const std::string &key, this->keys()){ -        args_str += key + pair_delim + (*this)[key] + arg_delim; +        args_str += ((count++)? arg_delim : "") + key + pair_delim + (*this)[key];      }      return args_str;  } diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 814affdd0..4a45c263e 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -24,6 +24,13 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp      ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.hpp      ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp  ) + +INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/dboard/CMakeLists.txt) +INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/CMakeLists.txt) +INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/CMakeLists.txt) diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 6093583d3..3e995009e 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_rfx.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_xcvr2450.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp  ) diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 766deac78..9180828d8 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -16,6 +16,7 @@  //  #include <uhd/usrp/subdev_props.hpp> +#include <uhd/types/dict.hpp>  #include <uhd/types/ranges.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp> @@ -138,17 +139,14 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, ""); //vector of 1 empty string          return; -    case SUBDEV_PROP_QUADRATURE: -        val = (get_subdev_name() == "AB"); //only quadrature in ab mode -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; -        return; +    case SUBDEV_PROP_CONNECTION:{ +            static const uhd::dict<std::string, subdev_conn_t> name_to_conn = map_list_of +                ("A",  SUBDEV_CONN_REAL_I) +                ("B",  SUBDEV_CONN_REAL_Q) +                ("AB", SUBDEV_CONN_COMPLEX_IQ) +            ; +            val = name_to_conn[get_subdev_name()]; +        } return;      case SUBDEV_PROP_USE_LO_OFFSET:          val = false; @@ -237,16 +235,8 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, ""); //vector of 1 empty string          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp new file mode 100644 index 000000000..03e6b6255 --- /dev/null +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -0,0 +1,610 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +// No RX IO Pins Used + +// RX IO Functions + +#include "max2118_regs.hpp" +#include <uhd/utils/static.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/utils/warning.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/dboard_base.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <boost/thread.hpp> +#include <boost/math/special_functions/round.hpp> +#include <utility> +#include <cmath> + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The DBSRX constants + **********************************************************************/ +static const bool dbsrx_debug = false; + +static const freq_range_t dbsrx_freq_range(0.8e9, 2.4e9); + +static const freq_range_t dbsrx_pfd_freq_range(0.15e6, 2.01e6); + +static const prop_names_t dbsrx_antennas = list_of("J3"); + +static const uhd::dict<std::string, gain_range_t> dbsrx_gain_ranges = map_list_of +    ("GC1", gain_range_t(0, 56, 0.5)) +    ("GC2", gain_range_t(0, 24, 1)) +; + +/*********************************************************************** + * The DBSRX dboard class + **********************************************************************/ +class dbsrx : public rx_dboard_base{ +public: +    dbsrx(ctor_args_t args, boost::uint8_t max2118_addr); +    ~dbsrx(void); + +    void rx_get(const wax::obj &key, wax::obj &val); +    void rx_set(const wax::obj &key, const wax::obj &val); + +private: +    double _lo_freq; +    float _bandwidth; +    uhd::dict<std::string, float> _gains; +    max2118_write_regs_t _max2118_write_regs; +    max2118_read_regs_t _max2118_read_regs; +    boost::uint8_t _max2118_addr; //0x67 or 0x65 depending on which side + +    void set_lo_freq(double target_freq); +    void set_gain(float gain, const std::string &name); +    void set_bandwidth(float bandwidth); + +    void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ +        start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5)); +        stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x5)); + +        for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ +            int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; + +            //create buffer for register data (+1 for start address) +            byte_vector_t regs_vector(num_bytes + 1); + +            //first byte is the address of first register +            regs_vector[0] = start_addr; + +            //get the register data +            for(int i=0; i<num_bytes; i++){ +                regs_vector[1+i] = _max2118_write_regs.get_reg(start_addr+i); +                if(dbsrx_debug) std::cerr << boost::format( +                    "DBSRX: send reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" +                ) % int(start_addr+i) % int(regs_vector[1+i]) % int(start_addr) % num_bytes << std::endl; +            } + +            //send the data +            this->get_iface()->write_i2c( +                _max2118_addr, regs_vector +            ); +        } +    } + +    void read_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ +        static const boost::uint8_t status_addr = 0x0; +        start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x1)); +        stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x1)); + +        for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t)){ +            int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) ? sizeof(boost::uint32_t) : stop_reg - start_addr + 1; + +            //create buffer for register data +            byte_vector_t regs_vector(num_bytes); + +            //read from i2c +            regs_vector = this->get_iface()->read_i2c( +                _max2118_addr, num_bytes +            ); + +            for(boost::uint8_t i=0; i < num_bytes; i++){ +                if (i + start_addr >= status_addr){ +                    _max2118_read_regs.set_reg(i + start_addr, regs_vector[i]); +                } +                if(dbsrx_debug) std::cerr << boost::format( +                    "DBSRX: read reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" +                ) % int(start_addr+i) % int(regs_vector[i]) % int(start_addr) % num_bytes << std::endl; +            } +        } +    } + +    /*! +     * Is the LO locked? +     * \return true for locked +     */ +    bool get_locked(void){ +        read_reg(0x0, 0x0); + +        //mask and return lock detect +        bool locked = 5 >= _max2118_read_regs.adc and _max2118_read_regs.adc >= 2; + +        if(dbsrx_debug) std::cerr << boost::format( +            "DBSRX: locked %d" +        ) % locked << std::endl; + +        return locked; +    } + +}; + +/*********************************************************************** + * Register the DBSRX dboard + **********************************************************************/ +// FIXME 0x67 is the default i2c address on USRP2 +//       need to handle which side for USRP1 with different address +static dboard_base::sptr make_dbsrx(dboard_base::ctor_args_t args){ +    return dboard_base::sptr(new dbsrx(args, 0x67)); +} + +//dbid for USRP2 version +UHD_STATIC_BLOCK(reg_dbsrx_dboard){ +    //register the factory function for the rx dbid +    dboard_manager::register_dboard(0x000D, &make_dbsrx, "DBSRX"); +} + +//dbid for USRP1 version +UHD_STATIC_BLOCK(reg_dbsrx_on_usrp1_dboard){ +    //register the factory function for the rx dbid +    dboard_manager::register_dboard(0x0002, &make_dbsrx, "DBSRX"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +dbsrx::dbsrx(ctor_args_t args, boost::uint8_t max2118_addr) : rx_dboard_base(args){ +    //warn user about incorrect DBID on USRP1, requires R193 populated +    if (this->get_iface()->get_mboard_name() == "usrp1" and this->get_rx_id() == 0x000D) +        uhd::print_warning( +            str(boost::format( +                "DBSRX: incorrect dbid\n" +                "%s expects dbid 0x0002 and R193\n" +                "found dbid == %d\n" +                "Please see the daughterboard app notes"  +                ) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string())) +        ); + +    //warn user about incorrect DBID on non-USRP1, requires R194 populated +    if (this->get_iface()->get_mboard_name() != "usrp1" and this->get_rx_id() == 0x0002) +        uhd::print_warning( +            str(boost::format( +                "DBSRX: incorrect dbid\n" +                "%s expects dbid 0x000D and R194\n" +                "found dbid == %d\n" +                "Please see the daughterboard app notes"  +                ) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string())) +        ); + +    //enable only the clocks we need +    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); + +    //set the gpio directions and atr controls (identically) +    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs + +    //set the i2c address for the max2118 +    _max2118_addr = max2118_addr; + +    //send initial register settings +    this->send_reg(0x0, 0x5); + +    //set defaults for LO, gains, and filter bandwidth +    _bandwidth = 33e6; +    set_lo_freq(dbsrx_freq_range.min); + +    BOOST_FOREACH(const std::string &name, dbsrx_gain_ranges.keys()){ +        set_gain(dbsrx_gain_ranges[name].min, name); +    } + +    set_bandwidth(33e6); // default bandwidth from datasheet +} + +dbsrx::~dbsrx(void){ +} + + +/*********************************************************************** + * Tuning + **********************************************************************/ +void dbsrx::set_lo_freq(double target_freq){ +    target_freq = std::clip(target_freq, dbsrx_freq_range.min, dbsrx_freq_range.max); + +    double actual_freq=0.0, pfd_freq=0.0, ref_clock=0.0; +    int R=0, N=0, r=0, m=0; +    bool update_filter_settings = false; + +    //choose refclock +    std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX); +    BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){ +        if (ref_clock > 27.0e6) continue; + +        //choose m_divider such that filter tuning constraint is met +        m = 31; +        while ((ref_clock/m < 1e6 or ref_clock/m > 2.5e6) and m > 0){ m--; } + +        if(dbsrx_debug) std::cerr << boost::format( +            "DBSRX: trying ref_clock %f and m_divider %d" +        ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl; + +        if (m >= 32) continue; + +        //choose R +        for(r = 0; r <= 6; r += 1) { +            //compute divider from setting +            R = 1 << (r+1); +            if (dbsrx_debug) std::cerr << boost::format("DBSRX R:%d\n") % R << std::endl; + +            //compute PFD compare frequency = ref_clock/R +            pfd_freq = ref_clock / R; + +            //constrain the PFD frequency to specified range +            if ((pfd_freq < dbsrx_pfd_freq_range.min) or (pfd_freq > dbsrx_pfd_freq_range.max)) continue; + +            //compute N +            N = int(std::floor(target_freq/pfd_freq)); + +            //constrain N to specified range +            if ((N < 256) or (N > 32768)) continue; + +            goto done_loop; +        } +    }  + +    //Assert because we failed to find a suitable combination of ref_clock, R and N  +    UHD_ASSERT_THROW(ref_clock/(1 << m) < 1e6 or ref_clock/(1 << m) > 2.5e6); +    UHD_ASSERT_THROW((pfd_freq < dbsrx_pfd_freq_range.min) or (pfd_freq > dbsrx_pfd_freq_range.max)); +    UHD_ASSERT_THROW((N < 256) or (N > 32768)); +    done_loop: + +    if(dbsrx_debug) std::cerr << boost::format( +        "DBSRX: choose ref_clock %f and m_divider %d" +    ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl; + +    //if ref_clock or m divider changed, we need to update the filter settings +    if (ref_clock != this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) or m != _max2118_write_regs.m_divider) update_filter_settings = true; + +    //compute resulting output frequency +    actual_freq = pfd_freq * N; + +    //apply ref_clock, R, and N settings +    this->get_iface()->set_clock_rate(dboard_iface::UNIT_RX, ref_clock); +    ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); +    _max2118_write_regs.m_divider = m; +    _max2118_write_regs.r_divider = (max2118_write_regs_t::r_divider_t) r; +    _max2118_write_regs.set_n_divider(N); +    _max2118_write_regs.ade_vco_ade_read = max2118_write_regs_t::ADE_VCO_ADE_READ_ENABLED; +     +    //compute prescaler variables +    int scaler = actual_freq > 1125e6 ? 2 : 4; +    _max2118_write_regs.div2 = scaler == 4 ? max2118_write_regs_t::DIV2_DIV4 : max2118_write_regs_t::DIV2_DIV2; + +    if(dbsrx_debug) std::cerr << boost::format( +        "DBSRX: scaler %d, actual_freq %f MHz, register bit: %d" +    ) % scaler % (actual_freq/1e6) % int(_max2118_write_regs.div2) << std::endl; + +    //compute vco frequency and select vco +    double vco_freq = actual_freq * scaler; +    if (vco_freq < 2433e6) +        _max2118_write_regs.osc_band = 0; +    else if (vco_freq < 2711e6) +        _max2118_write_regs.osc_band = 1; +    else if (vco_freq < 3025e6) +        _max2118_write_regs.osc_band = 2; +    else if (vco_freq < 3341e6) +        _max2118_write_regs.osc_band = 3; +    else if (vco_freq < 3727e6) +        _max2118_write_regs.osc_band = 4; +    else if (vco_freq < 4143e6) +        _max2118_write_regs.osc_band = 5; +    else if (vco_freq < 4493e6) +        _max2118_write_regs.osc_band = 6; +    else +        _max2118_write_regs.osc_band = 7; + +    //send settings over i2c +    send_reg(0x0, 0x4); + +    //check vtune for lock condition +    read_reg(0x0, 0x0); + +    if(dbsrx_debug) std::cerr << boost::format( +        "DBSRX: initial guess for vco %d, vtune adc %d" +    ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl; + +    //if we are out of lock for chosen vco, change vco +    while ((_max2118_read_regs.adc == 0) or (_max2118_read_regs.adc == 7)){ + +        //vtune is too low, try lower frequency vco +        if (_max2118_read_regs.adc == 0){ +            if (_max2118_write_regs.osc_band == 0){ +                uhd::print_warning( +                    str(boost::format( +                        "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"  +                        ) % int(_max2118_write_regs.osc_band)) +                ); +                UHD_ASSERT_THROW(_max2118_read_regs.adc == 0); +            } +            if (_max2118_write_regs.osc_band <= 0) break; +            _max2118_write_regs.osc_band -= 1; +        } + +        //vtune is too high, try higher frequency vco +        if (_max2118_read_regs.adc == 7){ +            if (_max2118_write_regs.osc_band == 7){ +                uhd::print_warning( +                    str(boost::format( +                        "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"  +                        ) % int(_max2118_write_regs.osc_band)) +                ); +                UHD_ASSERT_THROW(_max2118_read_regs.adc == 0); +            } +            if (_max2118_write_regs.osc_band >= 7) break; +            _max2118_write_regs.osc_band += 1; +        } + +        if(dbsrx_debug) std::cerr << boost::format( +            "DBSRX: trying vco %d, vtune adc %d" +        ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl; + +        //update vco selection and check vtune +        send_reg(0x2, 0x2); +        read_reg(0x0, 0x0); +    } +       +    if(dbsrx_debug) std::cerr << boost::format( +        "DBSRX: final vco %d, vtune adc %d" +    ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl; + +    //select charge pump bias current +    if (_max2118_read_regs.adc <= 2) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_100UA; +    else if (_max2118_read_regs.adc >= 5) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_400UA; +    else _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_200UA; +     +    //update charge pump bias current setting +    send_reg(0x2, 0x2); + +    //compute actual tuned frequency +    _lo_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) / std::pow(2.0,(1 + _max2118_write_regs.r_divider)) * _max2118_write_regs.get_n_divider(); + +    //debug output of calculated variables +    if (dbsrx_debug) std::cerr +        << boost::format("DBSRX tune:\n") +        << boost::format("    VCO=%d, CP=%d, PFD Freq=%fMHz\n") % int(_max2118_write_regs.osc_band) % _max2118_write_regs.cp_current % (pfd_freq/1e6) +        << boost::format("    R=%d, N=%f, scaler=%d, div2=%d\n") % R % N % scaler % int(_max2118_write_regs.div2) +        << boost::format("    Ref    Freq=%fMHz\n") % (ref_clock/1e6) +        << boost::format("    Target Freq=%fMHz\n") % (target_freq/1e6) +        << boost::format("    Actual Freq=%fMHz\n") % (_lo_freq/1e6) +        << std::endl; + +    if (update_filter_settings) set_bandwidth(_bandwidth); +    get_locked(); +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +/*! + * Convert a requested gain for the GC2 vga into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 5 bit the register value + */ +static int gain_to_gc2_vga_reg(float &gain){ +    int reg = 0; +    gain = std::clip<float>(float(boost::math::iround(gain)), dbsrx_gain_ranges["GC2"].min, dbsrx_gain_ranges["GC2"].max); + +    // Half dB steps from 0-5dB, 1dB steps from 5-24dB +    if (gain < 5) { +        reg = boost::math::iround(31.0 - gain/0.5); +        gain = float(boost::math::iround(gain) * 0.5); +    } else { +        reg = boost::math::iround(22.0 - (gain - 4.0)); +        gain = float(boost::math::iround(gain)); +    } + +    if (dbsrx_debug) std::cerr << boost::format( +        "DBSRX GC2 Gain: %f dB, reg: %d" +    ) % gain % reg << std::endl; + +    return reg; +} + +/*! + * Convert a requested gain for the GC1 rf vga into the dac_volts value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return dac voltage value + */ +static float gain_to_gc1_rfvga_dac(float &gain){ +    //clip the input +    gain = std::clip<float>(gain, dbsrx_gain_ranges["GC1"].min, dbsrx_gain_ranges["GC1"].max); + +    //voltage level constants +    static const float max_volts = float(1.2), min_volts = float(2.7); +    static const float slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].max; + +    //calculate the voltage for the aux dac +    float dac_volts = gain*slope + min_volts; + +    if (dbsrx_debug) std::cerr << boost::format( +        "DBSRX GC1 Gain: %f dB, dac_volts: %f V" +    ) % gain % dac_volts << std::endl; + +    //the actual gain setting +    gain = (dac_volts - min_volts)/slope; + +    return dac_volts; +} + +void dbsrx::set_gain(float gain, const std::string &name){ +    assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name"); +    if (name == "GC2"){ +        _max2118_write_regs.gc2 = gain_to_gc2_vga_reg(gain); +        send_reg(0x5, 0x5); +    } +    else if(name == "GC1"){ +        //write the new voltage to the aux dac +        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain)); +    } +    else UHD_THROW_INVALID_CODE_PATH(); +    _gains[name] = gain; +} + +/*********************************************************************** + * Bandwidth Handling + **********************************************************************/ +void dbsrx::set_bandwidth(float bandwidth){ +    //clip the input +    bandwidth = std::clip<float>(bandwidth, 4e6, 33e6); + +    double ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); +     +    //NOTE: _max2118_write_regs.m_divider set in set_lo_freq + +    //compute f_dac setting +    _max2118_write_regs.f_dac = std::clip<int>(int((((bandwidth*_max2118_write_regs.m_divider)/ref_clock) - 4)/0.145),0,127); + +    //determine actual bandwidth +    _bandwidth = float((ref_clock/(_max2118_write_regs.m_divider))*(4+0.145*_max2118_write_regs.f_dac)); + +    if (dbsrx_debug) std::cerr << boost::format( +        "DBSRX Filter Bandwidth: %f MHz, m: %d, f_dac: %d\n" +    ) % (_bandwidth/1e6) % int(_max2118_write_regs.m_divider) % int(_max2118_write_regs.f_dac) << std::endl; + +    this->send_reg(0x3, 0x4); +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = get_rx_id().to_pp_string(); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        assert_has(_gains.keys(), name, "dbsrx gain name"); +        val = _gains[name]; +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name"); +        val = dbsrx_gain_ranges[name]; +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(dbsrx_gain_ranges.keys()); +        return; + +    case SUBDEV_PROP_FREQ: +        val = _lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = dbsrx_freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = std::string("J3"); +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES: +        val = dbsrx_antennas; +        return; + +/* +    case SUBDEV_PROP_QUADRATURE: +        val = true; +        return; + +    case SUBDEV_PROP_IQ_SWAPPED: +        val = false; +        return; + +    case SUBDEV_PROP_SPECTRUM_INVERTED: +        val = false; +        return; +*/ +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ; +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = false; +        return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = this->get_locked(); +        return; + +/* +    case SUBDEV_PROP_RSSI: +        val = this->get_rssi(); +        return; +*/ + +    case SUBDEV_PROP_BANDWIDTH: +        val = _bandwidth; +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        this->set_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        this->set_gain(val.as<float>(), name); +        return; + +    case SUBDEV_PROP_BANDWIDTH: +        this->set_bandwidth(val.as<float>()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    } +} + diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 2d6088983..b6b44199a 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -43,6 +43,7 @@  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/algorithm.hpp> +#include <uhd/usrp/dboard_id.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_manager.hpp>  #include <boost/assign/list_of.hpp> @@ -65,6 +66,10 @@ static const prop_names_t rfx_rx_antennas = list_of("TX/RX")("RX2");  static const uhd::dict<std::string, gain_range_t> rfx_tx_gain_ranges; //empty  static const uhd::dict<std::string, gain_range_t> rfx_rx_gain_ranges = map_list_of +    ("PGA0", gain_range_t(0, 70, float(0.022))) +; + +static const uhd::dict<std::string, gain_range_t> rfx400_rx_gain_ranges = map_list_of      ("PGA0", gain_range_t(0, 45, float(0.022)))  ; @@ -88,6 +93,7 @@ public:  private:      freq_range_t _freq_range; +    uhd::dict<std::string, gain_range_t> _rx_gain_ranges;      uhd::dict<dboard_iface::unit_t, bool> _div2;      double       _rx_lo_freq, _tx_lo_freq;      std::string  _rx_ant; @@ -166,6 +172,14 @@ rfx_xcvr::rfx_xcvr(      _div2[dboard_iface::UNIT_RX] = rx_div2;      _div2[dboard_iface::UNIT_TX] = tx_div2; +    if(this->get_rx_id() == 0x0024) { //RFX400 +        _rx_gain_ranges = rfx400_rx_gain_ranges; +    } +    else { +        _rx_gain_ranges = rfx_rx_gain_ranges; +    } + +      //enable the clocks that we need      this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);      this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); @@ -193,8 +207,8 @@ rfx_xcvr::rfx_xcvr(      set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0);      set_rx_ant("RX2"); -    BOOST_FOREACH(const std::string &name, rfx_rx_gain_ranges.keys()){ -        set_rx_gain(rfx_rx_gain_ranges[name].min, name); +    BOOST_FOREACH(const std::string &name, _rx_gain_ranges.keys()){ +        set_rx_gain(_rx_gain_ranges[name].min, name);      }  } @@ -227,10 +241,10 @@ void rfx_xcvr::set_tx_ant(const std::string &ant){  /***********************************************************************   * Gain Handling   **********************************************************************/ -static float rx_pga0_gain_to_dac_volts(float &gain){ +static float rx_pga0_gain_to_dac_volts(float &gain, float range){      //voltage level constants (negative slope)      static const float max_volts = float(.2), min_volts = float(1.2); -    static const float slope = (max_volts-min_volts)/45; +    static const float slope = (max_volts-min_volts)/(range);      //calculate the voltage for the aux dac      float dac_volts = std::clip<float>(gain*slope + min_volts, max_volts, min_volts); @@ -247,9 +261,10 @@ void rfx_xcvr::set_tx_gain(float, const std::string &name){  }  void rfx_xcvr::set_rx_gain(float gain, const std::string &name){ -    assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name"); +    assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name");      if(name == "PGA0"){ -        float dac_volts = rx_pga0_gain_to_dac_volts(gain); +        float dac_volts = rx_pga0_gain_to_dac_volts(gain,  +                              (_rx_gain_ranges["PGA0"].max - _rx_gain_ranges["PGA0"].min));          _rx_gains[name] = gain;          //write the new voltage to the aux dac @@ -402,12 +417,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN_RANGE: -        assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name"); -        val = rfx_rx_gain_ranges[name]; +        assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name"); +        val = _rx_gain_ranges[name];          return;      case SUBDEV_PROP_GAIN_NAMES: -        val = prop_names_t(rfx_rx_gain_ranges.keys()); +        val = prop_names_t(_rx_gain_ranges.keys());          return;      case SUBDEV_PROP_FREQ: @@ -426,16 +441,8 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){          val = rfx_rx_antennas;          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = true; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_QI;          return;      case SUBDEV_PROP_USE_LO_OFFSET: @@ -516,16 +523,8 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){          val = rfx_tx_antennas;          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp index ced27e34d..9dd9b550b 100644 --- a/host/lib/usrp/dboard/db_unknown.cpp +++ b/host/lib/usrp/dboard/db_unknown.cpp @@ -119,16 +119,8 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, ""); //vector of 1 empty string          return; -    case SUBDEV_PROP_QUADRATURE: -        val = false; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: @@ -218,16 +210,8 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, ""); //vector of 1 empty string          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 2b2822b6b..3038ce30b 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -86,7 +86,7 @@ using namespace boost::assign;   **********************************************************************/  static const bool wbx_debug = false; -static const freq_range_t wbx_freq_range(50e6, 2.22e9); +static const freq_range_t wbx_freq_range(68.75e6, 2.2e9);  static const prop_names_t wbx_tx_antennas = list_of("TX/RX"); @@ -439,6 +439,7 @@ double wbx_xcvr::set_lo_freq(      regs.reference_divide_by_2 = T;      regs.reference_doubler = D;      regs.band_select_clock_div = BS; +    UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));      regs.rf_divider_select = rfdivsel_to_enum[RFdiv];      //write the registers @@ -509,16 +510,8 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){          val = wbx_rx_antennas;          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: @@ -603,16 +596,8 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){          val = wbx_tx_antennas;          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 5032b6f31..2c94bcd2d 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -481,16 +481,8 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){          val = xcvr_antennas;          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = false; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_IQ;          return;      case SUBDEV_PROP_USE_LO_OFFSET: @@ -579,16 +571,8 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){          val = xcvr_antennas;          return; -    case SUBDEV_PROP_QUADRATURE: -        val = true; -        return; - -    case SUBDEV_PROP_IQ_SWAPPED: -        val = true; -        return; - -    case SUBDEV_PROP_SPECTRUM_INVERTED: -        val = false; +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_QI;          return;      case SUBDEV_PROP_USE_LO_OFFSET: diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp index eafb8897f..6c4e29d9e 100644 --- a/host/lib/usrp/dboard_base.cpp +++ b/host/lib/usrp/dboard_base.cpp @@ -26,12 +26,12 @@ using namespace uhd::usrp;   * dboard_base dboard dboard_base class   **********************************************************************/  struct dboard_base::impl{ -    ctor_args_impl args; -    impl(ctor_args_t args) : args(*args){} +    dboard_ctor_args_t args;  };  dboard_base::dboard_base(ctor_args_t args){ -    _impl = UHD_PIMPL_MAKE(impl, (args)); +    _impl = UHD_PIMPL_MAKE(impl, ()); +    _impl->args = *static_cast<dboard_ctor_args_t *>(args);  }  dboard_base::~dboard_base(void){ diff --git a/host/lib/usrp/dboard_ctor_args.hpp b/host/lib/usrp/dboard_ctor_args.hpp index 13abe79e8..708f2ea08 100644 --- a/host/lib/usrp/dboard_ctor_args.hpp +++ b/host/lib/usrp/dboard_ctor_args.hpp @@ -15,18 +15,22 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#ifndef INCLUDED_DBOARD_CTOR_ARGS_HPP -#define INCLUDED_DBOARD_CTOR_ARGS_HPP +#ifndef INCLUDED_LIBUHD_USRP_DBOARD_CTOR_ARGS_HPP +#define INCLUDED_LIBUHD_USRP_DBOARD_CTOR_ARGS_HPP  #include <uhd/usrp/dboard_id.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_iface.hpp>  #include <string> -struct uhd::usrp::dboard_base::ctor_args_impl{ -    std::string               sd_name; -    dboard_iface::sptr        db_iface; -    dboard_id_t               rx_id, tx_id; -}; +namespace uhd{ namespace usrp{ -#endif /* INCLUDED_DBOARD_CTOR_ARGS_HPP */ +    struct dboard_ctor_args_t{ +        std::string               sd_name; +        dboard_iface::sptr        db_iface; +        dboard_id_t               rx_id, tx_id; +    }; + +}} //namespace + +#endif /* INCLUDED_LIBUHD_USRP_DBOARD_CTOR_ARGS_HPP */ diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 6321e018f..ab80875f5 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -18,7 +18,6 @@  #include "dboard_ctor_args.hpp"  #include <uhd/usrp/dboard_manager.hpp>  #include <uhd/usrp/subdev_props.hpp> -#include <uhd/utils/gain_handler.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/types/dict.hpp> @@ -98,33 +97,18 @@ public:      enum type_t{RX_TYPE, TX_TYPE};      //structors -    subdev_proxy(dboard_base::sptr subdev, type_t type) -    : _subdev(subdev), _type(type){ -        //initialize gain props struct -        gain_handler::props_t gain_props; -        gain_props.value = SUBDEV_PROP_GAIN; -        gain_props.range = SUBDEV_PROP_GAIN_RANGE; -        gain_props.names = SUBDEV_PROP_GAIN_NAMES; - -        //make a new gain handler -        _gain_handler = gain_handler::make( -            this->get_link(), gain_props, -            boost::bind(&gain_handler::is_equal<subdev_prop_t>, _1, _2) -        ); -    } - -    ~subdev_proxy(void){ +    subdev_proxy(dboard_base::sptr subdev, type_t type): +        _subdev(subdev), _type(type) +    {          /* NOP */      }  private: -    gain_handler::sptr   _gain_handler;      dboard_base::sptr   _subdev;      type_t              _type;      //forward the get calls to the rx or tx      void get(const wax::obj &key, wax::obj &val){ -        if (_gain_handler->intercept_get(key, val)) return;          switch(_type){          case RX_TYPE: return _subdev->rx_get(key, val);          case TX_TYPE: return _subdev->tx_get(key, val); @@ -133,7 +117,6 @@ private:      //forward the set calls to the rx or tx      void set(const wax::obj &key, const wax::obj &val){ -        if (_gain_handler->intercept_set(key, val)) return;          switch(_type){          case RX_TYPE: return _subdev->rx_set(key, val);          case TX_TYPE: return _subdev->tx_set(key, val); @@ -242,7 +225,7 @@ dboard_manager_impl::dboard_manager_impl(      set_nice_dboard_if();      //dboard constructor args -    dboard_base::ctor_args_impl db_ctor_args; +    dboard_ctor_args_t db_ctor_args;      db_ctor_args.db_iface = iface;      //make xcvr subdevs (make one subdev for both rx and tx dboards) diff --git a/host/lib/usrp/dsp_utils.hpp b/host/lib/usrp/dsp_utils.hpp index 13186f354..ebed12c41 100644 --- a/host/lib/usrp/dsp_utils.hpp +++ b/host/lib/usrp/dsp_utils.hpp @@ -22,6 +22,7 @@  #include <uhd/types/dict.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/types/stream_cmd.hpp> +#include <uhd/usrp/subdev_props.hpp>  #include <boost/cstdint.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/tuple/tuple.hpp> @@ -37,37 +38,36 @@ namespace dsp_type1{      /*!       * Calculate the rx mux word from properties. -     * \param is_quadrature true if the subdev is complex -     * \param is_iq_swapped true if the i and q are reversed +     * \param subdev_conn the subdev connection type       * \param the 32-bit rx mux control word       */      static inline boost::uint32_t calc_rx_mux_word( -        bool is_quadrature, -        bool is_iq_swapped +        subdev_conn_t subdev_conn      ){ -        boost::uint32_t rx_mux = 0; -        if (is_quadrature){ -            rx_mux = (0x01 << 2) | (0x00 << 0); //Q=ADC1, I=ADC0 -        }else{ -            rx_mux = (0x11 << 2) | (0x00 << 0); //Q=ZERO, I=ADC0 +        switch(subdev_conn){ +        case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 2) | (0x0 << 0); //DDC0Q=ADC1, DDC0I=ADC0 +        case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 2) | (0x1 << 0); //DDC0Q=ADC0, DDC0I=ADC1 +        case SUBDEV_CONN_REAL_I:     return (0x3 << 2) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0 +        case SUBDEV_CONN_REAL_Q:     return (0x1 << 2) | (0x3 << 0); //DDC0Q=ADC1, DDC0I=ZERO +        default:                     UHD_THROW_INVALID_CODE_PATH();          } -        if (is_iq_swapped){ -            rx_mux = (rx_mux << 2) | (rx_mux >> 2); -        } -        return rx_mux;      }      /*!       * Calculate the tx mux word from properties. -     * \param is_iq_swapped true if the i and q are reversed +     * \param subdev_conn the subdev connection type       * \param the 32-bit tx mux control word       */ -    static inline boost::uint32_t calc_tx_mux_word(bool is_iq_swapped){ -        boost::uint32_t tx_mux = 0x10; -        if (is_iq_swapped){ -            tx_mux = (tx_mux << 4) | (tx_mux >> 4); +    static inline boost::uint32_t calc_tx_mux_word( +        subdev_conn_t subdev_conn +    ){ +        switch(subdev_conn){ +        case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC1=DUC0Q, DAC0=DUC0I +        case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC1=DUC0I, DAC0=DUC0Q +        case SUBDEV_CONN_REAL_I:     return (0xf << 4) | (0x0 << 0); //DAC1=ZERO,  DAC0=DUC0I +        case SUBDEV_CONN_REAL_Q:     return (0x0 << 4) | (0xf << 0); //DAC1=DUC0I, DAC0=ZERO +        default:                     UHD_THROW_INVALID_CODE_PATH();          } -        return tx_mux;      }      /*! @@ -82,11 +82,11 @@ namespace dsp_type1{          double &freq,          double codec_rate      ){ -        UHD_ASSERT_THROW(std::abs(freq) < codec_rate/2.0); +        UHD_ASSERT_THROW(std::abs(freq) <= codec_rate/2.0);          static const double scale_factor = std::pow(2.0, 32);          //calculate the freq register word (signed) -        boost::int32_t freq_word = boost::math::iround((freq / codec_rate) * scale_factor); +        boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / codec_rate) * scale_factor));          //update the actual frequency          freq = (double(freq_word) / scale_factor) * codec_rate; diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index b40f98226..e78d38fc0 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -18,7 +18,9 @@  #include <uhd/usrp/mimo_usrp.hpp>  #include <uhd/usrp/tune_helper.hpp>  #include <uhd/utils/assert.hpp> +#include <uhd/utils/gain_group.hpp>  #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/usrp/device_props.hpp> @@ -33,6 +35,11 @@  using namespace uhd;  using namespace uhd::usrp; +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ +    double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>(); +    return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} +  /***********************************************************************   * MIMO USRP Implementation   **********************************************************************/ @@ -41,29 +48,12 @@ public:      mimo_usrp_impl(const device_addr_t &addr){          _dev = device::make(addr); -        //extract each mboard and its sub-devices -        BOOST_FOREACH(const std::string &name, (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>()){ -            _mboards.push_back((*_dev)[named_prop_t(DEVICE_PROP_MBOARD, name)]); -            _rx_dsps.push_back(_mboards.back()[MBOARD_PROP_RX_DSP]); -            _tx_dsps.push_back(_mboards.back()[MBOARD_PROP_TX_DSP]); - -            //extract rx subdevice -            _rx_dboards.push_back(_mboards.back()[MBOARD_PROP_RX_DBOARD]); -            std::string rx_subdev_in_use = _rx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); -            _rx_subdevs.push_back(_rx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]); - -            //extract tx subdevice -            _tx_dboards.push_back(_mboards.back()[MBOARD_PROP_TX_DBOARD]); -            std::string tx_subdev_in_use = _tx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); -            _tx_subdevs.push_back(_tx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)]); -        } -          //set the clock config across all mboards (TODO set through api)          clock_config_t clock_config;          clock_config.ref_source = clock_config_t::REF_SMA;          clock_config.pps_source = clock_config_t::PPS_SMA; -        BOOST_FOREACH(wax::obj mboard, _mboards){ -            mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; +        for (size_t chan = 0; chan < get_num_channels(); chan++){ +            _mboard(chan)[MBOARD_PROP_CLOCK_CONFIG] = clock_config;          }      } @@ -82,7 +72,7 @@ public:          )              % (*_dev)[DEVICE_PROP_NAME].as<std::string>()          ); -        for (size_t i = 0; i < get_num_channels(); i++){ +        for (size_t chan = 0; chan < get_num_channels(); chan++){              buff += str(boost::format(                  "  Channel: %u\n"                  "    Mboard: %s\n" @@ -92,21 +82,21 @@ public:                  "    TX DSP: %s\n"                  "    TX Dboard: %s\n"                  "    TX Subdev: %s\n" -            ) % i -                % _mboards.at(i)[MBOARD_PROP_NAME].as<std::string>() -                % _rx_dsps.at(i)[DSP_PROP_NAME].as<std::string>() -                % _rx_dboards.at(i)[DBOARD_PROP_NAME].as<std::string>() -                % _rx_subdevs.at(i)[SUBDEV_PROP_NAME].as<std::string>() -                % _tx_dsps.at(i)[DSP_PROP_NAME].as<std::string>() -                % _tx_dboards.at(i)[DBOARD_PROP_NAME].as<std::string>() -                % _tx_subdevs.at(i)[SUBDEV_PROP_NAME].as<std::string>() +            ) % chan +                % _mboard(chan)[MBOARD_PROP_NAME].as<std::string>() +                % _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>() +                % _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>()              );          }          return buff;      }      size_t get_num_channels(void){ -        return _mboards.size(); +        return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().size();      }      /******************************************************************* @@ -114,12 +104,12 @@ public:       ******************************************************************/      time_spec_t get_time_now(void){          //the time on the first mboard better be the same on all -        return _mboards.front()[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +        return _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();      }      void set_time_next_pps(const time_spec_t &time_spec){ -        BOOST_FOREACH(wax::obj mboard, _mboards){ -            mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +        for (size_t chan = 0; chan < get_num_channels(); chan++){ +            _mboard(chan)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;          }      } @@ -141,33 +131,42 @@ public:          boost::this_thread::sleep(boost::posix_time::seconds(1));          //verify that the time registers are read to be within a few RTT -        for (size_t i = 1; i < get_num_channels(); i++){ -            time_spec_t time_0 = _mboards.front()[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); -            time_spec_t time_i = _mboards.at(i)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +        for (size_t chan = 1; chan < get_num_channels(); chan++){ +            time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +            time_spec_t time_i = _mboard(chan)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();              if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big -                std::cerr << boost::format( -                    "Error: time deviation between board %d and board 0.\n" -                    "    Board 0 time is %f seconds.\n" -                    "    Board %d time is %f seconds.\n" -                ) % i % time_0.get_real_secs() % i % time_i.get_real_secs() << std::endl; +                uhd::print_warning(str(boost::format( +                    "Detected time deviation between board %d and board 0.\n" +                    "Board 0 time is %f seconds.\n" +                    "Board %d time is %f seconds.\n" +                ) % chan % time_0.get_real_secs() % chan % time_i.get_real_secs()));              }          }      }      void issue_stream_cmd(const stream_cmd_t &stream_cmd){ -        BOOST_FOREACH(wax::obj mboard, _mboards){ -            mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd; +        for (size_t chan = 0; chan < get_num_channels(); chan++){ +            _mboard(chan)[MBOARD_PROP_STREAM_CMD] = stream_cmd;          }      }      /*******************************************************************       * RX methods       ******************************************************************/ +    void set_rx_subdev_spec(size_t chan, const subdev_spec_t &spec){ +        UHD_ASSERT_THROW(spec.size() <= 1); +        _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; +    } + +    subdev_spec_t get_rx_subdev_spec(size_t chan){ +        return _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); +    } +      void set_rx_rate_all(double rate){          std::vector<double> _actual_rates; -        BOOST_FOREACH(wax::obj rx_dsp, _rx_dsps){ -            rx_dsp[DSP_PROP_HOST_RATE] = rate; -            _actual_rates.push_back(rx_dsp[DSP_PROP_HOST_RATE].as<double>()); +        for (size_t chan = 0; chan < get_num_channels(); chan++){ +            _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; +            _actual_rates.push_back(_rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>());          }          _rx_rate = _actual_rates.front();          if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error( @@ -180,57 +179,70 @@ public:      }      tune_result_t set_rx_freq(size_t chan, double target_freq){ -        return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq); +        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq);      }      tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ -        return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq, lo_off); +        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq, lo_off); +    } + +    double get_rx_freq(size_t chan){ +        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 _rx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(); +        return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan));      }      void set_rx_gain(size_t chan, float gain){ -        _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain; +        return _rx_gain_group(chan)->set_value(gain);      }      float get_rx_gain(size_t chan){ -        return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as<float>(); +        return _rx_gain_group(chan)->get_value();      }      gain_range_t get_rx_gain_range(size_t chan){ -        return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _rx_gain_group(chan)->get_range();      }      void set_rx_antenna(size_t chan, const std::string &ant){ -        _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant; +        _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;      }      std::string get_rx_antenna(size_t chan){ -        return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); +        return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();      }      std::vector<std::string> get_rx_antennas(size_t chan){ -        return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +        return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();      }      bool get_rx_lo_locked(size_t chan){ -        return _rx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>(); +        return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();      }      float read_rssi(size_t chan){ -        return _rx_subdevs.at(chan)[SUBDEV_PROP_RSSI].as<float>(); +        return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>();      }      /*******************************************************************       * TX methods       ******************************************************************/ +    void set_tx_subdev_spec(size_t chan, const subdev_spec_t &spec){ +        UHD_ASSERT_THROW(spec.size() <= 1); +        _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; +    } + +    subdev_spec_t get_tx_subdev_spec(size_t chan){ +        return _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); +    } +      void set_tx_rate_all(double rate){          std::vector<double> _actual_rates; -        BOOST_FOREACH(wax::obj tx_dsp, _tx_dsps){ -            tx_dsp[DSP_PROP_HOST_RATE] = rate; -            _actual_rates.push_back(tx_dsp[DSP_PROP_HOST_RATE].as<double>()); +        for (size_t chan = 0; chan < get_num_channels(); chan++){ +            _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; +            _actual_rates.push_back(_tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>());          }          _tx_rate = _actual_rates.front();          if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error( @@ -243,54 +255,85 @@ public:      }      tune_result_t set_tx_freq(size_t chan, double target_freq){ -        return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq); +        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq);      }      tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ -        return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq, lo_off); +        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq, lo_off); +    } + +    double get_tx_freq(size_t chan){ +        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 _tx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(); +        return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan));      }      void set_tx_gain(size_t chan, float gain){ -        _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain; +        return _tx_gain_group(chan)->set_value(gain);      }      float get_tx_gain(size_t chan){ -        return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as<float>(); +        return _tx_gain_group(chan)->get_value();      }      gain_range_t get_tx_gain_range(size_t chan){ -        return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _tx_gain_group(chan)->get_range();      }      void set_tx_antenna(size_t chan, const std::string &ant){ -        _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant; +        _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;      }      std::string get_tx_antenna(size_t chan){ -        return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); +        return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();      }      std::vector<std::string> get_tx_antennas(size_t chan){ -        return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +        return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();      }      bool get_tx_lo_locked(size_t chan){ -        return _tx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>(); +        return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();      }  private:      device::sptr _dev; -    std::vector<wax::obj> _mboards; -    std::vector<wax::obj> _rx_dsps; -    std::vector<wax::obj> _tx_dsps; -    std::vector<wax::obj> _rx_dboards; -    std::vector<wax::obj> _tx_dboards; -    std::vector<wax::obj> _rx_subdevs; -    std::vector<wax::obj> _tx_subdevs; +    wax::obj _mboard(size_t chan){ +        prop_names_t names = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>(); +        return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, names.at(chan))]; +    } +    wax::obj _rx_dsp(size_t chan){ +        return _mboard(chan)[MBOARD_PROP_RX_DSP]; +    } +    wax::obj _tx_dsp(size_t chan){ +        return _mboard(chan)[MBOARD_PROP_TX_DSP]; +    } +    wax::obj _rx_dboard(size_t chan){ +        std::string db_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; +        return _mboard(chan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; +    } +    wax::obj _tx_dboard(size_t chan){ +        std::string db_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; +        return _mboard(chan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; +    } +    wax::obj _rx_subdev(size_t chan){ +        std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().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 = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().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 = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().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 = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    }      //shadows      double _rx_rate, _tx_rate; diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp new file mode 100644 index 000000000..0aa03a6cc --- /dev/null +++ b/host/lib/usrp/misc_utils.cpp @@ -0,0 +1,114 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "misc_utils.hpp" +#include <uhd/utils/gain_group.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/codec_props.hpp> +#include <boost/bind.hpp> +#include <boost/foreach.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +static const size_t subdev_gain_priority = 1; //higher, closer to the antenna +static const size_t codec_gain_priority = 0; + +/*********************************************************************** + * codec gain group helper functions: + *    do this so we dont have to bind a templated function + **********************************************************************/ +static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>(); +} + +static float get_codec_gain_i(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>(); +} + +static float get_codec_gain_q(wax::obj codec, const std::string &name){ +    return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>(); +} + +static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){ +    codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain; +    codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain; +} + +static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){ +    codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain; +} + +static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){ +    codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain; +} + +/*********************************************************************** + * subdev gain group helper functions: + *    do this so we dont have to bind a templated function + **********************************************************************/ +static float get_subdev_gain(wax::obj subdev, const std::string &name){ +    return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>(); +} + +static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){ +    return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>(); +} + +static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){ +    subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain; +} + +/*********************************************************************** + * gain group factory function for usrp + **********************************************************************/ +gain_group::sptr usrp::make_gain_group(wax::obj subdev, wax::obj codec){ +    gain_group::sptr gg = gain_group::make(); +    gain_fcns_t fcns; +    //add all the subdev gains first (antenna to dsp order) +    BOOST_FOREACH(const std::string &name, subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()){ +        fcns.get_range = boost::bind(&get_subdev_gain_range, subdev, name); +        fcns.get_value = boost::bind(&get_subdev_gain, subdev, name); +        fcns.set_value = boost::bind(&set_subdev_gain, subdev, name, _1); +        gg->register_fcns(fcns, subdev_gain_priority); +    } +    //add all the codec gains last (antenna to dsp order) +    BOOST_FOREACH(const std::string &name, codec[CODEC_PROP_GAIN_NAMES].as<prop_names_t>()){ +        fcns.get_range = boost::bind(&get_codec_gain_range, codec, name); + +        //register the value functions depending upon the connection type +        switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ +        case SUBDEV_CONN_COMPLEX_IQ: +        case SUBDEV_CONN_COMPLEX_QI: +            fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); //same as Q +            fcns.set_value = boost::bind(&set_codec_gain_both, codec, name, _1); //sets both +            break; + +        case SUBDEV_CONN_REAL_I: +            fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); +            fcns.set_value = boost::bind(&set_codec_gain_i, codec, name, _1); +            break; + +        case SUBDEV_CONN_REAL_Q: +            fcns.get_value = boost::bind(&get_codec_gain_q, codec, name); +            fcns.set_value = boost::bind(&set_codec_gain_q, codec, name, _1); +            break; +        } +        gg->register_fcns(fcns, codec_gain_priority); +    } +    return gg; +} diff --git a/host/lib/usrp/misc_utils.hpp b/host/lib/usrp/misc_utils.hpp new file mode 100644 index 000000000..7fe3c899d --- /dev/null +++ b/host/lib/usrp/misc_utils.hpp @@ -0,0 +1,35 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP +#define INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP + +#include <uhd/config.hpp> +#include <uhd/wax.hpp> +#include <uhd/utils/gain_group.hpp> + +namespace uhd{ namespace usrp{ + +    /*! +     * Create a gain group that represents the subdevice and its codec. +     */ +    gain_group::sptr make_gain_group(wax::obj subdev, wax::obj codec); + +}} //namespace + +#endif /* INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP */ + diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index 56e82d7ee..60b25a647 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -18,6 +18,7 @@  #include <uhd/usrp/simple_usrp.hpp>  #include <uhd/usrp/tune_helper.hpp>  #include <uhd/utils/assert.hpp> +#include <uhd/utils/gain_group.hpp>  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/usrp/device_props.hpp> @@ -26,10 +27,16 @@  #include <boost/foreach.hpp>  #include <boost/format.hpp>  #include <stdexcept> +#include <iostream>  using namespace uhd;  using namespace uhd::usrp; +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ +    double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>(); +    return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} +  /***********************************************************************   * Simple USRP Implementation   **********************************************************************/ @@ -37,19 +44,6 @@ class simple_usrp_impl : public simple_usrp{  public:      simple_usrp_impl(const device_addr_t &addr){          _dev = device::make(addr); -        _mboard = (*_dev)[DEVICE_PROP_MBOARD]; -        _rx_dsp = _mboard[MBOARD_PROP_RX_DSP]; -        _tx_dsp = _mboard[MBOARD_PROP_TX_DSP]; - -        //extract rx subdevice -        _rx_dboard = _mboard[MBOARD_PROP_RX_DBOARD]; -        std::string rx_subdev_in_use = _rx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); -        _rx_subdev = _rx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]; - -        //extract tx subdevice -        _tx_dboard = _mboard[MBOARD_PROP_TX_DBOARD]; -        std::string tx_subdev_in_use = _tx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0); -        _tx_subdev = _tx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)];      }      ~simple_usrp_impl(void){ @@ -73,13 +67,13 @@ public:              "  TX Subdev: %s\n"          )              % (*_dev)[DEVICE_PROP_NAME].as<std::string>() -            % _mboard[MBOARD_PROP_NAME].as<std::string>() -            % _rx_dsp[DSP_PROP_NAME].as<std::string>() -            % _rx_dboard[DBOARD_PROP_NAME].as<std::string>() -            % _rx_subdev[SUBDEV_PROP_NAME].as<std::string>() -            % _tx_dsp[DSP_PROP_NAME].as<std::string>() -            % _tx_dboard[DBOARD_PROP_NAME].as<std::string>() -            % _tx_subdev[SUBDEV_PROP_NAME].as<std::string>() +            % _mboard()[MBOARD_PROP_NAME].as<std::string>() +            % _rx_dsp()[DSP_PROP_NAME].as<std::string>() +            % _rx_dboard()[DBOARD_PROP_NAME].as<std::string>() +            % _rx_subdev()[SUBDEV_PROP_NAME].as<std::string>() +            % _tx_dsp()[DSP_PROP_NAME].as<std::string>() +            % _tx_dboard()[DBOARD_PROP_NAME].as<std::string>() +            % _tx_subdev()[SUBDEV_PROP_NAME].as<std::string>()          );      } @@ -87,140 +81,192 @@ public:       * Misc       ******************************************************************/      time_spec_t get_time_now(void){ -        return _mboard[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +        return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();      }      void set_time_now(const time_spec_t &time_spec){ -        _mboard[MBOARD_PROP_TIME_NOW] = time_spec; +        _mboard()[MBOARD_PROP_TIME_NOW] = time_spec;      }      void set_time_next_pps(const time_spec_t &time_spec){ -        _mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +        _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;      }      void issue_stream_cmd(const stream_cmd_t &stream_cmd){ -        _mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd; +        _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd;      }      void set_clock_config(const clock_config_t &clock_config){ -        _mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config; +        _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config;      }      /*******************************************************************       * RX methods       ******************************************************************/ +    void set_rx_subdev_spec(const subdev_spec_t &spec){ +        _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; +        std::cout << "RX " << _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl; +    } + +    subdev_spec_t get_rx_subdev_spec(void){ +        return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); +    } +      void set_rx_rate(double rate){ -        _rx_dsp[DSP_PROP_HOST_RATE] = rate; +        _rx_dsp()[DSP_PROP_HOST_RATE] = rate;      }      double get_rx_rate(void){ -        return _rx_dsp[DSP_PROP_HOST_RATE].as<double>(); +        return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>();      }      tune_result_t set_rx_freq(double target_freq){ -        return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq); +        return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq);      }      tune_result_t set_rx_freq(double target_freq, double lo_off){ -        return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq, lo_off); +        return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq, lo_off); +    } + +    double get_rx_freq(void){ +        return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp());      }      freq_range_t get_rx_freq_range(void){ -        return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(); +        return add_dsp_shift(_rx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp());      }      void set_rx_gain(float gain){ -        _rx_subdev[SUBDEV_PROP_GAIN] = gain; +        return _rx_gain_group()->set_value(gain);      }      float get_rx_gain(void){ -        return _rx_subdev[SUBDEV_PROP_GAIN].as<float>(); +        return _rx_gain_group()->get_value();      }      gain_range_t get_rx_gain_range(void){ -        return _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _rx_gain_group()->get_range();      }      void set_rx_antenna(const std::string &ant){ -        _rx_subdev[SUBDEV_PROP_ANTENNA] = ant; +        _rx_subdev()[SUBDEV_PROP_ANTENNA] = ant;      }      std::string get_rx_antenna(void){ -        return _rx_subdev[SUBDEV_PROP_ANTENNA].as<std::string>(); +        return _rx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>();      }      std::vector<std::string> get_rx_antennas(void){ -        return _rx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +        return _rx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();      }      bool get_rx_lo_locked(void){ -        return _rx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>(); +        return _rx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>();      }      float read_rssi(void){ -        return _rx_subdev[SUBDEV_PROP_RSSI].as<float>(); +        return _rx_subdev()[SUBDEV_PROP_RSSI].as<float>();      }      /*******************************************************************       * TX methods       ******************************************************************/ +    void set_tx_subdev_spec(const subdev_spec_t &spec){ +        _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; +        std::cout << "TX " << _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl; +    } + +    subdev_spec_t get_tx_subdev_spec(void){ +        return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); +    } +      void set_tx_rate(double rate){ -        _tx_dsp[DSP_PROP_HOST_RATE] = rate; +        _tx_dsp()[DSP_PROP_HOST_RATE] = rate;      }      double get_tx_rate(void){ -        return _tx_dsp[DSP_PROP_HOST_RATE].as<double>(); +        return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>();      }      tune_result_t set_tx_freq(double target_freq){ -        return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq); +        return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq);      }      tune_result_t set_tx_freq(double target_freq, double lo_off){ -        return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq, lo_off); +        return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq, lo_off); +    } + +    double get_tx_freq(void){ +        return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp());      }      freq_range_t get_tx_freq_range(void){ -        return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(); +        return add_dsp_shift(_tx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp());      }      void set_tx_gain(float gain){ -        _tx_subdev[SUBDEV_PROP_GAIN] = gain; +        return _tx_gain_group()->set_value(gain);      }      float get_tx_gain(void){ -        return _tx_subdev[SUBDEV_PROP_GAIN].as<float>(); +        return _tx_gain_group()->get_value();      }      gain_range_t get_tx_gain_range(void){ -        return _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>(); +        return _tx_gain_group()->get_range();      }      void set_tx_antenna(const std::string &ant){ -        _tx_subdev[SUBDEV_PROP_ANTENNA] = ant; +        _tx_subdev()[SUBDEV_PROP_ANTENNA] = ant;      }      std::string get_tx_antenna(void){ -        return _tx_subdev[SUBDEV_PROP_ANTENNA].as<std::string>(); +        return _tx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>();      }      std::vector<std::string> get_tx_antennas(void){ -        return _tx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +        return _tx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();      }      bool get_tx_lo_locked(void){ -        return _tx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>(); +        return _tx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>();      }  private:      device::sptr _dev; -    wax::obj _mboard; -    wax::obj _rx_dsp; -    wax::obj _tx_dsp; -    wax::obj _rx_dboard; -    wax::obj _tx_dboard; -    wax::obj _rx_subdev; -    wax::obj _tx_subdev; +    wax::obj _mboard(void){ +        return (*_dev)[DEVICE_PROP_MBOARD]; +    } +    wax::obj _rx_dsp(void){ +        return _mboard()[MBOARD_PROP_RX_DSP]; +    } +    wax::obj _tx_dsp(void){ +        return _mboard()[MBOARD_PROP_TX_DSP]; +    } +    wax::obj _rx_dboard(void){ +        std::string db_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; +        return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; +    } +    wax::obj _tx_dboard(void){ +        std::string db_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; +        return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; +    } +    wax::obj _rx_subdev(void){ +        std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _rx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; +    } +    wax::obj _tx_subdev(void){ +        std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _tx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; +    } +    gain_group::sptr _rx_gain_group(void){ +        std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _rx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    } +    gain_group::sptr _tx_gain_group(void){ +        std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; +        return _tx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    }  };  /*********************************************************************** diff --git a/host/lib/usrp/subdev_spec.cpp b/host/lib/usrp/subdev_spec.cpp new file mode 100644 index 000000000..0f00e2f74 --- /dev/null +++ b/host/lib/usrp/subdev_spec.cpp @@ -0,0 +1,77 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/usrp/subdev_spec.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/format.hpp> +#include <boost/foreach.hpp> +#include <stdexcept> +#include <sstream> + +using namespace uhd; +using namespace uhd::usrp; + +subdev_spec_pair_t::subdev_spec_pair_t( +    const std::string &db_name, const std::string &sd_name +): +    db_name(db_name), +    sd_name(sd_name) +{ +    /* NOP */ +} + +subdev_spec_t::subdev_spec_t(const std::string &markup){ +    std::vector<std::string> pairs; +    boost::split(pairs, markup, boost::is_any_of("\t ")); +    BOOST_FOREACH(const std::string &pair, pairs){ +        if (pair == "") continue; +        std::vector<std::string> db_sd; +        boost::split(db_sd, pair, boost::is_any_of(":")); +        switch(db_sd.size()){ +        case 1: this->push_back(subdev_spec_pair_t("", db_sd.front())); break; +        case 2: this->push_back(subdev_spec_pair_t(db_sd.front(), db_sd.back())); break; +        default: throw std::runtime_error("invalid subdev-spec markup string: "+markup); +        } +    } +} + +std::string subdev_spec_t::to_pp_string(void) const{ +    if (this->size() == 0) return "Empty Subdevice Specification"; + +    std::stringstream ss; +    size_t count = 0; +    ss << "Subdevice Specification:" << std::endl; +    BOOST_FOREACH(const subdev_spec_pair_t &pair, *this){ +        std::string db_name = pair.db_name; +        if (db_name == "") db_name = "0"; +        std::string sd_name = pair.sd_name; +        if (sd_name == "") sd_name = "0"; +        ss << boost::format( +            "    Channel %d: Daughterboard %s, Subdevice %s" +        ) % (count++) % db_name % sd_name << std::endl; +    } +    return ss.str(); +} + +std::string subdev_spec_t::to_string(void) const{ +    std::string markup; +    size_t count = 0; +    BOOST_FOREACH(const subdev_spec_pair_t &pair, *this){ +        markup += ((count++)? " " : "") + pair.db_name + ":" + pair.sd_name; +    } +    return markup; +} diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp index 082c39f6d..e516477d3 100644 --- a/host/lib/usrp/tune_helper.cpp +++ b/host/lib/usrp/tune_helper.cpp @@ -16,25 +16,24 @@  //  #include <uhd/usrp/tune_helper.hpp> -#include <uhd/utils/algorithm.hpp>  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/dsp_props.hpp> +#include <uhd/usrp/dboard_iface.hpp> //unit_t +#include <boost/math/special_functions/sign.hpp>  #include <cmath>  using namespace uhd;  using namespace uhd::usrp;  /*********************************************************************** - * Tune Helper Function + * Tune Helper Functions   **********************************************************************/  static tune_result_t tune_xx_subdev_and_dxc( -    bool is_tx, +    dboard_iface::unit_t unit,      wax::obj subdev, wax::obj dxc,      double target_freq, double lo_offset  ){      wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; -    bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as<bool>(); -    bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>();      wax::obj dxc_freq_proxy = dxc[DSP_PROP_FREQ_SHIFT];      double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as<double>(); @@ -43,55 +42,52 @@ static tune_result_t tune_xx_subdev_and_dxc(      subdev_freq_proxy = target_inter_freq;      double actual_inter_freq = subdev_freq_proxy.as<double>(); -    // Calculate the DDC setting that will downconvert the baseband from the -    // daughterboard to our target frequency. -    double delta_freq = target_freq - actual_inter_freq; -    int delta_sign = std::signum(delta_freq); -    delta_freq *= delta_sign; -    delta_freq = std::fmod(delta_freq, dxc_sample_rate); -    bool inverted = delta_freq > dxc_sample_rate/2.0; -    double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); -    target_dxc_freq *= delta_sign; - -    // If the spectrum is inverted, and the daughterboard doesn't do -    // quadrature downconversion, we can fix the inversion by flipping the -    // sign of the dxc_freq...  (This only happens using the basic_rx board) -    if (subdev_spectrum_inverted){ -        inverted = not inverted; -    } -    if (inverted and not subdev_quadrature){ -        target_dxc_freq *= -1.0; -        inverted = not inverted; -    } -    // down conversion versus up conversion, fight! -    // your mother is ugly and your going down... -    target_dxc_freq *= (is_tx)? -1.0 : +1.0; +    //perform the correction correction for dxc rates outside of nyquist +    double delta_freq = std::fmod(target_freq - actual_inter_freq, dxc_sample_rate); +    bool outside_of_nyquist = std::abs(delta_freq) > dxc_sample_rate/2.0; +    double target_dxc_freq = (outside_of_nyquist)? +        boost::math::sign(delta_freq)*dxc_sample_rate - delta_freq : -delta_freq; + +    //invert the sign on the dxc freq given the following conditions +    if (unit == dboard_iface::UNIT_TX) target_dxc_freq *= -1.0;      dxc_freq_proxy = target_dxc_freq;      double actual_dxc_freq = dxc_freq_proxy.as<double>(); -    //return some kind of tune result tuple/struct +    //load and return the tune result      tune_result_t tune_result;      tune_result.target_inter_freq = target_inter_freq;      tune_result.actual_inter_freq = actual_inter_freq;      tune_result.target_dsp_freq = target_dxc_freq;      tune_result.actual_dsp_freq = actual_dxc_freq; -    tune_result.spectrum_inverted = inverted;      return tune_result;  } +static double derive_freq_from_xx_subdev_and_dxc( +    dboard_iface::unit_t unit, +    wax::obj subdev, wax::obj dxc +){ +    //extract actual dsp and IF frequencies +    double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>(); +    double actual_dxc_freq = dxc[DSP_PROP_FREQ_SHIFT].as<double>(); + +    //invert the sign on the dxc freq given the following conditions +    if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0; + +    return actual_inter_freq - actual_dxc_freq; +} +  /***********************************************************************   * RX Tune   **********************************************************************/ -tune_result_t uhd::usrp::tune_rx_subdev_and_ddc( +tune_result_t usrp::tune_rx_subdev_and_dsp(      wax::obj subdev, wax::obj ddc,      double target_freq, double lo_offset  ){ -    bool is_tx = false; -    return tune_xx_subdev_and_dxc(is_tx, subdev, ddc, target_freq, lo_offset); +    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, target_freq, lo_offset);  } -tune_result_t uhd::usrp::tune_rx_subdev_and_ddc( +tune_result_t usrp::tune_rx_subdev_and_dsp(      wax::obj subdev, wax::obj ddc,      double target_freq  ){ @@ -100,21 +96,24 @@ tune_result_t uhd::usrp::tune_rx_subdev_and_ddc(      if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){          lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as<double>();      } -    return tune_rx_subdev_and_ddc(subdev, ddc, target_freq, lo_offset); +    return tune_rx_subdev_and_dsp(subdev, ddc, target_freq, lo_offset); +} + +double usrp::derive_freq_from_rx_subdev_and_dsp(wax::obj subdev, wax::obj ddc){ +    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc);  }  /***********************************************************************   * TX Tune   **********************************************************************/ -tune_result_t uhd::usrp::tune_tx_subdev_and_duc( +tune_result_t usrp::tune_tx_subdev_and_dsp(      wax::obj subdev, wax::obj duc,      double target_freq, double lo_offset  ){ -    bool is_tx = true; -    return tune_xx_subdev_and_dxc(is_tx, subdev, duc, target_freq, lo_offset); +    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, target_freq, lo_offset);  } -tune_result_t uhd::usrp::tune_tx_subdev_and_duc( +tune_result_t usrp::tune_tx_subdev_and_dsp(      wax::obj subdev, wax::obj duc,      double target_freq  ){ @@ -123,5 +122,9 @@ tune_result_t uhd::usrp::tune_tx_subdev_and_duc(      if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){          lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as<double>();      } -    return tune_tx_subdev_and_duc(subdev, duc, target_freq, lo_offset); +    return tune_tx_subdev_and_dsp(subdev, duc, target_freq, lo_offset); +} + +double usrp::derive_freq_from_tx_subdev_and_dsp(wax::obj subdev, wax::obj duc){ +    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc);  } diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 99d0b8bdd..796126d07 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index b9be037c0..02227afad 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -86,7 +86,7 @@ public:      void set_rate_rx_dboard_clock(double rate){          assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate"); -        size_t divider = size_t(rate/get_master_clock_rate()); +        size_t divider = size_t(get_master_clock_rate()/rate);          //bypass when the divider ratio is one          _ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0;          //calculate the low and high dividers @@ -118,7 +118,7 @@ public:      void set_rate_tx_dboard_clock(double rate){          assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate"); -        size_t divider = size_t(rate/get_master_clock_rate()); +        size_t divider = size_t(get_master_clock_rate()/rate);          //bypass when the divider ratio is one          _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;          //calculate the low and high dividers diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp new file mode 100644 index 000000000..b9d51abf5 --- /dev/null +++ b/host/lib/usrp/usrp2/codec_impl.cpp @@ -0,0 +1,96 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp2_impl.hpp" +#include <uhd/usrp/codec_props.hpp> +#include <boost/bind.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void usrp2_mboard_impl::codec_init(void){ +    //make proxies +    _rx_codec_proxy = wax_obj_proxy::make( +        boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2), +        boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2) +    ); +    _tx_codec_proxy = wax_obj_proxy::make( +        boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2), +        boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2) +    ); +} + +/*********************************************************************** + * RX Codec Properties + **********************************************************************/ +void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<codec_prop_t>()){ +    case CODEC_PROP_NAME: +        val = std::string("usrp2 adc"); +        return; + +    case CODEC_PROP_OTHERS: +        val = prop_names_t(); +        return; + +    case CODEC_PROP_GAIN_NAMES: +        val = prop_names_t(); //no gain elements to be controlled +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void usrp2_mboard_impl::rx_codec_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} + +/*********************************************************************** + * TX Codec Properties + **********************************************************************/ +void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<codec_prop_t>()){ +    case CODEC_PROP_NAME: +        val = std::string("usrp2 dac - ad9777"); +        return; + +    case CODEC_PROP_OTHERS: +        val = prop_names_t(); +        return; + +    case CODEC_PROP_GAIN_NAMES: +        val = prop_names_t(); //no gain elements to be controlled +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 6f2fb9396..1b9a4bb97 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -37,6 +37,8 @@ public:      usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);      ~usrp2_dboard_iface(void); +    std::string get_mboard_name(void){return "usrp2";} +      void write_aux_dac(unit_t, aux_dac_t, float);      float read_aux_adc(unit_t, aux_adc_t); diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index fa8d1a674..075f22388 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -15,10 +15,10 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp"  #include "../dsp_utils.hpp" +#include "../misc_utils.hpp"  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/dboard_props.hpp>  #include <uhd/utils/assert.hpp> @@ -35,8 +35,8 @@ using namespace uhd::usrp;   **********************************************************************/  void usrp2_mboard_impl::dboard_init(void){      //read the dboard eeprom to extract the dboard ids -    _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); -    _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); +    _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); +    _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));      //create a new dboard interface and manager      _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl); @@ -53,10 +53,6 @@ void usrp2_mboard_impl::dboard_init(void){          boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2),          boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2)      ); - -    //init the subdevs in use (use the first subdevice) -    rx_dboard_set(DBOARD_PROP_USED_SUBDEVS, prop_names_t(1, _dboard_manager->get_rx_subdev_names().at(0))); -    tx_dboard_set(DBOARD_PROP_USED_SUBDEVS, prop_names_t(1, _dboard_manager->get_tx_subdev_names().at(0)));  }  /*********************************************************************** @@ -80,10 +76,6 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_manager->get_rx_subdev_names();          return; -    case DBOARD_PROP_USED_SUBDEVS: -        val = _rx_subdevs_in_use; -        return; -      case DBOARD_PROP_DBOARD_ID:          val = _rx_db_eeprom.id;          return; @@ -92,27 +84,26 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_iface;          return; +    case DBOARD_PROP_CODEC: +        val = _rx_codec_proxy->get_link(); +        return; + +    case DBOARD_PROP_GAIN_GROUP: +        val = make_gain_group( +            _dboard_manager->get_rx_subdev(name), _rx_codec_proxy->get_link() +        ); +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  }  void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){      switch(key.as<dboard_prop_t>()){ -    case DBOARD_PROP_USED_SUBDEVS:{ -            _rx_subdevs_in_use = val.as<prop_names_t>(); -            UHD_ASSERT_THROW(_rx_subdevs_in_use.size() == 1); -            wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0)); -            std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl; -            _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word( -                rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>(), -                rx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>() -            )); -        } -        return;      case DBOARD_PROP_DBOARD_ID:          _rx_db_eeprom.id = val.as<dboard_id_t>(); -        _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes()); +        _iface->write_eeprom(USRP2_I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());          return;      default: UHD_THROW_PROP_SET_ERROR(); @@ -140,10 +131,6 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_manager->get_tx_subdev_names();          return; -    case DBOARD_PROP_USED_SUBDEVS: -        val = _tx_subdevs_in_use; -        return; -      case DBOARD_PROP_DBOARD_ID:          val = _tx_db_eeprom.id;          return; @@ -152,26 +139,26 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){          val = _dboard_iface;          return; +    case DBOARD_PROP_CODEC: +        val = _tx_codec_proxy->get_link(); +        return; + +    case DBOARD_PROP_GAIN_GROUP: +        val = make_gain_group( +            _dboard_manager->get_tx_subdev(name), _tx_codec_proxy->get_link() +        ); +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  }  void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){      switch(key.as<dboard_prop_t>()){ -    case DBOARD_PROP_USED_SUBDEVS:{ -            _tx_subdevs_in_use = val.as<prop_names_t>(); -            UHD_ASSERT_THROW(_tx_subdevs_in_use.size() == 1); -            wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0)); -            std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl; -            _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word( -                tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>() -            )); -        } -        return;      case DBOARD_PROP_DBOARD_ID:          _tx_db_eeprom.id = val.as<dboard_id_t>(); -        _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes()); +        _iface->write_eeprom(USRP2_I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());          return;      default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index fd728e393..a781c1a21 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -32,9 +32,9 @@ extern "C" {      #define __stdint(type) type  #endif -//defines the protocol version in this shared header -//increment this value when the protocol is changed -#define USRP2_PROTO_VERSION 5 +//fpga and firmware compatibility numbers +#define USRP2_FPGA_COMPAT_NUM 1 +#define USRP2_FW_COMPAT_NUM 5  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 @@ -44,6 +44,22 @@ extern "C" {  #define USRP2_UDP_CTRL_PORT 49152  #define USRP2_UDP_DATA_PORT 49153 +//////////////////////////////////////////////////////////////////////// +// I2C addresses +//////////////////////////////////////////////////////////////////////// +#define USRP2_I2C_DEV_EEPROM  0x50 // 24LC02[45]:  7-bits 1010xxx +#define	USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0) +#define	USRP2_I2C_ADDR_TX_DB  (USRP2_I2C_DEV_EEPROM | 0x4) +#define	USRP2_I2C_ADDR_RX_DB  (USRP2_I2C_DEV_EEPROM | 0x5) + +//////////////////////////////////////////////////////////////////////// +// EEPROM Layout +//////////////////////////////////////////////////////////////////////// +#define USRP2_EE_MBOARD_REV_LSB  0x00 //1 byte +#define USRP2_EE_MBOARD_REV_MSB  0x01 //1 byte +#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define USRP2_EE_MBOARD_IP_ADDR  0x0C //uint32, big-endian +  typedef enum{      USRP2_CTRL_ID_HUH_WHAT = ' ',      //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 430f28390..9e29edd82 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -32,6 +32,8 @@ using namespace uhd::usrp;  using namespace uhd::transport;  namespace asio = boost::asio; +static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; +  /***********************************************************************   * io impl details (internal to this file)   * - pirate crew @@ -44,7 +46,8 @@ struct usrp2_impl::io_impl{      io_impl(size_t num_frames, size_t width):          packet_handler_recv_state(width), -        recv_pirate_booty(alignment_buffer_type::make(num_frames, width)) +        recv_pirate_booty(alignment_buffer_type::make(num_frames, width)), +        async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))      {          /* NOP */      } @@ -55,9 +58,9 @@ struct usrp2_impl::io_impl{          recv_pirate_crew.join_all();      } -    bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ +    bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, size_t timeout_ms){          boost::this_thread::disable_interruption di; //disable because the wait can throw -        return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); +        return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(timeout_ms));      }      //state management for the vrt packet handler code @@ -69,6 +72,7 @@ struct usrp2_impl::io_impl{      boost::thread_group recv_pirate_crew;      bool recv_pirate_crew_raiding;      alignment_buffer_type::sptr recv_pirate_booty; +    bounded_buffer<async_metadata_t>::sptr async_msg_fifo;  };  /*********************************************************************** @@ -93,12 +97,31 @@ void usrp2_impl::io_impl::recv_pirate_loop(              //extract the vrt header packet info              vrt::if_packet_info_t if_packet_info;              if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); -            vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info); +            const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>(); +            vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info); + +            //handle a tx async report message +            if (if_packet_info.sid == 1 and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + +                //fill in the async metadata +                async_metadata_t metadata; +                metadata.channel = index; +                metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; +                metadata.time_spec = time_spec_t( +                    time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq() +                ); +                metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info); + +                //print the famous U, and push the metadata into the message queue +                if (metadata.event_code & underflow_flags) std::cerr << "U"; +                async_msg_fifo->push_with_pop_on_full(metadata); +                continue; +            }              //handle the packet count / sequence number              if (if_packet_info.packet_count != next_packet_seq){                  //std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16; -                std::cerr << "O"; //report overrun (drops in the kernel) +                std::cerr << "O"; //report overflow (drops in the kernel)              }              next_packet_seq = (if_packet_info.packet_count+1)%16; @@ -121,11 +144,13 @@ void usrp2_impl::io_impl::recv_pirate_loop(   **********************************************************************/  void usrp2_impl::io_init(void){      //send a small data packet so the usrp2 knows the udp source port -    for(size_t i = 0; i < _data_transports.size(); i++){ -        managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff(); -        boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); -        memcpy(send_buff->cast<void*>(), &data, sizeof(data)); +    BOOST_FOREACH(zero_copy_if::sptr data_transport, _data_transports){ +        managed_send_buffer::sptr send_buff = data_transport->get_send_buff(); +        static const boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); +        std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));          send_buff->commit(sizeof(data)); +        //drain the recv buffers (may have junk) +        while (data_transport->get_recv_buff().get());      }      //the number of recv frames is the number for the first transport @@ -150,6 +175,18 @@ void usrp2_impl::io_init(void){  }  /*********************************************************************** + * Async Data + **********************************************************************/ +bool usrp2_impl::recv_async_msg( +    async_metadata_t &async_metadata, size_t timeout_ms +){ +    boost::this_thread::disable_interruption di; //disable because the wait can throw +    return _io_impl->async_msg_fifo->pop_with_timed_wait( +        async_metadata, boost::posix_time::milliseconds(timeout_ms) +    ); +} + +/***********************************************************************   * Send Data   **********************************************************************/  bool get_send_buffs( @@ -164,10 +201,8 @@ bool get_send_buffs(  }  size_t usrp2_impl::send( -    const std::vector<const void *> &buffs, -    size_t num_samps, -    const tx_metadata_t &metadata, -    const io_type_t &io_type, +    const std::vector<const void *> &buffs, size_t num_samps, +    const tx_metadata_t &metadata, const io_type_t &io_type,      send_mode_t send_mode  ){      return vrt_packet_handler::send( @@ -186,11 +221,9 @@ size_t usrp2_impl::send(   * Receive Data   **********************************************************************/  size_t usrp2_impl::recv( -    const std::vector<void *> &buffs, -    size_t num_samps, -    rx_metadata_t &metadata, -    const io_type_t &io_type, -    recv_mode_t recv_mode +    const std::vector<void *> &buffs, size_t num_samps, +    rx_metadata_t &metadata, const io_type_t &io_type, +    recv_mode_t recv_mode, size_t timeout_ms  ){      return vrt_packet_handler::recv(          _io_impl->packet_handler_recv_state,       //last state of the recv handler @@ -199,6 +232,6 @@ size_t usrp2_impl::recv(          io_type, _io_helper.get_rx_otw_type(),     //input and output types to convert          _mboards.front()->get_master_clock_freq(), //master clock tick rate          uhd::transport::vrt::if_hdr_unpack_be, -        boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1) +        boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout_ms)      );  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 7518d3114..610aade14 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -45,8 +45,8 @@ usrp2_mboard_impl::usrp2_mboard_impl(      _iface = usrp2_iface::make(ctrl_transport);      //extract the mboard rev numbers -    _rev_lo = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_LSB, 1).at(0); -    _rev_hi = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_MSB, 1).at(0); +    _rev_lo = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, 1).at(0); +    _rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0);      //contruct the interfaces to mboard perifs      _clock_ctrl = usrp2_clock_ctrl::make(_iface); @@ -67,7 +67,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(          _allowed_decim_and_interp_rates.push_back(i);      } -    //setup the vrt rx registers +    //init the rx control registers      _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet());      _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);      _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset @@ -81,6 +81,12 @@ usrp2_mboard_impl::usrp2_mboard_impl(      _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0);      _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); +    //init the tx control registers +    _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0);    //1 channel +    _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset +    _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, 1);  //sid 1 (different from rx) +    _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); +      //init the ddc      init_ddc_config(); @@ -90,8 +96,20 @@ usrp2_mboard_impl::usrp2_mboard_impl(      //initialize the clock configuration      init_clock_config(); +    //init the codec before the dboard +    codec_init(); +      //init the tx and rx dboards (do last)      dboard_init(); + +    //set default subdev specs +    (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t(); +    (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t(); + +    //Issue a stop streaming command (in case it was left running). +    //Since this command is issued before the networking is setup, +    //most if not all junk packets will never make it to the socket. +    this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);  }  usrp2_mboard_impl::~usrp2_mboard_impl(void){ @@ -174,14 +192,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){      //handle the other props      if (key.type() == typeid(std::string)){          if (key.as<std::string>() == "mac-addr"){ -            byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6); +            byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6);              val = mac_addr_t::from_bytes(bytes).to_string();              return;          }          if (key.as<std::string>() == "ip-addr"){              boost::asio::ip::address_v4::bytes_type bytes; -            std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes); +            std::copy(_iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, 4), bytes);              val = boost::asio::ip::address_v4(bytes).to_string();              return;          } @@ -252,6 +270,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){          }          return; +    case MBOARD_PROP_RX_SUBDEV_SPEC: +        val = _rx_subdev_spec; +        return; + +    case MBOARD_PROP_TX_SUBDEV_SPEC: +        val = _tx_subdev_spec; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -264,14 +290,14 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){      if (key.type() == typeid(std::string)){          if (key.as<std::string>() == "mac-addr"){              byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes(); -            _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes); +            _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, bytes);              return;          }          if (key.as<std::string>() == "ip-addr"){              byte_vector_t bytes(4);              std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes); -            _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes); +            _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, bytes);              return;          }      } @@ -296,6 +322,38 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){          issue_ddc_stream_cmd(val.as<stream_cmd_t>());          return; +    case MBOARD_PROP_RX_SUBDEV_SPEC: +        _rx_subdev_spec = val.as<subdev_spec_t>(); +        //handle automatic +        if (_rx_subdev_spec.empty()) _rx_subdev_spec.push_back( +            subdev_spec_pair_t("", _dboard_manager->get_rx_subdev_names().front()) +        ); +        //sanity check +        UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1); +        uhd::assert_has((*this)[MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>(), _rx_subdev_spec.front().db_name, "rx dboard names"); +        uhd::assert_has(_dboard_manager->get_rx_subdev_names(), _rx_subdev_spec.front().sd_name, "rx subdev names"); +        //set the mux +        _iface->poke32(U2_REG_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>() +        )); +        return; + +    case MBOARD_PROP_TX_SUBDEV_SPEC: +        _tx_subdev_spec = val.as<subdev_spec_t>(); +        //handle automatic +        if (_tx_subdev_spec.empty()) _tx_subdev_spec.push_back( +            subdev_spec_pair_t("", _dboard_manager->get_tx_subdev_names().front()) +        ); +        //sanity check +        UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1); +        uhd::assert_has((*this)[MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>(), _tx_subdev_spec.front().db_name, "tx dboard names"); +        uhd::assert_has(_dboard_manager->get_tx_subdev_names(), _tx_subdev_spec.front().sd_name, "tx subdev names"); +        //set the mux +        _iface->poke32(U2_REG_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>() +        )); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index eaaa722ac..4124221ef 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -15,6 +15,7 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // +#include "usrp2_regs.hpp"  #include "usrp2_iface.hpp"  #include <uhd/utils/assert.hpp>  #include <uhd/types/dict.hpp> @@ -22,12 +23,25 @@  #include <boost/foreach.hpp>  #include <boost/asio.hpp> //used for htonl and ntohl  #include <boost/assign/list_of.hpp> +#include <boost/format.hpp>  #include <stdexcept>  #include <algorithm>  using namespace uhd;  using namespace uhd::transport; +/*! + * FIXME: large timeout, ethernet pause frames... + * + * Use a large timeout to work-around the fact that + * flow-control may throttle outgoing control packets + * due to its use of ethernet pause frames. + * + * This will be fixed when host-based flow control is implemented, + * along with larger incoming send buffers using the on-board SRAM. + */ +static const size_t CONTROL_TIMEOUT_MS = 3000; //3 seconds +  class usrp2_iface_impl : public usrp2_iface{  public:  /*********************************************************************** @@ -35,6 +49,15 @@ public:   **********************************************************************/      usrp2_iface_impl(udp_simple::sptr ctrl_transport){          _ctrl_transport = ctrl_transport; + +         //check the fpga compatibility number +        const boost::uint32_t fpga_compat_num = this->peek32(U2_REG_COMPAT_NUM_RB); +        if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){ +            throw std::runtime_error(str(boost::format( +                "Expected fpga compatibility number %d, but got %d:\n" +                "The fpga build is not compatible with the host code build." +            ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_compat_num)); +        }      }      ~usrp2_iface_impl(void){ @@ -156,7 +179,7 @@ public:          //fill in the seq number and send          usrp2_ctrl_data_t out_copy = out_data; -        out_copy.proto_ver = htonl(USRP2_PROTO_VERSION); +        out_copy.proto_ver = htonl(USRP2_FW_COMPAT_NUM);          out_copy.seq = htonl(++_ctrl_seq_num);          _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); @@ -164,13 +187,12 @@ public:          boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv          const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);          while(true){ -            size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem)); -            if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_PROTO_VERSION){ -                throw std::runtime_error(str( -                    boost::format("Expected protocol version %d, but got %d\n" -                    "The firmware build does not match the host code build." -                    ) % int(USRP2_PROTO_VERSION) % ntohl(ctrl_data_in->proto_ver) -                )); +            size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem), CONTROL_TIMEOUT_MS); +            if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_FW_COMPAT_NUM){ +                throw std::runtime_error(str(boost::format( +                    "Expected protocol compatibility number %d, but got %d:\n" +                    "The firmware build is not compatible with the host code build." +                ) % int(USRP2_FW_COMPAT_NUM) % ntohl(ctrl_data_in->proto_ver)));              }              if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){                  return *ctrl_data_in; diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 9cc32104e..12fd4730a 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -26,22 +26,6 @@  #include <utility>  #include "fw_common.h" -//////////////////////////////////////////////////////////////////////// -// I2C addresses -//////////////////////////////////////////////////////////////////////// -#define I2C_DEV_EEPROM  0x50 // 24LC02[45]:  7-bits 1010xxx -#define	I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) -#define	I2C_ADDR_TX_DB  (I2C_DEV_EEPROM | 0x4) -#define	I2C_ADDR_RX_DB  (I2C_DEV_EEPROM | 0x5) - -//////////////////////////////////////////////////////////////////////// -// EEPROM Layout -//////////////////////////////////////////////////////////////////////// -#define EE_MBOARD_REV_LSB  0x00 //1 byte -#define EE_MBOARD_REV_MSB  0x01 //1 byte -#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes -#define EE_MBOARD_IP_ADDR  0x0C //uint32, big-endian -  /*!   * The usrp2 interface class:   * Provides a set of functions to implementation layer. diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 02f53bc69..21f411afe 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -35,6 +35,9 @@ using namespace uhd::usrp;  using namespace uhd::transport;  namespace asio = boost::asio; +//! wait this long for a control response when discovering devices +static const size_t DISCOVERY_TIMEOUT_MS = 100; +  /***********************************************************************   * Helper Functions   **********************************************************************/ @@ -94,7 +97,7 @@ static uhd::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_PROTO_VERSION); +    ctrl_data_out.proto_ver = htonl(USRP2_FW_COMPAT_NUM);      ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);      udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); @@ -102,7 +105,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){      boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv      const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);      while(true){ -        size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem)); +        size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem), DISCOVERY_TIMEOUT_MS);          //std::cout << len << "\n";          if (len > offsetof(usrp2_ctrl_data_t, data)){              //handle the received data diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ab23830c0..157d17057 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -35,6 +35,7 @@  #include <uhd/transport/udp_simple.hpp> //mtu  #include <uhd/transport/udp_zero_copy.hpp>  #include <uhd/usrp/dboard_manager.hpp> +#include <uhd/usrp/subdev_spec.hpp>  /*!   * Make a usrp2 dboard interface. @@ -143,6 +144,7 @@ private:      //properties for this mboard      void get(const wax::obj &, wax::obj &);      void set(const wax::obj &, const wax::obj &); +    uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;      //interfaces      usrp2_iface::sptr _iface; @@ -161,18 +163,25 @@ private:      void update_clock_config(void);      void set_time_spec(const uhd::time_spec_t &time_spec, bool now); +    //properties interface for the codec +    void codec_init(void); +    void rx_codec_get(const wax::obj &, wax::obj &); +    void rx_codec_set(const wax::obj &, const wax::obj &); +    void tx_codec_get(const wax::obj &, wax::obj &); +    void tx_codec_set(const wax::obj &, const wax::obj &); +    wax_obj_proxy::sptr _rx_codec_proxy; +    wax_obj_proxy::sptr _tx_codec_proxy; +      //properties interface for rx dboard      void rx_dboard_get(const wax::obj &, wax::obj &);      void rx_dboard_set(const wax::obj &, const wax::obj &);      wax_obj_proxy::sptr _rx_dboard_proxy; -    uhd::prop_names_t _rx_subdevs_in_use;      uhd::usrp::dboard_eeprom_t _rx_db_eeprom;      //properties interface for tx dboard      void tx_dboard_get(const wax::obj &, wax::obj &);      void tx_dboard_set(const wax::obj &, const wax::obj &);      wax_obj_proxy::sptr _tx_dboard_proxy; -    uhd::prop_names_t _tx_subdevs_in_use;      uhd::usrp::dboard_eeprom_t _tx_db_eeprom;      //methods and shadows for the ddc dsp @@ -224,8 +233,7 @@ public:      }      size_t send(          const std::vector<const void *> &, size_t, -        const uhd::tx_metadata_t &, -        const uhd::io_type_t &, +        const uhd::tx_metadata_t &, const uhd::io_type_t &,          uhd::device::send_mode_t      );      size_t get_max_recv_samps_per_packet(void) const{ @@ -233,10 +241,10 @@ public:      }      size_t recv(          const std::vector<void *> &, size_t, -        uhd::rx_metadata_t &, -        const uhd::io_type_t &, -        uhd::device::recv_mode_t +        uhd::rx_metadata_t &, const uhd::io_type_t &, +        uhd::device::recv_mode_t, size_t      ); +    bool recv_async_msg(uhd::async_metadata_t &, size_t);  private:      //device properties interface diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 1a5864c85..9d306090b 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -107,6 +107,7 @@  #define U2_REG_TIME64_SECS_RB  (0xCC00 + 4*10)  #define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11) +#define U2_REG_COMPAT_NUM_RB   (0xCC00 + 4*12)  //pps flags (see above)  #define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) @@ -226,7 +227,7 @@  #define U2_REG_ATR_FULL_RXSIDE  U2_REG_ATR_BASE + 14  /////////////////////////////////////////////////// -// VITA RX CTRL regs +// RX CTRL regs  ///////////////////////////////////////////////////  // The following 3 are logically a single command register.  // They are clocked into the underlying fifo when time_ticks is written. @@ -241,4 +242,16 @@  #define U2_REG_RX_CTRL_NSAMPS_PER_PKT    _SR_ADDR(SR_RX_CTRL + 7)  #define U2_REG_RX_CTRL_NCHANNELS         _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources +/////////////////////////////////////////////////// +// TX CTRL regs +/////////////////////////////////////////////////// +#define U2_REG_TX_CTRL_NUM_CHAN          _SR_ADDR(SR_TX_CTRL + 0) +#define U2_REG_TX_CTRL_CLEAR_STATE       _SR_ADDR(SR_TX_CTRL + 1) +#define U2_REG_TX_CTRL_REPORT_SID        _SR_ADDR(SR_TX_CTRL + 2) +#define U2_REG_TX_CTRL_POLICY            _SR_ADDR(SR_TX_CTRL + 3) + +#define U2_FLAG_TX_CTRL_POLICY_WAIT          (0x1 << 0) +#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET   (0x1 << 1) +#define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST    (0x1 << 2) +  #endif /* INCLUDED_USRP2_REGS_HPP */ diff --git a/host/lib/usrp/usrp_e/CMakeLists.txt b/host/lib/usrp/usrp_e/CMakeLists.txt index db6d162d4..1d64d29d2 100644 --- a/host/lib/usrp/usrp_e/CMakeLists.txt +++ b/host/lib/usrp/usrp_e/CMakeLists.txt @@ -18,27 +18,14 @@  #This file will be included by cmake, use absolute paths!  ######################################################################## -# Helpful macro to check for required headers -######################################################################## -INCLUDE(CheckIncludeFileCXX) -SET(HAVE_USRP_E_REQUIRED_HEADERS TRUE) -MACRO(USRP_E_REQUIRE_HEADER header variable) -    CHECK_INCLUDE_FILE_CXX(${header} ${variable}) -    IF(NOT ${variable}) -        SET(HAVE_USRP_E_REQUIRED_HEADERS FALSE) -    ENDIF(NOT ${variable}) -ENDMACRO(USRP_E_REQUIRE_HEADER) - -########################################################################  # Conditionally configure the USRP-E support  ########################################################################  MESSAGE(STATUS "Configuring usrp-e support...") -USRP_E_REQUIRE_HEADER(linux/ioctl.h      HAVE_LINUX_IOCTL_H) -USRP_E_REQUIRE_HEADER(linux/spi/spidev.h HAVE_LINUX_SPI_SPIDEV_H) -USRP_E_REQUIRE_HEADER(linux/usrp_e.h     HAVE_LINUX_USRP_E_H) +INCLUDE(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(linux/usrp_e.h HAVE_LINUX_USRP_E_H) -IF(HAVE_USRP_E_REQUIRED_HEADERS) +IF(HAVE_LINUX_USRP_E_H)      MESSAGE(STATUS "  Building usrp-e support.")      LIBUHD_APPEND_SOURCES(          ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/clock_ctrl.cpp @@ -57,6 +44,6 @@ IF(HAVE_USRP_E_REQUIRED_HEADERS)          ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_iface.hpp          ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_regs.hpp      ) -ELSE(HAVE_USRP_E_REQUIRED_HEADERS) +ELSE(HAVE_LINUX_USRP_E_H)      MESSAGE(STATUS "  Skipping usrp-e support.") -ENDIF(HAVE_USRP_E_REQUIRED_HEADERS) +ENDIF(HAVE_LINUX_USRP_E_H) diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt new file mode 100644 index 000000000..68945545a --- /dev/null +++ b/host/lib/utils/CMakeLists.txt @@ -0,0 +1,87 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +#This file will be included by cmake, use absolute paths! + +######################################################################## +# Setup defines for process scheduling +######################################################################## +MESSAGE(STATUS "Configuring priority scheduling...") + +INCLUDE(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES(" +    #include <pthread.h> +    int main(){ +        struct sched_param sp; +        pthread_setschedparam(pthread_self(), SCHED_RR, &sp); +        return 0; +    } +    " HAVE_PTHREAD_SETSCHEDPARAM +) + +CHECK_CXX_SOURCE_COMPILES(" +    #include <windows.h> +    int main(){ +        SetThreadPriority(GetCurrentThread(), 0); +        SetPriorityClass(GetCurrentProcess(), 0); +        return 0; +    } +    " HAVE_WIN_SETTHREADPRIORITY +) + +IF(HAVE_PTHREAD_SETSCHEDPARAM) +    MESSAGE(STATUS "  Priority scheduling supported through pthread_setschedparam.") +    ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM) +ELSEIF(HAVE_WIN_SETTHREADPRIORITY) +    MESSAGE(STATUS "  Priority scheduling supported through windows SetThreadPriority.") +    ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY) +ELSE(HAVE_PTHREAD_SETSCHEDPARAM) +    MESSAGE(STATUS "  Priority scheduling not supported.") +ENDIF(HAVE_PTHREAD_SETSCHEDPARAM) + +######################################################################## +# Setup defines for module loading +######################################################################## +MESSAGE(STATUS "Configuring module loading...") + +INCLUDE(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H) +CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H) + +IF(HAVE_DLFCN_H) +    MESSAGE(STATUS "  Module loading supported through dlopen.") +    ADD_DEFINITIONS(-DHAVE_DLFCN_H) +    LIBUHD_APPEND_LIBS(${CMAKE_DL_LIBS}) +ELSEIF(HAVE_WINDOWS_H) +    MESSAGE(STATUS "  Module loading supported through LoadLibrary.") +    ADD_DEFINITIONS(-DHAVE_WINDOWS_H) +ELSE(HAVE_DLFCN_H) +    MESSAGE(STATUS "  Module loading not supported.") +ENDIF(HAVE_DLFCN_H) + +######################################################################## +# Append sources +######################################################################## +LIBUHD_APPEND_SOURCES( +    ${CMAKE_SOURCE_DIR}/lib/utils/assert.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/gain_group.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/load_modules.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/paths.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/props.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/thread_priority.cpp +    ${CMAKE_SOURCE_DIR}/lib/utils/warning.cpp +) diff --git a/host/lib/utils/assert.cpp b/host/lib/utils/assert.cpp new file mode 100644 index 000000000..7ace9024c --- /dev/null +++ b/host/lib/utils/assert.cpp @@ -0,0 +1,24 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/assert.hpp> + +using namespace uhd; + +assert_error::assert_error(const std::string &what) : std::runtime_error(what){ +    /* NOP */ +} diff --git a/host/lib/utils/gain_group.cpp b/host/lib/utils/gain_group.cpp new file mode 100644 index 000000000..c113719c8 --- /dev/null +++ b/host/lib/utils/gain_group.cpp @@ -0,0 +1,149 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/gain_group.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <algorithm> +#include <vector> +#include <iostream> + +using namespace uhd; + +static const bool verbose = false; + +static bool compare_by_step_size( +    const size_t &rhs, const size_t &lhs, std::vector<gain_fcns_t> &fcns +){ +    return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step; +} + +/*********************************************************************** + * gain group implementation + **********************************************************************/ +class gain_group_impl : public gain_group{ +public: +    gain_group_impl(void){ +        /*NOP*/ +    } + +    gain_range_t get_range(void){ +        float overall_min = 0, overall_max = 0, overall_step = 0; +        BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ +            const gain_range_t range = fcns.get_range(); +            overall_min += range.min; +            overall_max += range.max; +            //the overall step is the min (zero is invalid, first run) +            if (overall_step == 0) overall_step = range.step; +            overall_step = std::min(overall_step, range.step); +        } +        return gain_range_t(overall_min, overall_max, overall_step); +    } + +    float get_value(void){ +        float overall_gain = 0; +        BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ +            overall_gain += fcns.get_value(); +        } +        return overall_gain; +    } + +    void set_value(float gain){ +        std::vector<gain_fcns_t> all_fcns = get_all_fcns(); +        if (all_fcns.size() == 0) return; //nothing to set! + +        //get the max step size among the gains +        float max_step = 0; +        BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ +            max_step = std::max(max_step, fcns.get_range().step); +        } + +        //create gain bucket to distribute power +        std::vector<float> gain_bucket; + +        //distribute power according to priority (round to max step) +        float gain_left_to_distribute = gain; +        BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ +            const gain_range_t range = fcns.get_range(); +            gain_bucket.push_back( +                max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step) +            ); +            gain_left_to_distribute -= gain_bucket.back(); +        } + +        //get a list of indexes sorted by step size large to small +        std::vector<size_t> indexes_step_size_dec; +        for (size_t i = 0; i < all_fcns.size(); i++){ +            indexes_step_size_dec.push_back(i); +        } +        std::sort( +            indexes_step_size_dec.begin(), indexes_step_size_dec.end(), +            boost::bind(&compare_by_step_size, _1, _2, all_fcns) +        ); +        UHD_ASSERT_THROW( +            all_fcns.at(indexes_step_size_dec.front()).get_range().step >= +            all_fcns.at(indexes_step_size_dec.back()).get_range().step +        ); + +        //distribute the remainder (less than max step) +        //fill in the largest step sizes first that are less than the remainder +        BOOST_FOREACH(size_t i, indexes_step_size_dec){ +            const gain_range_t range = all_fcns.at(i).get_range(); +            float additional_gain = range.step*int( +                std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max +            )/range.step) - gain_bucket.at(i); +            gain_bucket.at(i) += additional_gain; +            gain_left_to_distribute -= additional_gain; +        } +        if (verbose) std::cout << "gain_left_to_distribute " << gain_left_to_distribute << std::endl; + +        //now write the bucket out to the individual gain values +        for (size_t i = 0; i < gain_bucket.size(); i++){ +            if (verbose) std::cout << gain_bucket.at(i) << std::endl; +            all_fcns.at(i).set_value(gain_bucket.at(i)); +        } +    } + +    void register_fcns( +        const gain_fcns_t &gain_fcns, size_t priority +    ){ +        _registry[priority].push_back(gain_fcns); +    } + +private: +    //! get the gain function sets in order (highest priority first) +    std::vector<gain_fcns_t> get_all_fcns(void){ +        std::vector<gain_fcns_t> all_fcns; +        BOOST_FOREACH(size_t key, std::sorted(_registry.keys())){ +            const std::vector<gain_fcns_t> &fcns = _registry[key]; +            all_fcns.insert(all_fcns.begin(), fcns.begin(), fcns.end()); +        } +        return all_fcns; +    } + +    uhd::dict<size_t, std::vector<gain_fcns_t> > _registry; +}; + +/*********************************************************************** + * gain group factory function + **********************************************************************/ +gain_group::sptr gain_group::make(void){ +    return sptr(new gain_group_impl()); +} diff --git a/host/lib/load_modules.cpp b/host/lib/utils/load_modules.cpp index dbb8d0695..623d31eb6 100644 --- a/host/lib/load_modules.cpp +++ b/host/lib/utils/load_modules.cpp @@ -18,13 +18,12 @@  #include <uhd/utils/static.hpp>  #include <boost/format.hpp>  #include <boost/foreach.hpp> -#include <boost/algorithm/string.hpp>  #include <boost/filesystem.hpp> -#include <boost/program_options.hpp>  #include <iostream>  #include <stdexcept> +#include <string> +#include <vector> -namespace po = boost::program_options;  namespace fs = boost::filesystem;  /*********************************************************************** @@ -32,7 +31,6 @@ namespace fs = boost::filesystem;   **********************************************************************/  #if defined(HAVE_DLFCN_H)  #include <dlfcn.h> -static const std::string env_path_sep = ":";  static void load_module(const std::string &file_name){      if (dlopen(file_name.c_str(), RTLD_LAZY) == NULL){ @@ -44,7 +42,6 @@ static void load_module(const std::string &file_name){  #elif defined(HAVE_WINDOWS_H)  #include <windows.h> -static const std::string env_path_sep = ";";  static void load_module(const std::string &file_name){      if (LoadLibrary(file_name.c_str()) == NULL){ @@ -55,7 +52,6 @@ static void load_module(const std::string &file_name){  }  #else -static const std::string env_path_sep = ":";  static void load_module(const std::string &file_name){      throw std::runtime_error(str( @@ -74,9 +70,9 @@ static void load_module(const std::string &file_name){   * Does not throw, prints to std error.   * \param path the filesystem path   */ -static void load_path(const fs::path &path){ +static void load_module_path(const fs::path &path){      if (not fs::exists(path)){ -        std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl; +        //std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl;          return;      } @@ -87,7 +83,7 @@ static void load_path(const fs::path &path){              dir_itr != fs::directory_iterator();              ++dir_itr          ){ -            load_path(dir_itr->path()); +            load_module_path(dir_itr->path());          }          return;      } @@ -101,46 +97,13 @@ static void load_path(const fs::path &path){      }  } -//! The string constant for the module path environment variable -static const std::string MODULE_PATH_KEY = "UHD_MODULE_PATH"; +std::vector<fs::path> get_module_paths(void); //defined in paths.cpp  /*! - * Name mapper function for the environment variable parser. - * Map environment variable names (that we use) to option names. - * \param the variable name - * \return the option name or blank string - */ -static std::string name_mapper(const std::string &var_name){ -    if (var_name == MODULE_PATH_KEY) return var_name; -    return ""; -} - -/*! - * Load all the modules given by the module path enviroment variable. - * The path variable may be several paths split by path separators. + * Load all the modules given in the module paths.   */  UHD_STATIC_BLOCK(load_modules){ -    //register the options -    std::string env_module_path; -    po::options_description desc("UHD Module Options"); -    desc.add_options() -        (MODULE_PATH_KEY.c_str(), po::value<std::string>(&env_module_path)->default_value("")) -    ; - -    //parse environment variables -    po::variables_map vm; -    po::store(po::parse_environment(desc, &name_mapper), vm); -    po::notify(vm); - -    if (env_module_path == "") return; -    //std::cout << "env_module_path: " << env_module_path << std::endl; - -    //split the path at the path separators -    std::vector<std::string> module_paths; -    boost::split(module_paths, env_module_path, boost::is_any_of(env_path_sep)); - -    //load modules in each path -    BOOST_FOREACH(const std::string &module_path, module_paths){ -        load_path(fs::system_complete(fs::path(module_path))); +    BOOST_FOREACH(const fs::path &path, get_module_paths()){ +        load_module_path(path);      }  } diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp new file mode 100644 index 000000000..0805a44fe --- /dev/null +++ b/host/lib/utils/paths.cpp @@ -0,0 +1,103 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "constants.hpp" +#include <uhd/config.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/program_options.hpp> +#include <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <stdexcept> +#include <string> +#include <vector> + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + +/*********************************************************************** + * Determine the paths separator + **********************************************************************/ +#ifdef UHD_PLATFORM_WIN32 +    static const std::string env_path_sep = ";"; +#else +    static const std::string env_path_sep = ":"; +#endif /*UHD_PLATFORM_WIN32*/ + +/*********************************************************************** + * Get a list of paths for an environment variable + **********************************************************************/ +static std::string name_mapper(const std::string &key, const std::string &var_name){ +    return (var_name == key)? var_name : ""; +} + +static std::vector<fs::path> get_env_paths(const std::string &var_name){ +    //register the options +    std::string var_value; +    po::options_description desc; +    desc.add_options() +        (var_name.c_str(), po::value<std::string>(&var_value)->default_value("")) +    ; + +    //parse environment variables +    po::variables_map vm; +    po::store(po::parse_environment(desc, boost::bind(&name_mapper, var_name, _1)), vm); +    po::notify(vm); + +    //split the path at the path separators +    std::vector<std::string> path_strings; +    boost::split(path_strings, var_value, boost::is_any_of(env_path_sep)); + +    //convert to filesystem path, filter blank paths +    std::vector<fs::path> paths; +    BOOST_FOREACH(std::string &path_string, path_strings){ +        if (path_string.size() == 0) continue; +        paths.push_back(fs::system_complete(path_string)); +    } +    return paths; +} + +/*********************************************************************** + * Get a list of special purpose paths + **********************************************************************/ +static const fs::path pkg_data_path = fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR; + +std::vector<fs::path> get_image_paths(void){ +    std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH"); +    paths.push_back(pkg_data_path / "images"); +    return paths; +} + +std::vector<fs::path> get_module_paths(void){ +    std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH"); +    paths.push_back(pkg_data_path / "modules"); +    return paths; +} + +/*********************************************************************** + * Find a image in the image paths + **********************************************************************/ +std::string find_image_path(const std::string &image_name){ +    if (fs::exists(image_name)){ +        return fs::system_complete(image_name).file_string(); +    } +    BOOST_FOREACH(const fs::path &path, get_image_paths()){ +        fs::path image_path = path / image_name; +        if (fs::exists(image_path)) return image_path.file_string(); +    } +    throw std::runtime_error("Could not find path for image: " + image_name); +} diff --git a/host/lib/utils.cpp b/host/lib/utils/props.cpp index d2f4dfc6e..fac5fe24f 100644 --- a/host/lib/utils.cpp +++ b/host/lib/utils/props.cpp @@ -15,28 +15,18 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <uhd/utils/assert.hpp>  #include <uhd/utils/props.hpp> -#include <stdexcept>  using namespace uhd; -/*********************************************************************** - * Assert - **********************************************************************/ -assert_error::assert_error(const std::string &what) : std::runtime_error(what){ -    /* NOP */ -} - -/*********************************************************************** - * Props - **********************************************************************/  named_prop_t::named_prop_t( -    const wax::obj &key_, -    const std::string &name_ -){ -    key = key_; -    name = name_; +    const wax::obj &key, +    const std::string &name +): +    key(key), +    name(name) +{ +    /* NOP */  }  typedef boost::tuple<wax::obj, std::string> named_prop_tuple; diff --git a/host/lib/thread_priority.cpp b/host/lib/utils/thread_priority.cpp index c35e5fcb1..c35e5fcb1 100644 --- a/host/lib/thread_priority.cpp +++ b/host/lib/utils/thread_priority.cpp diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp new file mode 100644 index 000000000..ae4d4c7aa --- /dev/null +++ b/host/lib/utils/warning.cpp @@ -0,0 +1,36 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/warning.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <iostream> +#include <vector> + +using namespace uhd; + +void uhd::print_warning(const std::string &msg){ +    //extract the message lines +    std::vector<std::string> lines; +    boost::split(lines, msg, boost::is_any_of("\n")); + +    //print the warning message +    std::cerr << std::endl << "Warning:" << std::endl; +    BOOST_FOREACH(const std::string &line, lines){ +        std::cerr << "    " << line << std::endl; +    } +} diff --git a/host/lib/version.cpp b/host/lib/version.cpp new file mode 100644 index 000000000..5edbca09b --- /dev/null +++ b/host/lib/version.cpp @@ -0,0 +1,23 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "constants.hpp" +#include <uhd/version.hpp> + +std::string uhd::get_version_string(void){ +    return UHD_VERSION_STRING; +} diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt index 74f3376e6..c620fd641 100644 --- a/host/test/CMakeLists.txt +++ b/host/test/CMakeLists.txt @@ -26,8 +26,11 @@ ADD_EXECUTABLE(main_test      convert_types_test.cpp      dict_test.cpp      error_test.cpp -    gain_handler_test.cpp +    gain_group_test.cpp +    subdev_spec_test.cpp +    tune_helper_test.cpp      vrt_test.cpp +    warning_test.cpp      wax_test.cpp  )  TARGET_LINK_LIBRARIES(main_test uhd) diff --git a/host/test/addr_test.cpp b/host/test/addr_test.cpp index 0c50200d6..d4b45aa1a 100644 --- a/host/test/addr_test.cpp +++ b/host/test/addr_test.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(test_device_addr){      uhd::device_addr_t new_dev_addr(args_str);      //they should be the same size -    BOOST_CHECK_EQUAL(dev_addr.size(), new_dev_addr.size()); +    BOOST_REQUIRE_EQUAL(dev_addr.size(), new_dev_addr.size());      //the keys should match      std::vector<std::string> old_dev_addr_keys = dev_addr.keys(); diff --git a/host/test/gain_group_test.cpp b/host/test/gain_group_test.cpp new file mode 100644 index 000000000..6a6af8eb2 --- /dev/null +++ b/host/test/gain_group_test.cpp @@ -0,0 +1,122 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/test/unit_test.hpp> +#include <uhd/utils/gain_group.hpp> +#include <boost/bind.hpp> +#include <boost/math/special_functions/round.hpp> +#include <iostream> + +#define rint(x) boost::math::iround(x) + +using namespace uhd; + +/*********************************************************************** + * Define gain element classes with needed functions + **********************************************************************/ +class gain_element1{ +public: + +    gain_range_t get_range(void){ +        return gain_range_t(0, 90, 1); +    } + +    float get_value(void){ +        return _gain; +    } + +    void set_value(float gain){ +        float step = get_range().step; +        _gain = step*rint(gain/step); +    } + +private: +    float _gain; +}; + +class gain_element2{ +public: + +    gain_range_t get_range(void){ +        return gain_range_t(-20, 10, 0.1); +    } + +    float get_value(void){ +        return _gain; +    } + +    void set_value(float gain){ +        float step = get_range().step; +        _gain = step*rint(gain/step); +    } + +private: +    float _gain; +}; + +//create static instances of gain elements to be shared by the tests +static gain_element1 g1; +static gain_element2 g2; + +static gain_group::sptr get_gain_group(size_t pri1 = 0, size_t pri2 = 0){ +    //create instance of gain group +    gain_fcns_t gain_fcns; +    gain_group::sptr gg(gain_group::make()); + +    //load gain group with function sets +    gain_fcns.get_range = boost::bind(&gain_element1::get_range, &g1); +    gain_fcns.get_value = boost::bind(&gain_element1::get_value, &g1); +    gain_fcns.set_value = boost::bind(&gain_element1::set_value, &g1, _1); +    gg->register_fcns(gain_fcns, pri1); + +    gain_fcns.get_range = boost::bind(&gain_element2::get_range, &g2); +    gain_fcns.get_value = boost::bind(&gain_element2::get_value, &g2); +    gain_fcns.set_value = boost::bind(&gain_element2::set_value, &g2, _1); +    gg->register_fcns(gain_fcns, pri2); + +    return gg; +} + +/*********************************************************************** + * Test cases + **********************************************************************/ +static const double tolerance = 0.001; + +BOOST_AUTO_TEST_CASE(test_gain_group_overall){ +    gain_group::sptr gg = get_gain_group(); + +    //test the overall stuff +    gg->set_value(80); +    BOOST_CHECK_CLOSE(gg->get_value(), float(80), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().min, float(-20), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().max, float(100), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().step, float(0.1), tolerance); +} + +BOOST_AUTO_TEST_CASE(test_gain_group_priority){ +    gain_group::sptr gg = get_gain_group(0, 1); + +    //test the overall stuff +    gg->set_value(80); +    BOOST_CHECK_CLOSE(gg->get_value(), float(80), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().min, float(-20), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().max, float(100), tolerance); +    BOOST_CHECK_CLOSE(gg->get_range().step, float(0.1), tolerance); + +    //test the the higher priority gain got filled first (gain 2) +    BOOST_CHECK_CLOSE(g2.get_value(), g2.get_range().max, tolerance); +} diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp deleted file mode 100644 index 5a9f2b714..000000000 --- a/host/test/gain_handler_test.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include <boost/test/unit_test.hpp> -#include <uhd/utils/gain_handler.hpp> -#include <uhd/types/ranges.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/utils/props.hpp> -#include <boost/bind.hpp> -#include <iostream> - -using namespace uhd; - -enum prop_t{ -    PROP_GAIN_VALUE, -    PROP_GAIN_RANGE, -    PROP_GAIN_NAMES -}; - -class gainful_obj : public wax::obj{ -public: -    gainful_obj(void){ -        //initialize gain props struct -        gain_handler::props_t gain_props; -        gain_props.value = PROP_GAIN_VALUE; -        gain_props.range = PROP_GAIN_RANGE; -        gain_props.names = PROP_GAIN_NAMES; -        //make a new gain handler -        _gain_handler = gain_handler::make( -            this->get_link(), gain_props, -            boost::bind(&gain_handler::is_equal<prop_t>, _1, _2) -        ); -        _gain_values["g0"] = 0; -        _gain_values["g1"] = 0; -        _gain_ranges["g0"] = gain_range_t(-10, 0, float(.1)); -        _gain_ranges["g1"] = gain_range_t(0, 100, float(1.5)); -    } - -    ~gainful_obj(void){} - -private: -    void get(const wax::obj &key_, wax::obj &val){ -        if (_gain_handler->intercept_get(key_, val)) return; - -        wax::obj key; std::string name; -        boost::tie(key, name) = extract_named_prop(key_); - -        //handle the get request conditioned on the key -        switch(key.as<prop_t>()){ -        case PROP_GAIN_VALUE: -            val = _gain_values[name]; -            return; - -        case PROP_GAIN_RANGE: -            val = _gain_ranges[name]; -            return; - -        case PROP_GAIN_NAMES: -            val = _gain_values.keys(); -            return; - -        default: UHD_THROW_PROP_GET_ERROR(); -        } -    } - -    void set(const wax::obj &key_, const wax::obj &val){ -        if (_gain_handler->intercept_set(key_, val)) return; - -        wax::obj key; std::string name; -        boost::tie(key, name) = extract_named_prop(key_); - -        //handle the get request conditioned on the key -        switch(key.as<prop_t>()){ -        case PROP_GAIN_VALUE: -            _gain_values[name] = val.as<float>(); -            return; - -        default: UHD_THROW_PROP_SET_ERROR(); -        } -    } - -    gain_handler::sptr _gain_handler; -    uhd::dict<std::string, float> _gain_values; -    uhd::dict<std::string, gain_range_t> _gain_ranges; - -}; - -BOOST_AUTO_TEST_CASE(test_gain_handler){ -    std::cout << "Testing the gain handler..." << std::endl; -    gainful_obj go0; - -    BOOST_CHECK_THROW( -        go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as<float>(), -        std::exception -    ); - -    std::cout << "verifying the overall min, max, step" << std::endl; -    gain_range_t gain = go0[PROP_GAIN_RANGE].as<gain_range_t>(); -    BOOST_CHECK_EQUAL(gain.min, float(-10)); -    BOOST_CHECK_EQUAL(gain.max, float(100)); -    BOOST_CHECK_EQUAL(gain.step, float(1.5)); - -    std::cout << "verifying the overall gain" << std::endl; -    go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = float(-5); -    go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = float(30); -    BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as<float>(), float(25)); -} diff --git a/host/test/subdev_spec_test.cpp b/host/test/subdev_spec_test.cpp new file mode 100644 index 000000000..8817d5eee --- /dev/null +++ b/host/test/subdev_spec_test.cpp @@ -0,0 +1,45 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/test/unit_test.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <boost/foreach.hpp> +#include <iostream> + +BOOST_AUTO_TEST_CASE(test_subdevice_spec){ +    std::cout << "Testing subdevice specification..." << std::endl; + +    //load the subdev spec with something +    uhd::usrp::subdev_spec_t sd_spec; +    sd_spec.push_back(uhd::usrp::subdev_spec_pair_t("A", "AB")); +    sd_spec.push_back(uhd::usrp::subdev_spec_pair_t("B", "AB")); + +    //convert to and from args string +    std::cout << "Pretty Print: " << std::endl << sd_spec.to_pp_string(); +    std::string markup_str = sd_spec.to_string(); +    std::cout << "Markup String: " << markup_str << std::endl; +    uhd::usrp::subdev_spec_t new_sd_spec(markup_str); + +    //they should be the same size +    BOOST_REQUIRE_EQUAL(sd_spec.size(), new_sd_spec.size()); + +    //the contents should match +    for (size_t i = 0; i < sd_spec.size(); i++){ +        BOOST_CHECK_EQUAL(sd_spec.at(i).db_name, new_sd_spec.at(i).db_name); +        BOOST_CHECK_EQUAL(sd_spec.at(i).sd_name, new_sd_spec.at(i).sd_name); +    } +} diff --git a/host/test/tune_helper_test.cpp b/host/test/tune_helper_test.cpp new file mode 100644 index 000000000..570f47293 --- /dev/null +++ b/host/test/tune_helper_test.cpp @@ -0,0 +1,174 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/test/unit_test.hpp> +#include <uhd/usrp/tune_helper.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/dsp_props.hpp> +#include <iostream> + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Dummy properties objects + **********************************************************************/ +class dummy_subdev : public wax::obj{ +public: +    dummy_subdev(double resolution): +        _resolution(resolution) +    { +        /* NOP */ +    } +private: +    void get(const wax::obj &key, wax::obj &val){ +        switch(key.as<subdev_prop_t>()){ + +        case SUBDEV_PROP_FREQ: +            val = _freq; +            return; + +        case SUBDEV_PROP_USE_LO_OFFSET: +            val = false; +            return; + +        default: UHD_THROW_PROP_GET_ERROR(); +        } +    } + +    void set(const wax::obj &key, const wax::obj &val){ +        switch(key.as<subdev_prop_t>()){ +        case SUBDEV_PROP_FREQ: +            _freq = _resolution*int(val.as<double>()/_resolution); +            return; + +        default: UHD_THROW_PROP_SET_ERROR(); +        } +    } + +    double _freq, _resolution; +}; + +class dummy_subdev_basic : public wax::obj{ +private: +    void get(const wax::obj &key, wax::obj &val){ +        switch(key.as<subdev_prop_t>()){ + +        case SUBDEV_PROP_FREQ: +            val = double(0.0); //always zero +            return; + +        case SUBDEV_PROP_USE_LO_OFFSET: +            val = false; +            return; + +        default: UHD_THROW_PROP_GET_ERROR(); +        } +    } + +    void set(const wax::obj &key, const wax::obj &){ +        switch(key.as<subdev_prop_t>()){ +        case SUBDEV_PROP_FREQ: +            // do nothing +            return; + +        default: UHD_THROW_PROP_SET_ERROR(); +        } +    } +}; + +class dummy_dsp : public wax::obj{ +public: +    dummy_dsp(double codec_rate): +        _codec_rate(codec_rate) +    { +        /* NOP */ +    } +private: +    void get(const wax::obj &key, wax::obj &val){ +        switch(key.as<dsp_prop_t>()){ +        case DSP_PROP_CODEC_RATE: +            val = _codec_rate; +            return; + +        case DSP_PROP_FREQ_SHIFT: +            val = _freq_shift; +            return; + +        default: UHD_THROW_PROP_GET_ERROR(); +        } +    } + +    void set(const wax::obj &key, const wax::obj &val){ +        switch(key.as<dsp_prop_t>()){ +        case DSP_PROP_FREQ_SHIFT: +            _freq_shift = val.as<double>(); +            return; + +        default: UHD_THROW_PROP_SET_ERROR(); +        } +    } + +    double _codec_rate, _freq_shift; +}; + +/*********************************************************************** + * Test cases + **********************************************************************/ +static const double tolerance = 0.001; + +BOOST_AUTO_TEST_CASE(test_tune_helper_rx){ +    dummy_subdev subdev(1e6); +    dummy_dsp dsp(100e6); + +    std::cout << "Testing tune helper RX automatic LO offset" << std::endl; +    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()); +    BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); +} + +BOOST_AUTO_TEST_CASE(test_tune_helper_tx){ +    dummy_subdev subdev(1e6); +    dummy_dsp dsp(100e6); + +    std::cout << "Testing tune helper TX automatic LO offset" << std::endl; +    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()); +    BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); +} + +BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){ +    dummy_subdev_basic subdev; +    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(), 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()); +    BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance); +} diff --git a/host/test/warning_test.cpp b/host/test/warning_test.cpp new file mode 100644 index 000000000..6202c4270 --- /dev/null +++ b/host/test/warning_test.cpp @@ -0,0 +1,29 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/test/unit_test.hpp> +#include <uhd/utils/warning.hpp> +#include <iostream> + +BOOST_AUTO_TEST_CASE(test_print_warning){ +    std::cerr << "---begin print test ---" << std::endl; +    uhd::print_warning( +        "This is a test print for a warning message.\n" +        "And this is the second line of the test print.\n" +    ); +    std::cerr << "---end print test ---" << std::endl; +} diff --git a/host/uhd.pc.in b/host/uhd.pc.in index 2a34e9cfd..536f254ed 100644 --- a/host/uhd.pc.in +++ b/host/uhd.pc.in @@ -1,10 +1,10 @@  prefix=@CMAKE_INSTALL_PREFIX@  exec_prefix=${prefix} -libdir=${prefix}/@LIBRARY_DIR@ +libdir=${exec_prefix}/@LIBRARY_DIR@  includedir=${prefix}/@INCLUDE_DIR@  Name: @CPACK_PACKAGE_NAME@ -Description: Universal Hardware Driver +Description: @CPACK_PACKAGE_DESCRIPTION_SUMMARY@  Requires:  Version: @CPACK_PACKAGE_VERSION@  Libs: -L${libdir} -luhd diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 1e8e726d2..097317516 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -21,6 +21,7 @@  #include <uhd/usrp/device_props.hpp>  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/usrp/dboard_props.hpp> +#include <uhd/usrp/codec_props.hpp>  #include <uhd/usrp/dsp_props.hpp>  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/dboard_id.hpp> @@ -88,14 +89,25 @@ static std::string get_subdev_pp_string(const std::string &type, wax::obj subdev          ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.min % gain_range.max % gain_range.step << std::endl;      } -    ss << boost::format("Is Quadrature: %s") % (subdev[usrp::SUBDEV_PROP_QUADRATURE].as<bool>()? "Yes" : "No") << std::endl; -    ss << boost::format("Is IQ Swapped: %s") % (subdev[usrp::SUBDEV_PROP_IQ_SWAPPED].as<bool>()? "Yes" : "No") << std::endl; -    ss << boost::format("Is Spectrum Inverted: %s") % (subdev[usrp::SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>()? "Yes" : "No") << std::endl; +    ss << boost::format("Connection Type: %c") % char(subdev[usrp::SUBDEV_PROP_CONNECTION].as<usrp::subdev_conn_t>()) << std::endl;      ss << boost::format("Uses LO offset: %s") % (subdev[usrp::SUBDEV_PROP_USE_LO_OFFSET].as<bool>()? "Yes" : "No") << std::endl;      return ss.str();  } +static std::string get_codec_pp_string(const std::string &type, wax::obj codec){ +    std::stringstream ss; +    ss << boost::format("%s Codec: %s") % type % codec[usrp::CODEC_PROP_NAME].as<std::string>() << std::endl; +    //ss << std::endl; +    prop_names_t gain_names(codec[usrp::CODEC_PROP_GAIN_NAMES].as<prop_names_t>()); +    if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl; +    BOOST_FOREACH(const std::string &gain_name, gain_names){ +        gain_range_t gain_range(codec[named_prop_t(usrp::CODEC_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>()); +        ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.min % gain_range.max % gain_range.step << std::endl; +    } +    return ss.str(); +} +  static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard){      std::stringstream ss;      ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl; @@ -103,6 +115,7 @@ static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard      BOOST_FOREACH(const std::string &subdev_name, dboard[usrp::DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){          ss << make_border(get_subdev_pp_string(type, dboard[named_prop_t(usrp::DBOARD_PROP_SUBDEV, subdev_name)]));      } +    ss << make_border(get_codec_pp_string(type, dboard[usrp::DBOARD_PROP_CODEC]));      return ss.str();  } diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py index d47a4f5f4..1db5e59ce 100755 --- a/host/utils/usrp2_card_burner.py +++ b/host/utils/usrp2_card_burner.py @@ -21,6 +21,7 @@ import tempfile  import subprocess  import urllib  import optparse +import math  import os  import re @@ -59,6 +60,14 @@ def get_dd_path():          return dd_path      return 'dd' +def int_ceil_div(num, den): +    return int(math.ceil(float(num)/float(den))) + +def get_tmp_file(): +    tmp = tempfile.mkstemp() +    os.close(tmp[0]) +    return tmp[1] +  ########################################################################  # list possible devices  ######################################################################## @@ -136,10 +145,12 @@ def get_raw_device_hints():  # write and verify with dd  ########################################################################  def verify_image(image_file, device_file, offset): -    #create a temporary file to store the readback -    tmp = tempfile.mkstemp() -    os.close(tmp[0]) -    tmp_file = tmp[1] +    #create a temporary file to store the readback image +    tmp_file = get_tmp_file() + +    #read the image data +    img_data = open(image_file, 'rb').read() +    count = int_ceil_div(len(img_data), SECTOR_SIZE)      #execute a dd subprocess      verbose = command( @@ -148,24 +159,33 @@ def verify_image(image_file, device_file, offset):          "if=%s"%device_file,          "skip=%d"%(offset/SECTOR_SIZE),          "bs=%d"%SECTOR_SIZE, -        "count=%d"%(MAX_FILE_SIZE/SECTOR_SIZE), +        "count=%d"%count,      ) -    #read in the image and readback -    img_data = open(image_file, 'rb').read() -    tmp_data = open(tmp_file, 'rb').read(len(img_data)) -      #verfy the data +    tmp_data = open(tmp_file, 'rb').read(len(img_data))      if img_data != tmp_data: return 'Verification Failed:\n%s'%verbose      return 'Verification Passed:\n%s'%verbose  def write_image(image_file, device_file, offset): +    #create a temporary file to store the padded image +    tmp_file = get_tmp_file() + +    #write the padded image data +    img_data = open(image_file, 'rb').read() +    count = int_ceil_div(len(img_data), SECTOR_SIZE) +    pad_len = SECTOR_SIZE*count - len(img_data) +    pad_str = ''.join([chr(0)]*pad_len) #zero-padding +    open(tmp_file, 'wb').write(img_data + pad_str) + +    #execute a dd subprocess      verbose = command(          get_dd_path(), -        "if=%s"%image_file, +        "if=%s"%tmp_file,          "of=%s"%device_file,          "seek=%d"%(offset/SECTOR_SIZE),          "bs=%d"%SECTOR_SIZE, +        "count=%d"%count,      )      try: #exec the sync command (only works on linux) diff --git a/host/utils/usrp2_card_burner_gui.py b/host/utils/usrp2_card_burner_gui.py index 61fbadbe3..58b7a514a 100755 --- a/host/utils/usrp2_card_burner_gui.py +++ b/host/utils/usrp2_card_burner_gui.py @@ -17,7 +17,7 @@  #  import usrp2_card_burner #import implementation -import Tkinter, Tkconstants, tkFileDialog, tkFont, tkMessageBox +import Tkinter, tkFileDialog, tkFont, tkMessageBox  import os  class BinFileEntry(Tkinter.Frame): @@ -53,7 +53,7 @@ class BinFileEntry(Tkinter.Frame):  class DeviceEntryWidget(Tkinter.Frame):      """ -    Simple  entry widget for getting the raw device name. +    Simple entry widget for getting the raw device name.      Combines a label, entry, and helpful text box with hints.      """ diff --git a/images/.gitignore b/images/.gitignore new file mode 100644 index 000000000..8947b7a83 --- /dev/null +++ b/images/.gitignore @@ -0,0 +1,2 @@ +/build +/images diff --git a/images/CMakeLists.txt b/images/CMakeLists.txt new file mode 100644 index 000000000..75cb4c9d3 --- /dev/null +++ b/images/CMakeLists.txt @@ -0,0 +1,42 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(UHD-images NONE) + +######################################################################## +# Config Files (include order is important) +######################################################################## +INCLUDE(${CMAKE_SOURCE_DIR}/../host/config/Python.cmake) +INCLUDE(${CMAKE_SOURCE_DIR}/../host/config/Version.cmake) + +######################################################################## +# Setup CPack +######################################################################## +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ettus Research - Universal Hardware Driver Images") +SET(CPACK_PACKAGE_VENDOR              "Ettus Research LLC") +SET(CPACK_PACKAGE_CONTACT             "support@ettus.com") +SET(CPACK_PACKAGE_VERSION_MAJOR ${UHD_VERSION_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${UHD_VERSION_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH ${UHD_VERSION_PATCH}) +INCLUDE(CPack) #include after setting vars +MESSAGE(STATUS "Version: ${CPACK_PACKAGE_VERSION}") + +######################################################################## +# Install Images +######################################################################## +INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/images DESTINATION share/uhd) diff --git a/images/Makefile b/images/Makefile new file mode 100644 index 000000000..6ab54e6ac --- /dev/null +++ b/images/Makefile @@ -0,0 +1,86 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +all: +	@echo "Pick a specific target" + +######################################################################## +# Common Variables +######################################################################## +TOP_DIR = $(shell pwd) +TOP_FW_DIR = $(TOP_DIR)/../firmware +TOP_FPGA_DIR = $(TOP_DIR)/../fpga +BUILT_IMAGES_DIR = $(TOP_DIR)/images +CMAKE_BUILD_DIR = $(TOP_DIR)/build + +##filled in below +IMAGES_LIST = + +######################################################################## +# USRP2 firmware +######################################################################## +_usrp2_fw_dir = $(TOP_FW_DIR)/microblaze +_usrp2_fw_bin = $(BUILT_IMAGES_DIR)/usrp2_fw.bin +IMAGES_LIST += $(_usrp2_fw_bin) + +$(_usrp2_fw_bin): +	cd $(_usrp2_fw_dir) && ./bootstrap +	cd $(_usrp2_fw_dir) && ./configure --host=mb +	make -C $(_usrp2_fw_dir) clean +	make -C $(_usrp2_fw_dir) all +	cp $(_usrp2_fw_dir)/usrp2/usrp2_txrx_uhd.bin $@ + +######################################################################## +# USRP2 fpga +######################################################################## +_usrp2_fpga_dir = $(TOP_FPGA_DIR)/usrp2/top/u2_rev3 +_usrp2_fpga_bin = $(BUILT_IMAGES_DIR)/usrp2_fpga.bin +IMAGES_LIST += $(_usrp2_fpga_bin) + +$(_usrp2_fpga_bin): +	cd $(_usrp2_fpga_dir) && make -f Makefile.udp clean +	cd $(_usrp2_fpga_dir) && make -f Makefile.udp bin +	cp $(_usrp2_fpga_dir)/build-udp/u2_rev3.bin $@ + +######################################################################## +# Build rules +######################################################################## +##little rule to make the images directory +$(BUILT_IMAGES_DIR): +	mkdir $@ + +images: $(BUILT_IMAGES_DIR) $(IMAGES_LIST) + +clean: +	$(RM) -rf $(BUILT_IMAGES_DIR) +	$(RM) -rf $(CMAKE_BUILD_DIR) + +#packages that a linux machine can build +linux-packages: +	mkdir -p $(CMAKE_BUILD_DIR) + +	cd $(CMAKE_BUILD_DIR) && cmake -DCPACK_GENERATOR=TGZ $(TOP_DIR) +	make -C $(CMAKE_BUILD_DIR) package + +	cd $(CMAKE_BUILD_DIR) && cmake -DCPACK_GENERATOR=ZIP $(TOP_DIR) +	make -C $(CMAKE_BUILD_DIR) package + +	cd $(CMAKE_BUILD_DIR) && cmake -DCPACK_GENERATOR=DEB $(TOP_DIR) +	make -C $(CMAKE_BUILD_DIR) package + +	cd $(CMAKE_BUILD_DIR) && cmake -DCPACK_GENERATOR=RPM $(TOP_DIR) +	make -C $(CMAKE_BUILD_DIR) package diff --git a/images/README b/images/README new file mode 100644 index 000000000..ec8391826 --- /dev/null +++ b/images/README @@ -0,0 +1,20 @@ +The images directory contains the following: +    - a Makefile for building firmware and fpga images +    - a CMake file for building an images package + +The Makefile and build systems for the images are probably Unix specific. +Its best to build the images on a Unix system with standard build tools. +The CMake package target will create an images package for your system. + +To build the images (unix): +    make clean +    make images + +To build the package (unix): +    mkdir build +    cd build +    cmake -DCPACK_GENERATOR=<type> ../ +    make package + +The package generator types are described here: +    http://www.cmake.org/Wiki/CMake:CPackPackageGenerators | 
